1 /* 2 * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 import java.awt.Color; 24 import java.awt.Font; 25 import java.awt.Graphics2D; 26 import java.awt.RenderingHints; 27 import java.awt.image.BufferedImage; 28 import java.io.IOException; 29 30 /** 31 * @test 32 * @bug 8015070 33 * @summary Tests for artifacts around the edges of anti-aliased text 34 * drawn over translucent background color. 35 */ 36 public class AntialiasedTextArtifact { 37 /* Image dimensions */ 38 private static final int TEST_IMAGE_WIDTH = 200; 39 private static final int TEST_IMAGE_HEIGHT = 100; 40 41 /* 42 * The artifacts appear when text is drawn ontop of translucent 43 * background. In other words, a background with alpha channel. 44 * Hence we test the algorithm for image types that contain either 45 * straight alpha channel or pre-multiplied alpha channel. There 46 * are few other types as well that contain alpha channel. However, 47 * it would suffice to test on the most common formats TYPE_INT_ARGB 48 * and TYPE_INT_ARGB_PRE. 49 */ 50 private static final int[] TYPES = {BufferedImage.TYPE_INT_ARGB, 51 BufferedImage.TYPE_INT_ARGB_PRE}; 52 53 public static void main(String[] args) throws IOException { 54 /* Iterate over different image types */ 55 for (int type : TYPES) { 56 BufferedImage testImg = getBufferedImage(type); 57 58 /* Draw anti-aliased string and check for artifacts */ 59 drawAntialiasedString(testImg); 60 checkArtifact(testImg); 61 } 62 } 63 64 private static BufferedImage getBufferedImage(int imageType) { 65 /* Create a Graphics2D object from the given image type */ 66 BufferedImage image = new BufferedImage(TEST_IMAGE_WIDTH, 67 TEST_IMAGE_HEIGHT, 68 imageType); 69 return image; 70 } 71 72 private static void drawAntialiasedString(BufferedImage image) { 73 /* Create Graphics2D object */ 74 Graphics2D graphics = (Graphics2D) image.getGraphics(); 75 76 /* Fill the image with translucent color */ 77 graphics.setColor(new Color(127, 127, 127, 127)); 78 graphics.fillRect(0, 0, TEST_IMAGE_WIDTH, TEST_IMAGE_HEIGHT); 79 80 /* Drawstring with Antialiasing hint */ 81 graphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, 82 RenderingHints.VALUE_TEXT_ANTIALIAS_ON); 83 Font font = new Font("Verdana" , Font.PLAIN, 60); 84 graphics.setFont(font); 85 graphics.setColor(new Color(255, 0, 0)); 86 graphics.drawString("Save", 30, 65); 87 graphics.dispose(); 88 } 89 90 private static void checkArtifact(BufferedImage image) throws IOException { 91 int componentMask = 0xff; 92 int colorThreshold = 200; 93 int rowIndex = 0; 94 int colIndex = 0; 95 96 /* Loop through every pixel to check for possible artifact */ 97 for (rowIndex = 0; rowIndex < image.getHeight(); rowIndex++) { 98 for (colIndex = 0; colIndex < image.getWidth(); colIndex++) { 99 /* 100 * API: getRGB(x,y) returns color in INT_ARGB color space. 101 * Extract individual color components with a simple mask. 102 */ 103 int colorValue = image.getRGB(colIndex, rowIndex); 104 int colorComponent1 = colorValue & componentMask; 105 int colorComponent2 = (colorValue>>8) & componentMask; 106 int colorComponent3 = (colorValue>>16) & componentMask; 107 108 /* 109 * Artifacts are predominantly a subjective decision based on 110 * the quality of the rendered image content. However, in the 111 * current use-case, the artifacts around the edges of the anti 112 * aliased text appear like spots of white pixels without any 113 * relation to the color of foreground text or the background 114 * translucent shape. 115 * 116 * To identify the artifact pixels, each color component from 117 * the testImage is compared with a constant threshold. The 118 * component threshold has been set based on observation from 119 * different experiments on mulitple Java versions. 120 */ 121 if (colorComponent1 >= colorThreshold 122 && colorComponent2 >= colorThreshold 123 && colorComponent3 >= colorThreshold) { 124 /* Artifact has been noticed. Report error. */ 125 throw new RuntimeException("Test Failed."); 126 } 127 } 128 } 129 } 130 }