/*
 * @(#)ClearType.java  1.2.1  2004-07-16
 *
 * Copyright (c) 1999 Werner Randelshofer, Immensee, Switzerland.
 * All rights reserved.
 *
 * You may not use, copy or modify this file, except in compliance with the
 * license agreement you entered into with Werner Randelshofer.
 * For details see accompanying license terms.
 */
/*
 * Source taken from
 * http://blog.monstuff.com/archives/000022.html
 */
package org.monte.media.image;

import java.awt.*;
import java.awt.geom.*;
import java.awt.image.*;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class ClearType {

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {

            public void run() {
                JFrame f = new JFrame();
                f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                f.setSize(430,180);
                f.setTitle("ClearType");
                JPanel p = new JPanel() {

                    public void update(Graphics g) {
                        paint(g);
                    }

                    public void paint(Graphics g) {
                        Font f = new Font("Times New Roman", Font.PLAIN, 18);

                        Graphics2D grph =(Graphics2D) g;
                        grph.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);
                        g.setFont(f);
                        g.setColor(Color.white);
                        g.fillRect(0, 0, getWidth(), getHeight());
                        g.setColor(Color.black);
                        g.drawString("Sample Text String", 5, getFontMetrics(f).getHeight());
                        drawClearType(g, "Sample Text String", 5, getFontMetrics(f).getHeight() * 3);
                    }

                    public void drawClearType(Graphics g, String s, int x, int y) {
                        Font f = g.getFont();
                       FontMetrics fm = getFontMetrics(f);
                        int width = fm.stringWidth(s) * 3;
                        int height = fm.getHeight();
                        BufferedImage img = (BufferedImage) createImage(width, height);
                        Graphics2D grph = img.createGraphics();
                        grph.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);
                        grph.setColor(Color.white);
                        grph.fillRect(0, 0, width, height);
                        grph.setColor(Color.black);
                        grph.setFont(f.deriveFont(AffineTransform.getScaleInstance(3, 1)));
                        grph.drawString(s, 0, height - fm.getMaxDescent());
                        int[] pixelsA = getPixelArray(img);
                        int[] pixels = new int[pixelsA.length];
                        int[] newpixels = new int[(width / 3) * height];
                        for (int i = 0; i < width * height; i++) {
                            newpixels[i / 3] = (0xff << 24);
                            if (i != width * height - 1) {
                                pixels[i + 1] = fuzz(pixels[i + 1], pixelsA[i]);
                            }
                            pixels[i] = fuzz(pixels[i], pixelsA[i]);
                            if (i != 0) {
                                pixels[i - 1] = fuzz(pixels[i - 1], pixelsA[i]);
                            }
                        }
                        for (int i = 0; i < width * height; i++) {
                            switch (i % 3) {
                                case 0:
                                    newpixels[i / 3] |= (pixels[i]) & 0xff0000;
                                    break;
                                case 1:
                                    newpixels[i / 3] |= (pixels[i]) & 0xff00;
                                    break;
                                case 2:
                                    newpixels[i / 3] |= (pixels[i]) & 0xff;
                                    break;
                            }
                        }
                        grph.dispose();
                        g.drawImage(imageFromPixels(newpixels, width / 3, height), x, y - height, width / 3, height, this);
                        g.drawImage(img, x,y,width,height,this);
                    }
                };
                f.setContentPane(p);
                f.setVisible(true);
            }
        });
    }

    /** Adds one third of b to a */
    private static int fuzz(int a, int b) {
        int red = ((b >> 16) & 0xff) / 3 + ((a >> 16) & 0xff);
        int green = ((b >> 8) & 0xff) / 3 + ((a >> 8) & 0xff);
        int blue = (b & 0xff) / 3 + (a & 0xff);
        return (0xff << 24) | (red << 16) | (green << 8) | blue;
    }

    private static int[] getPixelArray(Image img) {
        int width = img.getWidth(null);
        int height = img.getHeight(null);
        int[] pixels = new int[width * height];
        PixelGrabber pg = new PixelGrabber(img, 0, 0, width, height, pixels, 0, width);
        try {
            pg.grabPixels();
        } catch (Exception e) {
        }
        return pixels;
    }

    /** Renders an image with clear type. Note the width of the image must be divideable by 3. */
    public static void drawClearType(Graphics g, Image img, int x, int y, int superY, ImageObserver observer) {
        int width = img.getWidth(null);
        int height = img.getHeight(null);
        int[] pixelsA = getPixelArray(img);
        int[] pixels = new int[pixelsA.length];
        int[] newpixels = new int[(width / 3) * height];
        for (int i = 0; i < width * height; i++) {
            newpixels[i / 3] = (0xff << 24);
            if (i != width * height - 1) {
                pixels[i + 1] = fuzz(pixels[i + 1], pixelsA[i]);
            }
            pixels[i] = fuzz(pixels[i], pixelsA[i]);
            if (i != 0) {
                pixels[i - 1] = fuzz(pixels[i - 1], pixelsA[i]);
            }
        }
        for (int i = 0; i < width * height; i++) {
            switch (i % 3) {
                case 0:
                    newpixels[i / 3] |= (pixels[i]) & 0xff0000;
                    break;
                case 1:
                    newpixels[i / 3] |= (pixels[i]) & 0xff00;
                    break;
                case 2:
                    newpixels[i / 3] |= (pixels[i]) & 0xff;
                    break;
            }
        }
        g.drawImage(imageFromPixels(newpixels, width / 3, height), x, y, width / 3, height / superY, observer);
    }

    private static Image imageFromPixels(int[] pixels, int width, int height) {
        return Toolkit.getDefaultToolkit().createImage(new MemoryImageSource(width, height, pixels, 0, width));
    }
}

