diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/base/BaseReader.java b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/base/BaseReader.java
index c3e89a1788..0de867d957 100644
--- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/base/BaseReader.java
+++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/base/BaseReader.java
@@ -2,8 +2,11 @@ package eu.kanade.tachiyomi.ui.reader.viewer.base;
 
 import android.view.MotionEvent;
 
+import com.davemorrissey.labs.subscaleview.decoder.ImageDecoder;
 import com.davemorrissey.labs.subscaleview.decoder.ImageRegionDecoder;
+import com.davemorrissey.labs.subscaleview.decoder.RapidImageDecoder;
 import com.davemorrissey.labs.subscaleview.decoder.RapidImageRegionDecoder;
+import com.davemorrissey.labs.subscaleview.decoder.SkiaImageDecoder;
 import com.davemorrissey.labs.subscaleview.decoder.SkiaImageRegionDecoder;
 
 import java.util.List;
@@ -17,6 +20,7 @@ public abstract class BaseReader extends BaseFragment {
     protected int currentPage;
     protected List<Page> pages;
     protected Class<? extends ImageRegionDecoder> regionDecoderClass;
+    protected Class<? extends ImageDecoder> bitmapDecoderClass;
 
     public static final int RAPID_DECODER = 0;
     public static final int SKIA_DECODER = 1;
@@ -50,14 +54,16 @@ public abstract class BaseReader extends BaseFragment {
     public abstract void onPageListReady(List<Page> pages, int currentPage);
     public abstract boolean onImageTouch(MotionEvent motionEvent);
 
-    public void setRegionDecoderClass(int value) {
+    public void setDecoderClass(int value) {
         switch (value) {
             case RAPID_DECODER:
             default:
                 regionDecoderClass = RapidImageRegionDecoder.class;
+                bitmapDecoderClass = RapidImageDecoder.class;
                 break;
             case SKIA_DECODER:
                 regionDecoderClass = SkiaImageRegionDecoder.class;
+                bitmapDecoderClass = SkiaImageDecoder.class;
                 break;
         }
     }
@@ -66,6 +72,10 @@ public abstract class BaseReader extends BaseFragment {
         return regionDecoderClass;
     }
 
+    public Class<? extends ImageDecoder> getBitmapDecoderClass() {
+        return bitmapDecoderClass;
+    }
+
     public ReaderActivity getReaderActivity() {
         return (ReaderActivity) getActivity();
     }
diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerReader.java b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerReader.java
index c11570534e..d3d49c2bc3 100644
--- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerReader.java
+++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerReader.java
@@ -63,7 +63,7 @@ public abstract class PagerReader extends BaseReader {
         subscriptions = new CompositeSubscription();
         subscriptions.add(getReaderActivity().getPreferences().imageDecoder()
                 .asObservable()
-                .doOnNext(this::setRegionDecoderClass)
+                .doOnNext(this::setDecoderClass)
                 .skip(1)
                 .distinctUntilChanged()
                 .subscribe(v -> adapter.notifyDataSetChanged()));
diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerReaderFragment.java b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerReaderFragment.java
index 4c3125225b..ffcd8429c0 100644
--- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerReaderFragment.java
+++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerReaderFragment.java
@@ -66,6 +66,7 @@ public class PagerReaderFragment extends BaseFragment {
         imageView.setPanLimit(SubsamplingScaleImageView.PAN_LIMIT_INSIDE);
         imageView.setMinimumScaleType(parentFragment.scaleType);
         imageView.setRegionDecoderClass(parentFragment.getRegionDecoderClass());
+        imageView.setBitmapDecoderClass(parentFragment.getBitmapDecoderClass());
         imageView.setOnTouchListener((v, motionEvent) -> parentFragment.onImageTouch(motionEvent));
         imageView.setOnImageEventListener(new SubsamplingScaleImageView.DefaultOnImageEventListener() {
             @Override
diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonHolder.java b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonHolder.java
index fdc90ebba1..ad10fbf20b 100644
--- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonHolder.java
+++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonHolder.java
@@ -38,6 +38,8 @@ public class WebtoonHolder extends RecyclerView.ViewHolder {
         imageView.setPanLimit(SubsamplingScaleImageView.PAN_LIMIT_INSIDE);
         imageView.setMinimumScaleType(SubsamplingScaleImageView.SCALE_TYPE_FIT_WIDTH);
         imageView.setMaxScale(10);
+        imageView.setRegionDecoderClass(adapter.getReader().getRegionDecoderClass());
+        imageView.setBitmapDecoderClass(adapter.getReader().getBitmapDecoderClass());
         imageView.setOnTouchListener(touchListener);
         imageView.setMaxDimensions(maxDim, maxDim);
         imageView.setOnImageEventListener(new SubsamplingScaleImageView.DefaultOnImageEventListener() {
@@ -99,7 +101,6 @@ public class WebtoonHolder extends RecyclerView.ViewHolder {
         setErrorButtonVisible(false);
         setProgressVisible(false);
         setImageVisible(true);
-        imageView.setRegionDecoderClass(adapter.getReader().getRegionDecoderClass());
         imageView.setImage(ImageSource.uri(page.getImagePath()));
     }
 
diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonReader.java b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonReader.java
index cdc574d046..f7adb06f45 100644
--- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonReader.java
+++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonReader.java
@@ -45,10 +45,10 @@ public class WebtoonReader extends BaseReader {
 
         decoderSubscription = getReaderActivity().getPreferences().imageDecoder()
                 .asObservable()
-                .doOnNext(this::setRegionDecoderClass)
+                .doOnNext(this::setDecoderClass)
                 .skip(1)
                 .distinctUntilChanged()
-                .subscribe(v -> adapter.notifyDataSetChanged());
+                .subscribe(v -> recycler.setAdapter(adapter));
 
         gestureDetector = new GestureDetector(getActivity(), new SimpleOnGestureListener() {
             @Override
diff --git a/libs/SubsamplingScaleImageView/src/com/davemorrissey/labs/subscaleview/decoder/RapidImageDecoder.java b/libs/SubsamplingScaleImageView/src/com/davemorrissey/labs/subscaleview/decoder/RapidImageDecoder.java
new file mode 100644
index 0000000000..432468bdfb
--- /dev/null
+++ b/libs/SubsamplingScaleImageView/src/com/davemorrissey/labs/subscaleview/decoder/RapidImageDecoder.java
@@ -0,0 +1,24 @@
+package com.davemorrissey.labs.subscaleview.decoder;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.net.Uri;
+
+import rapid.decoder.BitmapDecoder;
+
+/**
+ * A very simple implementation of {@link com.davemorrissey.labs.subscaleview.decoder.ImageRegionDecoder}
+ * using the RapidDecoder library (https://github.com/suckgamony/RapidDecoder). For PNGs, this can
+ * give more reliable decoding and better performance. For JPGs, it is slower and can run out of
+ * memory with large images, but has better support for grayscale and CMYK images.
+ *
+ * This is an incomplete and untested implementation provided as an example only.
+ */
+public class RapidImageDecoder implements ImageDecoder {
+
+    @Override
+    public Bitmap decode(Context context, Uri uri) throws Exception {
+        return BitmapDecoder.from(context, uri).useBuiltInDecoder(true).config(Bitmap.Config.RGB_565).decode();
+    }
+
+}
\ No newline at end of file