diff --git a/src/main/java/azgracompress/io/loader/BasicLoader.java b/src/main/java/azgracompress/io/loader/BasicLoader.java
index 3e11384b046d91f27c083c4367c5c6fb36294e78..04330f0900beacee7aadf381aa17d58ad553dfae 100644
--- a/src/main/java/azgracompress/io/loader/BasicLoader.java
+++ b/src/main/java/azgracompress/io/loader/BasicLoader.java
@@ -26,11 +26,67 @@ public abstract class BasicLoader {
     public abstract int[] loadPlaneData(final int plane) throws IOException;
 
     protected int valueAt(final int plane, final int offset) {
+        new Exception().printStackTrace(System.err);
         assert (false) : "Unimplemented overload of BasicLoader::valueAt()";
         return Integer.MIN_VALUE;
     }
 
-    protected int[][] loadBlocksImplLoadPlaneData(final V2i blockDim, final Range<Integer> planeRange) throws IOException {
+    protected int[][] loadRowVectorsImplByLoadPlaneData(final int vectorSize, final Range<Integer> planeRange) throws IOException {
+        final int rowVectorCount = (int) Math.ceil((double) dims.getX() / (double) vectorSize);
+        final int vectorCount = dims.getZ() * dims.getY() * rowVectorCount;
+
+        int[][] rowVectors = new int[vectorCount][vectorSize];
+
+        int vectorIndex = 0;
+        int baseX;
+
+        for (int plane = planeRange.getFrom(); plane < planeRange.getTo(); plane++) {
+            final int[] planeData = loadPlaneData(plane);
+            for (int row = 0; row < dims.getY(); row++) {
+                for (int rowVectorIndex = 0; rowVectorIndex < rowVectorCount; rowVectorIndex++) {
+                    // Copy single vector.
+                    baseX = rowVectorIndex * vectorSize;
+
+                    for (int vectorX = 0; vectorX < vectorSize; vectorX++) {
+                        if (baseX + vectorX >= dims.getY())
+                            break;
+                        rowVectors[vectorIndex][vectorX] = planeData[Chunk2D.index((baseX + vectorX), row, dims.getY())];
+                    }
+                    ++vectorIndex;
+                }
+            }
+        }
+        return rowVectors;
+    }
+
+    protected int[][] loadRowVectorsImplByValueAt(final int vectorSize, final Range<Integer> planeRange) {
+        final int rowVectorCount = (int) Math.ceil((double) dims.getX() / (double) vectorSize);
+        final int vectorCount = dims.getZ() * dims.getY() * rowVectorCount;
+
+        int[][] rowVectors = new int[vectorCount][vectorSize];
+
+        int vectorIndex = 0;
+        int baseX;
+
+        for (int plane = planeRange.getFrom(); plane < planeRange.getTo(); plane++) {
+            for (int row = 0; row < dims.getY(); row++) {
+                for (int rowVectorIndex = 0; rowVectorIndex < rowVectorCount; rowVectorIndex++) {
+                    // Copy single vector.
+                    baseX = rowVectorIndex * vectorSize;
+
+                    for (int vectorX = 0; vectorX < vectorSize; vectorX++) {
+                        if (baseX + vectorX >= dims.getY())
+                            break;
+                        rowVectors[vectorIndex][vectorX] = valueAt(plane, Chunk2D.index((baseX + vectorX), row, dims.getY()));
+                    }
+                    ++vectorIndex;
+                }
+            }
+        }
+        return rowVectors;
+    }
+
+    protected int[][] loadBlocksImplByLoadPlaneData(final V2i blockDim, final Range<Integer> planeRange) throws IOException {
         final int blockSize = blockDim.multiplyTogether();
         final int planeCount = planeRange.getTo() - planeRange.getFrom();
         final int blockCount = planeCount * Chunk2D.calculateRequiredChunkCount(dims.toV2i(), blockDim);
diff --git a/src/main/java/azgracompress/io/loader/IPlaneLoader.java b/src/main/java/azgracompress/io/loader/IPlaneLoader.java
index 7e20bac003cf6680bbe604457a6ca22a1cfebe2a..db338cf36b6dffa12b8b59b228e0ac968495f555 100644
--- a/src/main/java/azgracompress/io/loader/IPlaneLoader.java
+++ b/src/main/java/azgracompress/io/loader/IPlaneLoader.java
@@ -54,6 +54,27 @@ public interface IPlaneLoader {
      */
     int[] loadAllPlanesU16Data() throws IOException;
 
+    /**
+     * Load row vectors from the entire dataset.
+     *
+     * @param vectorSize Width of the row vector.
+     * @return Row vector data from the entire dataset.
+     * @throws IOException When fails to load plane data.
+     */
+    default int[][] loadRowVectors(final int vectorSize) throws IOException {
+        return loadRowVectors(vectorSize, new Range<>(0, getImageDimensions().getZ()));
+    }
+
+    /**
+     * Load row vectors from specified plane range in the dataset.
+     *
+     * @param vectorSize Width of the row vector.
+     * @param planeRange Source plane range.
+     * @return Row vector data from the specified plane range.
+     * @throws IOException When fails to load plane data.
+     */
+    int[][] loadRowVectors(final int vectorSize, final Range<Integer> planeRange) throws IOException;
+
     /**
      * Load blocks from the entire dataset.
      *
diff --git a/src/main/java/azgracompress/io/loader/ImageJBufferLoader.java b/src/main/java/azgracompress/io/loader/ImageJBufferLoader.java
index c43bcfcdf80d35046e8ed3422190767d5280bb86..baea7c955fcc79e482a1e7a23f0cd186177858f9 100644
--- a/src/main/java/azgracompress/io/loader/ImageJBufferLoader.java
+++ b/src/main/java/azgracompress/io/loader/ImageJBufferLoader.java
@@ -93,7 +93,12 @@ public final class ImageJBufferLoader extends BasicLoader implements IPlaneLoade
     }
 
     @Override
-    public int[][] loadBlocks(V2i blockDim, Range<Integer> planeRange) throws IOException {
+    public int[][] loadRowVectors(final int vectorSize, final Range<Integer> planeRange) {
+        return loadRowVectorsImplByValueAt(vectorSize, planeRange);
+    }
+
+    @Override
+    public int[][] loadBlocks(V2i blockDim, Range<Integer> planeRange) {
         return loadBlocksImplByValueAt(blockDim, planeRange);
     }
 
diff --git a/src/main/java/azgracompress/io/loader/RawDataLoader.java b/src/main/java/azgracompress/io/loader/RawDataLoader.java
index 701a509c1591a99ac7a3f9f7cc3d76a9b4ed7433..385f17f8d66343b53f0b9d91c09d40ed9b7275c6 100644
--- a/src/main/java/azgracompress/io/loader/RawDataLoader.java
+++ b/src/main/java/azgracompress/io/loader/RawDataLoader.java
@@ -117,9 +117,14 @@ public final class RawDataLoader extends BasicLoader implements IPlaneLoader {
         return values;
     }
 
+    @Override
+    public int[][] loadRowVectors(final int vectorSize, final Range<Integer> planeRange) throws IOException {
+        return loadRowVectorsImplByLoadPlaneData(vectorSize, planeRange);
+    }
+
     @Override
     public int[][] loadBlocks(V2i blockDim, Range<Integer> planeRange) throws IOException {
-        return loadBlocksImplLoadPlaneData(blockDim, planeRange);
+        return loadBlocksImplByLoadPlaneData(blockDim, planeRange);
     }
 
     @Override
diff --git a/src/main/java/azgracompress/io/loader/SCIFIOLoader.java b/src/main/java/azgracompress/io/loader/SCIFIOLoader.java
index 4e151663e18d1fc80cd10c4b383ed97aadc54c08..7b4d0128f5f70f2deca0be8068672bd5442e7b11 100644
--- a/src/main/java/azgracompress/io/loader/SCIFIOLoader.java
+++ b/src/main/java/azgracompress/io/loader/SCIFIOLoader.java
@@ -16,10 +16,6 @@ public final class SCIFIOLoader extends BasicLoader implements IPlaneLoader {
     private final FileInputData inputDataInfo;
     private final Reader reader;
 
-    // Current plane buffer
-    private int currentPlaneIndex = -1;
-    private int[] currentPlaneData;
-
     /**
      * Create SCIFIO reader from input file.
      *
@@ -33,26 +29,6 @@ public final class SCIFIOLoader extends BasicLoader implements IPlaneLoader {
         this.reader = ScifioWrapper.getReader(this.inputDataInfo.getFilePath());
     }
 
-//    @Override
-//    protected int valueAt(int plane, int offset) {
-//        // TODO(Moravec): Measure if caching the current plane byte buffer make any sense.
-//        if (plane != currentPlaneIndex) {
-//            currentPlaneIndex = plane;
-//            try {
-//                currentPlaneData = TypeConverter.unsignedShortBytesToIntArray(reader.openPlane(0, currentPlaneIndex).getBytes());
-//            } catch (FormatException e) {
-//                System.err.println(e.toString());
-//                e.printStackTrace();
-//                assert (false) : "FormatException in SCIFIOLoader::valueAt()";
-//            } catch (IOException e) {
-//                System.err.println(e.toString());
-//                e.printStackTrace();
-//                assert (false) : "IOException in SCIFIOLoader::valueAt()";
-//            }
-//        }
-//        return currentPlaneData[offset];
-//    }
-
     @Override
     public int[] loadPlaneData(final int plane) throws IOException {
         byte[] planeBytes;
@@ -129,9 +105,14 @@ public final class SCIFIOLoader extends BasicLoader implements IPlaneLoader {
         return values;
     }
 
+    @Override
+    public int[][] loadRowVectors(final int vectorSize, final Range<Integer> planeRange) throws IOException {
+        return loadRowVectorsImplByLoadPlaneData(vectorSize, planeRange);
+    }
+
     @Override
     public int[][] loadBlocks(V2i blockDim, Range<Integer> planeRange) throws IOException {
-        return loadBlocksImplLoadPlaneData(blockDim, planeRange);
+        return loadBlocksImplByLoadPlaneData(blockDim, planeRange);
     }
 
     @Override