// We compress horizontally first, then vertically // which I think may be the fastest way. // // Up to 7 pixel columns and 7 pixel rows may be discarded // (those not fitting in an 8x8 block). The discarded pixels are // along the right and bottom border of the image, respectively. sclass FastDownscale8x8 { int w, h, w2, h2; int[] horizontallyScaledPixels, finalPixels; void scaleHorizontally(BufferedImage img) { scaleHorizontally(grabbableIntPixels(img)); } void scaleHorizontally(GrabbableIntPixels gp) { int scaleX = 8, scaleY = scaleX; w = gp.w; int h = this.h = gp.h; int w2 = this.w2 = w/scaleX, h2 = this.h2 = h/scaleY; int[] newPixels = horizontallyScaledPixels = new int[w2*h]; int iRow = gp.offset, iOut = 0; int[] pixels = gp.data; for (int y = 0; y < h; y++) { int iIn = iRow; for x to w2: { int r = 0, g = 0, b = 0; for subX to 8: { int rgb = pixels[iIn+subX]; r += (rgb >> 16) & 0xFF; g += (rgb >> 8) & 0xFF; b += rgb & 0xFF; } iIn += 8; newPixels[iOut++] = rgbIntFullAlpha(r/scaleX, g/scaleX, b/scaleX); } iRow += gp.scanlineStride; } // for y } void scaleVertically { int scaleX = 8, scaleY = scaleX; int[] pixels = horizontallyScaledPixels; int[] newPixels = finalPixels = new int[w2*h2]; int iRow = 0, iOut = 0; for (int y = 0; y < h2; y++) { int iIn = iRow; for x to w2: { int r = 0, g = 0, b = 0; int iIn2 = iIn; for subY to 8: { int rgb = pixels[iIn2]; iIn2 += w2; r += (rgb >> 16) & 0xFF; g += (rgb >> 8) & 0xFF; b += rgb & 0xFF; } iIn++; newPixels[iOut++] = rgbIntFullAlpha(r/scaleX, g/scaleX, b/scaleX); } iRow += w2*scaleY; } // for y } BufferedImage get(BufferedImage img) { scaleHorizontally(img); scaleVertically(); ret get(); } BufferedImage get() { ret bufferedImage(w2, h2, finalPixels); } }