diff --git a/src/main/java/azgracompress/benchmark/BenchmarkBase.java b/src/main/java/azgracompress/benchmark/BenchmarkBase.java
index 8e20bd7f21a9ced52e7a190fb169f937a4860d1d..622dadd9226fc445e6bde059c7978e24c5fef406 100644
--- a/src/main/java/azgracompress/benchmark/BenchmarkBase.java
+++ b/src/main/java/azgracompress/benchmark/BenchmarkBase.java
@@ -33,27 +33,11 @@ abstract class BenchmarkBase {
 
     protected final int workerCount;
 
-    protected BenchmarkBase(final String inputFile,
-                            final String outputDirectory,
-                            final int[] planes,
-                            final V3i rawImageDims) {
-        this.inputFile = inputFile;
-        this.outputDirectory = outputDirectory;
-        this.planes = planes;
-        this.rawImageDims = rawImageDims;
-
-        hasReferencePlane = false;
-        referencePlaneIndex = -1;
-        codebookSize = 256;
-
-        hasCacheFolder = false;
-        cacheFolder = null;
-        hasGeneralQuantizer = false;
-
-        workerCount = 1;
-    }
+    protected final ParsedCliOptions options;
 
     protected BenchmarkBase(final ParsedCliOptions options) {
+        this.options = options;
+
         final InputFileInfo ifi = options.getInputFileInfo();
         this.inputFile = ifi.getFilePath();
         this.outputDirectory = options.getOutputFile();
@@ -98,32 +82,32 @@ abstract class BenchmarkBase {
         return file.getAbsolutePath();
     }
 
-    /**
-     * Load u16 plane from RAW file.
-     *
-     * @param planeIndex Zero based plane index.
-     * @return u16 plane.
-     */
-    protected ImageU16 loadPlane(final int planeIndex) {
-        try {
-            return RawDataIO.loadImageU16(inputFile, rawImageDims, planeIndex);
-        } catch (Exception ex) {
-            ex.printStackTrace();
-        }
-        return null;
-    }
-
-    /**
-     * Load U16 plane data from RAW file.
-     *
-     * @param planeIndex Zero based plane index.
-     * @return U16 array of image plane data.
-     */
-    protected int[] loadPlaneData(final int planeIndex) {
-        ImageU16 plane = loadPlane(planeIndex);
-
-        return (plane != null) ? plane.getData() : new int[0];
-    }
+    //    /**
+    //     * Load u16 plane from RAW file.
+    //     *
+    //     * @param planeIndex Zero based plane index.
+    //     * @return u16 plane.
+    //     */
+    //    protected ImageU16 loadPlane(final int planeIndex) {
+    //        try {
+    //            return RawDataIO.loadImageU16(inputFile, rawImageDims, planeIndex);
+    //        } catch (Exception ex) {
+    //            ex.printStackTrace();
+    //        }
+    //        return null;
+    //    }
+
+    //    /**
+    //     * Load U16 plane data from RAW file.
+    //     *
+    //     * @param planeIndex Zero based plane index.
+    //     * @return U16 array of image plane data.
+    //     */
+    //    protected int[] loadPlaneData(final int planeIndex) {
+    //        ImageU16 plane = loadPlane(planeIndex);
+    //
+    //        return (plane != null) ? plane.getData() : new int[0];
+    //    }
 
 
     /**
diff --git a/src/main/java/azgracompress/benchmark/ScalarQuantizationBenchmark.java b/src/main/java/azgracompress/benchmark/ScalarQuantizationBenchmark.java
index 6c0897a26ffe6a8b60a2ec49cff1bb617cade5a9..13f3b7aa5c405b8a0fd89d5bd72d950fe054d294 100644
--- a/src/main/java/azgracompress/benchmark/ScalarQuantizationBenchmark.java
+++ b/src/main/java/azgracompress/benchmark/ScalarQuantizationBenchmark.java
@@ -2,9 +2,9 @@ package azgracompress.benchmark;
 
 import azgracompress.U16;
 import azgracompress.cli.ParsedCliOptions;
-import azgracompress.data.V3i;
 import azgracompress.de.DeException;
 import azgracompress.de.shade.ILShadeSolver;
+import azgracompress.io.ConcretePlaneLoader;
 import azgracompress.quantization.QTrainIteration;
 import azgracompress.quantization.QuantizationValueCache;
 import azgracompress.quantization.scalar.LloydMaxU16ScalarQuantization;
@@ -18,13 +18,6 @@ import java.io.OutputStreamWriter;
 public class ScalarQuantizationBenchmark extends BenchmarkBase {
     private boolean useDiffEvolution = false;
 
-    public ScalarQuantizationBenchmark(final String inputFile,
-                                       final String outputDirectory,
-                                       final int[] planes,
-                                       final V3i rawImageDims) {
-        super(inputFile, outputDirectory, planes, rawImageDims);
-    }
-
     public ScalarQuantizationBenchmark(final ParsedCliOptions options) {
         super(options);
     }
@@ -32,12 +25,22 @@ public class ScalarQuantizationBenchmark extends BenchmarkBase {
 
     @Override
     public void startBenchmark() {
+        ConcretePlaneLoader planeLoader = null;
+        try {
+            planeLoader = new ConcretePlaneLoader(options.getInputFileInfo());
+        } catch (Exception e) {
+            e.printStackTrace();
+            System.err.println("Unable to create SCIFIO reader.");
+            return;
+        }
+
         if (planes.length < 1) {
             return;
         }
         boolean dirCreated = new File(this.outputDirectory).mkdirs();
         System.out.println(String.format("|CODEBOOK| = %d", codebookSize));
         ScalarQuantizer quantizer = null;
+
         if (hasCacheFolder) {
             System.out.println("Loading codebook from cache");
             QuantizationValueCache cache = new QuantizationValueCache(cacheFolder);
@@ -51,11 +54,16 @@ public class ScalarQuantizationBenchmark extends BenchmarkBase {
             }
             System.out.println("Created quantizer from cache");
         } else if (hasReferencePlane) {
-            final int[] refPlaneData = loadPlaneData(referencePlaneIndex);
-            if (refPlaneData.length == 0) {
+            final int[] refPlaneData;
+
+            try {
+                refPlaneData = planeLoader.loadPlaneU16(referencePlaneIndex).getData();
+            } catch (IOException e) {
+                e.printStackTrace();
                 System.err.println("Failed to load reference plane data.");
                 return;
             }
+
             if (useDiffEvolution) {
                 quantizer = trainDifferentialEvolution(refPlaneData, codebookSize);
             } else {
@@ -67,7 +75,14 @@ public class ScalarQuantizationBenchmark extends BenchmarkBase {
         for (final int planeIndex : planes) {
             System.out.println(String.format("Loading plane %d ...", planeIndex));
             // NOTE(Moravec): Actual planeIndex is zero based.
-            final int[] planeData = loadPlaneData(planeIndex);
+            final int[] planeData;
+            try {
+                planeData = planeLoader.loadPlaneU16(planeIndex).getData();
+            } catch (IOException e) {
+                e.printStackTrace();
+                System.err.println("Failed to load plane data.");
+                return;
+            }
             if (planeData.length == 0) {
                 System.err.println(String.format("Failed to load plane %d data. Skipping plane.", planeIndex));
                 return;
diff --git a/src/main/java/azgracompress/benchmark/VectorQuantizationBenchmark.java b/src/main/java/azgracompress/benchmark/VectorQuantizationBenchmark.java
index 16562b64f6f06c7ced5a4b3207b7a584a55d94ee..ebae87d18614acc4b3876f727139b376c2861f77 100644
--- a/src/main/java/azgracompress/benchmark/VectorQuantizationBenchmark.java
+++ b/src/main/java/azgracompress/benchmark/VectorQuantizationBenchmark.java
@@ -2,6 +2,7 @@ package azgracompress.benchmark;
 
 import azgracompress.cli.ParsedCliOptions;
 import azgracompress.data.*;
+import azgracompress.io.ConcretePlaneLoader;
 import azgracompress.quantization.QuantizationValueCache;
 import azgracompress.quantization.vector.CodebookEntry;
 import azgracompress.quantization.vector.LBGResult;
@@ -17,10 +18,6 @@ public class VectorQuantizationBenchmark extends BenchmarkBase {
 
     final static V2i DEFAULT_QVECTOR = new V2i(3, 3);
 
-    public VectorQuantizationBenchmark(String inputFile, String outputDirectory, int[] planes, V3i rawImageDims) {
-        super(inputFile, outputDirectory, planes, rawImageDims);
-    }
-
     public VectorQuantizationBenchmark(final ParsedCliOptions options) {
         super(options);
     }
@@ -51,6 +48,14 @@ public class VectorQuantizationBenchmark extends BenchmarkBase {
         if (planes.length < 1) {
             return;
         }
+        ConcretePlaneLoader planeLoader = null;
+        try {
+            planeLoader = new ConcretePlaneLoader(options.getInputFileInfo());
+        } catch (Exception e) {
+            e.printStackTrace();
+            System.err.println("Unable to create SCIFIO reader.");
+            return;
+        }
         if (qVector.getY() > 1) {
             System.out.println("2D qVector");
         } else {
@@ -77,9 +82,11 @@ public class VectorQuantizationBenchmark extends BenchmarkBase {
             }
             System.out.println("Created quantizer from cache");
         } else if (hasReferencePlane) {
-            final ImageU16 plane = loadPlane(referencePlaneIndex);
-
-            if (plane == null) {
+            final ImageU16 plane;
+            try {
+                plane = planeLoader.loadPlaneU16(referencePlaneIndex);
+            } catch (IOException e) {
+                e.printStackTrace();
                 System.err.println("Failed to load reference plane data.");
                 return;
             }
@@ -93,11 +100,12 @@ public class VectorQuantizationBenchmark extends BenchmarkBase {
 
         for (final int planeIndex : planes) {
             System.out.println(String.format("Loading plane %d ...", planeIndex));
-            // NOTE(Moravec): Actual planeIndex is zero based.
-
-            final ImageU16 plane = loadPlane(planeIndex - 1);
 
-            if (plane == null) {
+            final ImageU16 plane;
+            try {
+                plane = planeLoader.loadPlaneU16(planeIndex);
+            } catch (IOException e) {
+                e.printStackTrace();
                 System.err.println(String.format("Failed to load plane %d data. Skipping plane.", planeIndex));
                 return;
             }
diff --git a/src/main/java/azgracompress/cli/InputFileInfo.java b/src/main/java/azgracompress/cli/InputFileInfo.java
index 48597c6a258a4bac1d2b6065a4e6f38ce6c4c40e..b8a6f073bff769397fa234a23974069e698f1658 100644
--- a/src/main/java/azgracompress/cli/InputFileInfo.java
+++ b/src/main/java/azgracompress/cli/InputFileInfo.java
@@ -12,6 +12,8 @@ public class InputFileInfo {
      */
     private final String filePath;
 
+    private boolean isRAW = true;
+
     private V3i dimension;
 
     private boolean planeIndexSet = false;
@@ -76,4 +78,12 @@ public class InputFileInfo {
     public V2i getPlaneRange() {
         return planeRange;
     }
+
+    public boolean isRAW() {
+        return isRAW;
+    }
+
+    public void setIsRaw(boolean RAW) {
+        isRAW = RAW;
+    }
 }
diff --git a/src/main/java/azgracompress/cli/ParsedCliOptions.java b/src/main/java/azgracompress/cli/ParsedCliOptions.java
index 549fea1d867beaaa24788ecd0640bc1e2ee49716..e1beddebec38f9ffb6e3c0b59945f236488d169d 100644
--- a/src/main/java/azgracompress/cli/ParsedCliOptions.java
+++ b/src/main/java/azgracompress/cli/ParsedCliOptions.java
@@ -130,7 +130,6 @@ public class ParsedCliOptions {
             return;
         }
 
-
         inputFileInfo = new InputFileInfo(inputFileArguments[0]);
 
         // Decompress and Inspect methods doesn't require additional file information.
@@ -159,7 +158,8 @@ public class ParsedCliOptions {
         // inputFileInfo is already created with TIFF type.
         //        assert (inputFileInfo.getFileType() == FileType.TIFF) : "Not TIFF type in parse Tiff arguments.";
 
-        Reader reader = null;
+        inputFileInfo.setIsRaw(false);
+        Reader reader;
         try {
             reader = ScifioWrapper.getReader(inputFileInfo.getFilePath());
         } catch (IOException | FormatException e) {
@@ -223,6 +223,7 @@ public class ParsedCliOptions {
             return;
         }
 
+        inputFileInfo.setIsRaw(true);
         parseImageDims(inputFileArguments[1], errorBuilder);
 
         // User specified plane index or plane range.
diff --git a/src/main/java/azgracompress/cli/functions/MeasurePlaneErrorFunction.java b/src/main/java/azgracompress/cli/functions/MeasurePlaneErrorFunction.java
index 2fac49bdcd488f1d9ecf5fe300f50660e3709239..b44f108527e39889f04a44bc6ba2585e3a42a0e9 100644
--- a/src/main/java/azgracompress/cli/functions/MeasurePlaneErrorFunction.java
+++ b/src/main/java/azgracompress/cli/functions/MeasurePlaneErrorFunction.java
@@ -2,15 +2,6 @@ package azgracompress.cli.functions;
 
 import azgracompress.cli.CustomFunctionBase;
 import azgracompress.cli.ParsedCliOptions;
-import azgracompress.data.ImageU16;
-import azgracompress.data.V3i;
-import azgracompress.io.RawDataIO;
-import azgracompress.utilities.Utils;
-
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.OutputStreamWriter;
-import java.util.Arrays;
 
 public class MeasurePlaneErrorFunction extends CustomFunctionBase {
     public MeasurePlaneErrorFunction(ParsedCliOptions options) {
@@ -66,53 +57,53 @@ public class MeasurePlaneErrorFunction extends CustomFunctionBase {
     }
 
     private boolean reportPlaneDifference(final String compressedFile, final String reportFile) {
-        final String referenceFile = "D:\\biology\\tiff_data\\benchmark\\fused_tp_10_ch_1_16bit.raw";
-
-        final V3i dims = new V3i(1041, 996, 946);
-        final int planePixelCount = dims.getX() * dims.getY();
-        System.out.println(options.report());
-        System.out.println("Run custom function.");
-        ImageU16 compressedPlane = null;
-        ImageU16 originalPlane = null;
-        ImageU16 differencePlane = null;
-
-        PlaneError[] planeErrors = new PlaneError[dims.getZ()];
-
-        for (int planeIndex = 0; planeIndex < dims.getZ(); planeIndex++) {
-            try {
-                originalPlane = RawDataIO.loadImageU16(referenceFile, dims, planeIndex);
-                compressedPlane = RawDataIO.loadImageU16(compressedFile, dims, planeIndex);
-            } catch (IOException e) {
-                e.printStackTrace();
-                return true;
-            }
-            final int[] diffData = Utils.getDifference(originalPlane.getData(), compressedPlane.getData());
-            Utils.applyAbsFunction(diffData);
-
-
-            final double absDiffSum = Arrays.stream(diffData).mapToDouble(v -> v).sum();
-            final double meanPixelError = absDiffSum / (double) planePixelCount;
-
-            planeErrors[planeIndex] = new PlaneError(planeIndex, absDiffSum, meanPixelError);
-            //            System.out.println("Finished plane: " + planeIndex);
-        }
-
-        try (FileOutputStream fos = new FileOutputStream(reportFile, false);
-             OutputStreamWriter writer = new OutputStreamWriter(fos)) {
-
-            writer.write("PlaneIndex\tErrorSum\tMeanError\n");
-
-            for (final PlaneError planeError : planeErrors) {
-                writer.write(String.format("%d\t%.4f\t%.4f\n",
-                                           planeError.getPlaneIndex(),
-                                           planeError.getAbsoluteError(),
-                                           planeError.getMeanAbsoluteError()));
-            }
-
-        } catch (IOException e) {
-            e.printStackTrace();
-        }
-        System.out.println("Finished reportPlaneDifference");
+//        final String referenceFile = "D:\\biology\\tiff_data\\benchmark\\fused_tp_10_ch_1_16bit.raw";
+//
+//        final V3i dims = new V3i(1041, 996, 946);
+//        final int planePixelCount = dims.getX() * dims.getY();
+//        System.out.println(options.report());
+//        System.out.println("Run custom function.");
+//        ImageU16 compressedPlane = null;
+//        ImageU16 originalPlane = null;
+//        ImageU16 differencePlane = null;
+//
+//        PlaneError[] planeErrors = new PlaneError[dims.getZ()];
+//
+//        for (int planeIndex = 0; planeIndex < dims.getZ(); planeIndex++) {
+//            try {
+//                originalPlane = RawDataIO.loadImageU16(referenceFile, dims, planeIndex);
+//                compressedPlane = RawDataIO.loadImageU16(compressedFile, dims, planeIndex);
+//            } catch (IOException e) {
+//                e.printStackTrace();
+//                return true;
+//            }
+//            final int[] diffData = Utils.getDifference(originalPlane.getData(), compressedPlane.getData());
+//            Utils.applyAbsFunction(diffData);
+//
+//
+//            final double absDiffSum = Arrays.stream(diffData).mapToDouble(v -> v).sum();
+//            final double meanPixelError = absDiffSum / (double) planePixelCount;
+//
+//            planeErrors[planeIndex] = new PlaneError(planeIndex, absDiffSum, meanPixelError);
+//            //            System.out.println("Finished plane: " + planeIndex);
+//        }
+//
+//        try (FileOutputStream fos = new FileOutputStream(reportFile, false);
+//             OutputStreamWriter writer = new OutputStreamWriter(fos)) {
+//
+//            writer.write("PlaneIndex\tErrorSum\tMeanError\n");
+//
+//            for (final PlaneError planeError : planeErrors) {
+//                writer.write(String.format("%d\t%.4f\t%.4f\n",
+//                                           planeError.getPlaneIndex(),
+//                                           planeError.getAbsoluteError(),
+//                                           planeError.getMeanAbsoluteError()));
+//            }
+//
+//        } catch (IOException e) {
+//            e.printStackTrace();
+//        }
+//        System.out.println("Finished reportPlaneDifference");
         return false;
     }
 }
diff --git a/src/main/java/azgracompress/compression/SQImageCompressor.java b/src/main/java/azgracompress/compression/SQImageCompressor.java
index 5a9e8684ed8a811bbde675f6404aa9663fbebea8..8dadac015b53275b0248598fc76714a2302a119e 100644
--- a/src/main/java/azgracompress/compression/SQImageCompressor.java
+++ b/src/main/java/azgracompress/compression/SQImageCompressor.java
@@ -5,8 +5,8 @@ import azgracompress.cli.InputFileInfo;
 import azgracompress.cli.ParsedCliOptions;
 import azgracompress.compression.exception.ImageCompressionException;
 import azgracompress.data.ImageU16;
+import azgracompress.io.ConcretePlaneLoader;
 import azgracompress.io.OutBitStream;
-import azgracompress.io.RawDataIO;
 import azgracompress.quantization.QuantizationValueCache;
 import azgracompress.quantization.scalar.LloydMaxU16ScalarQuantization;
 import azgracompress.quantization.scalar.ScalarQuantizer;
@@ -85,6 +85,13 @@ public class SQImageCompressor extends CompressorDecompressorBase implements IIm
         Stopwatch stopwatch = new Stopwatch();
         final boolean hasGeneralQuantizer = options.hasCodebookCacheFolder() || options.hasReferencePlaneIndex();
 
+        final ConcretePlaneLoader planeLoader;
+        try {
+            planeLoader = new ConcretePlaneLoader(inputFileInfo);
+        } catch (Exception e) {
+            throw new ImageCompressionException("Unable to create SCIFIO reader. " + e.getMessage());
+        }
+
         ScalarQuantizer quantizer = null;
         if (options.hasCodebookCacheFolder()) {
             Log("Loading codebook from cache file.");
@@ -96,10 +103,8 @@ public class SQImageCompressor extends CompressorDecompressorBase implements IIm
             stopwatch.restart();
             ImageU16 referencePlane = null;
             try {
-                referencePlane = RawDataIO.loadImageU16(inputFileInfo.getFilePath(),
-                                                        inputFileInfo.getDimensions(),
-                                                        options.getReferencePlaneIndex());
-            } catch (Exception ex) {
+                referencePlane = planeLoader.loadPlaneU16(options.getReferencePlaneIndex());
+            } catch (IOException ex) {
                 throw new ImageCompressionException("Unable to load reference plane data.", ex);
             }
 
@@ -121,10 +126,8 @@ public class SQImageCompressor extends CompressorDecompressorBase implements IIm
             ImageU16 plane = null;
 
             try {
-                plane = RawDataIO.loadImageU16(inputFileInfo.getFilePath(),
-                                               inputFileInfo.getDimensions(),
-                                               planeIndex);
-            } catch (Exception ex) {
+                plane = planeLoader.loadPlaneU16(planeIndex);
+            } catch (IOException ex) {
                 throw new ImageCompressionException("Unable to load plane data.", ex);
             }
 
@@ -152,13 +155,17 @@ public class SQImageCompressor extends CompressorDecompressorBase implements IIm
 
     private int[] loadConfiguredPlanesData() throws ImageCompressionException {
         final InputFileInfo inputFileInfo = options.getInputFileInfo();
+        final ConcretePlaneLoader planeLoader;
+        try {
+            planeLoader = new ConcretePlaneLoader(inputFileInfo);
+        } catch (Exception e) {
+            throw new ImageCompressionException("Unable to create SCIFIO reader. " + e.getMessage());
+        }
         int[] trainData = null;
         if (inputFileInfo.isPlaneIndexSet()) {
             try {
                 Log("Loading single plane data.");
-                trainData = RawDataIO.loadImageU16(inputFileInfo.getFilePath(),
-                                                   inputFileInfo.getDimensions(),
-                                                   inputFileInfo.getPlaneIndex()).getData();
+                trainData = planeLoader.loadPlaneU16(inputFileInfo.getPlaneIndex()).getData();
             } catch (IOException e) {
                 throw new ImageCompressionException("Failed to load reference image data.", e);
             }
@@ -166,7 +173,7 @@ public class SQImageCompressor extends CompressorDecompressorBase implements IIm
             Log("Loading plane range data.");
             final int[] planes = getPlaneIndicesForCompression();
             try {
-                trainData = RawDataIO.loadPlanesData(inputFileInfo.getFilePath(), inputFileInfo.getDimensions(), planes);
+                trainData = planeLoader.loadPlanesU16Data(planes);
             } catch (IOException e) {
                 e.printStackTrace();
                 throw new ImageCompressionException("Failed to load plane range data.", e);
@@ -174,7 +181,7 @@ public class SQImageCompressor extends CompressorDecompressorBase implements IIm
         } else {
             Log("Loading all planes data.");
             try {
-                trainData = RawDataIO.loadAllPlanesData(inputFileInfo.getFilePath(), inputFileInfo.getDimensions());
+                trainData = planeLoader.loadAllPlanesU16Data();
             } catch (IOException e) {
                 throw new ImageCompressionException("Failed to load all planes data.", e);
             }
@@ -185,7 +192,6 @@ public class SQImageCompressor extends CompressorDecompressorBase implements IIm
     @Override
     public void trainAndSaveCodebook() throws ImageCompressionException {
 
-
         int[] trainData = loadConfiguredPlanesData();
 
         LloydMaxU16ScalarQuantization lloydMax = new LloydMaxU16ScalarQuantization(trainData,
diff --git a/src/main/java/azgracompress/compression/VQImageCompressor.java b/src/main/java/azgracompress/compression/VQImageCompressor.java
index d4e62fed617853f85ba5605c6ad13e8dc77a9d46..b4c85a443db033aeacfa224541dd088e589b4738 100644
--- a/src/main/java/azgracompress/compression/VQImageCompressor.java
+++ b/src/main/java/azgracompress/compression/VQImageCompressor.java
@@ -5,8 +5,9 @@ import azgracompress.cli.ParsedCliOptions;
 import azgracompress.compression.exception.ImageCompressionException;
 import azgracompress.data.Chunk2D;
 import azgracompress.data.ImageU16;
+import azgracompress.io.ConcretePlaneLoader;
+import azgracompress.io.IPlaneLoader;
 import azgracompress.io.OutBitStream;
-import azgracompress.io.RawDataIO;
 import azgracompress.quantization.QuantizationValueCache;
 import azgracompress.quantization.vector.CodebookEntry;
 import azgracompress.quantization.vector.LBGResult;
@@ -90,6 +91,12 @@ public class VQImageCompressor extends CompressorDecompressorBase implements IIm
         final InputFileInfo inputFileInfo = options.getInputFileInfo();
         Stopwatch stopwatch = new Stopwatch();
         final boolean hasGeneralQuantizer = options.hasCodebookCacheFolder() || options.hasReferencePlaneIndex();
+        final ConcretePlaneLoader planeLoader;
+        try {
+            planeLoader = new ConcretePlaneLoader(inputFileInfo);
+        } catch (Exception e) {
+            throw new ImageCompressionException("Unable to create SCIFIO reader. " + e.getMessage());
+        }
         VectorQuantizer quantizer = null;
 
         if (options.hasCodebookCacheFolder()) {
@@ -102,10 +109,8 @@ public class VQImageCompressor extends CompressorDecompressorBase implements IIm
 
             ImageU16 referencePlane = null;
             try {
-                referencePlane = RawDataIO.loadImageU16(inputFileInfo.getFilePath(),
-                                                        inputFileInfo.getDimensions(),
-                                                        options.getReferencePlaneIndex());
-            } catch (Exception ex) {
+                referencePlane = planeLoader.loadPlaneU16(options.getReferencePlaneIndex());
+            } catch (IOException ex) {
                 throw new ImageCompressionException("Unable to load reference plane data.", ex);
             }
 
@@ -125,10 +130,8 @@ public class VQImageCompressor extends CompressorDecompressorBase implements IIm
 
             ImageU16 plane = null;
             try {
-                plane = RawDataIO.loadImageU16(inputFileInfo.getFilePath(),
-                                               inputFileInfo.getDimensions(),
-                                               planeIndex);
-            } catch (Exception ex) {
+                plane = planeLoader.loadPlaneU16(planeIndex);
+            } catch (IOException ex) {
                 throw new ImageCompressionException("Unable to load plane data.", ex);
             }
 
@@ -165,33 +168,38 @@ public class VQImageCompressor extends CompressorDecompressorBase implements IIm
      * @return Quantization vectors of configured quantization.
      * @throws IOException When reading fails.
      */
-    private int[][] loadPlaneQuantizationVectors(final int planeIndex) throws IOException {
-        ImageU16 refPlane = RawDataIO.loadImageU16(options.getInputFileInfo().getFilePath(),
-                                                   options.getInputFileInfo().getDimensions(),
-                                                   planeIndex);
-
+    private int[][] loadPlaneQuantizationVectors(final IPlaneLoader planeLoader,
+                                                 final int planeIndex) throws IOException {
+        ImageU16 refPlane = planeLoader.loadPlaneU16(planeIndex);
         return refPlane.toQuantizationVectors(options.getVectorDimension());
     }
 
     private int[][] loadConfiguredPlanesData() throws ImageCompressionException {
         final int vectorSize = options.getVectorDimension().getX() * options.getVectorDimension().getY();
-        final InputFileInfo ifi = options.getInputFileInfo();
+        final InputFileInfo inputFileInfo = options.getInputFileInfo();
+        final ConcretePlaneLoader planeLoader;
+        try {
+            planeLoader = new ConcretePlaneLoader(inputFileInfo);
+        } catch (Exception e) {
+            throw new ImageCompressionException("Unable to create SCIFIO reader. " + e.getMessage());
+        }
         int[][] trainData = null;
         Stopwatch s = new Stopwatch();
         s.start();
-        if (ifi.isPlaneIndexSet()) {
+        if (inputFileInfo.isPlaneIndexSet()) {
             Log("VQ: Loading single plane data.");
             try {
-                trainData = loadPlaneQuantizationVectors(ifi.getPlaneIndex());
+
+                trainData = loadPlaneQuantizationVectors(planeLoader, inputFileInfo.getPlaneIndex());
             } catch (IOException e) {
                 throw new ImageCompressionException("Failed to load reference image data.", e);
             }
         } else {
-            Log(ifi.isPlaneRangeSet() ? "VQ: Loading plane range data." : "VQ: Loading all planes data.");
+            Log(inputFileInfo.isPlaneRangeSet() ? "VQ: Loading plane range data." : "VQ: Loading all planes data.");
             final int[] planeIndices = getPlaneIndicesForCompression();
 
             final int chunkCountPerPlane = Chunk2D.calculateRequiredChunkCountPerPlane(
-                    ifi.getDimensions().toV2i(),
+                    inputFileInfo.getDimensions().toV2i(),
                     options.getVectorDimension());
             final int totalChunkCount = chunkCountPerPlane * planeIndices.length;
 
@@ -201,7 +209,7 @@ public class VQImageCompressor extends CompressorDecompressorBase implements IIm
             int planeCounter = 0;
             for (final int planeIndex : planeIndices) {
                 try {
-                    planeVectors = loadPlaneQuantizationVectors(planeIndex);
+                    planeVectors = loadPlaneQuantizationVectors(planeLoader, planeIndex);
                     assert (planeVectors.length == chunkCountPerPlane) : "Wrong chunk count per plane";
                 } catch (IOException e) {
                     throw new ImageCompressionException(String.format("Failed to load plane %d image data.",
diff --git a/src/main/java/azgracompress/data/ImageU16.java b/src/main/java/azgracompress/data/ImageU16.java
index ddd7b4e1dd34ffeb8ad2df6e89130aa836ea53ca..8c5f7a53020ebcab62013f79f6e8e7e6608d9b5a 100644
--- a/src/main/java/azgracompress/data/ImageU16.java
+++ b/src/main/java/azgracompress/data/ImageU16.java
@@ -8,13 +8,17 @@ public class ImageU16 {
     private final int height;
     private int[] data;
 
-    public ImageU16(int width, int height, int[] data) {
+    public ImageU16(final int width, final int height, final int[] data) {
         assert ((width * height) == data.length) : "Wrong data size in ImageU16 constructor.";
         this.width = width;
         this.height = height;
         this.data = data;
     }
 
+    public ImageU16(final V2i dims, final int[] data) {
+        this(dims.getX(), dims.getY(), data);
+    }
+
     private int index(final int x, final int y) {
         assert ((x >= 0 && x < height) && (y >= 0 && y < width)) : "Index out of bounds";
         return (x * width) + y;
diff --git a/src/main/java/azgracompress/io/ConcretePlaneLoader.java b/src/main/java/azgracompress/io/ConcretePlaneLoader.java
new file mode 100644
index 0000000000000000000000000000000000000000..12d7346a60c1ab3e4d0cbc6fe7e486bc002836dd
--- /dev/null
+++ b/src/main/java/azgracompress/io/ConcretePlaneLoader.java
@@ -0,0 +1,45 @@
+package azgracompress.io;
+
+import azgracompress.cli.InputFileInfo;
+import azgracompress.data.ImageU16;
+
+import java.io.IOException;
+
+public class ConcretePlaneLoader implements IPlaneLoader {
+
+    private final IPlaneLoader loader;
+
+    private final InputFileInfo inputFileInfo;
+
+    /**
+     * Create plane loader.
+     *
+     * @param inputFileInfo Information about input file.
+     * @throws Exception When fails to create SCIFIO reader.
+     */
+    public ConcretePlaneLoader(final InputFileInfo inputFileInfo) throws Exception {
+        this.inputFileInfo = inputFileInfo;
+
+        if (inputFileInfo.isRAW()) {
+            loader = new RawDataLoader(inputFileInfo);
+        } else {
+            loader = new SCIFIOLoader(inputFileInfo);
+        }
+    }
+
+
+    @Override
+    public ImageU16 loadPlaneU16(int plane) throws IOException {
+        return loader.loadPlaneU16(plane);
+    }
+
+    @Override
+    public int[] loadPlanesU16Data(int[] planes) throws IOException {
+        return loader.loadPlanesU16Data(planes);
+    }
+
+    @Override
+    public int[] loadAllPlanesU16Data() throws IOException {
+        return loader.loadAllPlanesU16Data();
+    }
+}
diff --git a/src/main/java/azgracompress/io/IPlaneLoader.java b/src/main/java/azgracompress/io/IPlaneLoader.java
new file mode 100644
index 0000000000000000000000000000000000000000..45026b5e04b3f62f24b9403b438e9e7ce9e056a9
--- /dev/null
+++ b/src/main/java/azgracompress/io/IPlaneLoader.java
@@ -0,0 +1,14 @@
+package azgracompress.io;
+
+import azgracompress.cli.InputFileInfo;
+import azgracompress.data.ImageU16;
+
+import java.io.IOException;
+
+public interface IPlaneLoader {
+    ImageU16 loadPlaneU16(final int plane) throws IOException;
+
+    int[] loadPlanesU16Data(int[] planes) throws IOException;
+
+    int[] loadAllPlanesU16Data() throws IOException;
+}
diff --git a/src/main/java/azgracompress/io/ImagePlaneIO.java b/src/main/java/azgracompress/io/ImagePlaneIO.java
deleted file mode 100644
index 69433036198bd857c3f2cf07ab1216376af85e5c..0000000000000000000000000000000000000000
--- a/src/main/java/azgracompress/io/ImagePlaneIO.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package azgracompress.io;
-
-import azgracompress.data.ImageU16;
-import azgracompress.data.V3i;
-import io.scif.jj2000.j2k.NotImplementedError;
-
-import java.io.IOException;
-
-/**
- * Class handling loading and writing of plane data.
- * Multiple data types should be supported.
- * For start: RAW, TIFF
- */
-public class ImagePlaneIO {
-
-    public static ImageU16 loadImageU16(final String rawFile,
-                                        final V3i rawDataDimension,
-                                        final int plane) throws IOException {
-
-        // TODO(Moravec): Handle loading of different types.
-        // TODO(Moravec): If the loaded image is not U16 convert it to U16 image.
-        throw new NotImplementedError();
-    }
-
-    public static int[] loadPlanesData(final String rawFile,
-                                       final V3i rawDataDims,
-                                       int[] planes) throws IOException {
-        // TODO(Moravec): Handle loading of different types.
-        // TODO(Moravec): If the loaded image is not U16 convert it to U16 image.
-        throw new NotImplementedError();
-    }
-
-    public static int[] loadAllPlanesData(final String rawFile, final V3i imageDims) throws IOException {
-        // TODO(Moravec): Handle loading of different types.
-        // TODO(Moravec): If the loaded image is not U16 convert it to U16 image.
-        throw new NotImplementedError();
-    }
-
-    public static void writeImageU16(final String rawFile,
-                                     final ImageU16 image,
-                                     final boolean littleEndian) throws IOException {
-
-        // TODO(Moravec): Handle writing of U16 image to multiple types.
-        throw new NotImplementedError();
-    }
-}
diff --git a/src/main/java/azgracompress/io/RawDataIO.java b/src/main/java/azgracompress/io/RawDataIO.java
index 5cf711f0271b8642282e2343d0eef24533218d9f..402df89490ae1281c60b4814598821c3f4684e18 100644
--- a/src/main/java/azgracompress/io/RawDataIO.java
+++ b/src/main/java/azgracompress/io/RawDataIO.java
@@ -1,119 +1,12 @@
 package azgracompress.io;
 
 import azgracompress.data.ImageU16;
-import azgracompress.data.V3i;
 import azgracompress.utilities.TypeConverter;
 
-import java.io.*;
-import java.util.Arrays;
+import java.io.FileOutputStream;
+import java.io.IOException;
 
 public class RawDataIO {
-    /**
-     * Load single U16 image from RAW data file.
-     *
-     * @param rawFile          Path to the raw file.
-     * @param rawDataDimension X (Width), Y (Height) of plane and Z(Number of planes)
-     * @param plane            Plane index.
-     * @return U16 image specified by the plane
-     */
-    public static ImageU16 loadImageU16(final String rawFile,
-                                        final V3i rawDataDimension,
-                                        final int plane) throws IOException {
-
-        byte[] buffer;
-        try (FileInputStream fileStream = new FileInputStream(rawFile)) {
-            final long planeSize = (long) rawDataDimension.getX() * (long) rawDataDimension.getY() * 2;
-            final long expectedFileSize = planeSize * rawDataDimension.getZ();
-            final long fileSize = fileStream.getChannel().size();
-
-
-            if (expectedFileSize != fileSize) {
-                throw new IOException(
-                        "File specified by `rawFile` doesn't contains raw data for image of dimensions " +
-                                "`rawDataDimension`");
-            }
-
-            final long planeOffset = plane * planeSize;
-
-            buffer = new byte[(int) planeSize];
-            if (fileStream.skip(planeOffset) != planeOffset) {
-                throw new IOException("Failed to skip.");
-            }
-            if (fileStream.read(buffer, 0, (int) planeSize) != planeSize) {
-                throw new IOException("Read wrong number of bytes.");
-            }
-        }
-
-        return new ImageU16(rawDataDimension.getX(),
-                            rawDataDimension.getY(),
-                            TypeConverter.unsignedShortBytesToIntArray(buffer));
-    }
-
-    public static int[] loadPlanesData(final String rawFile,
-                                       final V3i rawDataDims,
-                                       int[] planes) throws IOException {
-
-        if (planes.length < 1)
-            return new int[0];
-
-        final int planeValueCount = rawDataDims.getX() * rawDataDims.getY();
-        final long planeDataSize = 2 * (long) planeValueCount;
-
-        final long totalValueCount = (long) planeValueCount * planes.length;
-        int[] values = new int[(int) totalValueCount];
-
-
-        if (totalValueCount > (long) Integer.MAX_VALUE) {
-            throw new IOException("Integer count is too big.");
-        }
-
-        Arrays.sort(planes);
-
-        try (FileInputStream fileStream = new FileInputStream(rawFile);
-             DataInputStream dis = new DataInputStream(new BufferedInputStream(fileStream, 8192))) {
-
-            int lastIndex = 0;
-            int valIndex = 0;
-
-            for (final int planeIndex : planes) {
-                // Skip specific number of bytes to get to the next plane.
-                final int requestedSkip = (planeIndex == 0) ? 0 : ((planeIndex - lastIndex) - 1) * (int) planeDataSize;
-                lastIndex = planeIndex;
-
-                final int actualSkip = dis.skipBytes(requestedSkip);
-                if (requestedSkip != actualSkip) {
-                    throw new IOException("Skip operation failed.");
-                }
-
-                for (int i = 0; i < planeValueCount; i++) {
-                    values[valIndex++] = dis.readUnsignedShort();
-                }
-
-            }
-        }
-
-        return values;
-    }
-
-    public static int[] loadAllPlanesData(final String rawFile, final V3i imageDims) throws IOException {
-
-        final long dataSize = (long) imageDims.getX() * (long) imageDims.getY() * (long) imageDims.getZ();
-        int[] values = new int[(int) dataSize];
-
-        if (dataSize > (long) Integer.MAX_VALUE) {
-            throw new IOException("RawFile size is too big.");
-        }
-
-        try (FileInputStream fileStream = new FileInputStream(rawFile);
-             DataInputStream dis = new DataInputStream(new BufferedInputStream(fileStream, 8192))) {
-
-            for (int i = 0; i < (int) dataSize; i++) {
-                values[i] = dis.readUnsignedShort();
-            }
-        }
-
-        return values;
-    }
 
     public static void writeImageU16(final String rawFile,
                                      final ImageU16 image,
diff --git a/src/main/java/azgracompress/io/RawDataLoader.java b/src/main/java/azgracompress/io/RawDataLoader.java
new file mode 100644
index 0000000000000000000000000000000000000000..cb90165c80eb36ee88683ef7bcf4f32908a71088
--- /dev/null
+++ b/src/main/java/azgracompress/io/RawDataLoader.java
@@ -0,0 +1,115 @@
+package azgracompress.io;
+
+import azgracompress.cli.InputFileInfo;
+import azgracompress.data.ImageU16;
+import azgracompress.data.V3i;
+import azgracompress.utilities.TypeConverter;
+
+import java.io.*;
+import java.util.Arrays;
+
+public class RawDataLoader implements IPlaneLoader {
+    private final InputFileInfo inputFileInfo;
+
+    public RawDataLoader(final InputFileInfo inputFileInfo) {
+        this.inputFileInfo = inputFileInfo;
+    }
+
+    @Override
+    public ImageU16 loadPlaneU16(int plane) throws IOException {
+        byte[] buffer;
+        final V3i rawDataDimension = inputFileInfo.getDimensions();
+
+        try (FileInputStream fileStream = new FileInputStream(inputFileInfo.getFilePath())) {
+            final long planeSize = (long) rawDataDimension.getX() * (long) rawDataDimension.getY() * 2;
+            final long expectedFileSize = planeSize * rawDataDimension.getZ();
+            final long fileSize = fileStream.getChannel().size();
+
+
+            if (expectedFileSize != fileSize) {
+                throw new IOException(
+                        "File specified by `rawFile` doesn't contains raw data for image of dimensions " +
+                                "`rawDataDimension`");
+            }
+
+            final long planeOffset = plane * planeSize;
+
+            buffer = new byte[(int) planeSize];
+            if (fileStream.skip(planeOffset) != planeOffset) {
+                throw new IOException("Failed to skip.");
+            }
+            if (fileStream.read(buffer, 0, (int) planeSize) != planeSize) {
+                throw new IOException("Read wrong number of bytes.");
+            }
+        }
+
+        return new ImageU16(rawDataDimension.getX(),
+                            rawDataDimension.getY(),
+                            TypeConverter.unsignedShortBytesToIntArray(buffer));
+    }
+
+    @Override
+    public int[] loadPlanesU16Data(int[] planes) throws IOException {
+        if (planes.length < 1)
+            return new int[0];
+
+        final int planeValueCount = inputFileInfo.getDimensions().getX() * inputFileInfo.getDimensions().getY();
+        final long planeDataSize = 2 * (long) planeValueCount;
+
+        final long totalValueCount = (long) planeValueCount * planes.length;
+        int[] values = new int[(int) totalValueCount];
+
+
+        if (totalValueCount > (long) Integer.MAX_VALUE) {
+            throw new IOException("Integer count is too big.");
+        }
+
+        Arrays.sort(planes);
+
+        try (FileInputStream fileStream = new FileInputStream(inputFileInfo.getFilePath());
+             DataInputStream dis = new DataInputStream(new BufferedInputStream(fileStream, 8192))) {
+
+            int lastIndex = 0;
+            int valIndex = 0;
+
+            for (final int planeIndex : planes) {
+                // Skip specific number of bytes to get to the next plane.
+                final int requestedSkip = (planeIndex == 0) ? 0 : ((planeIndex - lastIndex) - 1) * (int) planeDataSize;
+                lastIndex = planeIndex;
+
+                final int actualSkip = dis.skipBytes(requestedSkip);
+                if (requestedSkip != actualSkip) {
+                    throw new IOException("Skip operation failed.");
+                }
+
+                for (int i = 0; i < planeValueCount; i++) {
+                    values[valIndex++] = dis.readUnsignedShort();
+                }
+
+            }
+        }
+
+        return values;
+    }
+
+    @Override
+    public int[] loadAllPlanesU16Data() throws IOException {
+        final V3i imageDims = inputFileInfo.getDimensions();
+        final long dataSize = (long) imageDims.getX() * (long) imageDims.getY() * (long) imageDims.getZ();
+        int[] values = new int[(int) dataSize];
+
+        if (dataSize > (long) Integer.MAX_VALUE) {
+            throw new IOException("RawFile size is too big.");
+        }
+
+        try (FileInputStream fileStream = new FileInputStream(inputFileInfo.getFilePath());
+             DataInputStream dis = new DataInputStream(new BufferedInputStream(fileStream, 8192))) {
+
+            for (int i = 0; i < (int) dataSize; i++) {
+                values[i] = dis.readUnsignedShort();
+            }
+        }
+
+        return values;
+    }
+}
diff --git a/src/main/java/azgracompress/io/SCIFIOLoader.java b/src/main/java/azgracompress/io/SCIFIOLoader.java
new file mode 100644
index 0000000000000000000000000000000000000000..3df37985ba100de81f599ab0cc7659f39592c116
--- /dev/null
+++ b/src/main/java/azgracompress/io/SCIFIOLoader.java
@@ -0,0 +1,51 @@
+package azgracompress.io;
+
+import azgracompress.ScifioWrapper;
+import azgracompress.cli.InputFileInfo;
+import azgracompress.data.ImageU16;
+import azgracompress.utilities.TypeConverter;
+import io.scif.FormatException;
+import io.scif.Reader;
+import io.scif.jj2000.j2k.NotImplementedError;
+
+import java.io.IOException;
+
+public class SCIFIOLoader implements IPlaneLoader {
+
+    private final InputFileInfo inputFileInfo;
+    private final Reader reader;
+
+    /**
+     * Create SCIFIO reader from input file.
+     *
+     * @param inputFileInfo Input file info.
+     * @throws IOException     When fails to create SCIFIO reader.
+     * @throws FormatException When fails to create SCIFIO reader.
+     */
+    public SCIFIOLoader(final InputFileInfo inputFileInfo) throws IOException, FormatException {
+        this.inputFileInfo = inputFileInfo;
+        this.reader = ScifioWrapper.getReader(this.inputFileInfo.getFilePath());
+    }
+
+    @Override
+    public ImageU16 loadPlaneU16(int plane) throws IOException {
+        byte[] planeBytes;
+        try {
+            planeBytes = reader.openPlane(0, plane).getBytes();
+        } catch (FormatException e) {
+            throw new IOException("Unable to open plane with the reader. " + e.getMessage());
+        }
+        final int[] data = TypeConverter.unsignedShortBytesToIntArray(planeBytes);
+        return new ImageU16(inputFileInfo.getDimensions().toV2i(), data);
+    }
+
+    @Override
+    public int[] loadPlanesU16Data(int[] planes) throws IOException {
+        throw new NotImplementedError("NOT IMPLEMENTED");
+    }
+
+    @Override
+    public int[] loadAllPlanesU16Data() throws IOException {
+        throw new NotImplementedError("NOT IMPLEMENTED");
+    }
+}