Source Code Cross Referenced for GIFImageWriter.java in  » 6.0-JDK-Modules » Java-Advanced-Imaging » com » sun » media » imageioimpl » plugins » gif » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » 6.0 JDK Modules » Java Advanced Imaging » com.sun.media.imageioimpl.plugins.gif 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * $RCSfile: GIFImageWriter.java,v $
0003:         *
0004:         * 
0005:         * Copyright (c) 2005 Sun Microsystems, Inc. All  Rights Reserved.
0006:         * 
0007:         * Redistribution and use in source and binary forms, with or without
0008:         * modification, are permitted provided that the following conditions
0009:         * are met: 
0010:         * 
0011:         * - Redistribution of source code must retain the above copyright 
0012:         *   notice, this  list of conditions and the following disclaimer.
0013:         * 
0014:         * - Redistribution in binary form must reproduce the above copyright
0015:         *   notice, this list of conditions and the following disclaimer in 
0016:         *   the documentation and/or other materials provided with the
0017:         *   distribution.
0018:         * 
0019:         * Neither the name of Sun Microsystems, Inc. or the names of 
0020:         * contributors may be used to endorse or promote products derived 
0021:         * from this software without specific prior written permission.
0022:         * 
0023:         * This software is provided "AS IS," without a warranty of any 
0024:         * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND 
0025:         * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, 
0026:         * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
0027:         * EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL 
0028:         * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF 
0029:         * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
0030:         * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR 
0031:         * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
0032:         * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
0033:         * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
0034:         * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
0035:         * POSSIBILITY OF SUCH DAMAGES. 
0036:         * 
0037:         * You acknowledge that this software is not designed or intended for 
0038:         * use in the design, construction, operation or maintenance of any 
0039:         * nuclear facility. 
0040:         *
0041:         * $Revision: 1.3 $
0042:         * $Date: 2006/03/24 22:30:10 $
0043:         * $State: Exp $
0044:         */
0045:
0046:        package com.sun.media.imageioimpl.plugins.gif;
0047:
0048:        import java.awt.Dimension;
0049:        import java.awt.Rectangle;
0050:        import java.awt.image.ColorModel;
0051:        import java.awt.image.ComponentSampleModel;
0052:        import java.awt.image.DataBufferByte;
0053:        import java.awt.image.IndexColorModel;
0054:        import java.awt.image.Raster;
0055:        import java.awt.image.RenderedImage;
0056:        import java.awt.image.SampleModel;
0057:        import java.awt.image.WritableRaster;
0058:        import java.io.IOException;
0059:        import java.nio.ByteOrder;
0060:        import java.util.Arrays;
0061:        import java.util.Iterator;
0062:        import java.util.Locale;
0063:        import javax.imageio.IIOException;
0064:        import javax.imageio.IIOImage;
0065:        import javax.imageio.ImageTypeSpecifier;
0066:        import javax.imageio.ImageWriteParam;
0067:        import javax.imageio.ImageWriter;
0068:        import javax.imageio.spi.ImageWriterSpi;
0069:        import javax.imageio.metadata.IIOInvalidTreeException;
0070:        import javax.imageio.metadata.IIOMetadata;
0071:        import javax.imageio.metadata.IIOMetadataFormatImpl;
0072:        import javax.imageio.metadata.IIOMetadataNode;
0073:        import javax.imageio.stream.ImageOutputStream;
0074:        import org.w3c.dom.Node;
0075:        import org.w3c.dom.NodeList;
0076:        import com.sun.media.imageioimpl.common.LZWCompressor;
0077:        import com.sun.media.imageioimpl.common.PaletteBuilder;
0078:
0079:        public class GIFImageWriter extends ImageWriter {
0080:            private static final boolean DEBUG = false; // XXX false for release!
0081:
0082:            static final String STANDARD_METADATA_NAME = IIOMetadataFormatImpl.standardMetadataFormatName;
0083:
0084:            static final String STREAM_METADATA_NAME = GIFWritableStreamMetadata.NATIVE_FORMAT_NAME;
0085:
0086:            static final String IMAGE_METADATA_NAME = GIFWritableImageMetadata.NATIVE_FORMAT_NAME;
0087:
0088:            /**
0089:             * The <code>output</code> case to an <code>ImageOutputStream</code>.
0090:             */
0091:            private ImageOutputStream stream = null;
0092:
0093:            /**
0094:             * Whether a sequence is being written.
0095:             */
0096:            private boolean isWritingSequence = false;
0097:
0098:            /**
0099:             * Whether the header has been written.
0100:             */
0101:            private boolean wroteSequenceHeader = false;
0102:
0103:            /**
0104:             * The stream metadata of a sequence.
0105:             */
0106:            private GIFWritableStreamMetadata theStreamMetadata = null;
0107:
0108:            /**
0109:             * The index of the image being written.
0110:             */
0111:            private int imageIndex = 0;
0112:
0113:            /**
0114:             * The number of bits represented by the value which should be a
0115:             * legal length for a color table.
0116:             */
0117:            private static int getNumBits(int value) throws IOException {
0118:                int numBits;
0119:                switch (value) {
0120:                case 2:
0121:                    numBits = 1;
0122:                    break;
0123:                case 4:
0124:                    numBits = 2;
0125:                    break;
0126:                case 8:
0127:                    numBits = 3;
0128:                    break;
0129:                case 16:
0130:                    numBits = 4;
0131:                    break;
0132:                case 32:
0133:                    numBits = 5;
0134:                    break;
0135:                case 64:
0136:                    numBits = 6;
0137:                    break;
0138:                case 128:
0139:                    numBits = 7;
0140:                    break;
0141:                case 256:
0142:                    numBits = 8;
0143:                    break;
0144:                default:
0145:                    throw new IOException("Bad palette length: " + value + "!");
0146:                }
0147:
0148:                return numBits;
0149:            }
0150:
0151:            /**
0152:             * Compute the source region and destination dimensions taking any
0153:             * parameter settings into account.
0154:             */
0155:            private static void computeRegions(Rectangle sourceBounds,
0156:                    Dimension destSize, ImageWriteParam p) {
0157:                ImageWriteParam param;
0158:                int periodX = 1;
0159:                int periodY = 1;
0160:                if (p != null) {
0161:                    int[] sourceBands = p.getSourceBands();
0162:                    if (sourceBands != null
0163:                            && (sourceBands.length != 1 || sourceBands[0] != 0)) {
0164:                        throw new IllegalArgumentException(
0165:                                "Cannot sub-band image!");
0166:                    }
0167:
0168:                    // Get source region and subsampling factors
0169:                    Rectangle sourceRegion = p.getSourceRegion();
0170:                    if (sourceRegion != null) {
0171:                        // Clip to actual image bounds
0172:                        sourceRegion = sourceRegion.intersection(sourceBounds);
0173:                        sourceBounds.setBounds(sourceRegion);
0174:                    }
0175:
0176:                    // Adjust for subsampling offsets
0177:                    int gridX = p.getSubsamplingXOffset();
0178:                    int gridY = p.getSubsamplingYOffset();
0179:                    sourceBounds.x += gridX;
0180:                    sourceBounds.y += gridY;
0181:                    sourceBounds.width -= gridX;
0182:                    sourceBounds.height -= gridY;
0183:
0184:                    // Get subsampling factors
0185:                    periodX = p.getSourceXSubsampling();
0186:                    periodY = p.getSourceYSubsampling();
0187:                }
0188:
0189:                // Compute output dimensions
0190:                destSize.setSize((sourceBounds.width + periodX - 1) / periodX,
0191:                        (sourceBounds.height + periodY - 1) / periodY);
0192:                if (destSize.width <= 0 || destSize.height <= 0) {
0193:                    throw new IllegalArgumentException("Empty source region!");
0194:                }
0195:            }
0196:
0197:            /**
0198:             * Create a color table from the image ColorModel and SampleModel.
0199:             */
0200:            private static byte[] createColorTable(ColorModel colorModel,
0201:                    SampleModel sampleModel) {
0202:                byte[] colorTable;
0203:                if (colorModel instanceof  IndexColorModel) {
0204:                    IndexColorModel icm = (IndexColorModel) colorModel;
0205:                    int mapSize = icm.getMapSize();
0206:
0207:                    /**
0208:                     * The GIF image format assumes that size of image palette
0209:                     * is power of two. We will use closest larger power of two 
0210:                     * as size of color table.
0211:                     */
0212:                    int ctSize = getGifPaletteSize(mapSize);
0213:
0214:                    byte[] reds = new byte[ctSize];
0215:                    byte[] greens = new byte[ctSize];
0216:                    byte[] blues = new byte[ctSize];
0217:                    icm.getReds(reds);
0218:                    icm.getGreens(greens);
0219:                    icm.getBlues(blues);
0220:
0221:                    /**
0222:                     * fill tail of color component arrays by replica of first color
0223:                     * in order to avoid appearance of extra colors in the color table
0224:                     */
0225:                    for (int i = mapSize; i < ctSize; i++) {
0226:                        reds[i] = reds[0];
0227:                        greens[i] = greens[0];
0228:                        blues[i] = blues[0];
0229:                    }
0230:
0231:                    colorTable = new byte[3 * ctSize];
0232:                    int idx = 0;
0233:                    for (int i = 0; i < ctSize; i++) {
0234:                        colorTable[idx++] = reds[i];
0235:                        colorTable[idx++] = greens[i];
0236:                        colorTable[idx++] = blues[i];
0237:                    }
0238:                } else if (sampleModel.getNumBands() == 1) {
0239:                    // create gray-scaled color table for single-banded images
0240:                    int numBits = sampleModel.getSampleSize()[0];
0241:                    if (numBits > 8) {
0242:                        numBits = 8;
0243:                    }
0244:                    int colorTableLength = 3 * (1 << numBits);
0245:                    colorTable = new byte[colorTableLength];
0246:                    for (int i = 0; i < colorTableLength; i++) {
0247:                        colorTable[i] = (byte) (i / 3);
0248:                    }
0249:                } else {
0250:                    // We do not have enough information here 
0251:                    // to create well-fit color table for RGB image.
0252:                    colorTable = null;
0253:                }
0254:
0255:                return colorTable;
0256:            }
0257:
0258:            /**
0259:             * According do GIF specification size of clor table (palette here) 
0260:             * must be in range from 2 to 256 and must be power of 2.
0261:             */
0262:            private static int getGifPaletteSize(int x) {
0263:                if (x <= 2) {
0264:                    return 2;
0265:                }
0266:                x = x - 1;
0267:                x = x | (x >> 1);
0268:                x = x | (x >> 2);
0269:                x = x | (x >> 4);
0270:                x = x | (x >> 8);
0271:                x = x | (x >> 16);
0272:                return x + 1;
0273:            }
0274:
0275:            public GIFImageWriter(GIFImageWriterSpi originatingProvider) {
0276:                super (originatingProvider);
0277:                if (DEBUG) {
0278:                    System.err.println("GIF Writer is created");
0279:                }
0280:            }
0281:
0282:            public boolean canWriteSequence() {
0283:                return true;
0284:            }
0285:
0286:            /**
0287:             * Merges <code>inData</code> into <code>outData</code>. The supplied
0288:             * metadata format name is attempted first and failing that the standard
0289:             * metadata format name is attempted.
0290:             */
0291:            private void convertMetadata(String metadataFormatName,
0292:                    IIOMetadata inData, IIOMetadata outData) {
0293:                String formatName = null;
0294:
0295:                String nativeFormatName = inData.getNativeMetadataFormatName();
0296:                if (nativeFormatName != null
0297:                        && nativeFormatName.equals(metadataFormatName)) {
0298:                    formatName = metadataFormatName;
0299:                } else {
0300:                    String[] extraFormatNames = inData
0301:                            .getExtraMetadataFormatNames();
0302:
0303:                    if (extraFormatNames != null) {
0304:                        for (int i = 0; i < extraFormatNames.length; i++) {
0305:                            if (extraFormatNames[i].equals(metadataFormatName)) {
0306:                                formatName = metadataFormatName;
0307:                                break;
0308:                            }
0309:                        }
0310:                    }
0311:                }
0312:
0313:                if (formatName == null
0314:                        && inData.isStandardMetadataFormatSupported()) {
0315:                    formatName = STANDARD_METADATA_NAME;
0316:                }
0317:
0318:                if (formatName != null) {
0319:                    try {
0320:                        Node root = inData.getAsTree(formatName);
0321:                        outData.mergeTree(formatName, root);
0322:                    } catch (IIOInvalidTreeException e) {
0323:                        // ignore
0324:                    }
0325:                }
0326:            }
0327:
0328:            /**
0329:             * Creates a default stream metadata object and merges in the
0330:             * supplied metadata.
0331:             */
0332:            public IIOMetadata convertStreamMetadata(IIOMetadata inData,
0333:                    ImageWriteParam param) {
0334:                if (inData == null) {
0335:                    throw new IllegalArgumentException("inData == null!");
0336:                }
0337:
0338:                IIOMetadata sm = getDefaultStreamMetadata(param);
0339:
0340:                convertMetadata(STREAM_METADATA_NAME, inData, sm);
0341:
0342:                return sm;
0343:            }
0344:
0345:            /**
0346:             * Creates a default image metadata object and merges in the
0347:             * supplied metadata.
0348:             */
0349:            public IIOMetadata convertImageMetadata(IIOMetadata inData,
0350:                    ImageTypeSpecifier imageType, ImageWriteParam param) {
0351:                if (inData == null) {
0352:                    throw new IllegalArgumentException("inData == null!");
0353:                }
0354:                if (imageType == null) {
0355:                    throw new IllegalArgumentException("imageType == null!");
0356:                }
0357:
0358:                GIFWritableImageMetadata im = (GIFWritableImageMetadata) getDefaultImageMetadata(
0359:                        imageType, param);
0360:
0361:                // Save interlace flag state.
0362:
0363:                boolean isProgressive = im.interlaceFlag;
0364:
0365:                convertMetadata(IMAGE_METADATA_NAME, inData, im);
0366:
0367:                // Undo change to interlace flag if not MODE_COPY_FROM_METADATA.
0368:
0369:                if (param != null
0370:                        && param.canWriteProgressive()
0371:                        && param.getProgressiveMode() != param.MODE_COPY_FROM_METADATA) {
0372:                    im.interlaceFlag = isProgressive;
0373:                }
0374:
0375:                return im;
0376:            }
0377:
0378:            public void endWriteSequence() throws IOException {
0379:                if (stream == null) {
0380:                    throw new IllegalStateException("output == null!");
0381:                }
0382:                if (!isWritingSequence) {
0383:                    throw new IllegalStateException(
0384:                            "prepareWriteSequence() was not invoked!");
0385:                }
0386:                writeTrailer();
0387:                resetLocal();
0388:            }
0389:
0390:            public IIOMetadata getDefaultImageMetadata(
0391:                    ImageTypeSpecifier imageType, ImageWriteParam param) {
0392:                GIFWritableImageMetadata imageMetadata = new GIFWritableImageMetadata();
0393:
0394:                // Image dimensions
0395:
0396:                SampleModel sampleModel = imageType.getSampleModel();
0397:
0398:                Rectangle sourceBounds = new Rectangle(sampleModel.getWidth(),
0399:                        sampleModel.getHeight());
0400:                Dimension destSize = new Dimension();
0401:                computeRegions(sourceBounds, destSize, param);
0402:
0403:                imageMetadata.imageWidth = destSize.width;
0404:                imageMetadata.imageHeight = destSize.height;
0405:
0406:                // Interlacing
0407:
0408:                if (param != null
0409:                        && param.canWriteProgressive()
0410:                        && param.getProgressiveMode() == ImageWriteParam.MODE_DISABLED) {
0411:                    imageMetadata.interlaceFlag = false;
0412:                } else {
0413:                    imageMetadata.interlaceFlag = true;
0414:                }
0415:
0416:                // Local color table
0417:
0418:                ColorModel colorModel = imageType.getColorModel();
0419:
0420:                imageMetadata.localColorTable = createColorTable(colorModel,
0421:                        sampleModel);
0422:
0423:                // Transparency
0424:
0425:                if (colorModel instanceof  IndexColorModel) {
0426:                    int transparentIndex = ((IndexColorModel) colorModel)
0427:                            .getTransparentPixel();
0428:                    if (transparentIndex != -1) {
0429:                        imageMetadata.transparentColorFlag = true;
0430:                        imageMetadata.transparentColorIndex = transparentIndex;
0431:                    }
0432:                }
0433:
0434:                return imageMetadata;
0435:            }
0436:
0437:            public IIOMetadata getDefaultStreamMetadata(ImageWriteParam param) {
0438:                GIFWritableStreamMetadata streamMetadata = new GIFWritableStreamMetadata();
0439:                streamMetadata.version = "89a";
0440:                return streamMetadata;
0441:            }
0442:
0443:            public ImageWriteParam getDefaultWriteParam() {
0444:                return new GIFImageWriteParam(getLocale());
0445:            }
0446:
0447:            public void prepareWriteSequence(IIOMetadata streamMetadata)
0448:                    throws IOException {
0449:
0450:                if (stream == null) {
0451:                    throw new IllegalStateException("Output is not set.");
0452:                }
0453:
0454:                resetLocal();
0455:
0456:                // Save the possibly converted stream metadata as an instance variable.
0457:                if (streamMetadata == null) {
0458:                    this .theStreamMetadata = (GIFWritableStreamMetadata) getDefaultStreamMetadata(null);
0459:                } else {
0460:                    this .theStreamMetadata = new GIFWritableStreamMetadata();
0461:                    convertMetadata(STREAM_METADATA_NAME, streamMetadata,
0462:                            theStreamMetadata);
0463:                }
0464:
0465:                this .isWritingSequence = true;
0466:            }
0467:
0468:            public void reset() {
0469:                super .reset();
0470:                resetLocal();
0471:            }
0472:
0473:            /**
0474:             * Resets locally defined instance variables.
0475:             */
0476:            private void resetLocal() {
0477:                this .isWritingSequence = false;
0478:                this .wroteSequenceHeader = false;
0479:                this .theStreamMetadata = null;
0480:                this .imageIndex = 0;
0481:            }
0482:
0483:            public void setOutput(Object output) {
0484:                super .setOutput(output);
0485:                if (output != null) {
0486:                    if (!(output instanceof  ImageOutputStream)) {
0487:                        throw new IllegalArgumentException(
0488:                                "output is not an ImageOutputStream");
0489:                    }
0490:                    this .stream = (ImageOutputStream) output;
0491:                    this .stream.setByteOrder(ByteOrder.LITTLE_ENDIAN);
0492:                } else {
0493:                    this .stream = null;
0494:                }
0495:            }
0496:
0497:            public void write(IIOMetadata sm, IIOImage iioimage,
0498:                    ImageWriteParam p) throws IOException {
0499:                if (stream == null) {
0500:                    throw new IllegalStateException("output == null!");
0501:                }
0502:                if (iioimage == null) {
0503:                    throw new IllegalArgumentException("iioimage == null!");
0504:                }
0505:                if (iioimage.hasRaster()) {
0506:                    throw new UnsupportedOperationException(
0507:                            "canWriteRasters() == false!");
0508:                }
0509:
0510:                resetLocal();
0511:
0512:                GIFWritableStreamMetadata streamMetadata;
0513:                if (sm == null) {
0514:                    streamMetadata = (GIFWritableStreamMetadata) getDefaultStreamMetadata(p);
0515:                } else {
0516:                    streamMetadata = (GIFWritableStreamMetadata) convertStreamMetadata(
0517:                            sm, p);
0518:                }
0519:
0520:                write(true, true, streamMetadata, iioimage, p);
0521:            }
0522:
0523:            public void writeToSequence(IIOImage image, ImageWriteParam param)
0524:                    throws IOException {
0525:                if (stream == null) {
0526:                    throw new IllegalStateException("output == null!");
0527:                }
0528:                if (image == null) {
0529:                    throw new IllegalArgumentException("image == null!");
0530:                }
0531:                if (image.hasRaster()) {
0532:                    throw new UnsupportedOperationException(
0533:                            "canWriteRasters() == false!");
0534:                }
0535:                if (!isWritingSequence) {
0536:                    throw new IllegalStateException(
0537:                            "prepareWriteSequence() was not invoked!");
0538:                }
0539:
0540:                write(!wroteSequenceHeader, false, theStreamMetadata, image,
0541:                        param);
0542:
0543:                if (!wroteSequenceHeader) {
0544:                    wroteSequenceHeader = true;
0545:                }
0546:
0547:                this .imageIndex++;
0548:            }
0549:
0550:            private boolean needToCreateIndex(RenderedImage image) {
0551:
0552:                SampleModel sampleModel = image.getSampleModel();
0553:                ColorModel colorModel = image.getColorModel();
0554:
0555:                return sampleModel.getNumBands() != 1
0556:                        || sampleModel.getSampleSize()[0] > 8
0557:                        || colorModel.getComponentSize()[0] > 8;
0558:            }
0559:
0560:            /**
0561:             * Writes any extension blocks, the Image Descriptor, the image data,
0562:             * and optionally the header (Signature and Logical Screen Descriptor)
0563:             * and trailer (Block Terminator).
0564:             *
0565:             * @param writeHeader Whether to write the header.
0566:             * @param writeTrailer Whether to write the trailer.
0567:             * @param sm The stream metadata or <code>null</code> if
0568:             * <code>writeHeader</code> is <code>false</code>.
0569:             * @param iioimage The image and image metadata.
0570:             * @param p The write parameters.
0571:             *
0572:             * @throws IllegalArgumentException if the number of bands is not 1.
0573:             * @throws IllegalArgumentException if the number of bits per sample is
0574:             * greater than 8.
0575:             * @throws IllegalArgumentException if the color component size is
0576:             * greater than 8.
0577:             * @throws IllegalArgumentException if <code>writeHeader</code> is
0578:             * <code>true</code> and <code>sm</code> is <code>null</code>.
0579:             * @throws IllegalArgumentException if <code>writeHeader</code> is
0580:             * <code>false</code> and a sequence is not being written.
0581:             */
0582:            private void write(boolean writeHeader, boolean writeTrailer,
0583:                    IIOMetadata sm, IIOImage iioimage, ImageWriteParam p)
0584:                    throws IOException {
0585:                clearAbortRequest();
0586:
0587:                RenderedImage image = iioimage.getRenderedImage();
0588:
0589:                // Check for ability to encode image.
0590:                if (needToCreateIndex(image)) {
0591:                    image = PaletteBuilder.createIndexedImage(image);
0592:                    iioimage.setRenderedImage(image);
0593:                }
0594:
0595:                ColorModel colorModel = image.getColorModel();
0596:                SampleModel sampleModel = image.getSampleModel();
0597:
0598:                // Determine source region and destination dimensions.
0599:                Rectangle sourceBounds = new Rectangle(image.getMinX(), image
0600:                        .getMinY(), image.getWidth(), image.getHeight());
0601:                Dimension destSize = new Dimension();
0602:                computeRegions(sourceBounds, destSize, p);
0603:
0604:                // Convert any provided image metadata.
0605:                GIFWritableImageMetadata imageMetadata = null;
0606:                if (iioimage.getMetadata() != null) {
0607:                    imageMetadata = new GIFWritableImageMetadata();
0608:                    convertMetadata(IMAGE_METADATA_NAME,
0609:                            iioimage.getMetadata(), imageMetadata);
0610:                    // Converted rgb image can use palette different from global.
0611:                    // In order to avoid color artefacts we want to be sure we use
0612:                    // appropriate palette. For this we initialize local color table
0613:                    // from current color and sample models.
0614:                    // At this point we can guarantee that local color table can be
0615:                    // build because image was already converted to indexed or
0616:                    // gray-scale representations
0617:                    if (imageMetadata.localColorTable == null) {
0618:                        imageMetadata.localColorTable = createColorTable(
0619:                                colorModel, sampleModel);
0620:
0621:                        // in case of indexed image we should take care of 
0622:                        // transparent pixels
0623:                        if (colorModel instanceof  IndexColorModel) {
0624:                            IndexColorModel icm = (IndexColorModel) colorModel;
0625:                            int index = icm.getTransparentPixel();
0626:                            imageMetadata.transparentColorFlag = (index != -1);
0627:                            if (imageMetadata.transparentColorFlag) {
0628:                                imageMetadata.transparentColorIndex = index;
0629:                            }
0630:                            /* NB: transparentColorFlag might have not beed reset for
0631:                               greyscale images but explicitly reseting it here
0632:                               is potentially not right thing to do until we have way
0633:                               to find whether current value was explicitly set by
0634:                               the user.
0635:                             */
0636:                        }
0637:                    }
0638:                }
0639:
0640:                // Global color table values.
0641:                byte[] globalColorTable = null;
0642:
0643:                // Write the header (Signature+Logical Screen Descriptor+
0644:                // Global Color Table).
0645:                if (writeHeader) {
0646:                    if (sm == null) {
0647:                        throw new IllegalArgumentException(
0648:                                "Cannot write null header!");
0649:                    }
0650:
0651:                    GIFWritableStreamMetadata streamMetadata = (GIFWritableStreamMetadata) sm;
0652:
0653:                    // Set the version if not set.
0654:                    if (streamMetadata.version == null) {
0655:                        streamMetadata.version = "89a";
0656:                    }
0657:
0658:                    // Set the Logical Screen Desriptor if not set.
0659:                    if (streamMetadata.logicalScreenWidth == GIFMetadata.UNDEFINED_INTEGER_VALUE) {
0660:                        streamMetadata.logicalScreenWidth = destSize.width;
0661:                    }
0662:
0663:                    if (streamMetadata.logicalScreenHeight == GIFMetadata.UNDEFINED_INTEGER_VALUE) {
0664:                        streamMetadata.logicalScreenHeight = destSize.height;
0665:                    }
0666:
0667:                    if (streamMetadata.colorResolution == GIFMetadata.UNDEFINED_INTEGER_VALUE) {
0668:                        streamMetadata.colorResolution = colorModel != null ? colorModel
0669:                                .getComponentSize()[0]
0670:                                : sampleModel.getSampleSize()[0];
0671:                    }
0672:
0673:                    // Set the Global Color Table if not set, i.e., if not
0674:                    // provided in the stream metadata.
0675:                    if (streamMetadata.globalColorTable == null) {
0676:                        if (isWritingSequence && imageMetadata != null
0677:                                && imageMetadata.localColorTable != null) {
0678:                            // Writing a sequence and a local color table was
0679:                            // provided in the metadata of the first image: use it.
0680:                            streamMetadata.globalColorTable = imageMetadata.localColorTable;
0681:                        } else if (imageMetadata == null
0682:                                || imageMetadata.localColorTable == null) {
0683:                            // Create a color table.
0684:                            streamMetadata.globalColorTable = createColorTable(
0685:                                    colorModel, sampleModel);
0686:                        }
0687:                    }
0688:
0689:                    // Set the Global Color Table. At this point it should be
0690:                    // A) the global color table provided in stream metadata, if any;
0691:                    // B) the local color table of the image metadata, if any, if
0692:                    //    writing a sequence;
0693:                    // C) a table created on the basis of the first image ColorModel
0694:                    //    and SampleModel if no local color table is available; or
0695:                    // D) null if none of the foregoing conditions obtain (which
0696:                    //    should only be if a sequence is not being written and
0697:                    //    a local color table is provided in image metadata).
0698:                    globalColorTable = streamMetadata.globalColorTable;
0699:
0700:                    // Write the header.
0701:                    int bitsPerPixel;
0702:                    if (globalColorTable != null) {
0703:                        bitsPerPixel = getNumBits(globalColorTable.length / 3);
0704:                    } else if (imageMetadata != null
0705:                            && imageMetadata.localColorTable != null) {
0706:                        bitsPerPixel = getNumBits(imageMetadata.localColorTable.length / 3);
0707:                    } else {
0708:                        bitsPerPixel = sampleModel.getSampleSize(0);
0709:                    }
0710:                    writeHeader(streamMetadata, bitsPerPixel);
0711:                } else if (isWritingSequence) {
0712:                    globalColorTable = theStreamMetadata.globalColorTable;
0713:                } else {
0714:                    throw new IllegalArgumentException(
0715:                            "Must write header for single image!");
0716:                }
0717:
0718:                // Write extension blocks, Image Descriptor, and image data.
0719:                writeImage(iioimage.getRenderedImage(), imageMetadata, p,
0720:                        globalColorTable, sourceBounds, destSize);
0721:
0722:                // Write the trailer.
0723:                if (writeTrailer) {
0724:                    writeTrailer();
0725:                }
0726:            }
0727:
0728:            /**
0729:             * Writes any extension blocks, the Image Descriptor, and the image data
0730:             *
0731:             * @param iioimage The image and image metadata.
0732:             * @param param The write parameters.
0733:             * @param globalColorTable The Global Color Table.
0734:             * @param sourceBounds The source region.
0735:             * @param destSize The destination dimensions.
0736:             */
0737:            private void writeImage(RenderedImage image,
0738:                    GIFWritableImageMetadata imageMetadata,
0739:                    ImageWriteParam param, byte[] globalColorTable,
0740:                    Rectangle sourceBounds, Dimension destSize)
0741:                    throws IOException {
0742:                ColorModel colorModel = image.getColorModel();
0743:                SampleModel sampleModel = image.getSampleModel();
0744:
0745:                boolean writeGraphicsControlExtension;
0746:                if (imageMetadata == null) {
0747:                    // Create default metadata.
0748:                    imageMetadata = (GIFWritableImageMetadata) getDefaultImageMetadata(
0749:                            new ImageTypeSpecifier(image), param);
0750:
0751:                    // Set GraphicControlExtension flag only if there is
0752:                    // transparency.
0753:                    writeGraphicsControlExtension = imageMetadata.transparentColorFlag;
0754:                } else {
0755:                    // Check for GraphicControlExtension element.
0756:                    NodeList list = null;
0757:                    try {
0758:                        IIOMetadataNode root = (IIOMetadataNode) imageMetadata
0759:                                .getAsTree(IMAGE_METADATA_NAME);
0760:                        list = root
0761:                                .getElementsByTagName("GraphicControlExtension");
0762:                    } catch (IllegalArgumentException iae) {
0763:                        // Should never happen.
0764:                    }
0765:
0766:                    // Set GraphicControlExtension flag if element present.
0767:                    writeGraphicsControlExtension = list != null
0768:                            && list.getLength() > 0;
0769:
0770:                    // If progressive mode is not MODE_COPY_FROM_METADATA, ensure
0771:                    // the interlacing is set per the ImageWriteParam mode setting.
0772:                    if (param != null && param.canWriteProgressive()) {
0773:                        if (param.getProgressiveMode() == ImageWriteParam.MODE_DISABLED) {
0774:                            imageMetadata.interlaceFlag = false;
0775:                        } else if (param.getProgressiveMode() == ImageWriteParam.MODE_DEFAULT) {
0776:                            imageMetadata.interlaceFlag = true;
0777:                        }
0778:                    }
0779:                }
0780:
0781:                // Unset local color table if equal to global color table.
0782:                if (Arrays.equals(globalColorTable,
0783:                        imageMetadata.localColorTable)) {
0784:                    imageMetadata.localColorTable = null;
0785:                }
0786:
0787:                // Override dimensions
0788:                imageMetadata.imageWidth = destSize.width;
0789:                imageMetadata.imageHeight = destSize.height;
0790:
0791:                // Write Graphics Control Extension.
0792:                if (writeGraphicsControlExtension) {
0793:                    writeGraphicControlExtension(imageMetadata);
0794:                }
0795:
0796:                // Write extension blocks.
0797:                writePlainTextExtension(imageMetadata);
0798:                writeApplicationExtension(imageMetadata);
0799:                writeCommentExtension(imageMetadata);
0800:
0801:                // Write Image Descriptor
0802:                int bitsPerPixel = getNumBits(imageMetadata.localColorTable == null ? (globalColorTable == null ? sampleModel
0803:                        .getSampleSize(0)
0804:                        : globalColorTable.length / 3)
0805:                        : imageMetadata.localColorTable.length / 3);
0806:                writeImageDescriptor(imageMetadata, bitsPerPixel);
0807:
0808:                // Write image data
0809:                writeRasterData(image, sourceBounds, destSize, param,
0810:                        imageMetadata.interlaceFlag);
0811:            }
0812:
0813:            private void writeRows(RenderedImage image,
0814:                    LZWCompressor compressor, int sx, int sdx, int sy, int sdy,
0815:                    int sw, int dy, int ddy, int dw, int dh,
0816:                    int numRowsWritten, int progressReportRowPeriod)
0817:                    throws IOException {
0818:                if (DEBUG)
0819:                    System.out.println("Writing unoptimized");
0820:
0821:                int[] sbuf = new int[sw];
0822:                byte[] dbuf = new byte[dw];
0823:
0824:                Raster raster = image.getNumXTiles() == 1
0825:                        && image.getNumYTiles() == 1 ? image.getTile(0, 0)
0826:                        : image.getData();
0827:                for (int y = dy; y < dh; y += ddy) {
0828:                    if (numRowsWritten % progressReportRowPeriod == 0) {
0829:                        if (abortRequested()) {
0830:                            processWriteAborted();
0831:                            return;
0832:                        }
0833:                        processImageProgress((numRowsWritten * 100.0F) / dh);
0834:                    }
0835:
0836:                    raster.getSamples(sx, sy, sw, 1, 0, sbuf);
0837:                    for (int i = 0, j = 0; i < dw; i++, j += sdx) {
0838:                        dbuf[i] = (byte) sbuf[j];
0839:                    }
0840:                    compressor.compress(dbuf, 0, dw);
0841:                    numRowsWritten++;
0842:                    sy += sdy;
0843:                }
0844:            }
0845:
0846:            private void writeRowsOpt(byte[] data, int offset, int lineStride,
0847:                    LZWCompressor compressor, int dy, int ddy, int dw, int dh,
0848:                    int numRowsWritten, int progressReportRowPeriod)
0849:                    throws IOException {
0850:                if (DEBUG)
0851:                    System.out.println("Writing optimized");
0852:
0853:                offset += dy * lineStride;
0854:                lineStride *= ddy;
0855:                for (int y = dy; y < dh; y += ddy) {
0856:                    if (numRowsWritten % progressReportRowPeriod == 0) {
0857:                        if (abortRequested()) {
0858:                            processWriteAborted();
0859:                            return;
0860:                        }
0861:                        processImageProgress((numRowsWritten * 100.0F) / dh);
0862:                    }
0863:
0864:                    compressor.compress(data, offset, dw);
0865:                    numRowsWritten++;
0866:                    offset += lineStride;
0867:                }
0868:            }
0869:
0870:            private void writeRasterData(RenderedImage image,
0871:                    Rectangle sourceBounds, Dimension destSize,
0872:                    ImageWriteParam param, boolean interlaceFlag)
0873:                    throws IOException {
0874:
0875:                int sourceXOffset = sourceBounds.x;
0876:                int sourceYOffset = sourceBounds.y;
0877:                int sourceWidth = sourceBounds.width;
0878:                int sourceHeight = sourceBounds.height;
0879:
0880:                int destWidth = destSize.width;
0881:                int destHeight = destSize.height;
0882:
0883:                int periodX;
0884:                int periodY;
0885:                if (param == null) {
0886:                    periodX = 1;
0887:                    periodY = 1;
0888:                } else {
0889:                    periodX = param.getSourceXSubsampling();
0890:                    periodY = param.getSourceYSubsampling();
0891:                }
0892:
0893:                SampleModel sampleModel = image.getSampleModel();
0894:                int bitsPerPixel = sampleModel.getSampleSize()[0];
0895:
0896:                int initCodeSize = bitsPerPixel;
0897:                if (initCodeSize == 1) {
0898:                    initCodeSize++;
0899:                }
0900:                stream.write(initCodeSize);
0901:
0902:                LZWCompressor compressor = new LZWCompressor(stream,
0903:                        initCodeSize, false);
0904:
0905:                boolean isOptimizedCase = periodX == 1
0906:                        && periodY == 1
0907:                        && sampleModel instanceof  ComponentSampleModel
0908:                        && image.getNumXTiles() == 1
0909:                        && image.getNumYTiles() == 1
0910:                        && image.getTile(0, 0).getDataBuffer() instanceof  DataBufferByte;
0911:
0912:                int numRowsWritten = 0;
0913:
0914:                int progressReportRowPeriod = Math.max(destHeight / 20, 1);
0915:
0916:                processImageStarted(imageIndex);
0917:
0918:                if (interlaceFlag) {
0919:                    if (DEBUG)
0920:                        System.out.println("Writing interlaced");
0921:
0922:                    if (isOptimizedCase) {
0923:                        Raster tile = image.getTile(0, 0);
0924:                        byte[] data = ((DataBufferByte) tile.getDataBuffer())
0925:                                .getData();
0926:                        ComponentSampleModel csm = (ComponentSampleModel) tile
0927:                                .getSampleModel();
0928:                        int offset = csm
0929:                                .getOffset(
0930:                                        sourceXOffset
0931:                                                - tile
0932:                                                        .getSampleModelTranslateX(),
0933:                                        sourceYOffset
0934:                                                - tile
0935:                                                        .getSampleModelTranslateY(),
0936:                                        0);
0937:                        int lineStride = csm.getScanlineStride();
0938:
0939:                        writeRowsOpt(data, offset, lineStride, compressor, 0,
0940:                                8, destWidth, destHeight, numRowsWritten,
0941:                                progressReportRowPeriod);
0942:
0943:                        if (abortRequested()) {
0944:                            return;
0945:                        }
0946:
0947:                        numRowsWritten += destHeight / 8;
0948:
0949:                        writeRowsOpt(data, offset, lineStride, compressor, 4,
0950:                                8, destWidth, destHeight, numRowsWritten,
0951:                                progressReportRowPeriod);
0952:
0953:                        if (abortRequested()) {
0954:                            return;
0955:                        }
0956:
0957:                        numRowsWritten += (destHeight - 4) / 8;
0958:
0959:                        writeRowsOpt(data, offset, lineStride, compressor, 2,
0960:                                4, destWidth, destHeight, numRowsWritten,
0961:                                progressReportRowPeriod);
0962:
0963:                        if (abortRequested()) {
0964:                            return;
0965:                        }
0966:
0967:                        numRowsWritten += (destHeight - 2) / 4;
0968:
0969:                        writeRowsOpt(data, offset, lineStride, compressor, 1,
0970:                                2, destWidth, destHeight, numRowsWritten,
0971:                                progressReportRowPeriod);
0972:                    } else {
0973:                        writeRows(image, compressor, sourceXOffset, periodX,
0974:                                sourceYOffset, 8 * periodY, sourceWidth, 0, 8,
0975:                                destWidth, destHeight, numRowsWritten,
0976:                                progressReportRowPeriod);
0977:
0978:                        if (abortRequested()) {
0979:                            return;
0980:                        }
0981:
0982:                        numRowsWritten += destHeight / 8;
0983:
0984:                        writeRows(image, compressor, sourceXOffset, periodX,
0985:                                sourceYOffset + 4 * periodY, 8 * periodY,
0986:                                sourceWidth, 4, 8, destWidth, destHeight,
0987:                                numRowsWritten, progressReportRowPeriod);
0988:
0989:                        if (abortRequested()) {
0990:                            return;
0991:                        }
0992:
0993:                        numRowsWritten += (destHeight - 4) / 8;
0994:
0995:                        writeRows(image, compressor, sourceXOffset, periodX,
0996:                                sourceYOffset + 2 * periodY, 4 * periodY,
0997:                                sourceWidth, 2, 4, destWidth, destHeight,
0998:                                numRowsWritten, progressReportRowPeriod);
0999:
1000:                        if (abortRequested()) {
1001:                            return;
1002:                        }
1003:
1004:                        numRowsWritten += (destHeight - 2) / 4;
1005:
1006:                        writeRows(image, compressor, sourceXOffset, periodX,
1007:                                sourceYOffset + periodY, 2 * periodY,
1008:                                sourceWidth, 1, 2, destWidth, destHeight,
1009:                                numRowsWritten, progressReportRowPeriod);
1010:                    }
1011:                } else {
1012:                    if (DEBUG)
1013:                        System.out.println("Writing non-interlaced");
1014:
1015:                    if (isOptimizedCase) {
1016:                        Raster tile = image.getTile(0, 0);
1017:                        byte[] data = ((DataBufferByte) tile.getDataBuffer())
1018:                                .getData();
1019:                        ComponentSampleModel csm = (ComponentSampleModel) tile
1020:                                .getSampleModel();
1021:                        int offset = csm
1022:                                .getOffset(
1023:                                        sourceXOffset
1024:                                                - tile
1025:                                                        .getSampleModelTranslateX(),
1026:                                        sourceYOffset
1027:                                                - tile
1028:                                                        .getSampleModelTranslateY(),
1029:                                        0);
1030:                        int lineStride = csm.getScanlineStride();
1031:
1032:                        writeRowsOpt(data, offset, lineStride, compressor, 0,
1033:                                1, destWidth, destHeight, numRowsWritten,
1034:                                progressReportRowPeriod);
1035:                    } else {
1036:                        writeRows(image, compressor, sourceXOffset, periodX,
1037:                                sourceYOffset, periodY, sourceWidth, 0, 1,
1038:                                destWidth, destHeight, numRowsWritten,
1039:                                progressReportRowPeriod);
1040:                    }
1041:                }
1042:
1043:                if (abortRequested()) {
1044:                    return;
1045:                }
1046:
1047:                processImageProgress(100.0F);
1048:
1049:                compressor.flush();
1050:
1051:                stream.write(0x00);
1052:
1053:                processImageComplete();
1054:            }
1055:
1056:            private void writeHeader(String version, int logicalScreenWidth,
1057:                    int logicalScreenHeight, int colorResolution,
1058:                    int pixelAspectRatio, int backgroundColorIndex,
1059:                    boolean sortFlag, int bitsPerPixel, byte[] globalColorTable)
1060:                    throws IOException {
1061:                try {
1062:                    // Signature
1063:                    stream.writeBytes("GIF" + version);
1064:
1065:                    // Screen Descriptor
1066:                    // Width
1067:                    stream.writeShort((short) logicalScreenWidth);
1068:
1069:                    // Height
1070:                    stream.writeShort((short) logicalScreenHeight);
1071:
1072:                    // Global Color Table
1073:                    // Packed fields
1074:                    int packedFields = globalColorTable != null ? 0x80 : 0x00;
1075:                    packedFields |= ((colorResolution - 1) & 0x7) << 4;
1076:                    if (sortFlag) {
1077:                        packedFields |= 0x8;
1078:                    }
1079:                    packedFields |= (bitsPerPixel - 1);
1080:                    stream.write(packedFields);
1081:
1082:                    // Background color index
1083:                    stream.write(backgroundColorIndex);
1084:
1085:                    // Pixel aspect ratio
1086:                    stream.write(pixelAspectRatio);
1087:
1088:                    // Global Color Table
1089:                    if (globalColorTable != null) {
1090:                        stream.write(globalColorTable);
1091:                    }
1092:                } catch (IOException e) {
1093:                    throw new IIOException("I/O error writing header!", e);
1094:                }
1095:            }
1096:
1097:            private void writeHeader(IIOMetadata streamMetadata,
1098:                    int bitsPerPixel) throws IOException {
1099:
1100:                GIFWritableStreamMetadata sm;
1101:                if (streamMetadata instanceof  GIFWritableStreamMetadata) {
1102:                    sm = (GIFWritableStreamMetadata) streamMetadata;
1103:                } else {
1104:                    sm = new GIFWritableStreamMetadata();
1105:                    Node root = streamMetadata.getAsTree(STREAM_METADATA_NAME);
1106:                    sm.setFromTree(STREAM_METADATA_NAME, root);
1107:                }
1108:
1109:                writeHeader(sm.version, sm.logicalScreenWidth,
1110:                        sm.logicalScreenHeight, sm.colorResolution,
1111:                        sm.pixelAspectRatio, sm.backgroundColorIndex,
1112:                        sm.sortFlag, bitsPerPixel, sm.globalColorTable);
1113:            }
1114:
1115:            private void writeGraphicControlExtension(int disposalMethod,
1116:                    boolean userInputFlag, boolean transparentColorFlag,
1117:                    int delayTime, int transparentColorIndex)
1118:                    throws IOException {
1119:                try {
1120:                    stream.write(0x21);
1121:                    stream.write(0xf9);
1122:
1123:                    stream.write(4);
1124:
1125:                    int packedFields = (disposalMethod & 0x3) << 2;
1126:                    if (userInputFlag) {
1127:                        packedFields |= 0x2;
1128:                    }
1129:                    if (transparentColorFlag) {
1130:                        packedFields |= 0x1;
1131:                    }
1132:                    stream.write(packedFields);
1133:
1134:                    stream.writeShort((short) delayTime);
1135:
1136:                    stream.write(transparentColorIndex);
1137:                    stream.write(0x00);
1138:                } catch (IOException e) {
1139:                    throw new IIOException(
1140:                            "I/O error writing Graphic Control Extension!", e);
1141:                }
1142:            }
1143:
1144:            private void writeGraphicControlExtension(
1145:                    GIFWritableImageMetadata im) throws IOException {
1146:                writeGraphicControlExtension(im.disposalMethod,
1147:                        im.userInputFlag, im.transparentColorFlag,
1148:                        im.delayTime, im.transparentColorIndex);
1149:            }
1150:
1151:            private void writeBlocks(byte[] data) throws IOException {
1152:                if (data != null && data.length > 0) {
1153:                    int offset = 0;
1154:                    while (offset < data.length) {
1155:                        int len = Math.min(data.length - offset, 255);
1156:                        stream.write(len);
1157:                        stream.write(data, offset, len);
1158:                        offset += len;
1159:                    }
1160:                }
1161:            }
1162:
1163:            private void writePlainTextExtension(GIFWritableImageMetadata im)
1164:                    throws IOException {
1165:                if (im.hasPlainTextExtension) {
1166:                    try {
1167:                        stream.write(0x21);
1168:                        stream.write(0x1);
1169:
1170:                        stream.write(12);
1171:
1172:                        stream.writeShort(im.textGridLeft);
1173:                        stream.writeShort(im.textGridTop);
1174:                        stream.writeShort(im.textGridWidth);
1175:                        stream.writeShort(im.textGridHeight);
1176:                        stream.write(im.characterCellWidth);
1177:                        stream.write(im.characterCellHeight);
1178:                        stream.write(im.textForegroundColor);
1179:                        stream.write(im.textBackgroundColor);
1180:
1181:                        writeBlocks(im.text);
1182:
1183:                        stream.write(0x00);
1184:                    } catch (IOException e) {
1185:                        throw new IIOException(
1186:                                "I/O error writing Plain Text Extension!", e);
1187:                    }
1188:                }
1189:            }
1190:
1191:            private void writeApplicationExtension(GIFWritableImageMetadata im)
1192:                    throws IOException {
1193:                if (im.applicationIDs != null) {
1194:                    Iterator iterIDs = im.applicationIDs.iterator();
1195:                    Iterator iterCodes = im.authenticationCodes.iterator();
1196:                    Iterator iterData = im.applicationData.iterator();
1197:
1198:                    while (iterIDs.hasNext()) {
1199:                        try {
1200:                            stream.write(0x21);
1201:                            stream.write(0xff);
1202:
1203:                            stream.write(11);
1204:                            stream.write((byte[]) iterIDs.next(), 0, 8);
1205:                            stream.write((byte[]) iterCodes.next(), 0, 3);
1206:
1207:                            writeBlocks((byte[]) iterData.next());
1208:
1209:                            stream.write(0x00);
1210:                        } catch (IOException e) {
1211:                            throw new IIOException(
1212:                                    "I/O error writing Application Extension!",
1213:                                    e);
1214:                        }
1215:                    }
1216:                }
1217:            }
1218:
1219:            private void writeCommentExtension(GIFWritableImageMetadata im)
1220:                    throws IOException {
1221:                if (im.comments != null) {
1222:                    try {
1223:                        Iterator iter = im.comments.iterator();
1224:                        while (iter.hasNext()) {
1225:                            stream.write(0x21);
1226:                            stream.write(0xfe);
1227:                            writeBlocks((byte[]) iter.next());
1228:                            stream.write(0x00);
1229:                        }
1230:                    } catch (IOException e) {
1231:                        throw new IIOException(
1232:                                "I/O error writing Comment Extension!", e);
1233:                    }
1234:                }
1235:            }
1236:
1237:            private void writeImageDescriptor(int imageLeftPosition,
1238:                    int imageTopPosition, int imageWidth, int imageHeight,
1239:                    boolean interlaceFlag, boolean sortFlag, int bitsPerPixel,
1240:                    byte[] localColorTable) throws IOException {
1241:
1242:                try {
1243:                    stream.write(0x2c);
1244:
1245:                    stream.writeShort((short) imageLeftPosition);
1246:                    stream.writeShort((short) imageTopPosition);
1247:                    stream.writeShort((short) imageWidth);
1248:                    stream.writeShort((short) imageHeight);
1249:
1250:                    int packedFields = localColorTable != null ? 0x80 : 0x00;
1251:                    if (interlaceFlag) {
1252:                        packedFields |= 0x40;
1253:                    }
1254:                    if (sortFlag) {
1255:                        packedFields |= 0x8;
1256:                    }
1257:                    packedFields |= (bitsPerPixel - 1);
1258:                    stream.write(packedFields);
1259:
1260:                    if (localColorTable != null) {
1261:                        stream.write(localColorTable);
1262:                    }
1263:                } catch (IOException e) {
1264:                    throw new IIOException(
1265:                            "I/O error writing Image Descriptor!", e);
1266:                }
1267:            }
1268:
1269:            private void writeImageDescriptor(
1270:                    GIFWritableImageMetadata imageMetadata, int bitsPerPixel)
1271:                    throws IOException {
1272:
1273:                writeImageDescriptor(imageMetadata.imageLeftPosition,
1274:                        imageMetadata.imageTopPosition,
1275:                        imageMetadata.imageWidth, imageMetadata.imageHeight,
1276:                        imageMetadata.interlaceFlag, imageMetadata.sortFlag,
1277:                        bitsPerPixel, imageMetadata.localColorTable);
1278:            }
1279:
1280:            private void writeTrailer() throws IOException {
1281:                stream.write(0x3b);
1282:            }
1283:        }
1284:
1285:        class GIFImageWriteParam extends ImageWriteParam {
1286:            GIFImageWriteParam(Locale locale) {
1287:                super (locale);
1288:                this .canWriteCompressed = true;
1289:                this .canWriteProgressive = true;
1290:                this .compressionTypes = new String[] { "LZW", "lzw" };
1291:                this .compressionType = compressionTypes[0];
1292:            }
1293:
1294:            public void setCompressionMode(int mode) {
1295:                if (mode == MODE_DISABLED) {
1296:                    throw new UnsupportedOperationException(
1297:                            "MODE_DISABLED is not supported.");
1298:                }
1299:                super.setCompressionMode(mode);
1300:            }
1301:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.