diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/cache/ChapterCache.kt b/app/src/main/java/eu/kanade/tachiyomi/data/cache/ChapterCache.kt
index b56537ba6d..fa000a16d8 100644
--- a/app/src/main/java/eu/kanade/tachiyomi/data/cache/ChapterCache.kt
+++ b/app/src/main/java/eu/kanade/tachiyomi/data/cache/ChapterCache.kt
@@ -7,7 +7,7 @@ import com.google.gson.reflect.TypeToken
import com.jakewharton.disklrucache.DiskLruCache
import eu.kanade.tachiyomi.data.source.model.Page
import eu.kanade.tachiyomi.util.DiskUtils
-import eu.kanade.tachiyomi.util.saveTo
+import eu.kanade.tachiyomi.util.saveImageTo
import okhttp3.Response
import okio.Okio
import rx.Observable
@@ -185,7 +185,7 @@ class ChapterCache(private val context: Context) {
* @throws IOException image error.
*/
@Throws(IOException::class)
- fun putImageToCache(imageUrl: String, response: Response) {
+ fun putImageToCache(imageUrl: String, response: Response, reencode: Boolean) {
// Initialize editor (edits the values for an entry).
var editor: DiskLruCache.Editor? = null
@@ -195,12 +195,10 @@ class ChapterCache(private val context: Context) {
editor = diskCache.edit(key) ?: throw IOException("Unable to edit key")
// Get OutputStream and write image with Okio.
- response.body().source().saveTo(editor.newOutputStream(0))
+ response.body().source().saveImageTo(editor.newOutputStream(0), reencode)
diskCache.flush()
editor.commit()
- } catch (e: Exception) {
- throw IOException("Unable to save image")
} finally {
response.body().close()
editor?.abortUnlessCommitted()
diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadManager.kt b/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadManager.kt
index ea0677a9ab..c94712a24c 100644
--- a/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadManager.kt
+++ b/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadManager.kt
@@ -228,7 +228,14 @@ class DownloadManager(private val context: Context, private val sourceManager: S
page.status = Page.DOWNLOAD_IMAGE
return source.getImageProgressResponse(page)
.flatMap {
- it.body().source().saveTo(File(directory, filename))
+ try {
+ val file = File(directory, filename)
+ file.parentFile.mkdirs()
+ it.body().source().saveImageTo(file.outputStream(), preferences.reencodeImage())
+ } catch (e: Exception) {
+ it.body().close()
+ throw e
+ }
Observable.just(page)
}
.retry(2)
diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferenceKeys.kt b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferenceKeys.kt
index bfdbe74598..1a6ae9ade9 100644
--- a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferenceKeys.kt
+++ b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferenceKeys.kt
@@ -38,6 +38,8 @@ class PreferenceKeys(context: Context) {
val readWithVolumeKeys = context.getString(R.string.pref_read_with_volume_keys_key)
+ val reencodeImage = context.getString(R.string.pref_reencode_key)
+
val portraitColumns = context.getString(R.string.pref_library_columns_portrait_key)
val landscapeColumns = context.getString(R.string.pref_library_columns_landscape_key)
diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt
index c40d6461c6..01e91736e2 100644
--- a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt
+++ b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt
@@ -78,6 +78,8 @@ class PreferencesHelper(private val context: Context) {
fun readWithVolumeKeys() = rxPrefs.getBoolean(keys.readWithVolumeKeys, false)
+ fun reencodeImage() = prefs.getBoolean(keys.reencodeImage, false)
+
fun portraitColumns() = rxPrefs.getInteger(keys.portraitColumns, 0)
fun landscapeColumns() = rxPrefs.getInteger(keys.landscapeColumns, 0)
diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/source/base/Source.kt b/app/src/main/java/eu/kanade/tachiyomi/data/source/base/Source.kt
index 488d5c079c..23b87aaf96 100644
--- a/app/src/main/java/eu/kanade/tachiyomi/data/source/base/Source.kt
+++ b/app/src/main/java/eu/kanade/tachiyomi/data/source/base/Source.kt
@@ -181,7 +181,7 @@ abstract class Source(context: Context) : BaseSource() {
page.status = Page.DOWNLOAD_IMAGE
return getImageProgressResponse(page)
.flatMap { resp ->
- chapterCache.putImageToCache(page.imageUrl, resp)
+ chapterCache.putImageToCache(page.imageUrl, resp, prefs.reencodeImage())
Observable.just(page)
}
}
diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/OkioExtensions.kt b/app/src/main/java/eu/kanade/tachiyomi/util/OkioExtensions.kt
index 728c6a3892..29f31caa3b 100644
--- a/app/src/main/java/eu/kanade/tachiyomi/util/OkioExtensions.kt
+++ b/app/src/main/java/eu/kanade/tachiyomi/util/OkioExtensions.kt
@@ -1,5 +1,7 @@
package eu.kanade.tachiyomi.util
+import android.graphics.Bitmap
+import android.graphics.BitmapFactory
import okio.BufferedSource
import okio.Okio
import java.io.File
@@ -36,4 +38,25 @@ fun BufferedSource.saveTo(stream: OutputStream) {
it.flush()
}
}
+}
+
+/**
+ * Saves the given source to an output stream and closes both resources.
+ * The source is expected to be an image, and it may reencode the image.
+ *
+ * @param stream the stream where the source is copied.
+ * @param reencode whether to reencode the image or not.
+ */
+fun BufferedSource.saveImageTo(stream: OutputStream, reencode: Boolean = false) {
+ if (reencode) {
+ use {
+ val bitmap = BitmapFactory.decodeStream(it.inputStream())
+ stream.use {
+ bitmap.compress(Bitmap.CompressFormat.JPEG, 100, it)
+ }
+ bitmap.recycle()
+ }
+ } else {
+ saveTo(stream)
+ }
}
\ No newline at end of file
diff --git a/app/src/main/res/values/keys.xml b/app/src/main/res/values/keys.xml
index 91e6f5847b..d7cb6da960 100644
--- a/app/src/main/res/values/keys.xml
+++ b/app/src/main/res/values/keys.xml
@@ -33,6 +33,7 @@
pref_seamless_mode_key
reader_volume_keys
reader_tap
+ reencode_image
pref_filter_downloaded_key
pref_filter_unread_key
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 41fed448a3..b57a2edabb 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -158,6 +158,10 @@
Clear database
Delete manga and chapters that are not in your library
Are you sure? Read chapters and progress of non-library manga will be lost
+ Show warnings
+ Show warning messages during library sync
+ Reencode images
+ Enable reencoding if images can\'t be decoded. Expect best results with Skia
Version
diff --git a/app/src/main/res/xml/pref_advanced.xml b/app/src/main/res/xml/pref_advanced.xml
index 4ef3695ec9..035a98d8cf 100644
--- a/app/src/main/res/xml/pref_advanced.xml
+++ b/app/src/main/res/xml/pref_advanced.xml
@@ -11,4 +11,10 @@
android:key="@string/pref_clear_database_key"
android:summary="@string/pref_clear_database_summary"/>
+
+
\ No newline at end of file