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