High constrast regions become ‘darker’ when scaling down. Use this (slow) code to fixy fixy.
vs.
vs.
Have fun.
public static BufferedImage mipmapGammaCorrected(BufferedImage src, int level)
{
if (level < 1)
{
throw new IllegalArgumentException();
}
for (int i = 0; i < level; i++)
{
BufferedImage tmp = mipmapGammaCorrected(src);
if (i != 0)
src.flush(); // do not flush argument
src = tmp;
}
return src;
}
public static BufferedImage mipmapGammaCorrected(BufferedImage src)
{
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);
int r = gammaCorrectedAverage(p0, p1, p2, p3, 16);
int g = gammaCorrectedAverage(p0, p1, p2, p3, 8);
int b = gammaCorrectedAverage(p0, p1, p2, p3, 0);
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)
{
float x = ((a >> shift) & 0xFF) / 255.0f;
float y = ((b >> shift) & 0xFF) / 255.0f;
float z = ((c >> shift) & 0xFF) / 255.0f;
float w = ((d >> shift) & 0xFF) / 255.0f;
float e = x * x + y * y + z * z + w * w;
e = (float) Math.sqrt(e * 0.25f);
return (int) (e * 255.0f);
}