package aliview.gui.pane;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;
import java.util.Arrays;
import org.apache.log4j.Logger;
public class CharPixels {
private static final Logger logger = Logger.getLogger(CharPixels.class);
public static final int CASE_UNTOUCHED = 0;
public static final int CASE_UPPER = 1;
public static final int CASE_LOWER = 2;
private char ch;
private Color color;
// RGB array has to be volatile so no problems araise with the double lock in getPixels(),
// see: http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html
private volatile RGBArray rgbArray;
private int width;
private int height;
private Graphics2D g2;
private Color bgColor;
private Color fgColor;
private Font font;
private int minFontSize;
private int fontCase;
public CharPixels(char ch, int width, int height, Color fgColor, Color bgColor, Font font, int minFontSize, int fontCase){
if(width < 1){
width = 1;
}
if(height < 1){
height = 1;
}
this.ch = ch;
this.width = width;
this.height = height;
this.font = font;
this.fgColor = fgColor;
this.bgColor = bgColor;
this.minFontSize = minFontSize;
this.fontCase = fontCase;
}
public int[] getPixels() {
return getRGBArray().getBackend();
}
public RGBArray getRGBArray(){
if(rgbArray == null){
// this is double locked to avoid synchronized block after the lazy initialization of RGBArray object
// RGBArray has to be declared volatile above
// see: http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html and http://en.wikipedia.org/wiki/Double-checked_locking
synchronized(this){
// double check if rgbArray has been created while thread was waiting
if(rgbArray == null){
BufferedImage bi = createPixelImageBufferedImage();
int[] origData = ((DataBufferInt)bi.getRaster().getDataBuffer()).getData();
// copy array
int[] pixCopy = Arrays.copyOf(origData, origData.length);
rgbArray = new RGBArray(pixCopy, width, height);
}
}
}
return rgbArray;
}
private BufferedImage createPixelImageBufferedImage(){
BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
g2 = bi.createGraphics();
g2.setFont(font);
// g2.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
// g2.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
// This need to be off because I use exact font width in createAdjustedDerivedBaseFont
g2.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_OFF);
if(width < 10){
g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
}
// g2.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_SPEED);
g2.setColor(bgColor);
g2.fillRect(0, 0, width, height);
// Only draw if font is a good size
if(width > minFontSize){
g2.setColor(fgColor);
int leftCharOffset = (int)(0.15 * width);
int bottomCharOffset = (int)(0.2 * height);
char displayChar = ch;
if(fontCase == CASE_UPPER){
displayChar = Character.toUpperCase(ch);
}else if(fontCase == CASE_LOWER){
displayChar = Character.toLowerCase(ch);
}
g2.drawString("" + displayChar, leftCharOffset, height - bottomCharOffset);
}
// int[] origData = ((DataBufferInt)bi.getRaster().getDataBuffer()).getData();
// logger.info("color" + g2.getColor());
// logger.info("beforeA=" + origData[0]);
// g2.setColor(new Color(0,0,0,140));
// g2.fillRect(0, 0, width, height);
// origData = ((DataBufferInt)bi.getRaster().getDataBuffer()).getData();
// logger.info("after_A=" + origData[0]);
// g2.dispose();
return bi;
}
}