
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import javax.imageio.*;
import javax.imageio.metadata.*;
import javax.imageio.stream.*;
import javax.imageio.plugins.tiff.*;


public class BPSTest {

    private final static String FILENAME = "test.tiff";
    private final static int W = 20, H = 40;
    private final static Color C = Color.BLACK;

    private static final int TYPES[] = {

        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_GRAY,      BufferedImage.TYPE_USHORT_GRAY,
        BufferedImage.TYPE_BYTE_BINARY,    BufferedImage.TYPE_BYTE_INDEXED };

    private static final String NAMES[] = {

        "TYPE_INT_RGB",
        "TYPE_INT_ARGB",       "TYPE_INT_ARGB_PRE",
        "TYPE_INT_BGR",        "TYPE_3BYTE_BGR",
        "TYPE_4BYTE_ABGR",     "TYPE_4BYTE_ABGR_PRE",
        "TYPE_USHORT_565_RGB", "TYPE_USHORT_555_RGB",
        "TYPE_BYTE_GRAY",      "TYPE_USHORT_GRAY",
        "TYPE_BYTE_BINARY",    "TYPE_BYTE_INDEXED" };

    
    private int imgType;
    
    public BPSTest(int type) { imgType = type; }
    
    private ImageWriter getTIFFWriter() {

        java.util.Iterator<ImageWriter> writers =
            ImageIO.getImageWritersByFormatName("TIFF");
        if (!writers.hasNext()) {
            throw new RuntimeException("No writers available for TIFF format");
        }
        return writers.next();
    }

    private ImageReader getTIFFReader() {

        java.util.Iterator<ImageReader> readers =
            ImageIO.getImageReadersByFormatName("TIFF");
        if (!readers.hasNext()) {
            throw new RuntimeException("No readers available for TIFF format");
        }
        return readers.next();
    }

    private void writeImage() throws Exception {

        OutputStream s = new BufferedOutputStream(new FileOutputStream(FILENAME));
        try (ImageOutputStream ios = ImageIO.createImageOutputStream(s)) {

            ImageWriter writer = getTIFFWriter();
            writer.setOutput(ios);

            BufferedImage img =
                new BufferedImage(W, H, imgType);
            Graphics g = img.getGraphics();
            g.setColor(C);
            g.fillRect(0, 0, W, H);
            g.dispose();


            IIOMetadata meta = writer.getDefaultImageMetadata(
                    new ImageTypeSpecifier(img), writer.getDefaultWriteParam());
            writer.write(new IIOImage(img, null, meta));

            ios.flush();
            writer.dispose();
        }
        s.close();
    }

    private void checkBufferedImage(BufferedImage im) {

        check(im.getWidth()  == W, "invalid width for image");
        check(im.getHeight() == H, "invalid height for image");

        Color c = new Color(im.getRGB(W / 2, H / 2));
        check(c.equals(C), "invalid image color");
    }

    private void readImage() throws Exception {

        ImageReader reader = getTIFFReader();

        ImageInputStream s = ImageIO.createImageInputStream(new File(FILENAME));
        reader.setInput(s, false, true);

        int ni = reader.getNumImages(true);
        check(ni == 1, "invalid number of images");

        // read images and metadata
        IIOImage i = reader.readAll(0, null);
        BufferedImage
            bi = (BufferedImage) i.getRenderedImage();
        
        // check rendered images, just in case
        checkBufferedImage(bi);
        
        int csz[] = bi.getColorModel().getComponentSize();
        System.out.print("[ ");
        for (int c: csz) { System.out.print(c + " "); }
        System.out.print("] / ");
        

        TIFFDirectory dir = TIFFDirectory.createFromMetadata(i.getMetadata());
        TIFFField f = dir.getTIFFField(BaselineTIFFTagSet.TAG_BITS_PER_SAMPLE);
        if (f == null) { System.out.println("NULL"); }
        else {
            csz = f.getAsInts();
            System.out.print("[ ");
            for (int c: csz) { System.out.print(c + " "); }
            System.out.println("]");
        }
    }

    public void run() throws Exception {
        writeImage();
        readImage();
    }

    private void check(boolean ok, String msg) {
        if (!ok) { throw new RuntimeException(msg); }
    }

    public static void main(String[] args) throws Exception {
        
        for (int i = 0; i < TYPES.length; i++) {
            System.out.print(String.format("%1$-25s", NAMES[i]));
            (new BPSTest(TYPES[i])).run();
        }
    }
}
