content: 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);
  		
  		// Always Antialias is the best for now I would say
  		g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
  		
  //		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;
  	}
  
  }
  