private void scale(BufferedImage srcImg,byte[][] workPixels,BufferedImage outImage){
  final int[] tempPixels=new int[srcWidth];
  final byte[] srcPixels=new byte[srcWidth * nrChannels];
  final byte[] dstPixels=new byte[dstWidth * nrChannels];
  final BitSet isRowInitialized=new BitSet(srcHeight);
  for (int dstY=dstHeight - 1; dstY >= 0; dstY--) {
    final int yTimesNumContributors=dstY * verticalSubsamplingData.numContributors;
    final int max=verticalSubsamplingData.arrN[dstY];
{
      int index=yTimesNumContributors;
      for (int j=max - 1; j >= 0; j--) {
        int valueLocation=verticalSubsamplingData.arrPixel[index];
        index++;
        if (!isRowInitialized.get(valueLocation)) {
          isRowInitialized.set(valueLocation);
          ImageUtils.getPixelsBGR(srcImg,valueLocation,srcWidth,srcPixels,tempPixels);
          for (int channel=nrChannels - 1; channel >= 0; channel--) {
            getSamplesHorizontal(srcPixels,channel,tempPixels);
            for (int i=dstWidth - 1; i >= 0; i--) {
              int sampleLocation=i * nrChannels;
              final int horizontalMax=horizontalSubsamplingData.arrN[i];
              float sample=0.0f;
              int horizontalIndex=i * horizontalSubsamplingData.numContributors;
              for (int jj=horizontalMax - 1; jj >= 0; jj--) {
                sample+=tempPixels[horizontalSubsamplingData.arrPixel[horizontalIndex]] * horizontalSubsamplingData.arrWeight[horizontalIndex];
                horizontalIndex++;
              }
              putSample(workPixels[valueLocation],channel,(int)sample,sampleLocation);
            }
          }
        }
      }
    }
    for (int x=0; x < dstWidth; x++) {
      final int xLocation=x * nrChannels;
      final int sampleLocation=x * nrChannels;
      for (int channel=nrChannels - 1; channel >= 0; channel--) {
        float sample=0.0f;
        int index=yTimesNumContributors;
        for (int j=max - 1; j >= 0; j--) {
          int valueLocation=verticalSubsamplingData.arrPixel[index];
          sample+=(workPixels[valueLocation][xLocation + channel] & 0xff) * verticalSubsamplingData.arrWeight[index];
          index++;
        }
        putSample(dstPixels,channel,sample,sampleLocation);
      }
    }
    ImageUtils.setBGRPixels(dstPixels,outImage,0,dstY,dstWidth,1);
    setProgress(processedItems++,totalItems);
  }
}

private void scale ( BufferedImage srcImg , byte [ ] [ ] workPixels , BufferedImage outImage ) { final int [ ] tempPixels = new int [ srcWidth ] ; final byte [ ] srcPixels = new byte [ srcWidth * nrChannels ] ; final byte [ ] dstPixels = new byte [ dstWidth * nrChannels ] ; final BitSet isRowInitialized = new BitSet ( srcHeight ) ; for ( int dstY = dstHeight - 1 ; dstY >= 0 ; dstY -- ) { final int yTimesNumContributors = dstY * verticalSubsamplingData . numContributors ; final int max = verticalSubsamplingData . arrN [ dstY ] ; { int index = yTimesNumContributors ; for ( int j = max - 1 ; j >= 0 ; j -- ) { int valueLocation = verticalSubsamplingData . arrPixel [ index ] ; index ++ ; if ( ! isRowInitialized . get ( valueLocation ) ) { isRowInitialized . set ( valueLocation ) ; ImageUtils . getPixelsBGR ( srcImg , valueLocation , srcWidth , srcPixels , tempPixels ) ; for ( int channel = nrChannels - 1 ; channel >= 0 ; channel -- ) { getSamplesHorizontal ( srcPixels , channel , tempPixels ) ; for ( int i = dstWidth - 1 ; i >= 0 ; i -- ) { int sampleLocation = i * nrChannels ; final int horizontalMax = horizontalSubsamplingData . arrN [ i ] ; float sample = 0.0f ; int horizontalIndex = i * horizontalSubsamplingData . numContributors ; for ( int jj = horizontalMax - 1 ; jj >= 0 ; jj -- ) { sample += tempPixels [ horizontalSubsamplingData . arrPixel [ horizontalIndex ] ] * horizontalSubsamplingData . arrWeight [ horizontalIndex ] ; horizontalIndex ++ ; } putSample ( workPixels [ valueLocation ] , channel , ( int ) sample , sampleLocation ) ; } } } } } for ( int x = 0 ; x < dstWidth ; x ++ ) { final int xLocation = x * nrChannels ; final int sampleLocation = x * nrChannels ; for ( int channel = nrChannels - 1 ; channel >= 0 ; channel -- ) { float sample = 0.0f ; int index = yTimesNumContributors ; for ( int j = max - 1 ; j >= 0 ; j -- ) { int valueLocation = verticalSubsamplingData . arrPixel [ index ] ; sample += ( workPixels [ valueLocation ] [ xLocation + channel ] & 0xff ) * verticalSubsamplingData . arrWeight [ index ] ; index ++ ; } putSample ( dstPixels , channel , sample , sampleLocation ) ; } } ImageUtils . setBGRPixels ( dstPixels , outImage , 0 , dstY , dstWidth , 1 ) ; setProgress ( processedItems ++ , totalItems ) ; } }
pseudocode : for each for in destination image check that all dependent rows in source image is scaled horizontally and stored in work pixels if not then scale missing rows horizontal and store them in work pixels scale the destination row vertically and store the result in out pixels it may seem counter intuitive that the vertical scale is done for each row . the simple scaling algorithm would first scale the image horizontal ( a row at a time ) into the temp image , and then scale the temp image vertically ( a column at a time ) into the final image . the disadvantage of the simple approach is that you need a large temporary image . i have avoided this by doing the vertically scale a row at a time . scaling a single row vertically , needs the horizontally scaled rows that the scaling depends on . these dependencies will be lazy initialized . since we know the height of the ' window ' we work on ( the maximum number of source rows needed to calculate a dest row ) , the work pixels only needs to have the same height . instead of creating a temporary image with a height different from the source image ' s height , i created a double array where inner array is repeated ( so if the window height is 3 the first and the forth row is the same instance ) . this keeps algorithm a bit simpler ( the alternative would be to maintain a mapping between )
