7116979: Unexpected pixel colour when converting images to TYPE_BYTE_INDEXED
Summary: Unexpected pixel colour when converting images to TYPE_BYTE_INDEXED
Reviewed-by: prr, flar
--- a/jdk/make/data/x11wrappergen/sizes.32 Thu May 05 22:39:36 2016 -0700
+++ b/jdk/make/data/x11wrappergen/sizes.32 Fri May 06 06:52:13 2016 +0000
@@ -206,7 +206,8 @@
ColorData.img_oda_blue 32
ColorData.pGrayInverseLutData 36
ColorData.screendata 40
-ColorData 44
+ColorData.representsPrimaries 44
+ColorData 48
XFontStruct.ext_data 0
XFontStruct.fid 4
XFontStruct.direction 8
--- a/jdk/make/data/x11wrappergen/sizes.64 Thu May 05 22:39:36 2016 -0700
+++ b/jdk/make/data/x11wrappergen/sizes.64 Fri May 06 06:52:13 2016 +0000
@@ -206,6 +206,7 @@
ColorData.img_oda_blue 64
ColorData.pGrayInverseLutData 72
ColorData.screendata 80
+ColorData.representsPrimaries 84
ColorData 88
XFontStruct.ext_data 0
XFontStruct.fid 8
--- a/jdk/make/data/x11wrappergen/sizes.64-solaris-i386 Thu May 05 22:39:36 2016 -0700
+++ b/jdk/make/data/x11wrappergen/sizes.64-solaris-i386 Fri May 06 06:52:13 2016 +0000
@@ -206,6 +206,7 @@
ColorData.img_oda_blue 64
ColorData.pGrayInverseLutData 72
ColorData.screendata 80
+ColorData.representsPrimaries 84
ColorData 88
XFontStruct.ext_data 0
XFontStruct.fid 8
--- a/jdk/make/data/x11wrappergen/xlibtypes.txt Thu May 05 22:39:36 2016 -0700
+++ b/jdk/make/data/x11wrappergen/xlibtypes.txt Fri May 06 06:52:13 2016 +0000
@@ -749,6 +749,7 @@
img_oda_blue pointer byte
pGrayInverseLutData pointer int
screendata int
+ representsPrimaries int
AwtGraphicsConfigData
awt_depth int
--- a/jdk/src/java.desktop/share/native/libawt/awt/image/BufImgSurfaceData.c Thu May 05 22:39:36 2016 -0700
+++ b/jdk/src/java.desktop/share/native/libawt/awt/image/BufImgSurfaceData.c Fri May 06 06:52:13 2016 +0000
@@ -231,12 +231,14 @@
pRasInfo->redErrTable = NULL;
pRasInfo->grnErrTable = NULL;
pRasInfo->bluErrTable = NULL;
+ pRasInfo->representsPrimaries = 0;
} else {
pRasInfo->invColorTable = bipriv->cData->img_clr_tbl;
pRasInfo->redErrTable = bipriv->cData->img_oda_red;
pRasInfo->grnErrTable = bipriv->cData->img_oda_green;
pRasInfo->bluErrTable = bipriv->cData->img_oda_blue;
pRasInfo->invGrayTable = bipriv->cData->pGrayInverseLutData;
+ pRasInfo->representsPrimaries = bipriv->cData->representsPrimaries;
}
}
@@ -259,6 +261,59 @@
}
}
+static int calculatePrimaryColorsApproximation(int* cmap, unsigned char* cube, int cube_size) {
+ int i, j, k;
+ int index, value, color;
+ // values calculated from cmap
+ int r, g, b;
+ // maximum positive/negative variation allowed for r, g, b values for primary colors
+ int delta = 5;
+ // get the primary color cmap indices from corner of inverse color table
+ for (i = 0; i < cube_size; i += (cube_size - 1)) {
+ for (j = 0; j < cube_size; j += (cube_size - 1)) {
+ for (k = 0; k < cube_size; k += (cube_size - 1)) {
+ // calculate inverse color table index
+ index = i + cube_size * (j + cube_size * k);
+ // get value present in corners of inverse color table
+ value = cube[index];
+ // use the corner values as index for cmap
+ color = cmap[value];
+ // extract r,g,b values from cmap value
+ r = ((color) >> 16) & 0xff;
+ g = ((color) >> 8) & 0xff;
+ b = color & 0xff;
+ /*
+ * If i/j/k value is 0 optimum value of b/g/r should be 0 but we allow
+ * maximum positive variation of 5. If i/j/k value is 31 optimum value
+ * of b/g/r should be 255 but we allow maximum negative variation of 5.
+ */
+ if (i == 0) {
+ if (b > delta)
+ return 0;
+ } else {
+ if (b < (255 - delta))
+ return 0;
+ }
+ if (j == 0) {
+ if (g > delta)
+ return 0;
+ } else {
+ if (g < (255 - delta))
+ return 0;
+ }
+ if (k == 0) {
+ if (r > delta)
+ return 0;
+ } else {
+ if (r < (255 - delta))
+ return 0;
+ }
+ }
+ }
+ }
+ return 1;
+}
+
static ColorData *BufImg_SetupICM(JNIEnv *env,
BufImgSDOps *bisdo)
{
@@ -298,6 +353,7 @@
}
cData->img_clr_tbl = initCubemap(pRgb, bisdo->lutsize, 32);
+ cData->representsPrimaries = calculatePrimaryColorsApproximation(pRgb, cData->img_clr_tbl, 32);
if (allGray == JNI_TRUE) {
initInverseGrayLut(pRgb, bisdo->lutsize, cData);
}
--- a/jdk/src/java.desktop/share/native/libawt/java2d/SurfaceData.h Thu May 05 22:39:36 2016 -0700
+++ b/jdk/src/java.desktop/share/native/libawt/java2d/SurfaceData.h Fri May 06 06:52:13 2016 +0000
@@ -163,6 +163,7 @@
char *grnErrTable; /* Green ordered dither table */
char *bluErrTable; /* Blue ordered dither table */
int *invGrayTable; /* Inverse gray table */
+ int representsPrimaries; /* whether cmap represents primary colors */
union {
void *align; /* ensures strict alignment */
char data[SD_RASINFO_PRIVATE_SIZE];
--- a/jdk/src/java.desktop/share/native/libawt/java2d/loops/ByteIndexed.h Thu May 05 22:39:36 2016 -0700
+++ b/jdk/src/java.desktop/share/native/libawt/java2d/loops/ByteIndexed.h Fri May 06 06:52:13 2016 +0000
@@ -43,7 +43,7 @@
jint *PREFIX ## Lut;
#define DeclareByteIndexedStoreVars(PREFIX) \
- int PREFIX ## XDither, PREFIX ## YDither; \
+ int PREFIX ## XDither, PREFIX ## YDither, PREFIX ## RepPrims; \
char *PREFIX ## rerr, *PREFIX ## gerr, *PREFIX ## berr; \
unsigned char *PREFIX ## InvLut;
@@ -70,6 +70,7 @@
do { \
SetByteIndexedStoreVarsYPos(PREFIX, pRasInfo, (pRasInfo)->bounds.y1); \
PREFIX ## InvLut = (pRasInfo)->invColorTable; \
+ PREFIX ## RepPrims = (pRasInfo)->representsPrimaries; \
} while (0)
#define InitByteIndexedStoreVarsX(PREFIX, pRasInfo) \
@@ -168,9 +169,14 @@
#define StoreByteIndexedFrom3ByteRgb(pRas, PREFIX, x, r, g, b) \
do { \
- r += PREFIX ## rerr[PREFIX ## XDither]; \
- g += PREFIX ## gerr[PREFIX ## XDither]; \
- b += PREFIX ## berr[PREFIX ## XDither]; \
+ if (!(((r == 0) || (r == 255)) && \
+ ((g == 0) || (g == 255)) && \
+ ((b == 0) || (b == 255)) && \
+ PREFIX ## RepPrims)) { \
+ r += PREFIX ## rerr[PREFIX ## XDither]; \
+ g += PREFIX ## gerr[PREFIX ## XDither]; \
+ b += PREFIX ## berr[PREFIX ## XDither]; \
+ } \
ByteClamp3Components(r, g, b); \
(pRas)[x] = SurfaceData_InvColorMap(PREFIX ## InvLut, r, g, b); \
} while (0)
--- a/jdk/src/java.desktop/unix/native/common/awt/colordata.h Thu May 05 22:39:36 2016 -0700
+++ b/jdk/src/java.desktop/unix/native/common/awt/colordata.h Fri May 06 06:52:13 2016 +0000
@@ -44,6 +44,7 @@
char* img_oda_blue;
int *pGrayInverseLutData;
int screendata;
+ int representsPrimaries;
} ColorData;
--- a/jdk/src/java.desktop/windows/native/libawt/windows/colordata.h Thu May 05 22:39:36 2016 -0700
+++ b/jdk/src/java.desktop/windows/native/libawt/windows/colordata.h Fri May 06 06:52:13 2016 +0000
@@ -33,6 +33,7 @@
char* img_oda_blue;
unsigned char* img_clr_tbl;
int *pGrayInverseLutData;
+ int representsPrimaries;
} ColorData;
#define CANFREE(pData) (pData)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/java2d/loops/ConvertToByteIndexedTest.java Fri May 06 06:52:13 2016 +0000
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 7116979
+ * @summary Test verifies whether BufferedImage with primary colors are
+ * stored properly when we draw into ByteIndexed BufferedImage.
+ * @run main ConvertToByteIndexedTest
+ */
+
+import java.awt.Color;
+import java.awt.Graphics2D;
+import java.awt.image.BufferedImage;
+import java.util.HashMap;
+
+public class ConvertToByteIndexedTest {
+ static final int[] SRC_TYPES = new int[] {
+ BufferedImage.TYPE_INT_RGB,
+ BufferedImage.TYPE_INT_ARGB,
+ BufferedImage.TYPE_INT_ARGB_PRE,
+ BufferedImage.TYPE_INT_BGR,
+ BufferedImage.TYPE_3BYTE_BGR,
+ BufferedImage.TYPE_4BYTE_ABGR,
+ BufferedImage.TYPE_4BYTE_ABGR_PRE,
+ BufferedImage.TYPE_USHORT_565_RGB,
+ BufferedImage.TYPE_USHORT_555_RGB,
+ BufferedImage.TYPE_BYTE_INDEXED};
+
+ static final String[] TYPE_NAME = new String[] {
+ "INT_RGB",
+ "INT_ARGB",
+ "INT_ARGB_PRE",
+ "INT_BGR",
+ "3BYTE_BGR",
+ "4BYTE_ABGR",
+ "4BYTE_ABGR_PRE",
+ "USHORT_565_RGB",
+ "USHORT_555_RGB",
+ "BYTE_INDEXED"};
+
+ static final Color[] COLORS = new Color[] {
+ //Color.WHITE,
+ Color.BLACK,
+ Color.RED,
+ Color.YELLOW,
+ Color.GREEN,
+ Color.MAGENTA,
+ Color.CYAN,
+ Color.BLUE};
+
+ static final HashMap<Integer,String> TYPE_TABLE =
+ new HashMap<Integer,String>();
+
+ static {
+ for (int i = 0; i < SRC_TYPES.length; i++) {
+ TYPE_TABLE.put(new Integer(SRC_TYPES[i]), TYPE_NAME[i]);
+ }
+ }
+
+ static int width = 50;
+ static int height = 50;
+
+ public static void ConvertToByteIndexed(Color color, int srcType) {
+ // setup source image and graphics for conversion.
+ BufferedImage srcImage = new BufferedImage(width, height, srcType);
+ Graphics2D srcG2D = srcImage.createGraphics();
+ srcG2D.setColor(color);
+ srcG2D.fillRect(0, 0, width, height);
+
+ // setup destination image and graphics for conversion.
+ int dstType = BufferedImage.TYPE_BYTE_INDEXED;
+ BufferedImage dstImage = new BufferedImage(width, height, dstType);
+ Graphics2D dstG2D = (Graphics2D)dstImage.getGraphics();
+ // draw source image into Byte Indexed destination
+ dstG2D.drawImage(srcImage, 0, 0, null);
+
+ // draw into ARGB image to verify individual pixel value.
+ BufferedImage argbImage = new BufferedImage(width, height,
+ BufferedImage.TYPE_INT_ARGB);
+ Graphics2D argbG2D = (Graphics2D)argbImage.getGraphics();
+ argbG2D.drawImage(dstImage, 0, 0, null);
+
+ for (int i = 0; i < width; i++) {
+ for (int j = 0; j < height; j++) {
+ if (color.getRGB() != argbImage.getRGB(i, j)) {
+ throw new RuntimeException("Conversion from " +
+ TYPE_TABLE.get(srcType) + " to BYTE_INDEXED is not"
+ + " done properly for " + color);
+ }
+ }
+ }
+ }
+
+ public static void main(String args[]) {
+ for (int srcType : SRC_TYPES) {
+ for (Color color : COLORS) {
+ ConvertToByteIndexed(color, srcType);
+ }
+ }
+ }
+}