public void writeImage()

in src/main/java/org/apache/commons/imaging/formats/gif/GifImageParser.java [839:1086]


    public void writeImage(BufferedImage src, OutputStream os, Map params)
            throws ImageWriteException, IOException
    {
        // make copy of params; we'll clear keys as we consume them.
        params = new HashMap(params);

        boolean verbose = ParamMap.getParamBoolean(params, PARAM_KEY_VERBOSE,
                false);

        // clear format key.
        if (params.containsKey(PARAM_KEY_FORMAT))
            params.remove(PARAM_KEY_FORMAT);
        if (params.containsKey(PARAM_KEY_VERBOSE))
            params.remove(PARAM_KEY_VERBOSE);

        String xmpXml = null;
        if (params.containsKey(PARAM_KEY_XMP_XML))
        {
            xmpXml = (String) params.get(PARAM_KEY_XMP_XML);
            params.remove(PARAM_KEY_XMP_XML);
        }

        if (params.size() > 0)
        {
            Object firstKey = params.keySet().iterator().next();
            throw new ImageWriteException("Unknown parameter: " + firstKey);
        }

        int width = src.getWidth();
        int height = src.getHeight();

        boolean hasAlpha = new PaletteFactory().hasTransparency(src);

        int max_colors = hasAlpha ? 255 : 256;

        Palette palette2 = new PaletteFactory().makePaletteSimple(src,
                max_colors);
        // int palette[] = new PaletteFactory().makePaletteSimple(src, 256);
        // Map palette_map = paletteToMap(palette);

        if (palette2 == null)
        {
            palette2 = new PaletteFactory().makePaletteQuantized(src,
                    max_colors);
            if (verbose)
                System.out.println("quantizing");
        } else if (verbose)
            System.out.println("exact palette");

        if (palette2 == null)
            throw new ImageWriteException(
                    "Gif: can't write images with more than 256 colors");
        int palette_size = palette2.length() + (hasAlpha ? 1 : 0);

        BinaryOutputStream bos = new BinaryOutputStream(os, BYTE_ORDER_LSB);

        {
            // write Header
            os.write(0x47); // G magic numbers
            os.write(0x49); // I
            os.write(0x46); // F

            os.write(0x38); // 8 version magic numbers
            os.write(0x39); // 9
            os.write(0x61); // a

            // Logical Screen Descriptor.

            bos.write2Bytes(width);
            bos.write2Bytes(height);

            int colorTableScaleLessOne = (palette_size > 128) ? 7
                    : (palette_size > 64) ? 6 : (palette_size > 32) ? 5
                            : (palette_size > 16) ? 4 : (palette_size > 8) ? 3
                                    : (palette_size > 4) ? 2
                                            : (palette_size > 2) ? 1 : 0;

            int colorTableSizeInFormat = 1 << (colorTableScaleLessOne + 1);
            int actual_size = 3 * simple_pow(2, colorTableScaleLessOne + 1);
            {
                byte colorResolution = (byte) colorTableScaleLessOne; // TODO:

                boolean globalColorTableFlag = false;
                boolean sortFlag = false;
                int globalColorTableFlagMask = 1 << 7;
                int sortFlagMask = 8;
                int sizeOfGlobalColorTable = 0;

                int packedFields = ((globalColorTableFlag ? globalColorTableFlagMask
                        : 0)
                        | (sortFlag ? sortFlagMask : 0)
                        | ((7 & colorResolution) << 4) | (7 & sizeOfGlobalColorTable));
                bos.write(packedFields); // one byte
            }
            {
                byte BackgroundColorIndex = 0;
                bos.write(BackgroundColorIndex);
            }
            {
                byte PixelAspectRatio = 0;
                bos.write(PixelAspectRatio);
            }

            { // write Global Color Table.

            }

            { // ALWAYS write GraphicControlExtension
                bos.write(EXTENSION_CODE);
                bos.write((byte) 0xf9);
                // bos.write(0xff & (kGraphicControlExtension >> 8));
                // bos.write(0xff & (kGraphicControlExtension >> 0));

                bos.write((byte) 4); // block size;
                int packedFields = hasAlpha ? 1 : 0; // transparency flag
                bos.write((byte) packedFields);
                bos.write((byte) 0); // Delay Time
                bos.write((byte) 0); // Delay Time
                bos.write((byte) (hasAlpha ? palette2.length() : 0)); // Transparent
                // Color
                // Index
                bos.write((byte) 0); // terminator
            }

            if (null != xmpXml)
            {
                bos.write(EXTENSION_CODE);
                bos.write(APPLICATION_EXTENSION_LABEL);

                bos.write(XMP_APPLICATION_ID_AND_AUTH_CODE.length); // 0x0B
                bos.write(XMP_APPLICATION_ID_AND_AUTH_CODE);

                byte xmpXmlBytes[] = xmpXml.getBytes("utf-8");
                bos.write(xmpXmlBytes);

                // write "magic trailer"
                for (int magic = 0; magic <= 0xff; magic++)
                    bos.write(0xff - magic);

                bos.write((byte) 0); // terminator

            }

            { // Image Descriptor.
                bos.write(IMAGE_SEPARATOR);
                bos.write2Bytes(0); // Image Left Position
                bos.write2Bytes(0); // Image Top Position
                bos.write2Bytes(width); // Image Width
                bos.write2Bytes(height); // Image Height

                {
                    boolean LocalColorTableFlag = true;
                    // boolean LocalColorTableFlag = false;
                    boolean InterlaceFlag = false;
                    boolean SortFlag = false;
                    int SizeOfLocalColorTable = colorTableScaleLessOne;

                    // int SizeOfLocalColorTable = 0;

                    int PackedFields = ((LocalColorTableFlag ? LOCAL_COLOR_TABLE_FLAG_MASK
                            : 0)
                            | (InterlaceFlag ? INTERLACE_FLAG_MASK : 0)
                            | (SortFlag ? SORT_FLAG_MASK : 0) | (7 & SizeOfLocalColorTable));
                    bos.write(PackedFields); // one byte
                }
            }

            { // write Local Color Table.
                for (int i = 0; i < colorTableSizeInFormat; i++)
                {
                    if (i < palette2.length())
                    {
                        int rgb = palette2.getEntry(i);

                        int red = 0xff & (rgb >> 16);
                        int green = 0xff & (rgb >> 8);
                        int blue = 0xff & (rgb >> 0);

                        bos.write(red);
                        bos.write(green);
                        bos.write(blue);
                    } else
                    {
                        bos.write(0);
                        bos.write(0);
                        bos.write(0);
                    }
                }
            }

            { // get Image Data.
                int image_data_total = 0;

                int LZWMinimumCodeSize = colorTableScaleLessOne + 1;
//                LZWMinimumCodeSize = Math.max(8, LZWMinimumCodeSize);
                if (LZWMinimumCodeSize < 2)
                    LZWMinimumCodeSize = 2;

                // TODO:
                // make
                // better
                // choice
                // here.
                bos.write(LZWMinimumCodeSize);

                MyLzwCompressor compressor = new MyLzwCompressor(
                        LZWMinimumCodeSize, BYTE_ORDER_LSB, false); // GIF
                // Mode);

                byte imagedata[] = new byte[width * height];
                for (int y = 0; y < height; y++)
                {
                    for (int x = 0; x < width; x++)
                    {
                        int argb = src.getRGB(x, y);
                        int rgb = 0xffffff & argb;
                        int index;

                        if (hasAlpha)
                        {
                            int alpha = 0xff & (argb >> 24);
                            final int alphaThreshold = 255;
                            if (alpha < alphaThreshold)
                                index = palette2.length(); // is transparent
                            else
                                index = palette2.getPaletteIndex(rgb);
                        } else
                        {
                            index = palette2.getPaletteIndex(rgb);
                        }

                        imagedata[y * width + x] = (byte) index;
                    }
                }

                byte compressed[] = compressor.compress(imagedata);
                writeAsSubBlocks(bos, compressed);
                image_data_total += compressed.length;
            }

            // palette2.dump();

            bos.write(TERMINATOR_BYTE);
        }

        bos.close();
        os.close();
    }