public class ImageUtil { public static BufferedImage mipmapGammaCorrected( BufferedImage src, int level, double gamma) { if (level < 1) { throw new IllegalArgumentException(); } for (int i = 0; i < level; i++) { BufferedImage tmp = mipmapGammaCorrected(src, gamma); if (i != 0) src.flush(); // do not flush argument src = tmp; } return src; } public static BufferedImage mipmapGammaCorrected(BufferedImage src, double gamma) { int wSrc = src.getWidth(); int hSrc = src.getHeight(); if (wSrc % 2 != 0 || hSrc % 2 != 0) { throw new IllegalStateException("dimensions must be multiple of 2"); } int wDst = wSrc / 2; int hDst = hSrc / 2; int[] argbFull = src.getRGB(0, 0, wSrc, hSrc, null, 0, wSrc); int type = BufferedImage.TYPE_INT_RGB; if (src.getAlphaRaster() != null) { type = BufferedImage.TYPE_INT_ARGB; // merge alpha into RGB values int[] alphaFull = src.getAlphaRaster().getPixels(0, 0, wSrc, hSrc, (int[]) null); for (int i = 0; i < alphaFull.length; i++) { argbFull[i] = (alphaFull[i] << 24) | (argbFull[i] & 0x00FFFFFF); } } BufferedImage half = new BufferedImage(wDst, hDst, type); int[] argbHalf = new int[argbFull.length >>> 2]; for (int y = 0; y < hDst; y++) { for (int x = 0; x < wDst; x++) { int p0 = argbFull[((y << 1) | 0) * wSrc + ((x << 1) | 0)]; int p1 = argbFull[((y << 1) | 1) * wSrc + ((x << 1) | 0)]; int p2 = argbFull[((y << 1) | 1) * wSrc + ((x << 1) | 1)]; int p3 = argbFull[((y << 1) | 0) * wSrc + ((x << 1) | 1)]; int a = gammaCorrectedAverage(p0, p1, p2, p3, 24, gamma); int r = gammaCorrectedAverage(p0, p1, p2, p3, 16, gamma); int g = gammaCorrectedAverage(p0, p1, p2, p3, 8, gamma); int b = gammaCorrectedAverage(p0, p1, p2, p3, 0, gamma); argbHalf[y * wDst + x] = (a << 24) | (r << 16) | (g << 8) | (b << 0); } } half.setRGB(0, 0, wDst, hDst, argbHalf, 0, wDst); if (type == BufferedImage.TYPE_INT_ARGB) { // extract alpha from ARGB values int[] alpha = new int[argbHalf.length]; for (int i = 0; i < alpha.length; i++) alpha[i] = (argbHalf[i] >> 24) & 0xFF; half.getAlphaRaster().setPixels(0, 0, wDst, hDst, alpha); } return half; } static int gammaCorrectedAverage(int a, int b, int c, int d, int shift, double gamma) { double x = Math.pow(((a >> shift) & 0xFF) / 255.0f, gamma); double y = Math.pow(((b >> shift) & 0xFF) / 255.0f, gamma); double z = Math.pow(((c >> shift) & 0xFF) / 255.0f, gamma); double w = Math.pow(((d >> shift) & 0xFF) / 255.0f, gamma); return (int) Math.round(Math.pow((x+y+z+w) * 0.25f, 1.0 / gamma) * 255.0); } }
2009-08-25
Image :: mipmap with gamma
Most people don't realize that when you scale down an image, the gamma changes. For those who care, here is the code to fixy fixy:
Subscribe to:
Post Comments (Atom)
No comments:
Post a Comment