Source Code Cross Referenced for GIFImageDecoder.java in  » 6.0-JDK-Modules » Java-Advanced-Imaging » com » sun » media » jai » codecimpl » 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.jai.codecimpl 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         * $RCSfile: GIFImageDecoder.java,v $
003:         *
004:         * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
005:         *
006:         * Use is subject to license terms.
007:         *
008:         * $Revision: 1.2 $
009:         * $Date: 2006/06/17 00:02:28 $
010:         * $State: Exp $
011:         */
012:        package com.sun.media.jai.codecimpl;
013:
014:        import java.awt.Point;
015:        import java.awt.Rectangle;
016:        import java.awt.RenderingHints;
017:        import java.awt.image.BufferedImage;
018:        import java.awt.image.ColorModel;
019:        import java.awt.image.DataBuffer;
020:        import java.awt.image.ImageProducer;
021:        import java.awt.image.IndexColorModel;
022:        import java.awt.image.PixelInterleavedSampleModel;
023:        import java.awt.image.Raster;
024:        import java.awt.image.RenderedImage;
025:        import java.awt.image.SampleModel;
026:        import java.awt.image.WritableRaster;
027:        import java.io.IOException;
028:        import java.io.InputStream;
029:        import java.util.Arrays;
030:        import java.util.HashMap;
031:        import com.sun.media.jai.codec.ImageCodec;
032:        import com.sun.media.jai.codec.ImageDecodeParam;
033:        import com.sun.media.jai.codec.ImageDecoderImpl;
034:        import com.sun.media.jai.codec.SeekableStream;
035:        import com.sun.media.jai.codecimpl.ImagingListenerProxy;
036:        import com.sun.media.jai.codecimpl.util.ImagingException;
037:
038:        /**
039:         * @since EA3
040:         */
041:        public class GIFImageDecoder extends ImageDecoderImpl {
042:
043:            // The global color table.
044:            private byte[] globalColorTable = null;
045:
046:            // Whether the last page has been encountered.
047:            private boolean maxPageFound = false;
048:
049:            // The maximum allowable page for reading.
050:            private int maxPage;
051:
052:            // The previous page read.
053:            private int prevPage = -1;
054:
055:            // The previous page on which getTile() was invoked in this object.
056:            private int prevSyncedPage = -1;
057:
058:            // Map of Integer page numbers to RenderedImages.
059:            private HashMap images = new HashMap();
060:
061:            /**
062:             * Read the overall stream header and return the global color map
063:             * or <code>null</code>.
064:             */
065:            private static byte[] readHeader(SeekableStream input)
066:                    throws IOException {
067:                byte[] globalColorTable = null;
068:                try {
069:                    // Skip the version string and logical screen dimensions.
070:                    input.skipBytes(10);
071:
072:                    int packedFields = input.readUnsignedByte();
073:                    boolean globalColorTableFlag = (packedFields & 0x80) != 0;
074:                    int numGCTEntries = 1 << ((packedFields & 0x7) + 1);
075:
076:                    int backgroundColorIndex = input.readUnsignedByte();
077:
078:                    // Read the aspect ratio but ignore the returned value.
079:                    input.read();
080:
081:                    if (globalColorTableFlag) {
082:                        globalColorTable = new byte[3 * numGCTEntries];
083:                        input.readFully(globalColorTable);
084:                    } else {
085:                        globalColorTable = null;
086:                    }
087:                } catch (IOException e) {
088:                    String message = JaiI18N.getString("GIFImageDecoder0");
089:                    ImagingListenerProxy.errorOccurred(message,
090:                            new ImagingException(message, e),
091:                            GIFImageDecoder.class, false);
092:                    //            throw new IOException(JaiI18N.getString("GIFImageDecoder0"));
093:                }
094:
095:                return globalColorTable;
096:            }
097:
098:            public GIFImageDecoder(SeekableStream input, ImageDecodeParam param) {
099:                super (input, param);
100:            }
101:
102:            public GIFImageDecoder(InputStream input, ImageDecodeParam param) {
103:                super (input, param);
104:            }
105:
106:            public int getNumPages() throws IOException {
107:                int page = prevPage + 1;
108:
109:                while (!maxPageFound) {
110:                    try {
111:                        decodeAsRenderedImage(page++);
112:                    } catch (IOException e) {
113:                        // Ignore
114:                    }
115:                }
116:
117:                return maxPage + 1;
118:            }
119:
120:            public synchronized RenderedImage decodeAsRenderedImage(int page)
121:                    throws IOException {
122:
123:                // Verify that the index is in range.
124:                if (page < 0 || (maxPageFound && page > maxPage)) {
125:                    throw new IOException(JaiI18N.getString("GIFImageDecoder1"));
126:                }
127:
128:                // Attempt to get the image from the cache.
129:                Integer pageKey = new Integer(page);
130:                if (images.containsKey(pageKey)) {
131:                    return (RenderedImage) images.get(pageKey);
132:                }
133:
134:                // If the zeroth image, set the global color table.
135:                if (prevPage == -1) {
136:                    try {
137:                        globalColorTable = readHeader(input);
138:                    } catch (IOException e) {
139:                        maxPageFound = true;
140:                        maxPage = -1;
141:                        throw e;
142:                    }
143:                }
144:
145:                // Force previous data to be read.
146:                if (page > 0) {
147:                    for (int idx = prevSyncedPage + 1; idx < page; idx++) {
148:                        RenderedImage im = (RenderedImage) images
149:                                .get(new Integer(idx));
150:                        im.getTile(0, 0);
151:                        prevSyncedPage = idx;
152:                    }
153:                }
154:
155:                // Read as many images as possible.
156:                RenderedImage image = null;
157:                while (prevPage < page) {
158:                    int index = prevPage + 1;
159:                    RenderedImage ri = null;
160:                    try {
161:                        ri = new GIFImage(input, globalColorTable);
162:                        images.put(new Integer(index), ri);
163:                        if (index < page) {
164:                            ri.getTile(0, 0);
165:                            prevSyncedPage = index;
166:                        }
167:                        prevPage = index;
168:                        if (index == page) {
169:                            image = ri;
170:                            break;
171:                        }
172:                    } catch (IOException e) {
173:                        maxPageFound = true;
174:                        maxPage = prevPage;
175:                        String message = JaiI18N.getString("GIFImage3");
176:                        ImagingListenerProxy.errorOccurred(message,
177:                                new ImagingException(message, e), this , false);
178:                        //                throw e;
179:                    }
180:                }
181:
182:                return image;
183:            }
184:        }
185:
186:        /**
187:         * @since 1.1.1
188:         */
189:        class GIFImage extends SimpleRenderedImage {
190:            // Constants used to control interlacing.
191:            private static final int[] INTERLACE_INCREMENT = { 8, 8, 4, 2, -1 };
192:            private static final int[] INTERLACE_OFFSET = { 0, 4, 2, 1, -1 };
193:
194:            // The source stream.
195:            private SeekableStream input;
196:
197:            // The interlacing flag.
198:            private boolean interlaceFlag = false;
199:
200:            // Variables used by LZW decoding
201:            private byte[] block = new byte[255];
202:            private int blockLength = 0;
203:            private int bitPos = 0;
204:            private int nextByte = 0;
205:            private int initCodeSize;
206:            private int clearCode;
207:            private int eofCode;
208:            private int bitsLeft;
209:
210:            // 32-bit lookahead buffer
211:            private int next32Bits = 0;
212:
213:            // True if the end of the data blocks has been found,
214:            // and we are simply draining the 32-bit buffer
215:            private boolean lastBlockFound = false;
216:
217:            // The current interlacing pass, starting with 0.
218:            private int interlacePass = 0;
219:
220:            // The image's tile.
221:            private WritableRaster theTile = null;
222:
223:            // Read blocks of 1-255 bytes, stop at a 0-length block
224:            private void skipBlocks() throws IOException {
225:                while (true) {
226:                    int length = input.readUnsignedByte();
227:                    if (length == 0) {
228:                        break;
229:                    }
230:                    input.skipBytes(length);
231:                }
232:            }
233:
234:            /**
235:             * Create a new <code>GIFImage</code>.  The input stream must
236:             * be positioned at the start of the image, i.e., not at the
237:             * start of the overall stream.
238:             *
239:             * @param input the stream from which to read.
240:             * @param globalColorTable the global colormap of <code>null</code>.
241:             *
242:             * @throws IOException.
243:             */
244:            GIFImage(SeekableStream input, byte[] globalColorTable)
245:                    throws IOException {
246:                this .input = input;
247:
248:                byte[] localColorTable = null;
249:                boolean transparentColorFlag = false;
250:                int transparentColorIndex = 0;
251:
252:                // Read the image header initializing the local color table,
253:                // if any, and the transparent index, if any.
254:
255:                try {
256:                    long startPosition = input.getFilePointer();
257:                    while (true) {
258:                        int blockType = input.readUnsignedByte();
259:                        if (blockType == 0x2c) { // Image Descriptor
260:                            // Skip image top and left position.
261:                            input.skipBytes(4);
262:
263:                            width = input.readUnsignedShortLE();
264:                            height = input.readUnsignedShortLE();
265:
266:                            int idPackedFields = input.readUnsignedByte();
267:                            boolean localColorTableFlag = (idPackedFields & 0x80) != 0;
268:                            interlaceFlag = (idPackedFields & 0x40) != 0;
269:                            int numLCTEntries = 1 << ((idPackedFields & 0x7) + 1);
270:
271:                            if (localColorTableFlag) {
272:                                // Read color table if any
273:                                localColorTable = new byte[3 * numLCTEntries];
274:                                input.readFully(localColorTable);
275:                            } else {
276:                                localColorTable = null;
277:                            }
278:
279:                            // Now positioned at start of LZW-compressed pixels
280:                            break;
281:                        } else if (blockType == 0x21) { // Extension block
282:                            int label = input.readUnsignedByte();
283:
284:                            if (label == 0xf9) { // Graphics Control Extension
285:                                input.read(); // extension length
286:                                int gcePackedFields = input.readUnsignedByte();
287:                                transparentColorFlag = (gcePackedFields & 0x1) != 0;
288:
289:                                input.skipBytes(2); // delay time
290:
291:                                transparentColorIndex = input
292:                                        .readUnsignedByte();
293:
294:                                input.read(); // terminator
295:                            } else if (label == 0x1) { // Plain text extension
296:                                // Skip content.
297:                                input.skipBytes(13);
298:                                // Read but do not save content.
299:                                skipBlocks();
300:                            } else if (label == 0xfe) { // Comment extension
301:                                // Read but do not save content.
302:                                skipBlocks();
303:                            } else if (label == 0xff) { // Application extension
304:                                // Skip content.
305:                                input.skipBytes(12);
306:                                // Read but do not save content.
307:                                skipBlocks();
308:                            } else {
309:                                // Skip over unknown extension blocks
310:                                int length = 0;
311:                                do {
312:                                    length = input.readUnsignedByte();
313:                                    input.skipBytes(length);
314:                                } while (length > 0);
315:                            }
316:                        } else {
317:                            throw new IOException(JaiI18N
318:                                    .getString("GIFImage0")
319:                                    + " " + blockType + "!");
320:                        }
321:                    }
322:                } catch (IOException ioe) {
323:                    throw new IOException(JaiI18N.getString("GIFImage1"));
324:                }
325:
326:                // Set the image layout from the header information.
327:
328:                // Set the image and tile grid origin to (0, 0).
329:                minX = minY = tileGridXOffset = tileGridYOffset = 0;
330:
331:                // Force the image to have a single tile.
332:                tileWidth = width;
333:                tileHeight = height;
334:
335:                byte[] colorTable;
336:                if (localColorTable != null) {
337:                    colorTable = localColorTable;
338:                } else {
339:                    colorTable = globalColorTable;
340:                }
341:
342:                // Normalize color table length to 2^1, 2^2, 2^4, or 2^8
343:                int length = colorTable.length / 3;
344:                int bits;
345:                if (length == 2) {
346:                    bits = 1;
347:                } else if (length == 4) {
348:                    bits = 2;
349:                } else if (length == 8 || length == 16) {
350:                    // Bump from 3 to 4 bits
351:                    bits = 4;
352:                } else {
353:                    // Bump to 8 bits
354:                    bits = 8;
355:                }
356:                int lutLength = 1 << bits;
357:                byte[] r = new byte[lutLength];
358:                byte[] g = new byte[lutLength];
359:                byte[] b = new byte[lutLength];
360:
361:                // Entries from length + 1 to lutLength - 1 will be 0
362:                int rgbIndex = 0;
363:                for (int i = 0; i < length; i++) {
364:                    r[i] = colorTable[rgbIndex++];
365:                    g[i] = colorTable[rgbIndex++];
366:                    b[i] = colorTable[rgbIndex++];
367:                }
368:
369:                int[] bitsPerSample = new int[1];
370:                bitsPerSample[0] = bits;
371:
372:                sampleModel = new PixelInterleavedSampleModel(
373:                        DataBuffer.TYPE_BYTE, width, height, 1, width,
374:                        new int[] { 0 });
375:
376:                if (!transparentColorFlag) {
377:                    if (ImageCodec.isIndicesForGrayscale(r, g, b))
378:                        colorModel = ImageCodec
379:                                .createComponentColorModel(sampleModel);
380:                    else
381:                        colorModel = new IndexColorModel(bits, r.length, r, g,
382:                                b);
383:                } else {
384:                    colorModel = new IndexColorModel(bits, r.length, r, g, b,
385:                            transparentColorIndex);
386:                }
387:            }
388:
389:            // BEGIN LZW CODE
390:
391:            private void initNext32Bits() {
392:                next32Bits = block[0] & 0xff;
393:                next32Bits |= (block[1] & 0xff) << 8;
394:                next32Bits |= (block[2] & 0xff) << 16;
395:                next32Bits |= block[3] << 24;
396:                nextByte = 4;
397:            }
398:
399:            // Load a block (1-255 bytes) at a time, and maintain
400:            // a 32-bit lookahead buffer that is filled from the left
401:            // and extracted from the right.
402:            private int getCode(int codeSize, int codeMask) throws IOException {
403:                //if (bitPos + codeSize > 32) {
404:                if (bitsLeft <= 0) {
405:                    return eofCode; // No more data available
406:                }
407:
408:                int code = (next32Bits >> bitPos) & codeMask;
409:                bitPos += codeSize;
410:                bitsLeft -= codeSize;
411:
412:                // Shift in a byte of new data at a time
413:                while (bitPos >= 8 && !lastBlockFound) {
414:                    next32Bits >>>= 8;
415:                    bitPos -= 8;
416:
417:                    // Check if current block is out of bytes
418:                    if (nextByte >= blockLength) {
419:                        // Get next block size
420:                        blockLength = input.readUnsignedByte();
421:                        if (blockLength == 0) {
422:                            lastBlockFound = true;
423:                            if (bitsLeft < 0)
424:                                return eofCode;
425:                            else
426:                                return code;
427:                        } else {
428:                            int left = blockLength;
429:                            int off = 0;
430:                            while (left > 0) {
431:                                int nbytes = input.read(block, off, left);
432:                                off += nbytes;
433:                                left -= nbytes;
434:                            }
435:
436:                            bitsLeft += blockLength << 3;
437:                            nextByte = 0;
438:                        }
439:                    }
440:
441:                    next32Bits |= block[nextByte++] << 24;
442:                }
443:
444:                return code;
445:            }
446:
447:            private void initializeStringTable(int[] prefix, byte[] suffix,
448:                    byte[] initial, int[] length) {
449:                int numEntries = 1 << initCodeSize;
450:                for (int i = 0; i < numEntries; i++) {
451:                    prefix[i] = -1;
452:                    suffix[i] = (byte) i;
453:                    initial[i] = (byte) i;
454:                    length[i] = 1;
455:                }
456:
457:                // Fill in the entire table for robustness against
458:                // out-of-sequence codes.
459:                for (int i = numEntries; i < 4096; i++) {
460:                    prefix[i] = -1;
461:                    length[i] = 1;
462:                }
463:            }
464:
465:            private Point outputPixels(byte[] string, int len, Point streamPos,
466:                    byte[] rowBuf) {
467:                if (interlacePass < 0 || interlacePass > 3) {
468:                    return streamPos;
469:                }
470:
471:                for (int i = 0; i < len; i++) {
472:                    if (streamPos.x >= minX) {
473:                        rowBuf[streamPos.x - minX] = string[i];
474:                    }
475:
476:                    // Process end-of-row
477:                    ++streamPos.x;
478:                    if (streamPos.x == width) {
479:                        theTile.setDataElements(minX, streamPos.y, width, 1,
480:                                rowBuf);
481:
482:                        streamPos.x = 0;
483:                        if (interlaceFlag) {
484:                            streamPos.y += INTERLACE_INCREMENT[interlacePass];
485:                            if (streamPos.y >= height) {
486:                                ++interlacePass;
487:                                if (interlacePass > 3) {
488:                                    return streamPos;
489:                                }
490:                                streamPos.y = INTERLACE_OFFSET[interlacePass];
491:                            }
492:                        } else {
493:                            ++streamPos.y;
494:                        }
495:                    }
496:                }
497:
498:                return streamPos;
499:            }
500:
501:            // END LZW CODE
502:
503:            public synchronized Raster getTile(int tileX, int tileY) {
504:
505:                // Should be a unique tile.
506:                if (tileX != 0 || tileY != 0) {
507:                    throw new IllegalArgumentException(JaiI18N
508:                            .getString("GIFImage2"));
509:                }
510:
511:                // Return the tile if it's already computed.
512:                if (theTile != null) {
513:                    return theTile;
514:                }
515:
516:                // Initialize the destination image
517:                theTile = WritableRaster.createWritableRaster(sampleModel,
518:                        sampleModel.createDataBuffer(), null);
519:
520:                // Position in stream coordinates.
521:                Point streamPos = new Point(0, 0);
522:
523:                // Allocate a row of memory.
524:                byte[] rowBuf = new byte[width];
525:
526:                try {
527:                    // Read and decode the image data, fill in theTile.
528:                    this .initCodeSize = input.readUnsignedByte();
529:
530:                    // Read first data block
531:                    this .blockLength = input.readUnsignedByte();
532:                    int left = blockLength;
533:                    int off = 0;
534:                    while (left > 0) {
535:                        int nbytes = input.read(block, off, left);
536:                        left -= nbytes;
537:                        off += nbytes;
538:                    }
539:
540:                    this .bitPos = 0;
541:                    this .nextByte = 0;
542:                    this .lastBlockFound = false;
543:                    this .bitsLeft = this .blockLength << 3;
544:
545:                    // Init 32-bit buffer
546:                    initNext32Bits();
547:
548:                    this .clearCode = 1 << initCodeSize;
549:                    this .eofCode = clearCode + 1;
550:
551:                    int code, oldCode = 0;
552:
553:                    int[] prefix = new int[4096];
554:                    byte[] suffix = new byte[4096];
555:                    byte[] initial = new byte[4096];
556:                    int[] length = new int[4096];
557:                    byte[] string = new byte[4096];
558:
559:                    initializeStringTable(prefix, suffix, initial, length);
560:                    int tableIndex = (1 << initCodeSize) + 2;
561:                    int codeSize = initCodeSize + 1;
562:                    int codeMask = (1 << codeSize) - 1;
563:
564:                    while (true) {
565:                        code = getCode(codeSize, codeMask);
566:
567:                        if (code == clearCode) {
568:                            initializeStringTable(prefix, suffix, initial,
569:                                    length);
570:                            tableIndex = (1 << initCodeSize) + 2;
571:                            codeSize = initCodeSize + 1;
572:                            codeMask = (1 << codeSize) - 1;
573:                            code = getCode(codeSize, codeMask);
574:                            if (code == eofCode) {
575:                                return theTile;
576:                            }
577:                        } else if (code == eofCode) {
578:                            return theTile;
579:                        } else {
580:                            int newSuffixIndex;
581:                            if (code < tableIndex) {
582:                                newSuffixIndex = code;
583:                            } else { // code == tableIndex
584:                                newSuffixIndex = oldCode;
585:                            }
586:
587:                            int ti = tableIndex;
588:                            int oc = oldCode;
589:
590:                            prefix[ti] = oc;
591:                            suffix[ti] = initial[newSuffixIndex];
592:                            initial[ti] = initial[oc];
593:                            length[ti] = length[oc] + 1;
594:
595:                            ++tableIndex;
596:                            if ((tableIndex == (1 << codeSize))
597:                                    && (tableIndex < 4096)) {
598:                                ++codeSize;
599:                                codeMask = (1 << codeSize) - 1;
600:                            }
601:                        }
602:
603:                        // Reverse code
604:                        int c = code;
605:                        int len = length[c];
606:                        for (int i = len - 1; i >= 0; i--) {
607:                            string[i] = suffix[c];
608:                            c = prefix[c];
609:                        }
610:
611:                        outputPixels(string, len, streamPos, rowBuf);
612:                        oldCode = code;
613:                    }
614:                } catch (IOException e) {
615:                    String message = JaiI18N.getString("GIFImage3");
616:                    ImagingListenerProxy.errorOccurred(message,
617:                            new ImagingException(message, e), this , false);
618:                    //            throw new RuntimeException(JaiI18N.getString("GIFImage3"));
619:                } finally {
620:                    return theTile;
621:                }
622:            }
623:
624:            public void dispose() {
625:                theTile = null;
626:            }
627:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.