Source Code Cross Referenced for GifEncoder.java in  » J2EE » Sofia » com » salmonllc » util » 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 » J2EE » Sofia » com.salmonllc.util 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        //** Copyright Statement ***************************************************
0002:        //The Salmon Open Framework for Internet Applications (SOFIA)
0003:        // Copyright (C) 1999 - 2002, Salmon LLC
0004:        //
0005:        // This program is free software; you can redistribute it and/or
0006:        // modify it under the terms of the GNU General Public License version 2
0007:        // as published by the Free Software Foundation;
0008:        // 
0009:        // This program is distributed in the hope that it will be useful,
0010:        // but WITHOUT ANY WARRANTY; without even the implied warranty of
0011:        // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0012:        // GNU General Public License for more details.
0013:        // 
0014:        // You should have received a copy of the GNU General Public License
0015:        // along with this program; if not, write to the Free Software
0016:        // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
0017:        // 
0018:        // For more information please visit http://www.salmonllc.com
0019:        //** End Copyright Statement ***************************************************
0020:        package com.salmonllc.util;
0021:
0022:        // ImageEncoder - abstract class for writing out an image
0023:        //
0024:        // Copyright (C) 1996 by Jef Poskanzer <jef@acme.com>.  All rights reserved.
0025:        //
0026:        // Redistribution and use in source and binary forms, with or without
0027:        // modification, are permitted provided that the following conditions
0028:        // are met:
0029:        // 1. Redistributions of source code must retain the above copyright
0030:        //    notice, this list of conditions and the following disclaimer.
0031:        // 2. Redistributions in binary form must reproduce the above copyright
0032:        //    notice, this list of conditions and the following disclaimer in the
0033:        //    documentation and/or other materials provided with the distribution.
0034:        //
0035:        // THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
0036:        // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0037:        // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0038:        // ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
0039:        // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
0040:        // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
0041:        // OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
0042:        // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
0043:        // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
0044:        // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
0045:        // SUCH DAMAGE.
0046:        //
0047:        // Visit the ACME Labs Java page for up-to-date versions of this and other
0048:        // fine Java utilities: http://www.acme.com/java/
0049:
0050:        import java.util.*;
0051:        import java.io.*;
0052:        import java.awt.Image;
0053:        import java.awt.image.*;
0054:        import java.awt.*;
0055:
0056:        /**
0057:         * Class for writing out an image as a gif.
0058:         */
0059:
0060:        public class GifEncoder implements  ImageConsumer {
0061:
0062:            protected OutputStream out;
0063:
0064:            private ImageProducer producer;
0065:            private int width = -1;
0066:            private int height = -1;
0067:            private int hintflags = 0;
0068:            private boolean started = false;
0069:            private boolean encoding;
0070:            private IOException iox;
0071:            private static final ColorModel rgbModel = ColorModel
0072:                    .getRGBdefault();
0073:            private Hashtable props = null;
0074:
0075:            private boolean accumulate = false;
0076:            private int[] accumulator;
0077:
0078:            private boolean interlace = false;
0079:
0080:            int[][] rgbPixels;
0081:
0082:            IntHashtable colorHash;
0083:
0084:            // Adapted from ppmtogif, which is based on GIFENCOD by David
0085:            // Rowley <mgardi@watdscu.waterloo.edu>.  Lempel-Zim compression
0086:            // based on "compress".
0087:
0088:            int Width, Height;
0089:            boolean Interlace;
0090:            int curx, cury;
0091:            int CountDown;
0092:            int Pass = 0;
0093:
0094:            static final int EOF = -1;
0095:
0096:            // GIFCOMPR.C       - GIF Image compression routines
0097:            //
0098:            // Lempel-Ziv compression based on 'compress'.  GIF modifications by
0099:            // David Rowley (mgardi@watdcsu.waterloo.edu)
0100:
0101:            // General DEFINEs
0102:
0103:            static final int BITS = 12;
0104:
0105:            static final int HSIZE = 5003; // 80% occupancy
0106:
0107:            // GIF Image compression - modified 'compress'
0108:            //
0109:            // Based on: compress.c - File compression ala IEEE Computer, June 1984.
0110:            //
0111:            // By Authors:  Spencer W. Thomas      (decvax!harpo!utah-cs!utah-gr!thomas)
0112:            //              Jim McKie              (decvax!mcvax!jim)
0113:            //              Steve Davies           (decvax!vax135!petsd!peora!srd)
0114:            //              Ken Turkowski          (decvax!decwrl!turtlevax!ken)
0115:            //              James A. Woods         (decvax!ihnp4!ames!jaw)
0116:            //              Joe Orost              (decvax!vax135!petsd!joe)
0117:
0118:            int n_bits; // number of bits/code
0119:            int maxbits = BITS; // user settable max # bits/code
0120:            int maxcode; // maximum code, given n_bits
0121:            int maxmaxcode = 1 << BITS; // should NEVER generate this code
0122:
0123:            int[] htab = new int[HSIZE];
0124:            int[] codetab = new int[HSIZE];
0125:
0126:            int hsize = HSIZE; // for dynamic table sizing
0127:
0128:            int free_ent = 0; // first unused entry
0129:
0130:            // block compression parameters -- after all codes are used up,
0131:            // and compression rate changes, start over.
0132:            boolean clear_flg = false;
0133:
0134:            // Algorithm:  use open addressing double hashing (no chaining) on the
0135:            // prefix code / next character combination.  We do a variant of Knuth's
0136:            // algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime
0137:            // secondary probe.  Here, the modular division first probe is gives way
0138:            // to a faster exclusive-or manipulation.  Also do block compression with
0139:            // an adaptive reset, whereby the code table is cleared when the compression
0140:            // ratio decreases, but after the table fills.  The variable-length output
0141:            // codes are re-sized at this point, and a special CLEAR code is generated
0142:            // for the decompressor.  Late addition:  construct the table according to
0143:            // file size for noticeable speed improvement on small files.  Please direct
0144:            // questions about this implementation to ames!jaw.
0145:
0146:            int g_init_bits;
0147:
0148:            int ClearCode;
0149:            int EOFCode;
0150:
0151:            // output
0152:            //
0153:            // Output the given code.
0154:            // Inputs:
0155:            //      code:   A n_bits-bit integer.  If == -1, then EOF.  This assumes
0156:            //              that n_bits =< wordsize - 1.
0157:            // Outputs:
0158:            //      Outputs code to the file.
0159:            // Assumptions:
0160:            //      Chars are 8 bits long.
0161:            // Algorithm:
0162:            //      Maintain a BITS character long buffer (so that 8 codes will
0163:            // fit in it exactly).  Use the VAX insv instruction to insert each
0164:            // code in turn.  When the buffer fills up empty it and start over.
0165:
0166:            int cur_accum = 0;
0167:            int cur_bits = 0;
0168:
0169:            int masks[] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F,
0170:                    0x003F, 0x007F, 0x00FF, 0x01FF, 0x03FF, 0x07FF, 0x0FFF,
0171:                    0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF };
0172:
0173:            // GIF Specific routines
0174:
0175:            // Number of characters so far in this 'packet'
0176:            int a_count;
0177:
0178:            // Define the storage for the packet accumulator
0179:            byte[] accum = new byte[256];
0180:
0181:            class gifHashitem {
0182:                public int rgb;
0183:                public int count;
0184:                public int index;
0185:                public boolean isTransparent;
0186:
0187:                public gifHashitem(int rgb, int count, int index,
0188:                        boolean isTransparent) {
0189:                    this .rgb = rgb;
0190:                    this .count = count;
0191:                    this .index = index;
0192:                    this .isTransparent = isTransparent;
0193:                }
0194:            }
0195:
0196:            class IntHashtableEntry {
0197:                int hash;
0198:                int key;
0199:                Object value;
0200:                IntHashtableEntry next;
0201:
0202:                protected Object clone() {
0203:                    IntHashtableEntry entry = new IntHashtableEntry();
0204:                    entry.hash = hash;
0205:                    entry.key = key;
0206:                    entry.value = value;
0207:                    entry.next = (next != null) ? (IntHashtableEntry) next
0208:                            .clone() : null;
0209:                    return entry;
0210:                }
0211:            }
0212:
0213:            class IntHashtable extends Dictionary implements  Cloneable {
0214:                private IntHashtableEntry table[];
0215:                private int count;
0216:                private int threshold;
0217:                private float loadFactor;
0218:
0219:                public IntHashtable() {
0220:                    this (101, 0.75f);
0221:                }
0222:
0223:                public IntHashtable(int initialCapacity) {
0224:                    this (initialCapacity, 0.75f);
0225:                }
0226:
0227:                public IntHashtable(int initialCapacity, float loadFactor) {
0228:                    if (initialCapacity <= 0 || loadFactor <= 0.0)
0229:                        throw new IllegalArgumentException();
0230:                    this .loadFactor = loadFactor;
0231:                    table = new IntHashtableEntry[initialCapacity];
0232:                    threshold = (int) (initialCapacity * loadFactor);
0233:                }
0234:
0235:                public synchronized void clear() {
0236:                    IntHashtableEntry tab[] = table;
0237:                    for (int index = tab.length; --index >= 0;)
0238:                        tab[index] = null;
0239:                    count = 0;
0240:                }
0241:
0242:                public synchronized Object clone() {
0243:                    try {
0244:                        IntHashtable t = (IntHashtable) super .clone();
0245:                        t.table = new IntHashtableEntry[table.length];
0246:                        for (int i = table.length; i-- > 0;)
0247:                            t.table[i] = (table[i] != null) ? (IntHashtableEntry) table[i]
0248:                                    .clone()
0249:                                    : null;
0250:                        return t;
0251:                    } catch (CloneNotSupportedException e) {
0252:                        throw new InternalError();
0253:                    }
0254:                }
0255:
0256:                public synchronized boolean contains(Object value) {
0257:                    if (value == null)
0258:                        throw new NullPointerException();
0259:                    IntHashtableEntry tab[] = table;
0260:                    for (int i = tab.length; i-- > 0;) {
0261:                        for (IntHashtableEntry e = tab[i]; e != null; e = e.next) {
0262:                            if (e.value.equals(value))
0263:                                return true;
0264:                        }
0265:                    }
0266:                    return false;
0267:                }
0268:
0269:                public synchronized boolean containsKey(int key) {
0270:                    IntHashtableEntry tab[] = table;
0271:                    int hash = key;
0272:                    int index = (hash & 0x7FFFFFFF) % tab.length;
0273:                    for (IntHashtableEntry e = tab[index]; e != null; e = e.next) {
0274:                        if (e.hash == hash && e.key == key)
0275:                            return true;
0276:                    }
0277:                    return false;
0278:                }
0279:
0280:                public synchronized Enumeration elements() {
0281:                    return new IntHashtableEnumerator(table, false);
0282:                }
0283:
0284:                public synchronized Object get(int key) {
0285:                    IntHashtableEntry tab[] = table;
0286:                    int hash = key;
0287:                    int index = (hash & 0x7FFFFFFF) % tab.length;
0288:                    for (IntHashtableEntry e = tab[index]; e != null; e = e.next) {
0289:                        if (e.hash == hash && e.key == key)
0290:                            return e.value;
0291:                    }
0292:                    return null;
0293:                }
0294:
0295:                public Object get(Object okey) {
0296:                    if (!(okey instanceof  Integer))
0297:                        throw new InternalError("key is not an Integer");
0298:                    Integer ikey = (Integer) okey;
0299:                    int key = ikey.intValue();
0300:                    return get(key);
0301:                }
0302:
0303:                public boolean isEmpty() {
0304:                    return count == 0;
0305:                }
0306:
0307:                public synchronized Enumeration keys() {
0308:                    return new IntHashtableEnumerator(table, true);
0309:                }
0310:
0311:                public synchronized Object put(int key, Object value) {
0312:                    if (value == null)
0313:                        throw new NullPointerException();
0314:
0315:                    IntHashtableEntry tab[] = table;
0316:                    int hash = key;
0317:                    int index = (hash & 0x7FFFFFFF) % tab.length;
0318:                    for (IntHashtableEntry e = tab[index]; e != null; e = e.next) {
0319:                        if (e.hash == hash && e.key == key) {
0320:                            Object old = e.value;
0321:                            e.value = value;
0322:                            return old;
0323:                        }
0324:                    }
0325:
0326:                    if (count >= threshold) {
0327:                        rehash();
0328:                        return put(key, value);
0329:                    }
0330:
0331:                    IntHashtableEntry e = new IntHashtableEntry();
0332:                    e.hash = hash;
0333:                    e.key = key;
0334:                    e.value = value;
0335:                    e.next = tab[index];
0336:                    tab[index] = e;
0337:                    ++count;
0338:                    return null;
0339:                }
0340:
0341:                public Object put(Object okey, Object value) {
0342:                    if (!(okey instanceof  Integer))
0343:                        throw new InternalError("key is not an Integer");
0344:                    Integer ikey = (Integer) okey;
0345:                    int key = ikey.intValue();
0346:                    return put(key, value);
0347:                }
0348:
0349:                protected void rehash() {
0350:                    int oldCapacity = table.length;
0351:                    IntHashtableEntry oldTable[] = table;
0352:
0353:                    int newCapacity = oldCapacity * 2 + 1;
0354:                    IntHashtableEntry newTable[] = new IntHashtableEntry[newCapacity];
0355:
0356:                    threshold = (int) (newCapacity * loadFactor);
0357:                    table = newTable;
0358:
0359:                    for (int i = oldCapacity; i-- > 0;) {
0360:                        for (IntHashtableEntry old = oldTable[i]; old != null;) {
0361:                            IntHashtableEntry e = old;
0362:                            old = old.next;
0363:
0364:                            int index = (e.hash & 0x7FFFFFFF) % newCapacity;
0365:                            e.next = newTable[index];
0366:                            newTable[index] = e;
0367:                        }
0368:                    }
0369:                }
0370:
0371:                public synchronized Object remove(int key) {
0372:                    IntHashtableEntry tab[] = table;
0373:                    int hash = key;
0374:                    int index = (hash & 0x7FFFFFFF) % tab.length;
0375:                    for (IntHashtableEntry e = tab[index], prev = null; e != null; prev = e, e = e.next) {
0376:                        if (e.hash == hash && e.key == key) {
0377:                            if (prev != null)
0378:                                prev.next = e.next;
0379:                            else
0380:                                tab[index] = e.next;
0381:                            --count;
0382:                            return e.value;
0383:                        }
0384:                    }
0385:                    return null;
0386:                }
0387:
0388:                public Object remove(Object okey) {
0389:                    if (!(okey instanceof  Integer))
0390:                        throw new InternalError("key is not an Integer");
0391:                    Integer ikey = (Integer) okey;
0392:                    int key = ikey.intValue();
0393:                    return remove(key);
0394:                }
0395:
0396:                public int size() {
0397:                    return count;
0398:                }
0399:
0400:                public synchronized String toString() {
0401:                    int max = size() - 1;
0402:                    StringBuffer buf = new StringBuffer();
0403:                    Enumeration k = keys();
0404:                    Enumeration e = elements();
0405:                    buf.append("{");
0406:
0407:                    for (int i = 0; i <= max; ++i) {
0408:                        String s1 = k.nextElement().toString();
0409:                        String s2 = e.nextElement().toString();
0410:                        buf.append(s1 + "=" + s2);
0411:                        if (i < max)
0412:                            buf.append(", ");
0413:                    }
0414:                    buf.append("}");
0415:                    return buf.toString();
0416:                }
0417:            }
0418:
0419:            class IntHashtableEnumerator implements  Enumeration {
0420:                boolean keys;
0421:                int index;
0422:                IntHashtableEntry table[];
0423:                IntHashtableEntry entry;
0424:
0425:                IntHashtableEnumerator(IntHashtableEntry table[], boolean keys) {
0426:                    this .table = table;
0427:                    this .keys = keys;
0428:                    this .index = table.length;
0429:                }
0430:
0431:                public boolean hasMoreElements() {
0432:                    if (entry != null)
0433:                        return true;
0434:                    while (index-- > 0)
0435:                        if ((entry = table[index]) != null)
0436:                            return true;
0437:                    return false;
0438:                }
0439:
0440:                public Object nextElement() {
0441:                    if (entry == null)
0442:                        while ((index-- > 0)
0443:                                && ((entry = table[index]) == null))
0444:                            ;
0445:                    if (entry != null) {
0446:                        IntHashtableEntry e = entry;
0447:                        entry = e.next;
0448:                        return keys ? new Integer(e.key) : e.value;
0449:                    }
0450:                    throw new NoSuchElementException("IntHashtableEnumerator");
0451:                }
0452:            }
0453:
0454:            class TransparentFilter extends RGBImageFilter {
0455:                int transparentRGB;
0456:
0457:                public TransparentFilter(Color color) {
0458:                    transparentRGB = color.getRGB() & 0xFFFFFF;
0459:                    canFilterIndexColorModel = true;
0460:                }
0461:
0462:                public int filterRGB(int x, int y, int rgb) {
0463:                    if ((rgb & 0xFFFFFF) == transparentRGB)
0464:                        return 0;
0465:
0466:                    return rgb;
0467:                }
0468:            }
0469:
0470:            /// Constructor.
0471:            // @param producer The ImageProducer to encode.
0472:            // @param out The stream to write the bytes to.
0473:            private GifEncoder(ImageProducer producer, OutputStream out)
0474:                    throws IOException {
0475:                this .producer = producer;
0476:                this .out = out;
0477:            }
0478:
0479:            /**
0480:             * Constructor
0481:             *  @param img The image to encode.
0482:             *  @param out The stream to write the bytes to.
0483:             */
0484:            public GifEncoder(Image img, OutputStream out) throws IOException {
0485:                this (img.getSource(), out);
0486:            }
0487:
0488:            /**
0489:             * Constructor from Image with interlace setting.
0490:             * @param img The image to encode.
0491:             * @param out The stream to write the GIF to.
0492:             * @param interlace Whether to interlace.
0493:             */
0494:            public GifEncoder(Image img, OutputStream out, boolean interlace)
0495:                    throws IOException {
0496:                this (img, out);
0497:                this .interlace = interlace;
0498:            }
0499:
0500:            /** Constructor from Image with interlace setting.
0501:             * @param img The image to encode.
0502:             * @param out The stream to write the GIF to.
0503:             * @param interlace Whether to interlace.
0504:             * @param transparentColor The color to use for transparency
0505:             */
0506:            public GifEncoder(Image img, OutputStream out, boolean interlace,
0507:                    Color transparentColor) throws IOException {
0508:                RGBImageFilter f = new TransparentFilter(transparentColor);
0509:                this .producer = new FilteredImageSource(img.getSource(), f);
0510:                this .out = out;
0511:                this .interlace = interlace;
0512:            }
0513:
0514:            // Bump the 'curx' and 'cury' to point to the next pixel
0515:            void BumpPixel() {
0516:                // Bump the current X position
0517:                ++curx;
0518:
0519:                // If we are at the end of a scan line, set curx back to the beginning
0520:                // If we are interlaced, bump the cury to the appropriate spot,
0521:                // otherwise, just increment it.
0522:                if (curx == Width) {
0523:                    curx = 0;
0524:
0525:                    if (!Interlace)
0526:                        ++cury;
0527:                    else {
0528:                        switch (Pass) {
0529:                        case 0:
0530:                            cury += 8;
0531:                            if (cury >= Height) {
0532:                                ++Pass;
0533:                                cury = 4;
0534:                            }
0535:                            break;
0536:
0537:                        case 1:
0538:                            cury += 8;
0539:                            if (cury >= Height) {
0540:                                ++Pass;
0541:                                cury = 2;
0542:                            }
0543:                            break;
0544:
0545:                        case 2:
0546:                            cury += 4;
0547:                            if (cury >= Height) {
0548:                                ++Pass;
0549:                                cury = 1;
0550:                            }
0551:                            break;
0552:
0553:                        case 3:
0554:                            cury += 2;
0555:                            break;
0556:                        }
0557:                    }
0558:                }
0559:            }
0560:
0561:            // Set up the 'byte output' routine
0562:            void char_init() {
0563:                a_count = 0;
0564:            }
0565:
0566:            // Add a character to the end of the current packet, and if it is 254
0567:            // characters, flush the packet to disk.
0568:            void char_out(byte c, OutputStream outs) throws IOException {
0569:                accum[a_count++] = c;
0570:                if (a_count >= 254)
0571:                    flush_char(outs);
0572:            }
0573:
0574:            // Clear out the hash table
0575:
0576:            // table clear for block compress
0577:            void cl_block(OutputStream outs) throws IOException {
0578:                cl_hash(hsize);
0579:                free_ent = ClearCode + 2;
0580:                clear_flg = true;
0581:
0582:                output(ClearCode, outs);
0583:            }
0584:
0585:            // reset code table
0586:            void cl_hash(int hsize) {
0587:                for (int i = 0; i < hsize; ++i)
0588:                    htab[i] = -1;
0589:            }
0590:
0591:            void compress(int init_bits, OutputStream outs) throws IOException {
0592:                int fcode;
0593:                int i /* = 0 */;
0594:                int c;
0595:                int ent;
0596:                int disp;
0597:                int hsize_reg;
0598:                int hshift;
0599:
0600:                // Set up the globals:  g_init_bits - initial number of bits
0601:                g_init_bits = init_bits;
0602:
0603:                // Set up the necessary values
0604:                clear_flg = false;
0605:                n_bits = g_init_bits;
0606:                maxcode = MAXCODE(n_bits);
0607:
0608:                ClearCode = 1 << (init_bits - 1);
0609:                EOFCode = ClearCode + 1;
0610:                free_ent = ClearCode + 2;
0611:
0612:                char_init();
0613:
0614:                ent = GIFNextPixel();
0615:
0616:                hshift = 0;
0617:                for (fcode = hsize; fcode < 65536; fcode *= 2)
0618:                    ++hshift;
0619:                hshift = 8 - hshift; // set hash code range bound
0620:
0621:                hsize_reg = hsize;
0622:                cl_hash(hsize_reg); // clear hash table
0623:
0624:                output(ClearCode, outs);
0625:
0626:                outer_loop: while ((c = GIFNextPixel()) != EOF) {
0627:                    fcode = (c << maxbits) + ent;
0628:                    i = (c << hshift) ^ ent; // xor hashing
0629:
0630:                    if (htab[i] == fcode) {
0631:                        ent = codetab[i];
0632:                        continue;
0633:                    } else if (htab[i] >= 0) // non-empty slot
0634:                    {
0635:                        disp = hsize_reg - i; // secondary hash (after G. Knott)
0636:                        if (i == 0)
0637:                            disp = 1;
0638:                        do {
0639:                            if ((i -= disp) < 0)
0640:                                i += hsize_reg;
0641:
0642:                            if (htab[i] == fcode) {
0643:                                ent = codetab[i];
0644:                                continue outer_loop;
0645:                            }
0646:                        } while (htab[i] >= 0);
0647:                    }
0648:                    output(ent, outs);
0649:                    ent = c;
0650:                    if (free_ent < maxmaxcode) {
0651:                        codetab[i] = free_ent++; // code -> hashtable
0652:                        htab[i] = fcode;
0653:                    } else
0654:                        cl_block(outs);
0655:                }
0656:                // Put out the final code.
0657:                output(ent, outs);
0658:                output(EOFCode, outs);
0659:            }
0660:
0661:            // Our own methods.
0662:
0663:            /**
0664:             *  Call this method after initialization to do the encoding
0665:             */
0666:            public synchronized void encode() throws IOException {
0667:                encoding = true;
0668:                iox = null;
0669:                producer.startProduction(this );
0670:                while (encoding)
0671:                    try {
0672:                        wait();
0673:                    } catch (InterruptedException e) {
0674:                    }
0675:                if (iox != null)
0676:                    throw iox;
0677:            }
0678:
0679:            void encodeDone() throws IOException {
0680:                int transparentIndex = -1;
0681:                int transparentRgb = -1;
0682:                // Put all the pixels into a hash table.
0683:                colorHash = new IntHashtable();
0684:                int index = 0;
0685:                for (int row = 0; row < height; ++row) {
0686:                    for (int col = 0; col < width; ++col) {
0687:                        int rgb = rgbPixels[row][col];
0688:                        boolean isTransparent = ((rgb >>> 24) < 0x80);
0689:                        if (isTransparent) {
0690:                            if (transparentIndex < 0) {
0691:                                // First transparent color; remember it.
0692:                                transparentIndex = index;
0693:                                transparentRgb = rgb;
0694:                            } else if (rgb != transparentRgb) {
0695:                                // A second transparent color; replace it with
0696:                                // the first one.
0697:                                rgbPixels[row][col] = rgb = transparentRgb;
0698:                            }
0699:                        }
0700:                        gifHashitem item = (gifHashitem) colorHash.get(rgb);
0701:                        if (item == null) {
0702:                            if (index >= 256)
0703:                                throw new IOException(
0704:                                        "too many colors for a GIF");
0705:                            item = new gifHashitem(rgb, 1, index, isTransparent);
0706:                            ++index;
0707:                            colorHash.put(rgb, item);
0708:                        } else
0709:                            ++item.count;
0710:                    }
0711:                }
0712:
0713:                // Figure out how many bits to use.
0714:                int logColors;
0715:                if (index <= 2)
0716:                    logColors = 1;
0717:                else if (index <= 4)
0718:                    logColors = 2;
0719:                else if (index <= 16)
0720:                    logColors = 4;
0721:                else
0722:                    logColors = 8;
0723:
0724:                // Turn colors into colormap entries.
0725:                int mapSize = 1 << logColors;
0726:                byte[] reds = new byte[mapSize];
0727:                byte[] grns = new byte[mapSize];
0728:                byte[] blus = new byte[mapSize];
0729:                for (Enumeration e = colorHash.elements(); e.hasMoreElements();) {
0730:                    gifHashitem item = (gifHashitem) e.nextElement();
0731:                    reds[item.index] = (byte) ((item.rgb >> 16) & 0xff);
0732:                    grns[item.index] = (byte) ((item.rgb >> 8) & 0xff);
0733:                    blus[item.index] = (byte) (item.rgb & 0xff);
0734:                }
0735:
0736:                GIFEncode(out, width, height, interlace, (byte) 0,
0737:                        transparentIndex, logColors, reds, grns, blus);
0738:            }
0739:
0740:            private void encodeFinish() throws IOException {
0741:                if (accumulate) {
0742:                    encodePixels(0, 0, width, height, accumulator, 0, width);
0743:                    accumulator = null;
0744:                    accumulate = false;
0745:                }
0746:            }
0747:
0748:            void encodePixels(int x, int y, int w, int h, int[] rgbPixels,
0749:                    int off, int scansize) throws IOException {
0750:                // Save the pixels.
0751:                for (int row = 0; row < h; ++row)
0752:                    System.arraycopy(rgbPixels, row * scansize + off,
0753:                            this .rgbPixels[y + row], x, w);
0754:
0755:            }
0756:
0757:            private void encodePixelsWrapper(int x, int y, int w, int h,
0758:                    int[] rgbPixels, int off, int scansize) throws IOException {
0759:                if (!started) {
0760:                    started = true;
0761:                    encodeStart(width, height);
0762:                    if ((hintflags & TOPDOWNLEFTRIGHT) == 0) {
0763:                        accumulate = true;
0764:                        accumulator = new int[width * height];
0765:                    }
0766:                }
0767:                if (accumulate)
0768:                    for (int row = 0; row < h; ++row)
0769:                        System.arraycopy(rgbPixels, row * scansize + off,
0770:                                accumulator, (y + row) * width + x, w);
0771:                else
0772:                    encodePixels(x, y, w, h, rgbPixels, off, scansize);
0773:            }
0774:
0775:            void encodeStart(int width, int height) throws IOException {
0776:                this .width = width;
0777:                this .height = height;
0778:                rgbPixels = new int[height][width];
0779:            }
0780:
0781:            // Flush the packet to disk, and reset the accumulator
0782:            void flush_char(OutputStream outs) throws IOException {
0783:                if (a_count > 0) {
0784:                    outs.write(a_count);
0785:                    outs.write(accum, 0, a_count);
0786:                    a_count = 0;
0787:                }
0788:            }
0789:
0790:            byte GetPixel(int x, int y) throws IOException {
0791:                gifHashitem item = (gifHashitem) colorHash.get(rgbPixels[y][x]);
0792:                if (item == null)
0793:                    throw new IOException("color not found");
0794:                return (byte) item.index;
0795:            }
0796:
0797:            void GIFEncode(OutputStream outs, int Width, int Height,
0798:                    boolean Interlace, byte Background, int Transparent,
0799:                    int BitsPerPixel, byte[] Red, byte[] Green, byte[] Blue)
0800:                    throws IOException {
0801:                byte B;
0802:                int LeftOfs, TopOfs;
0803:                int ColorMapSize;
0804:                int InitCodeSize;
0805:                int i;
0806:
0807:                this .Width = Width;
0808:                this .Height = Height;
0809:                this .Interlace = Interlace;
0810:                ColorMapSize = 1 << BitsPerPixel;
0811:                LeftOfs = TopOfs = 0;
0812:
0813:                // Calculate number of bits we are expecting
0814:                CountDown = Width * Height;
0815:
0816:                // Indicate which pass we are on (if interlace)
0817:                Pass = 0;
0818:
0819:                // The initial code size
0820:                if (BitsPerPixel <= 1)
0821:                    InitCodeSize = 2;
0822:                else
0823:                    InitCodeSize = BitsPerPixel;
0824:
0825:                // Set up the current x and y position
0826:                curx = 0;
0827:                cury = 0;
0828:
0829:                // Write the Magic header
0830:                writeString(outs, "GIF89a");
0831:
0832:                // Write out the screen width and height
0833:                Putword(Width, outs);
0834:                Putword(Height, outs);
0835:
0836:                // Indicate that there is a global colour map
0837:                B = (byte) 0x80; // Yes, there is a color map
0838:                // OR in the resolution
0839:                B |= (byte) ((8 - 1) << 4);
0840:                // Not sorted
0841:                // OR in the Bits per Pixel
0842:                B |= (byte) ((BitsPerPixel - 1));
0843:
0844:                // Write it out
0845:                Putbyte(B, outs);
0846:
0847:                // Write out the Background colour
0848:                Putbyte(Background, outs);
0849:
0850:                // Pixel aspect ratio - 1:1.
0851:                //Putbyte( (byte) 49, outs );
0852:                // Java's GIF reader currently has a bug, if the aspect ratio byte is
0853:                // not zero it throws an ImageFormatException.  It doesn't know that
0854:                // 49 means a 1:1 aspect ratio.  Well, whatever, zero works with all
0855:                // the other decoders I've tried so it probably doesn't hurt.
0856:                Putbyte((byte) 0, outs);
0857:
0858:                // Write out the Global Colour Map
0859:                for (i = 0; i < ColorMapSize; ++i) {
0860:                    Putbyte(Red[i], outs);
0861:                    Putbyte(Green[i], outs);
0862:                    Putbyte(Blue[i], outs);
0863:                }
0864:
0865:                // Write out extension for transparent colour index, if necessary.
0866:                if (Transparent != -1) {
0867:                    Putbyte((byte) '!', outs);
0868:                    Putbyte((byte) 0xf9, outs);
0869:                    Putbyte((byte) 4, outs);
0870:                    Putbyte((byte) 1, outs);
0871:                    Putbyte((byte) 0, outs);
0872:                    Putbyte((byte) 0, outs);
0873:                    Putbyte((byte) Transparent, outs);
0874:                    Putbyte((byte) 0, outs);
0875:                }
0876:
0877:                // Write an Image separator
0878:                Putbyte((byte) ',', outs);
0879:
0880:                // Write the Image header
0881:                Putword(LeftOfs, outs);
0882:                Putword(TopOfs, outs);
0883:                Putword(Width, outs);
0884:                Putword(Height, outs);
0885:
0886:                // Write out whether or not the image is interlaced
0887:                if (Interlace)
0888:                    Putbyte((byte) 0x40, outs);
0889:                else
0890:                    Putbyte((byte) 0x00, outs);
0891:
0892:                // Write out the initial code size
0893:                Putbyte((byte) InitCodeSize, outs);
0894:
0895:                // Go and actually compress the data
0896:                compress(InitCodeSize + 1, outs);
0897:
0898:                // Write out a Zero-length packet (to end the series)
0899:                Putbyte((byte) 0, outs);
0900:
0901:                // Write the GIF file terminator
0902:                Putbyte((byte) ';', outs);
0903:            }
0904:
0905:            // Return the next pixel from the image
0906:            int GIFNextPixel() throws IOException {
0907:                byte r;
0908:
0909:                if (CountDown == 0)
0910:                    return EOF;
0911:
0912:                --CountDown;
0913:
0914:                r = GetPixel(curx, cury);
0915:
0916:                BumpPixel();
0917:
0918:                return r & 0xff;
0919:            }
0920:
0921:            public void imageComplete(int status) {
0922:                producer.removeConsumer(this );
0923:                if (status == ImageConsumer.IMAGEABORTED)
0924:                    iox = new IOException("image aborted");
0925:                else {
0926:                    try {
0927:                        encodeFinish();
0928:                        encodeDone();
0929:                    } catch (IOException e) {
0930:                        iox = e;
0931:                    }
0932:                }
0933:                stop();
0934:            }
0935:
0936:            final int MAXCODE(int n_bits) {
0937:                return (1 << n_bits) - 1;
0938:            }
0939:
0940:            void output(int code, OutputStream outs) throws IOException {
0941:                cur_accum &= masks[cur_bits];
0942:
0943:                if (cur_bits > 0)
0944:                    cur_accum |= (code << cur_bits);
0945:                else
0946:                    cur_accum = code;
0947:
0948:                cur_bits += n_bits;
0949:
0950:                while (cur_bits >= 8) {
0951:                    char_out((byte) (cur_accum & 0xff), outs);
0952:                    cur_accum >>= 8;
0953:                    cur_bits -= 8;
0954:                }
0955:
0956:                // If the next entry is going to be too big for the code size,
0957:                // then increase it, if possible.
0958:                if (free_ent > maxcode || clear_flg) {
0959:                    if (clear_flg) {
0960:                        maxcode = MAXCODE(n_bits = g_init_bits);
0961:                        clear_flg = false;
0962:                    } else {
0963:                        ++n_bits;
0964:                        if (n_bits == maxbits)
0965:                            maxcode = maxmaxcode;
0966:                        else
0967:                            maxcode = MAXCODE(n_bits);
0968:                    }
0969:                }
0970:
0971:                if (code == EOFCode) {
0972:                    // At EOF, write the rest of the buffer.
0973:                    while (cur_bits > 0) {
0974:                        char_out((byte) (cur_accum & 0xff), outs);
0975:                        cur_accum >>= 8;
0976:                        cur_bits -= 8;
0977:                    }
0978:
0979:                    flush_char(outs);
0980:                }
0981:            }
0982:
0983:            // Write out a byte to the GIF file
0984:            void Putbyte(byte b, OutputStream outs) throws IOException {
0985:                outs.write(b);
0986:            }
0987:
0988:            // Write out a word to the GIF file
0989:            void Putword(int w, OutputStream outs) throws IOException {
0990:                Putbyte((byte) (w & 0xff), outs);
0991:                Putbyte((byte) ((w >> 8) & 0xff), outs);
0992:            }
0993:
0994:            public void setColorModel(ColorModel model) {
0995:                // Ignore.
0996:            }
0997:
0998:            // Methods from ImageConsumer.
0999:
1000:            public void setDimensions(int width, int height) {
1001:                this .width = width;
1002:                this .height = height;
1003:            }
1004:
1005:            public void setHints(int hintflags) {
1006:                this .hintflags = hintflags;
1007:            }
1008:
1009:            public void setPixels(int x, int y, int w, int h, ColorModel model,
1010:                    byte[] pixels, int off, int scansize) {
1011:                int[] rgbPixels = new int[w];
1012:                for (int row = 0; row < h; ++row) {
1013:                    int rowOff = off + row * scansize;
1014:                    for (int col = 0; col < w; ++col)
1015:                        rgbPixels[col] = model
1016:                                .getRGB(pixels[rowOff + col] & 0xff);
1017:                    try {
1018:                        encodePixelsWrapper(x, y + row, w, 1, rgbPixels, 0, w);
1019:                    } catch (IOException e) {
1020:                        iox = e;
1021:                        stop();
1022:                        return;
1023:                    }
1024:                }
1025:            }
1026:
1027:            public void setPixels(int x, int y, int w, int h, ColorModel model,
1028:                    int[] pixels, int off, int scansize) {
1029:                if (model == rgbModel) {
1030:                    try {
1031:                        encodePixelsWrapper(x, y, w, h, pixels, off, scansize);
1032:                    } catch (IOException e) {
1033:                        iox = e;
1034:                        stop();
1035:                        return;
1036:                    }
1037:                } else {
1038:                    int[] rgbPixels = new int[w];
1039:                    for (int row = 0; row < h; ++row) {
1040:                        int rowOff = off + row * scansize;
1041:                        for (int col = 0; col < w; ++col)
1042:                            rgbPixels[col] = model.getRGB(pixels[rowOff + col]);
1043:                        try {
1044:                            encodePixelsWrapper(x, y + row, w, 1, rgbPixels, 0,
1045:                                    w);
1046:                        } catch (IOException e) {
1047:                            iox = e;
1048:                            stop();
1049:                            return;
1050:                        }
1051:                    }
1052:                }
1053:            }
1054:
1055:            public void setProperties(Hashtable props) {
1056:                this .props = props;
1057:            }
1058:
1059:            private synchronized void stop() {
1060:                encoding = false;
1061:                notifyAll();
1062:            }
1063:
1064:            static void writeString(OutputStream out, String str)
1065:                    throws IOException {
1066:                byte[] buf = str.getBytes();
1067:                out.write(buf);
1068:            }
1069:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.