Source Code Cross Referenced for PngEncoder.java in  » Swing-Library » wings3 » com » keypoint » 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 » Swing Library » wings3 » com.keypoint 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        package com.keypoint;
002:
003:        /**
004:         * PngEncoder takes a Java Image object and creates a byte string which can be saved as a PNG file.
005:         * The Image is presumed to use the DirectColorModel.
006:         *
007:         * Thanks to Jay Denny at KeyPoint Software
008:         *    http://www.keypoint.com/
009:         * who let me develop this code on company time.
010:         *
011:         * You may contact me with (probably very-much-needed) improvements,
012:         * comments, and bug fixes at:
013:         *
014:         *   david@catcode.com
015:         *
016:         * This library is free software; you can redistribute it and/or
017:         * modify it under the terms of the GNU Lesser General Public
018:         * License as published by the Free Software Foundation; either
019:         * version 2.1 of the License, or (at your option) any later version.
020:         * 
021:         * This library is distributed in the hope that it will be useful,
022:         * but WITHOUT ANY WARRANTY; without even the implied warranty of
023:         * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
024:         * Lesser General Public License for more details.
025:         * 
026:         * You should have received a copy of the GNU Lesser General Public
027:         * License along with this library; if not, write to the Free Software
028:         * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
029:         * A copy of the GNU LGPL may be found at
030:         * http://www.gnu.org/copyleft/lesser.html,
031:         *
032:         * @author J. David Eisenberg
033:         * @version 1.4, 31 March 2000
034:         */
035:
036:        import java.awt.*;
037:        import java.awt.image.ImageObserver;
038:        import java.awt.image.PixelGrabber;
039:        import java.io.ByteArrayOutputStream;
040:        import java.io.IOException;
041:        import java.util.zip.CRC32;
042:        import java.util.zip.Deflater;
043:        import java.util.zip.DeflaterOutputStream;
044:
045:        public class PngEncoder extends Object {
046:            /**
047:             * Constant specifying that alpha channel should be encoded.
048:             */
049:            public static final boolean ENCODE_ALPHA = true;
050:            /**
051:             * Constant specifying that alpha channel should not be encoded.
052:             */
053:            public static final boolean NO_ALPHA = false;
054:            /**
055:             * Constants for filters
056:             */
057:            public static final int FILTER_NONE = 0;
058:            public static final int FILTER_SUB = 1;
059:            public static final int FILTER_UP = 2;
060:            public static final int FILTER_LAST = 2;
061:
062:            protected byte[] pngBytes;
063:            protected byte[] priorRow;
064:            protected byte[] leftBytes;
065:            protected Image image;
066:            protected int width, height;
067:            protected int bytePos, maxPos;
068:            protected int hdrPos, dataPos, endPos;
069:            protected CRC32 crc = new CRC32();
070:            protected long crcValue;
071:            protected boolean encodeAlpha;
072:            protected int filter;
073:            protected int bytesPerPixel;
074:            protected int compressionLevel;
075:
076:            /**
077:             * Class constructor
078:             */
079:            public PngEncoder() {
080:                this (null, false, FILTER_NONE, 0);
081:            }
082:
083:            /**
084:             * Class constructor specifying Image to encode, with no alpha channel encoding.
085:             *
086:             * @param image A Java Image object which uses the DirectColorModel
087:             * @see java.awt.Image
088:             */
089:            public PngEncoder(Image image) {
090:                this (image, false, FILTER_NONE, 0);
091:            }
092:
093:            /**
094:             * Class constructor specifying Image to encode, and whether to encode alpha.
095:             *
096:             * @param image       A Java Image object which uses the DirectColorModel
097:             * @param encodeAlpha Encode the alpha channel? false=no; true=yes
098:             * @see java.awt.Image
099:             */
100:            public PngEncoder(Image image, boolean encodeAlpha) {
101:                this (image, encodeAlpha, FILTER_NONE, 0);
102:            }
103:
104:            /**
105:             * Class constructor specifying Image to encode, whether to encode alpha, and filter to use.
106:             *
107:             * @param image       A Java Image object which uses the DirectColorModel
108:             * @param encodeAlpha Encode the alpha channel? false=no; true=yes
109:             * @param whichFilter 0=none, 1=sub, 2=up
110:             * @see java.awt.Image
111:             */
112:            public PngEncoder(Image image, boolean encodeAlpha, int whichFilter) {
113:                this (image, encodeAlpha, whichFilter, 0);
114:            }
115:
116:            /**
117:             * Class constructor specifying Image source to encode, whether to encode alpha, filter to use, and compression level.
118:             *
119:             * @param image       A Java Image object
120:             * @param encodeAlpha Encode the alpha channel? false=no; true=yes
121:             * @param whichFilter 0=none, 1=sub, 2=up
122:             * @param compLevel   0..9
123:             * @see java.awt.Image
124:             */
125:            public PngEncoder(Image image, boolean encodeAlpha,
126:                    int whichFilter, int compLevel) {
127:                this .image = image;
128:                this .encodeAlpha = encodeAlpha;
129:                setFilter(whichFilter);
130:                if (compLevel >= 0 && compLevel <= 9) {
131:                    this .compressionLevel = compLevel;
132:                }
133:            }
134:
135:            /**
136:             * Set the image to be encoded
137:             *
138:             * @param image A Java Image object which uses the DirectColorModel
139:             * @see java.awt.Image
140:             * @see java.awt.image.DirectColorModel
141:             */
142:            public void setImage(Image image) {
143:                this .image = image;
144:                pngBytes = null;
145:            }
146:
147:            /**
148:             * Creates an array of bytes that is the PNG equivalent of the current image, specifying whether to encode alpha or not.
149:             *
150:             * @param encodeAlpha boolean false=no alpha, true=encode alpha
151:             * @return an array of bytes, or null if there was a problem
152:             */
153:            public byte[] pngEncode(boolean encodeAlpha) {
154:                byte[] pngIdBytes = { -119, 80, 78, 71, 13, 10, 26, 10 };
155:                int i;
156:
157:                if (image == null) {
158:                    return null;
159:                }
160:                width = image.getWidth(null);
161:                height = image.getHeight(null);
162:                //        this.image = image;
163:
164:                /*
165:                 * start with an array that is big enough to hold all the pixels
166:                 * (plus filter bytes), and an extra 200 bytes for header info
167:                 */
168:                pngBytes = new byte[((width + 1) * height * 3) + 200];
169:
170:                /*
171:                 * keep track of largest byte written to the array
172:                 */
173:                maxPos = 0;
174:
175:                bytePos = writeBytes(pngIdBytes, 0);
176:                hdrPos = bytePos;
177:                writeHeader();
178:                dataPos = bytePos;
179:                if (writeImageData()) {
180:                    writeEnd();
181:                    pngBytes = resizeByteArray(pngBytes, maxPos);
182:                } else {
183:                    pngBytes = null;
184:                }
185:                return pngBytes;
186:            }
187:
188:            /**
189:             * Creates an array of bytes that is the PNG equivalent of the current image.
190:             * Alpha encoding is determined by its setting in the constructor.
191:             *
192:             * @return an array of bytes, or null if there was a problem
193:             */
194:            public byte[] pngEncode() {
195:                return pngEncode(encodeAlpha);
196:            }
197:
198:            /**
199:             * Set the alpha encoding on or off.
200:             *
201:             * @param encodeAlpha false=no, true=yes
202:             */
203:            public void setEncodeAlpha(boolean encodeAlpha) {
204:                this .encodeAlpha = encodeAlpha;
205:            }
206:
207:            /**
208:             * Retrieve alpha encoding status.
209:             *
210:             * @return boolean false=no, true=yes
211:             */
212:            public boolean getEncodeAlpha() {
213:                return encodeAlpha;
214:            }
215:
216:            /**
217:             * Set the filter to use
218:             *
219:             * @param whichFilter from constant list
220:             */
221:            public void setFilter(int whichFilter) {
222:                this .filter = FILTER_NONE;
223:                if (whichFilter <= FILTER_LAST) {
224:                    this .filter = whichFilter;
225:                }
226:            }
227:
228:            /**
229:             * Retrieve filtering scheme
230:             *
231:             * @return int (see constant list)
232:             */
233:            public int getFilter() {
234:                return filter;
235:            }
236:
237:            /**
238:             * Set the compression level to use
239:             *
240:             * @param level 0 through 9
241:             */
242:            public void setCompressionLevel(int level) {
243:                if (level >= 0 && level <= 9) {
244:                    this .compressionLevel = level;
245:                }
246:            }
247:
248:            /**
249:             * Retrieve compression level
250:             *
251:             * @return int in range 0-9
252:             */
253:            public int getCompressionLevel() {
254:                return compressionLevel;
255:            }
256:
257:            /**
258:             * Increase or decrease the length of a byte array.
259:             *
260:             * @param array     The original array.
261:             * @param newLength The length you wish the new array to have.
262:             * @return Array of newly desired length. If shorter than the
263:             *         original, the trailing elements are truncated.
264:             */
265:            protected byte[] resizeByteArray(byte[] array, int newLength) {
266:                byte[] newArray = new byte[newLength];
267:                int oldLength = array.length;
268:
269:                System.arraycopy(array, 0, newArray, 0, Math.min(oldLength,
270:                        newLength));
271:                return newArray;
272:            }
273:
274:            /**
275:             * Write an array of bytes into the pngBytes array.
276:             * Note: This routine has the side effect of updating
277:             * maxPos, the largest element written in the array.
278:             * The array is resized by 1000 bytes or the length
279:             * of the data to be written, whichever is larger.
280:             *
281:             * @param data   The data to be written into pngBytes.
282:             * @param offset The starting point to write to.
283:             * @return The next place to be written to in the pngBytes array.
284:             */
285:            protected int writeBytes(byte[] data, int offset) {
286:                maxPos = Math.max(maxPos, offset + data.length);
287:                if (data.length + offset > pngBytes.length) {
288:                    pngBytes = resizeByteArray(pngBytes, pngBytes.length
289:                            + Math.max(1000, data.length));
290:                }
291:                System.arraycopy(data, 0, pngBytes, offset, data.length);
292:                return offset + data.length;
293:            }
294:
295:            /**
296:             * Write an array of bytes into the pngBytes array, specifying number of bytes to write.
297:             * Note: This routine has the side effect of updating
298:             * maxPos, the largest element written in the array.
299:             * The array is resized by 1000 bytes or the length
300:             * of the data to be written, whichever is larger.
301:             *
302:             * @param data   The data to be written into pngBytes.
303:             * @param nBytes The number of bytes to be written.
304:             * @param offset The starting point to write to.
305:             * @return The next place to be written to in the pngBytes array.
306:             */
307:            protected int writeBytes(byte[] data, int nBytes, int offset) {
308:                maxPos = Math.max(maxPos, offset + nBytes);
309:                if (nBytes + offset > pngBytes.length) {
310:                    pngBytes = resizeByteArray(pngBytes, pngBytes.length
311:                            + Math.max(1000, nBytes));
312:                }
313:                System.arraycopy(data, 0, pngBytes, offset, nBytes);
314:                return offset + nBytes;
315:            }
316:
317:            /**
318:             * Write a two-byte integer into the pngBytes array at a given position.
319:             *
320:             * @param n      The integer to be written into pngBytes.
321:             * @param offset The starting point to write to.
322:             * @return The next place to be written to in the pngBytes array.
323:             */
324:            protected int writeInt2(int n, int offset) {
325:                byte[] temp = { (byte) ((n >> 8) & 0xff), (byte) (n & 0xff) };
326:                return writeBytes(temp, offset);
327:            }
328:
329:            /**
330:             * Write a four-byte integer into the pngBytes array at a given position.
331:             *
332:             * @param n      The integer to be written into pngBytes.
333:             * @param offset The starting point to write to.
334:             * @return The next place to be written to in the pngBytes array.
335:             */
336:            protected int writeInt4(int n, int offset) {
337:                byte[] temp = { (byte) ((n >> 24) & 0xff),
338:                        (byte) ((n >> 16) & 0xff), (byte) ((n >> 8) & 0xff),
339:                        (byte) (n & 0xff) };
340:                return writeBytes(temp, offset);
341:            }
342:
343:            /**
344:             * Write a single byte into the pngBytes array at a given position.
345:             *
346:             * @param b      The integer to be written into pngBytes.
347:             * @param offset The starting point to write to.
348:             * @return The next place to be written to in the pngBytes array.
349:             */
350:            protected int writeByte(int b, int offset) {
351:                byte[] temp = { (byte) b };
352:                return writeBytes(temp, offset);
353:            }
354:
355:            /**
356:             * Write a string into the pngBytes array at a given position.
357:             * This uses the getBytes method, so the encoding used will
358:             * be its default.
359:             *
360:             * @param s      The string to be written into pngBytes.
361:             * @param offset The starting point to write to.
362:             * @return The next place to be written to in the pngBytes array.
363:             * @see java.lang.String#getBytes()
364:             */
365:            protected int writeString(String s, int offset) {
366:                return writeBytes(s.getBytes(), offset);
367:            }
368:
369:            /**
370:             * Write a PNG "IHDR" chunk into the pngBytes array.
371:             */
372:            protected void writeHeader() {
373:                int startPos;
374:
375:                startPos = bytePos = writeInt4(13, bytePos);
376:                bytePos = writeString("IHDR", bytePos);
377:                width = image.getWidth(null);
378:                height = image.getHeight(null);
379:                bytePos = writeInt4(width, bytePos);
380:                bytePos = writeInt4(height, bytePos);
381:                bytePos = writeByte(8, bytePos); // bit depth
382:                bytePos = writeByte((encodeAlpha) ? 6 : 2, bytePos); // direct model
383:                bytePos = writeByte(0, bytePos); // compression method
384:                bytePos = writeByte(0, bytePos); // filter method
385:                bytePos = writeByte(0, bytePos); // no interlace
386:                crc.reset();
387:                crc.update(pngBytes, startPos, bytePos - startPos);
388:                crcValue = crc.getValue();
389:                bytePos = writeInt4((int) crcValue, bytePos);
390:            }
391:
392:            /**
393:             * Perform "sub" filtering on the given row.
394:             * Uses temporary array leftBytes to store the original values
395:             * of the previous pixels.  The array is 16 bytes long, which
396:             * will easily hold two-byte samples plus two-byte alpha.
397:             *
398:             * @param pixels   The array holding the scan lines being built
399:             * @param startPos Starting position within pixels of bytes to be filtered.
400:             * @param width    Width of a scanline in pixels.
401:             */
402:            protected void filterSub(byte[] pixels, int startPos, int width) {
403:                int i;
404:                int offset = bytesPerPixel;
405:                int actualStart = startPos + offset;
406:                int nBytes = width * bytesPerPixel;
407:                int leftInsert = offset;
408:                int leftExtract = 0;
409:                byte current_byte;
410:
411:                for (i = actualStart; i < startPos + nBytes; i++) {
412:                    leftBytes[leftInsert] = pixels[i];
413:                    pixels[i] = (byte) ((pixels[i] - leftBytes[leftExtract]) % 256);
414:                    leftInsert = (leftInsert + 1) % 0x0f;
415:                    leftExtract = (leftExtract + 1) % 0x0f;
416:                }
417:            }
418:
419:            /**
420:             * Perform "up" filtering on the given row.
421:             * Side effect: refills the prior row with current row
422:             *
423:             * @param pixels   The array holding the scan lines being built
424:             * @param startPos Starting position within pixels of bytes to be filtered.
425:             * @param width    Width of a scanline in pixels.
426:             */
427:            protected void filterUp(byte[] pixels, int startPos, int width) {
428:                int i, nBytes;
429:                byte current_byte;
430:
431:                nBytes = width * bytesPerPixel;
432:
433:                for (i = 0; i < nBytes; i++) {
434:                    current_byte = pixels[startPos + i];
435:                    pixels[startPos + i] = (byte) ((pixels[startPos + i] - priorRow[i]) % 256);
436:                    priorRow[i] = current_byte;
437:                }
438:            }
439:
440:            /**
441:             * Write the image data into the pngBytes array.
442:             * This will write one or more PNG "IDAT" chunks. In order
443:             * to conserve memory, this method grabs as many rows as will
444:             * fit into 32K bytes, or the whole image; whichever is less.
445:             *
446:             * @return true if no errors; false if error grabbing pixels
447:             */
448:            protected boolean writeImageData() {
449:                int rowsLeft = height; // number of rows remaining to write
450:                int startRow = 0; // starting row to process this time through
451:                int nRows; // how many rows to grab at a time
452:
453:                byte[] scanLines; // the scan lines to be compressed
454:                int scanPos; // where we are in the scan lines
455:                int startPos; // where this line's actual pixels start (used for filtering)
456:
457:                byte[] compressedLines; // the resultant compressed lines
458:                int nCompressed; // how big is the compressed area?
459:
460:                int depth; // color depth ( handle only 8 or 32 )
461:
462:                PixelGrabber pg;
463:
464:                bytesPerPixel = (encodeAlpha) ? 4 : 3;
465:
466:                Deflater scrunch = new Deflater(compressionLevel);
467:                ByteArrayOutputStream outBytes = new ByteArrayOutputStream(1024);
468:
469:                DeflaterOutputStream compBytes = new DeflaterOutputStream(
470:                        outBytes, scrunch);
471:                try {
472:                    while (rowsLeft > 0) {
473:                        nRows = Math.min(32767 / (width * (bytesPerPixel + 1)),
474:                                rowsLeft);
475:                        // nRows = rowsLeft;
476:
477:                        int[] pixels = new int[width * nRows];
478:
479:                        pg = new PixelGrabber(image, 0, startRow, width, nRows,
480:                                pixels, 0, width);
481:                        try {
482:                            pg.grabPixels();
483:                        } catch (Exception e) {
484:                            System.err
485:                                    .println("interrupted waiting for pixels!");
486:                            return false;
487:                        }
488:                        if ((pg.getStatus() & ImageObserver.ABORT) != 0) {
489:                            System.err
490:                                    .println("image fetch aborted or errored");
491:                            return false;
492:                        }
493:
494:                        /*
495:                         * Create a data chunk. scanLines adds "nRows" for
496:                         * the filter bytes. 
497:                         */
498:                        scanLines = new byte[width * nRows * bytesPerPixel
499:                                + nRows];
500:
501:                        if (filter == FILTER_SUB) {
502:                            leftBytes = new byte[16];
503:                        }
504:                        if (filter == FILTER_UP) {
505:                            priorRow = new byte[width * bytesPerPixel];
506:                        }
507:
508:                        scanPos = 0;
509:                        startPos = 1;
510:                        for (int i = 0; i < width * nRows; i++) {
511:                            if (i % width == 0) {
512:                                scanLines[scanPos++] = (byte) filter;
513:                                startPos = scanPos;
514:                            }
515:                            scanLines[scanPos++] = (byte) ((pixels[i] >> 16) & 0xff);
516:                            scanLines[scanPos++] = (byte) ((pixels[i] >> 8) & 0xff);
517:                            scanLines[scanPos++] = (byte) ((pixels[i]) & 0xff);
518:                            if (encodeAlpha) {
519:                                scanLines[scanPos++] = (byte) ((pixels[i] >> 24) & 0xff);
520:                            }
521:                            if ((i % width == width - 1)
522:                                    && (filter != FILTER_NONE)) {
523:                                if (filter == FILTER_SUB) {
524:                                    filterSub(scanLines, startPos, width);
525:                                }
526:                                if (filter == FILTER_UP) {
527:                                    filterUp(scanLines, startPos, width);
528:                                }
529:                            }
530:                        }
531:
532:                        /*
533:                         * Write these lines to the output area
534:                         */
535:                        compBytes.write(scanLines, 0, scanPos);
536:
537:                        startRow += nRows;
538:                        rowsLeft -= nRows;
539:                    }
540:                    compBytes.close();
541:
542:                    /*
543:                     * Write the compressed bytes
544:                     */
545:                    compressedLines = outBytes.toByteArray();
546:                    nCompressed = compressedLines.length;
547:
548:                    crc.reset();
549:                    bytePos = writeInt4(nCompressed, bytePos);
550:                    bytePos = writeString("IDAT", bytePos);
551:                    crc.update("IDAT".getBytes());
552:                    bytePos = writeBytes(compressedLines, nCompressed, bytePos);
553:                    crc.update(compressedLines, 0, nCompressed);
554:
555:                    crcValue = crc.getValue();
556:                    bytePos = writeInt4((int) crcValue, bytePos);
557:                    scrunch.finish();
558:                    return true;
559:                } catch (IOException e) {
560:                    System.err.println(e.toString());
561:                    return false;
562:                }
563:            }
564:
565:            /**
566:             * Write a PNG "IEND" chunk into the pngBytes array.
567:             */
568:            protected void writeEnd() {
569:                bytePos = writeInt4(0, bytePos);
570:                bytePos = writeString("IEND", bytePos);
571:                crc.reset();
572:                crc.update("IEND".getBytes());
573:                crcValue = crc.getValue();
574:                bytePos = writeInt4((int) crcValue, bytePos);
575:            }
576:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.