diff --git a/booklore-api/src/main/java/com/adityachandel/booklore/model/dto/settings/KoboSettings.java b/booklore-api/src/main/java/com/adityachandel/booklore/model/dto/settings/KoboSettings.java
index 1a6f1138..47c0e1f2 100644
--- a/booklore-api/src/main/java/com/adityachandel/booklore/model/dto/settings/KoboSettings.java
+++ b/booklore-api/src/main/java/com/adityachandel/booklore/model/dto/settings/KoboSettings.java
@@ -11,4 +11,5 @@ public class KoboSettings {
private boolean convertCbxToEpub;
private int conversionLimitInMbForCbx;
private boolean forceEnableHyphenation;
+ private int conversionImageCompressionPercentage;
}
diff --git a/booklore-api/src/main/java/com/adityachandel/booklore/service/appsettings/SettingPersistenceHelper.java b/booklore-api/src/main/java/com/adityachandel/booklore/service/appsettings/SettingPersistenceHelper.java
index 9548deee..d1a0a6b1 100644
--- a/booklore-api/src/main/java/com/adityachandel/booklore/service/appsettings/SettingPersistenceHelper.java
+++ b/booklore-api/src/main/java/com/adityachandel/booklore/service/appsettings/SettingPersistenceHelper.java
@@ -255,6 +255,7 @@ public class SettingPersistenceHelper {
.conversionLimitInMb(100)
.convertCbxToEpub(false)
.conversionLimitInMbForCbx(100)
+ .conversionImageCompressionPercentage(85)
.forceEnableHyphenation(false)
.build();
}
diff --git a/booklore-api/src/main/java/com/adityachandel/booklore/service/book/BookDownloadService.java b/booklore-api/src/main/java/com/adityachandel/booklore/service/book/BookDownloadService.java
index a5b93542..3ba1ae69 100644
--- a/booklore-api/src/main/java/com/adityachandel/booklore/service/book/BookDownloadService.java
+++ b/booklore-api/src/main/java/com/adityachandel/booklore/service/book/BookDownloadService.java
@@ -96,6 +96,7 @@ public class BookDownloadService {
boolean convertEpubToKepub = isEpub && koboSettings.isConvertToKepub() && bookEntity.getFileSizeKb() <= (long) koboSettings.getConversionLimitInMb() * 1024;
boolean convertCbxToEpub = isCbx && koboSettings.isConvertCbxToEpub() && bookEntity.getFileSizeKb() <= (long) koboSettings.getConversionLimitInMbForCbx() * 1024;
+ int compressionPercentage = koboSettings.getConversionImageCompressionPercentage();
Path tempDir = null;
try {
File inputFile = new File(FileUtils.getBookFullPath(bookEntity));
@@ -106,7 +107,7 @@ public class BookDownloadService {
}
if (convertCbxToEpub) {
- fileToSend = cbxConversionService.convertCbxToEpub(inputFile, tempDir.toFile(), bookEntity);
+ fileToSend = cbxConversionService.convertCbxToEpub(inputFile, tempDir.toFile(), bookEntity,compressionPercentage);
}
if (convertEpubToKepub) {
diff --git a/booklore-api/src/main/java/com/adityachandel/booklore/service/kobo/CbxConversionService.java b/booklore-api/src/main/java/com/adityachandel/booklore/service/kobo/CbxConversionService.java
index 0215559d..31a3ad51 100644
--- a/booklore-api/src/main/java/com/adityachandel/booklore/service/kobo/CbxConversionService.java
+++ b/booklore-api/src/main/java/com/adityachandel/booklore/service/kobo/CbxConversionService.java
@@ -102,20 +102,20 @@ public class CbxConversionService {
* @throws IllegalArgumentException if the file format is not supported
* @throws IllegalStateException if no valid images are found in the archive
*/
- public File convertCbxToEpub(File cbxFile, File tempDir, BookEntity bookEntity)
+ public File convertCbxToEpub(File cbxFile, File tempDir, BookEntity bookEntity, int compressionPercentage)
throws IOException, TemplateException, RarException {
validateInputs(cbxFile, tempDir);
log.info("Starting CBX to EPUB conversion for: {}", cbxFile.getName());
- File outputFile = executeCbxConversion(cbxFile, tempDir, bookEntity);
+ File outputFile = executeCbxConversion(cbxFile, tempDir, bookEntity,compressionPercentage);
log.info("Successfully converted {} to {} (size: {} bytes)",
cbxFile.getName(), outputFile.getName(), outputFile.length());
return outputFile;
}
- private File executeCbxConversion(File cbxFile, File tempDir, BookEntity bookEntity)
+ private File executeCbxConversion(File cbxFile, File tempDir, BookEntity bookEntity,int compressionPercentage)
throws IOException, TemplateException, RarException {
Path epubFilePath = Paths.get(tempDir.getAbsolutePath(), cbxFile.getName() + ".epub");
@@ -136,7 +136,7 @@ public class CbxConversionService {
addMetaInfContainer(zipOut);
addStylesheet(zipOut);
- List contentGroups = addImagesAndPages(zipOut, imagePaths);
+ List contentGroups = addImagesAndPages(zipOut, imagePaths,compressionPercentage);
addContentOpf(zipOut, bookEntity, contentGroups);
addTocNcx(zipOut, bookEntity, contentGroups);
@@ -340,13 +340,13 @@ public class CbxConversionService {
zipOut.closeArchiveEntry();
}
- private List addImagesAndPages(ZipArchiveOutputStream zipOut, List imagePaths)
+ private List addImagesAndPages(ZipArchiveOutputStream zipOut, List imagePaths,int compressionPercentage)
throws IOException, TemplateException {
List contentGroups = new ArrayList<>();
if (!imagePaths.isEmpty()) {
- addImageToZipFromPath(zipOut, COVER_IMAGE_PATH, imagePaths.getFirst());
+ addImageToZipFromPath(zipOut, COVER_IMAGE_PATH, imagePaths.getFirst(),compressionPercentage);
}
for (int i = 0; i < imagePaths.size(); i++) {
@@ -358,7 +358,7 @@ public class CbxConversionService {
String imagePath = IMAGE_ROOT_PATH + imageFileName;
String htmlPath = HTML_ROOT_PATH + htmlFileName;
- addImageToZipFromPath(zipOut, imagePath, imageSourcePath);
+ addImageToZipFromPath(zipOut, imagePath, imageSourcePath,compressionPercentage);
String htmlContent = generatePageHtml(imageFileName, i + 1);
ZipArchiveEntry htmlEntry = new ZipArchiveEntry(htmlPath);
@@ -372,7 +372,7 @@ public class CbxConversionService {
return contentGroups;
}
- private void addImageToZipFromPath(ZipArchiveOutputStream zipOut, String epubImagePath, Path sourceImagePath)
+ private void addImageToZipFromPath(ZipArchiveOutputStream zipOut, String epubImagePath, Path sourceImagePath,int compressionPercentage)
throws IOException {
ZipArchiveEntry imageEntry = new ZipArchiveEntry(epubImagePath);
zipOut.putArchiveEntry(imageEntry);
@@ -385,7 +385,7 @@ public class CbxConversionService {
try (InputStream fis = Files.newInputStream(sourceImagePath)) {
BufferedImage image = ImageIO.read(fis);
if (image != null) {
- writeJpegImage(image, zipOut, 0.85f);
+ writeJpegImage(image, zipOut, compressionPercentage/100f);
} else {
log.warn("Could not decode image {}, copying raw bytes", sourceImagePath.getFileName());
try (InputStream rawStream = Files.newInputStream(sourceImagePath)) {
diff --git a/booklore-api/src/test/java/com/adityachandel/booklore/service/kobo/CbxConversionIntegrationTest.java b/booklore-api/src/test/java/com/adityachandel/booklore/service/kobo/CbxConversionIntegrationTest.java
index 26c5fbd1..6910f99c 100644
--- a/booklore-api/src/test/java/com/adityachandel/booklore/service/kobo/CbxConversionIntegrationTest.java
+++ b/booklore-api/src/test/java/com/adityachandel/booklore/service/kobo/CbxConversionIntegrationTest.java
@@ -42,7 +42,7 @@ class CbxConversionIntegrationTest {
File testCbzFile = createTestComicCbzFile();
BookEntity bookMetadata = createTestBookMetadata();
- File epubFile = conversionService.convertCbxToEpub(testCbzFile, tempDir.toFile(), bookMetadata);
+ File epubFile = conversionService.convertCbxToEpub(testCbzFile, tempDir.toFile(), bookMetadata,85);
assertThat(epubFile)
.exists()
diff --git a/booklore-api/src/test/java/com/adityachandel/booklore/service/kobo/CbxConversionServiceTest.java b/booklore-api/src/test/java/com/adityachandel/booklore/service/kobo/CbxConversionServiceTest.java
index dfbad12a..ed4d4170 100644
--- a/booklore-api/src/test/java/com/adityachandel/booklore/service/kobo/CbxConversionServiceTest.java
+++ b/booklore-api/src/test/java/com/adityachandel/booklore/service/kobo/CbxConversionServiceTest.java
@@ -42,7 +42,7 @@ class CbxConversionServiceTest {
@Test
void convertCbxToEpub_WithValidCbzFile_ShouldGenerateValidEpub() throws IOException, TemplateException, RarException {
- File epubFile = cbxConversionService.convertCbxToEpub(testCbzFile, tempDir.toFile(), testBookEntity);
+ File epubFile = cbxConversionService.convertCbxToEpub(testCbzFile, tempDir.toFile(), testBookEntity,85);
assertThat(epubFile).exists();
assertThat(epubFile.getName()).endsWith(".epub");
@@ -53,7 +53,7 @@ class CbxConversionServiceTest {
@Test
void convertCbxToEpub_WithNullCbxFile_ShouldThrowException() {
- assertThatThrownBy(() -> cbxConversionService.convertCbxToEpub(null, tempDir.toFile(), testBookEntity))
+ assertThatThrownBy(() -> cbxConversionService.convertCbxToEpub(null, tempDir.toFile(), testBookEntity,85))
.isInstanceOf(IllegalArgumentException.class)
.hasMessageContaining("Invalid CBX file");
}
@@ -62,7 +62,7 @@ class CbxConversionServiceTest {
void convertCbxToEpub_WithNonExistentFile_ShouldThrowException() {
File nonExistentFile = new File(tempDir.toFile(), "non-existent.cbz");
- assertThatThrownBy(() -> cbxConversionService.convertCbxToEpub(nonExistentFile, tempDir.toFile(), testBookEntity))
+ assertThatThrownBy(() -> cbxConversionService.convertCbxToEpub(nonExistentFile, tempDir.toFile(), testBookEntity,85))
.isInstanceOf(IllegalArgumentException.class)
.hasMessageContaining("Invalid CBX file");
}
@@ -71,14 +71,14 @@ class CbxConversionServiceTest {
void convertCbxToEpub_WithUnsupportedFileFormat_ShouldThrowException() throws IOException {
File unsupportedFile = Files.createFile(tempDir.resolve("test.txt")).toFile();
- assertThatThrownBy(() -> cbxConversionService.convertCbxToEpub(unsupportedFile, tempDir.toFile(), testBookEntity))
+ assertThatThrownBy(() -> cbxConversionService.convertCbxToEpub(unsupportedFile, tempDir.toFile(), testBookEntity,85))
.isInstanceOf(IllegalArgumentException.class)
.hasMessageContaining("Unsupported file format");
}
@Test
void convertCbxToEpub_WithNullTempDir_ShouldThrowException() {
- assertThatThrownBy(() -> cbxConversionService.convertCbxToEpub(testCbzFile, null, testBookEntity))
+ assertThatThrownBy(() -> cbxConversionService.convertCbxToEpub(testCbzFile, null, testBookEntity,85))
.isInstanceOf(IllegalArgumentException.class)
.hasMessageContaining("Invalid temp directory");
}
@@ -87,7 +87,7 @@ class CbxConversionServiceTest {
void convertCbxToEpub_WithEmptyCbzFile_ShouldThrowException() throws IOException {
File emptyCbzFile = createEmptyCbzFile();
- assertThatThrownBy(() -> cbxConversionService.convertCbxToEpub(emptyCbzFile, tempDir.toFile(), testBookEntity))
+ assertThatThrownBy(() -> cbxConversionService.convertCbxToEpub(emptyCbzFile, tempDir.toFile(), testBookEntity,85))
.isInstanceOf(IllegalStateException.class)
.hasMessageContaining("No valid images found");
}
@@ -118,7 +118,7 @@ class CbxConversionServiceTest {
@Test
void convertCbxToEpub_WithNullBookEntity_ShouldUseDefaultMetadata() throws IOException, TemplateException, RarException {
- File epubFile = cbxConversionService.convertCbxToEpub(testCbzFile, tempDir.toFile(), null);
+ File epubFile = cbxConversionService.convertCbxToEpub(testCbzFile, tempDir.toFile(), null,85);
assertThat(epubFile).exists();
verifyEpubStructure(epubFile);
@@ -128,7 +128,7 @@ class CbxConversionServiceTest {
void convertCbxToEpub_WithMultipleImages_ShouldPreservePageOrder() throws IOException, TemplateException, RarException {
File multiPageCbzFile = createMultiPageCbzFile();
- File epubFile = cbxConversionService.convertCbxToEpub(multiPageCbzFile, tempDir.toFile(), testBookEntity);
+ File epubFile = cbxConversionService.convertCbxToEpub(multiPageCbzFile, tempDir.toFile(), testBookEntity,85);
assertThat(epubFile).exists();
verifyPageOrderInEpub(epubFile, 5);
diff --git a/booklore-ui/src/app/features/settings/device-settings/component/kobo-sync-settings/kobo-sync-settings-component.html b/booklore-ui/src/app/features/settings/device-settings/component/kobo-sync-settings/kobo-sync-settings-component.html
index d3631097..134a7328 100644
--- a/booklore-ui/src/app/features/settings/device-settings/component/kobo-sync-settings/kobo-sync-settings-component.html
+++ b/booklore-ui/src/app/features/settings/device-settings/component/kobo-sync-settings/kobo-sync-settings-component.html
@@ -263,7 +263,26 @@
-
+
+
+
+
Conversion image compression: {{ koboSettings.conversionImageCompressionPercentage }}%
+
+
+
+ Comic book conversions can sometimes result in very large files. This setting allows you to compress the images during conversion to prevent size from shooting up.
+
+
+
diff --git a/booklore-ui/src/app/features/settings/device-settings/component/kobo-sync-settings/kobo-sync-settings-component.ts b/booklore-ui/src/app/features/settings/device-settings/component/kobo-sync-settings/kobo-sync-settings-component.ts
index 0847e345..15163e3d 100644
--- a/booklore-ui/src/app/features/settings/device-settings/component/kobo-sync-settings/kobo-sync-settings-component.ts
+++ b/booklore-ui/src/app/features/settings/device-settings/component/kobo-sync-settings/kobo-sync-settings-component.ts
@@ -48,6 +48,7 @@ export class KoboSyncSettingsComponent implements OnInit, OnDestroy {
convertToKepub: false,
conversionLimitInMb: 100,
convertCbxToEpub: false,
+ conversionImageCompressionPercentage: 85,
conversionLimitInMbForCbx: 100,
forceEnableHyphenation: false
};
@@ -138,6 +139,7 @@ export class KoboSyncSettingsComponent implements OnInit, OnDestroy {
this.koboSettings.convertCbxToEpub = settings?.koboSettings?.convertCbxToEpub ?? false;
this.koboSettings.conversionLimitInMbForCbx = settings?.koboSettings?.conversionLimitInMbForCbx ?? 100;
this.koboSettings.forceEnableHyphenation = settings?.koboSettings?.forceEnableHyphenation ?? false;
+ this.koboSettings.conversionImageCompressionPercentage = settings?.koboSettings?.conversionImageCompressionPercentage ?? 85;
});
}
diff --git a/booklore-ui/src/app/shared/model/app-settings.model.ts b/booklore-ui/src/app/shared/model/app-settings.model.ts
index ab1b51c3..13168f50 100644
--- a/booklore-ui/src/app/shared/model/app-settings.model.ts
+++ b/booklore-ui/src/app/shared/model/app-settings.model.ts
@@ -102,6 +102,7 @@ export interface PublicReviewSettings {
export interface KoboSettings {
convertToKepub: boolean;
conversionLimitInMb: number;
+ conversionImageCompressionPercentage: number;
convertCbxToEpub: boolean;
conversionLimitInMbForCbx: number;
forceEnableHyphenation: boolean;