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

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


0001:        /*
0002:         * $RCSfile: BMPImageWriter.java,v $
0003:         *
0004:         * 
0005:         * Copyright (c) 2005 Sun Microsystems, Inc. All  Rights Reserved.
0006:         * 
0007:         * Redistribution and use in source and binary forms, with or without
0008:         * modification, are permitted provided that the following conditions
0009:         * are met: 
0010:         * 
0011:         * - Redistribution of source code must retain the above copyright 
0012:         *   notice, this  list of conditions and the following disclaimer.
0013:         * 
0014:         * - Redistribution in binary form must reproduce the above copyright
0015:         *   notice, this list of conditions and the following disclaimer in 
0016:         *   the documentation and/or other materials provided with the
0017:         *   distribution.
0018:         * 
0019:         * Neither the name of Sun Microsystems, Inc. or the names of 
0020:         * contributors may be used to endorse or promote products derived 
0021:         * from this software without specific prior written permission.
0022:         * 
0023:         * This software is provided "AS IS," without a warranty of any 
0024:         * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND 
0025:         * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, 
0026:         * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
0027:         * EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL 
0028:         * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF 
0029:         * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
0030:         * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR 
0031:         * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
0032:         * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
0033:         * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
0034:         * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
0035:         * POSSIBILITY OF SUCH DAMAGES. 
0036:         * 
0037:         * You acknowledge that this software is not designed or intended for 
0038:         * use in the design, construction, operation or maintenance of any 
0039:         * nuclear facility. 
0040:         *
0041:         * $Revision: 1.2 $
0042:         * $Date: 2006/04/14 21:29:14 $
0043:         * $State: Exp $
0044:         */
0045:        package com.sun.media.imageioimpl.plugins.bmp;
0046:
0047:        import java.awt.Point;
0048:        import java.awt.Rectangle;
0049:        import java.awt.image.ColorModel;
0050:        import java.awt.image.ComponentSampleModel;
0051:        import java.awt.image.DataBuffer;
0052:        import java.awt.image.DataBufferByte;
0053:        import java.awt.image.DataBufferInt;
0054:        import java.awt.image.DataBufferShort;
0055:        import java.awt.image.DataBufferUShort;
0056:        import java.awt.image.DirectColorModel;
0057:        import java.awt.image.IndexColorModel;
0058:        import java.awt.image.MultiPixelPackedSampleModel;
0059:        import java.awt.image.BandedSampleModel;
0060:        import java.awt.image.Raster;
0061:        import java.awt.image.RenderedImage;
0062:        import java.awt.image.SampleModel;
0063:        import java.awt.image.SinglePixelPackedSampleModel;
0064:        import java.awt.image.WritableRaster;
0065:        import java.awt.image.BufferedImage;
0066:
0067:        import java.io.IOException;
0068:        import java.io.ByteArrayOutputStream;
0069:        import java.nio.ByteOrder;
0070:        import java.util.Iterator;
0071:
0072:        import javax.imageio.IIOImage;
0073:        import javax.imageio.IIOException;
0074:        import javax.imageio.ImageIO;
0075:        import javax.imageio.ImageTypeSpecifier;
0076:        import javax.imageio.ImageWriteParam;
0077:        import javax.imageio.ImageWriter;
0078:        import javax.imageio.metadata.IIOMetadata;
0079:        import javax.imageio.metadata.IIOMetadataNode;
0080:        import javax.imageio.metadata.IIOMetadataFormatImpl;
0081:        import javax.imageio.metadata.IIOInvalidTreeException;
0082:        import javax.imageio.spi.ImageWriterSpi;
0083:        import javax.imageio.stream.ImageOutputStream;
0084:        import javax.imageio.event.IIOWriteProgressListener;
0085:        import javax.imageio.event.IIOWriteWarningListener;
0086:
0087:        import org.w3c.dom.Node;
0088:        import org.w3c.dom.NodeList;
0089:
0090:        import com.sun.media.imageio.plugins.bmp.BMPImageWriteParam;
0091:        import com.sun.media.imageioimpl.common.ImageUtil;
0092:
0093:        /**
0094:         * The Java Image IO plugin writer for encoding a binary RenderedImage into
0095:         * a BMP format.
0096:         *
0097:         * The encoding process may clip, subsample using the parameters
0098:         * specified in the <code>ImageWriteParam</code>.
0099:         *
0100:         * @see com.sun.media.imageio.plugins.bmp.BMPImageWriteParam
0101:         */
0102:        public class BMPImageWriter extends ImageWriter implements  BMPConstants {
0103:            /** The output stream to write into */
0104:            private ImageOutputStream stream = null;
0105:            private ByteArrayOutputStream embedded_stream = null;
0106:            private int compressionType;
0107:            private boolean isTopDown;
0108:            private int w, h;
0109:            private int compImageSize = 0;
0110:            private int[] bitMasks;
0111:            private int[] bitPos;
0112:            private byte[] bpixels;
0113:            private short[] spixels;
0114:            private int[] ipixels;
0115:
0116:            /** Constructs <code>BMPImageWriter</code> based on the provided
0117:             *  <code>ImageWriterSpi</code>.
0118:             */
0119:            public BMPImageWriter(ImageWriterSpi originator) {
0120:                super (originator);
0121:            }
0122:
0123:            public void setOutput(Object output) {
0124:                super .setOutput(output); // validates output
0125:                if (output != null) {
0126:                    if (!(output instanceof  ImageOutputStream))
0127:                        throw new IllegalArgumentException(I18N
0128:                                .getString("BMPImageWriter0"));
0129:                    this .stream = (ImageOutputStream) output;
0130:                    stream.setByteOrder(ByteOrder.LITTLE_ENDIAN);
0131:                } else
0132:                    this .stream = null;
0133:            }
0134:
0135:            public ImageWriteParam getDefaultWriteParam() {
0136:                return new BMPImageWriteParam();
0137:            }
0138:
0139:            public IIOMetadata getDefaultStreamMetadata(ImageWriteParam param) {
0140:                return null;
0141:            }
0142:
0143:            public IIOMetadata getDefaultImageMetadata(
0144:                    ImageTypeSpecifier imageType, ImageWriteParam param) {
0145:                BMPMetadata meta = new BMPMetadata();
0146:                meta.initialize(imageType.getColorModel(), imageType
0147:                        .getSampleModel(), param);
0148:                return meta;
0149:            }
0150:
0151:            public IIOMetadata convertStreamMetadata(IIOMetadata inData,
0152:                    ImageWriteParam param) {
0153:                return null;
0154:            }
0155:
0156:            public IIOMetadata convertImageMetadata(IIOMetadata inData,
0157:                    ImageTypeSpecifier imageType, ImageWriteParam param) {
0158:
0159:                // Check arguments.
0160:                if (inData == null) {
0161:                    throw new IllegalArgumentException("inData == null!");
0162:                }
0163:                if (imageType == null) {
0164:                    throw new IllegalArgumentException("imageType == null!");
0165:                }
0166:
0167:                BMPMetadata outData = null;
0168:
0169:                // Obtain a BMPMetadata object.
0170:                if (inData instanceof  BMPMetadata) {
0171:                    // Clone the input metadata.
0172:                    outData = (BMPMetadata) ((BMPMetadata) inData).clone();
0173:                } else {
0174:                    try {
0175:                        outData = new BMPMetadata(inData);
0176:                    } catch (IIOInvalidTreeException e) {
0177:                        // XXX Warning
0178:                        outData = new BMPMetadata();
0179:                    }
0180:                }
0181:
0182:                // Update the metadata per the image type and param.
0183:                outData.initialize(imageType.getColorModel(), imageType
0184:                        .getSampleModel(), param);
0185:
0186:                return outData;
0187:            }
0188:
0189:            public boolean canWriteRasters() {
0190:                return true;
0191:            }
0192:
0193:            public void write(IIOMetadata streamMetadata, IIOImage image,
0194:                    ImageWriteParam param) throws IOException {
0195:
0196:                if (stream == null) {
0197:                    throw new IllegalStateException(I18N
0198:                            .getString("BMPImageWriter7"));
0199:                }
0200:
0201:                if (image == null) {
0202:                    throw new IllegalArgumentException(I18N
0203:                            .getString("BMPImageWriter8"));
0204:                }
0205:
0206:                clearAbortRequest();
0207:                processImageStarted(0);
0208:                if (param == null)
0209:                    param = getDefaultWriteParam();
0210:
0211:                BMPImageWriteParam bmpParam = (BMPImageWriteParam) param;
0212:
0213:                // Default is using 24 bits per pixel.
0214:                int bitsPerPixel = 24;
0215:                boolean isPalette = false;
0216:                int paletteEntries = 0;
0217:                IndexColorModel icm = null;
0218:
0219:                RenderedImage input = null;
0220:                Raster inputRaster = null;
0221:                boolean writeRaster = image.hasRaster();
0222:                Rectangle sourceRegion = param.getSourceRegion();
0223:                SampleModel sampleModel = null;
0224:                ColorModel colorModel = null;
0225:
0226:                compImageSize = 0;
0227:
0228:                if (writeRaster) {
0229:                    inputRaster = image.getRaster();
0230:                    sampleModel = inputRaster.getSampleModel();
0231:                    colorModel = ImageUtil.createColorModel(null, sampleModel);
0232:                    if (sourceRegion == null)
0233:                        sourceRegion = inputRaster.getBounds();
0234:                    else
0235:                        sourceRegion = sourceRegion.intersection(inputRaster
0236:                                .getBounds());
0237:                } else {
0238:                    input = image.getRenderedImage();
0239:                    sampleModel = input.getSampleModel();
0240:                    colorModel = input.getColorModel();
0241:                    Rectangle rect = new Rectangle(input.getMinX(), input
0242:                            .getMinY(), input.getWidth(), input.getHeight());
0243:                    if (sourceRegion == null)
0244:                        sourceRegion = rect;
0245:                    else
0246:                        sourceRegion = sourceRegion.intersection(rect);
0247:                }
0248:
0249:                IIOMetadata imageMetadata = image.getMetadata();
0250:                BMPMetadata bmpImageMetadata = null;
0251:                ImageTypeSpecifier imageType = new ImageTypeSpecifier(
0252:                        colorModel, sampleModel);
0253:                if (imageMetadata != null) {
0254:                    // Convert metadata.
0255:                    bmpImageMetadata = (BMPMetadata) convertImageMetadata(
0256:                            imageMetadata, imageType, param);
0257:                } else {
0258:                    // Use default.
0259:                    bmpImageMetadata = (BMPMetadata) getDefaultImageMetadata(
0260:                            imageType, param);
0261:                }
0262:
0263:                if (sourceRegion.isEmpty())
0264:                    throw new RuntimeException(I18N.getString("BMPImageWrite0"));
0265:
0266:                int scaleX = param.getSourceXSubsampling();
0267:                int scaleY = param.getSourceYSubsampling();
0268:                int xOffset = param.getSubsamplingXOffset();
0269:                int yOffset = param.getSubsamplingYOffset();
0270:
0271:                // cache the data type;
0272:                int dataType = sampleModel.getDataType();
0273:
0274:                sourceRegion.translate(xOffset, yOffset);
0275:                sourceRegion.width -= xOffset;
0276:                sourceRegion.height -= yOffset;
0277:
0278:                int minX = sourceRegion.x / scaleX;
0279:                int minY = sourceRegion.y / scaleY;
0280:                w = (sourceRegion.width + scaleX - 1) / scaleX;
0281:                h = (sourceRegion.height + scaleY - 1) / scaleY;
0282:                xOffset = sourceRegion.x % scaleX;
0283:                yOffset = sourceRegion.y % scaleY;
0284:
0285:                Rectangle destinationRegion = new Rectangle(minX, minY, w, h);
0286:                boolean noTransform = destinationRegion.equals(sourceRegion);
0287:
0288:                // Raw data can only handle bytes, everything greater must be ASCII.
0289:                int[] sourceBands = param.getSourceBands();
0290:                boolean noSubband = true;
0291:                int numBands = sampleModel.getNumBands();
0292:
0293:                if (sourceBands != null) {
0294:                    sampleModel = sampleModel
0295:                            .createSubsetSampleModel(sourceBands);
0296:                    colorModel = null;
0297:                    noSubband = false;
0298:                    numBands = sampleModel.getNumBands();
0299:                } else {
0300:                    sourceBands = new int[numBands];
0301:                    for (int i = 0; i < numBands; i++)
0302:                        sourceBands[i] = i;
0303:                }
0304:
0305:                int[] bandOffsets = null;
0306:                boolean bgrOrder = true;
0307:
0308:                if (sampleModel instanceof  ComponentSampleModel) {
0309:                    bandOffsets = ((ComponentSampleModel) sampleModel)
0310:                            .getBandOffsets();
0311:                    if (sampleModel instanceof  BandedSampleModel) {
0312:                        // for images with BandedSampleModel we can not work 
0313:                        //  with raster directly and must use writePixels()
0314:                        bgrOrder = false;
0315:                    } else {
0316:                        // we can work with raster directly only in case of 
0317:                        // BGR component order.
0318:                        // In any other case we must use writePixels() 
0319:                        for (int i = 0; i < bandOffsets.length; i++) {
0320:                            bgrOrder &= (bandOffsets[i] == (bandOffsets.length
0321:                                    - i - 1));
0322:                        }
0323:                    }
0324:                } else {
0325:                    if (sampleModel instanceof  SinglePixelPackedSampleModel) {
0326:
0327:                        // BugId 4892214: we can not work with raster directly
0328:                        // if image have different color order than RGB.
0329:                        // We should use writePixels() for such images.
0330:                        int[] bitOffsets = ((SinglePixelPackedSampleModel) sampleModel)
0331:                                .getBitOffsets();
0332:                        for (int i = 0; i < bitOffsets.length - 1; i++) {
0333:                            bgrOrder &= bitOffsets[i] > bitOffsets[i + 1];
0334:                        }
0335:                    }
0336:                }
0337:
0338:                if (bandOffsets == null) {
0339:                    // we will use getPixels() to extract pixel data for writePixels()
0340:                    // Please note that getPixels() provides rgb bands order.
0341:                    bandOffsets = new int[numBands];
0342:                    for (int i = 0; i < numBands; i++)
0343:                        bandOffsets[i] = i;
0344:                }
0345:
0346:                noTransform &= bgrOrder;
0347:
0348:                int sampleSize[] = sampleModel.getSampleSize();
0349:
0350:                //XXX: check more
0351:
0352:                // Number of bytes that a scanline for the image written out will have.
0353:                int destScanlineBytes = w * numBands;
0354:
0355:                switch (bmpParam.getCompressionMode()) {
0356:                case ImageWriteParam.MODE_EXPLICIT:
0357:                    compressionType = getCompressionType(bmpParam
0358:                            .getCompressionType());
0359:                    break;
0360:                case ImageWriteParam.MODE_COPY_FROM_METADATA:
0361:                    compressionType = bmpImageMetadata.compression;
0362:                    break;
0363:                case ImageWriteParam.MODE_DEFAULT:
0364:                    compressionType = getPreferredCompressionType(colorModel,
0365:                            sampleModel);
0366:                    break;
0367:                default:
0368:                    // ImageWriteParam.MODE_DISABLED:
0369:                    compressionType = BI_RGB;
0370:                }
0371:
0372:                if (!canEncodeImage(compressionType, colorModel, sampleModel)) {
0373:                    if (param.getCompressionMode() == ImageWriteParam.MODE_EXPLICIT) {
0374:                        throw new IIOException("Image can not be encoded with "
0375:                                + "compression type "
0376:                                + compressionTypeNames[compressionType]);
0377:                    } else {
0378:                        // Set to something appropriate
0379:                        compressionType = getPreferredCompressionType(
0380:                                colorModel, sampleModel);
0381:                    }
0382:                }
0383:
0384:                byte r[] = null, g[] = null, b[] = null, a[] = null;
0385:
0386:                if (compressionType == BMPConstants.BI_BITFIELDS) {
0387:                    bitsPerPixel = DataBuffer.getDataTypeSize(sampleModel
0388:                            .getDataType());
0389:
0390:                    if (bitsPerPixel != 16 && bitsPerPixel != 32) {
0391:                        // we should use 32bpp images in case of BI_BITFIELD
0392:                        // compression to avoid color conversion artefacts
0393:                        bitsPerPixel = 32;
0394:
0395:                        // Setting this flag to false ensures that generic
0396:                        // writePixels() will be used to store image data
0397:                        noTransform = false;
0398:                    }
0399:
0400:                    destScanlineBytes = w * bitsPerPixel + 7 >> 3;
0401:
0402:                    isPalette = true;
0403:                    paletteEntries = 3;
0404:                    r = new byte[paletteEntries];
0405:                    g = new byte[paletteEntries];
0406:                    b = new byte[paletteEntries];
0407:                    a = new byte[paletteEntries];
0408:
0409:                    int rmask = 0x00ff0000;
0410:                    int gmask = 0x0000ff00;
0411:                    int bmask = 0x000000ff;
0412:
0413:                    if (bitsPerPixel == 16) {
0414:                        /* NB: canEncodeImage() ensures we have image of
0415:                         * either USHORT_565_RGB or USHORT_555_RGB type here.
0416:                         * Technically, it should work for other direct color
0417:                         * model types but it might be non compatible with win98
0418:                         * and friends.
0419:                         */
0420:                        if (colorModel instanceof  DirectColorModel) {
0421:                            DirectColorModel dcm = (DirectColorModel) colorModel;
0422:                            rmask = dcm.getRedMask();
0423:                            gmask = dcm.getGreenMask();
0424:                            bmask = dcm.getBlueMask();
0425:                        } else {
0426:                            // it is unlikely, but if it happens, we should throw
0427:                            // an exception related to unsupported image format
0428:                            throw new IOException(
0429:                                    "Image can not be encoded with "
0430:                                            + "compression type "
0431:                                            + compressionTypeNames[compressionType]);
0432:                        }
0433:                    }
0434:                    writeMaskToPalette(rmask, 0, r, g, b, a);
0435:                    writeMaskToPalette(gmask, 1, r, g, b, a);
0436:                    writeMaskToPalette(bmask, 2, r, g, b, a);
0437:
0438:                    if (!noTransform) {
0439:                        // prepare info for writePixels procedure
0440:                        bitMasks = new int[3];
0441:                        bitMasks[0] = rmask;
0442:                        bitMasks[1] = gmask;
0443:                        bitMasks[2] = bmask;
0444:
0445:                        bitPos = new int[3];
0446:                        bitPos[0] = firstLowBit(rmask);
0447:                        bitPos[1] = firstLowBit(gmask);
0448:                        bitPos[2] = firstLowBit(bmask);
0449:                    }
0450:
0451:                    if (colorModel instanceof  IndexColorModel) {
0452:                        icm = (IndexColorModel) colorModel;
0453:                    }
0454:                } else { // handle BI_RGB compression
0455:                    if (colorModel instanceof  IndexColorModel) {
0456:                        isPalette = true;
0457:                        icm = (IndexColorModel) colorModel;
0458:                        paletteEntries = icm.getMapSize();
0459:
0460:                        if (paletteEntries <= 2) {
0461:                            bitsPerPixel = 1;
0462:                            destScanlineBytes = w + 7 >> 3;
0463:                        } else if (paletteEntries <= 16) {
0464:                            bitsPerPixel = 4;
0465:                            destScanlineBytes = w + 1 >> 1;
0466:                        } else if (paletteEntries <= 256) {
0467:                            bitsPerPixel = 8;
0468:                        } else {
0469:                            // Cannot be written as a Palette image. So write out as
0470:                            // 24 bit image.
0471:                            bitsPerPixel = 24;
0472:                            isPalette = false;
0473:                            paletteEntries = 0;
0474:                            destScanlineBytes = w * 3;
0475:                        }
0476:
0477:                        if (isPalette == true) {
0478:                            r = new byte[paletteEntries];
0479:                            g = new byte[paletteEntries];
0480:                            b = new byte[paletteEntries];
0481:
0482:                            icm.getReds(r);
0483:                            icm.getGreens(g);
0484:                            icm.getBlues(b);
0485:                        }
0486:
0487:                    } else {
0488:                        // Grey scale images
0489:                        if (numBands == 1) {
0490:
0491:                            isPalette = true;
0492:                            paletteEntries = 256;
0493:                            bitsPerPixel = sampleSize[0];
0494:
0495:                            destScanlineBytes = (w * bitsPerPixel + 7 >> 3);
0496:
0497:                            r = new byte[256];
0498:                            g = new byte[256];
0499:                            b = new byte[256];
0500:
0501:                            for (int i = 0; i < 256; i++) {
0502:                                r[i] = (byte) i;
0503:                                g[i] = (byte) i;
0504:                                b[i] = (byte) i;
0505:                            }
0506:
0507:                        } else {
0508:                            if (sampleModel instanceof  SinglePixelPackedSampleModel
0509:                                    && noSubband) {
0510:                                /* NB: the actual pixel size can be smaller than
0511:                                 * size of used DataBuffer element.
0512:                                 * For example: in case of TYPE_INT_RGB actual pixel
0513:                                 * size is 24 bits, but size of DataBuffere element
0514:                                 * is 32 bits
0515:                                 */
0516:                                int[] sample_sizes = sampleModel
0517:                                        .getSampleSize();
0518:                                bitsPerPixel = 0;
0519:                                for (int i = 0; i < sample_sizes.length; i++) {
0520:                                    bitsPerPixel += sample_sizes[i];
0521:                                }
0522:                                bitsPerPixel = roundBpp(bitsPerPixel);
0523:                                if (bitsPerPixel != DataBuffer
0524:                                        .getDataTypeSize(sampleModel
0525:                                                .getDataType())) {
0526:                                    noTransform = false;
0527:                                }
0528:                                destScanlineBytes = w * bitsPerPixel + 7 >> 3;
0529:                            }
0530:                        }
0531:                    }
0532:                }
0533:
0534:                // actual writing of image data
0535:                int fileSize = 0;
0536:                int offset = 0;
0537:                int headerSize = 0;
0538:                int imageSize = 0;
0539:                int xPelsPerMeter = bmpImageMetadata.xPixelsPerMeter;
0540:                int yPelsPerMeter = bmpImageMetadata.yPixelsPerMeter;
0541:                int colorsUsed = bmpImageMetadata.colorsUsed > 0 ? bmpImageMetadata.colorsUsed
0542:                        : paletteEntries;
0543:                int colorsImportant = paletteEntries;
0544:
0545:                // Calculate padding for each scanline
0546:                int padding = destScanlineBytes % 4;
0547:                if (padding != 0) {
0548:                    padding = 4 - padding;
0549:                }
0550:
0551:                // FileHeader is 14 bytes, BitmapHeader is 40 bytes,
0552:                // add palette size and that is where the data will begin
0553:                offset = 54 + paletteEntries * 4;
0554:
0555:                imageSize = (destScanlineBytes + padding) * h;
0556:                fileSize = imageSize + offset;
0557:                headerSize = 40;
0558:
0559:                long headPos = stream.getStreamPosition();
0560:
0561:                if (param instanceof  BMPImageWriteParam) {
0562:                    isTopDown = ((BMPImageWriteParam) param).isTopDown();
0563:                    // topDown = true is only allowed for RGB and BITFIELDS compression
0564:                    // types by the BMP specification
0565:                    if (compressionType != BI_RGB
0566:                            && compressionType != BI_BITFIELDS)
0567:                        isTopDown = false;
0568:                } else {
0569:                    isTopDown = false;
0570:                }
0571:
0572:                writeFileHeader(fileSize, offset);
0573:
0574:                writeInfoHeader(headerSize, bitsPerPixel);
0575:
0576:                // compression
0577:                stream.writeInt(compressionType);
0578:
0579:                // imageSize
0580:                stream.writeInt(imageSize);
0581:
0582:                // xPelsPerMeter
0583:                stream.writeInt(xPelsPerMeter);
0584:
0585:                // yPelsPerMeter
0586:                stream.writeInt(yPelsPerMeter);
0587:
0588:                // Colors Used
0589:                stream.writeInt(colorsUsed);
0590:
0591:                // Colors Important
0592:                stream.writeInt(colorsImportant);
0593:
0594:                // palette
0595:                if (isPalette == true) {
0596:
0597:                    // write palette
0598:                    if (compressionType == BMPConstants.BI_BITFIELDS) {
0599:                        // write masks for red, green and blue components.
0600:                        for (int i = 0; i < 3; i++) {
0601:                            int mask = (a[i] & 0xFF) + ((r[i] & 0xFF) * 0x100)
0602:                                    + ((g[i] & 0xFF) * 0x10000)
0603:                                    + ((b[i] & 0xFF) * 0x1000000);
0604:                            stream.writeInt(mask);
0605:                        }
0606:                    } else {
0607:                        for (int i = 0; i < paletteEntries; i++) {
0608:                            stream.writeByte(b[i]);
0609:                            stream.writeByte(g[i]);
0610:                            stream.writeByte(r[i]);
0611:                            stream.writeByte((byte) 0);// rgbReserved RGBQUAD entry
0612:                        }
0613:                    }
0614:                }
0615:
0616:                // Writing of actual image data
0617:                int scanlineBytes = w * numBands;
0618:
0619:                // Buffer for up to 8 rows of pixels
0620:                int[] pixels = new int[scanlineBytes * scaleX];
0621:
0622:                // Also create a buffer to hold one line of the data
0623:                // to be written to the file, so we can use array writes.
0624:                bpixels = new byte[destScanlineBytes];
0625:
0626:                int l;
0627:
0628:                if (compressionType == BMPConstants.BI_JPEG
0629:                        || compressionType == BMPConstants.BI_PNG) {
0630:                    // prepare embedded buffer
0631:                    embedded_stream = new ByteArrayOutputStream();
0632:                    writeEmbedded(image, bmpParam);
0633:                    // update the file/image Size
0634:                    embedded_stream.flush();
0635:                    imageSize = embedded_stream.size();
0636:
0637:                    long endPos = stream.getStreamPosition();
0638:                    fileSize = (int) (offset + imageSize);
0639:                    stream.seek(headPos);
0640:                    writeSize(fileSize, 2);
0641:                    stream.seek(headPos);
0642:                    writeSize(imageSize, 34);
0643:                    stream.seek(endPos);
0644:                    stream.write(embedded_stream.toByteArray());
0645:                    embedded_stream = null;
0646:
0647:                    if (abortRequested()) {
0648:                        processWriteAborted();
0649:                    } else {
0650:                        processImageComplete();
0651:                        stream.flushBefore(stream.getStreamPosition());
0652:                    }
0653:
0654:                    return;
0655:                }
0656:
0657:                int maxBandOffset = bandOffsets[0];
0658:                for (int i = 1; i < bandOffsets.length; i++)
0659:                    if (bandOffsets[i] > maxBandOffset)
0660:                        maxBandOffset = bandOffsets[i];
0661:
0662:                int[] pixel = new int[maxBandOffset + 1];
0663:
0664:                int destScanlineLength = destScanlineBytes;
0665:
0666:                if (noTransform && noSubband) {
0667:                    destScanlineLength = destScanlineBytes
0668:                            / (DataBuffer.getDataTypeSize(dataType) >> 3);
0669:                }
0670:                for (int i = 0; i < h; i++) {
0671:                    if (abortRequested()) {
0672:                        break;
0673:                    }
0674:
0675:                    int row = minY + i;
0676:
0677:                    if (!isTopDown)
0678:                        row = minY + h - i - 1;
0679:
0680:                    // Get the pixels
0681:                    Raster src = inputRaster;
0682:
0683:                    Rectangle srcRect = new Rectangle(minX * scaleX + xOffset,
0684:                            row * scaleY + yOffset, (w - 1) * scaleX + 1, 1);
0685:                    if (!writeRaster)
0686:                        src = input.getData(srcRect);
0687:
0688:                    if (noTransform && noSubband) {
0689:                        SampleModel sm = src.getSampleModel();
0690:                        int pos = 0;
0691:                        int startX = srcRect.x - src.getSampleModelTranslateX();
0692:                        int startY = srcRect.y - src.getSampleModelTranslateY();
0693:                        if (sm instanceof  ComponentSampleModel) {
0694:                            ComponentSampleModel csm = (ComponentSampleModel) sm;
0695:                            pos = csm.getOffset(startX, startY, 0);
0696:                            for (int nb = 1; nb < csm.getNumBands(); nb++) {
0697:                                if (pos > csm.getOffset(startX, startY, nb)) {
0698:                                    pos = csm.getOffset(startX, startY, nb);
0699:                                }
0700:                            }
0701:                        } else if (sm instanceof  MultiPixelPackedSampleModel) {
0702:                            MultiPixelPackedSampleModel mppsm = (MultiPixelPackedSampleModel) sm;
0703:                            pos = mppsm.getOffset(startX, startY);
0704:                        } else if (sm instanceof  SinglePixelPackedSampleModel) {
0705:                            SinglePixelPackedSampleModel sppsm = (SinglePixelPackedSampleModel) sm;
0706:                            pos = sppsm.getOffset(startX, startY);
0707:                        }
0708:
0709:                        if (compressionType == BMPConstants.BI_RGB
0710:                                || compressionType == BMPConstants.BI_BITFIELDS) {
0711:                            switch (dataType) {
0712:                            case DataBuffer.TYPE_BYTE:
0713:                                byte[] bdata = ((DataBufferByte) src
0714:                                        .getDataBuffer()).getData();
0715:                                stream.write(bdata, pos, destScanlineLength);
0716:                                break;
0717:
0718:                            case DataBuffer.TYPE_SHORT:
0719:                                short[] sdata = ((DataBufferShort) src
0720:                                        .getDataBuffer()).getData();
0721:                                stream.writeShorts(sdata, pos,
0722:                                        destScanlineLength);
0723:                                break;
0724:
0725:                            case DataBuffer.TYPE_USHORT:
0726:                                short[] usdata = ((DataBufferUShort) src
0727:                                        .getDataBuffer()).getData();
0728:                                stream.writeShorts(usdata, pos,
0729:                                        destScanlineLength);
0730:                                break;
0731:
0732:                            case DataBuffer.TYPE_INT:
0733:                                int[] idata = ((DataBufferInt) src
0734:                                        .getDataBuffer()).getData();
0735:                                stream
0736:                                        .writeInts(idata, pos,
0737:                                                destScanlineLength);
0738:                                break;
0739:                            }
0740:
0741:                            for (int k = 0; k < padding; k++) {
0742:                                stream.writeByte(0);
0743:                            }
0744:                        } else if (compressionType == BMPConstants.BI_RLE4) {
0745:                            if (bpixels == null
0746:                                    || bpixels.length < scanlineBytes)
0747:                                bpixels = new byte[scanlineBytes];
0748:                            src.getPixels(srcRect.x, srcRect.y, srcRect.width,
0749:                                    srcRect.height, pixels);
0750:                            for (int h = 0; h < scanlineBytes; h++) {
0751:                                bpixels[h] = (byte) pixels[h];
0752:                            }
0753:                            encodeRLE4(bpixels, scanlineBytes);
0754:                        } else if (compressionType == BMPConstants.BI_RLE8) {
0755:                            //byte[] bdata =
0756:                            //((DataBufferByte)src.getDataBuffer()).getData();
0757:                            //System.out.println("bdata.length="+bdata.length);
0758:                            //System.arraycopy(bdata, pos, bpixels, 0, scanlineBytes);
0759:                            if (bpixels == null
0760:                                    || bpixels.length < scanlineBytes)
0761:                                bpixels = new byte[scanlineBytes];
0762:                            src.getPixels(srcRect.x, srcRect.y, srcRect.width,
0763:                                    srcRect.height, pixels);
0764:                            for (int h = 0; h < scanlineBytes; h++) {
0765:                                bpixels[h] = (byte) pixels[h];
0766:                            }
0767:
0768:                            encodeRLE8(bpixels, scanlineBytes);
0769:                        }
0770:                    } else {
0771:                        src.getPixels(srcRect.x, srcRect.y, srcRect.width,
0772:                                srcRect.height, pixels);
0773:
0774:                        if (scaleX != 1 || maxBandOffset != numBands - 1) {
0775:                            for (int j = 0, k = 0, n = 0; j < w; j++, k += scaleX
0776:                                    * numBands, n += numBands) {
0777:                                System.arraycopy(pixels, k, pixel, 0,
0778:                                        pixel.length);
0779:
0780:                                for (int m = 0; m < numBands; m++) {
0781:                                    // pixel data is provided here in RGB order
0782:                                    pixels[n + m] = pixel[sourceBands[m]];
0783:                                }
0784:                            }
0785:                        }
0786:                        writePixels(0, scanlineBytes, bitsPerPixel, pixels,
0787:                                padding, numBands, icm);
0788:                    }
0789:
0790:                    processImageProgress(100.0f * (((float) i) / ((float) h)));
0791:                }
0792:
0793:                if (compressionType == BMPConstants.BI_RLE4
0794:                        || compressionType == BMPConstants.BI_RLE8) {
0795:                    // Write the RLE EOF marker and
0796:                    stream.writeByte(0);
0797:                    stream.writeByte(1);
0798:                    incCompImageSize(2);
0799:                    // update the file/image Size
0800:                    imageSize = compImageSize;
0801:                    fileSize = compImageSize + offset;
0802:                    long endPos = stream.getStreamPosition();
0803:                    stream.seek(headPos);
0804:                    writeSize(fileSize, 2);
0805:                    stream.seek(headPos);
0806:                    writeSize(imageSize, 34);
0807:                    stream.seek(endPos);
0808:                }
0809:
0810:                if (abortRequested()) {
0811:                    processWriteAborted();
0812:                } else {
0813:                    processImageComplete();
0814:                    stream.flushBefore(stream.getStreamPosition());
0815:                }
0816:            }
0817:
0818:            private void writePixels(int l, int scanlineBytes,
0819:                    int bitsPerPixel, int pixels[], int padding, int numBands,
0820:                    IndexColorModel icm) throws IOException {
0821:                int pixel = 0;
0822:                int k = 0;
0823:                switch (bitsPerPixel) {
0824:
0825:                case 1:
0826:
0827:                    for (int j = 0; j < scanlineBytes / 8; j++) {
0828:                        bpixels[k++] = (byte) ((pixels[l++] << 7)
0829:                                | (pixels[l++] << 6) | (pixels[l++] << 5)
0830:                                | (pixels[l++] << 4) | (pixels[l++] << 3)
0831:                                | (pixels[l++] << 2) | (pixels[l++] << 1) | pixels[l++]);
0832:                    }
0833:
0834:                    // Partially filled last byte, if any
0835:                    if (scanlineBytes % 8 > 0) {
0836:                        pixel = 0;
0837:                        for (int j = 0; j < scanlineBytes % 8; j++) {
0838:                            pixel |= (pixels[l++] << (7 - j));
0839:                        }
0840:                        bpixels[k++] = (byte) pixel;
0841:                    }
0842:                    stream.write(bpixels, 0, (scanlineBytes + 7) / 8);
0843:
0844:                    break;
0845:
0846:                case 4:
0847:                    if (compressionType == BMPConstants.BI_RLE4) {
0848:                        byte[] bipixels = new byte[scanlineBytes];
0849:                        for (int h = 0; h < scanlineBytes; h++) {
0850:                            bipixels[h] = (byte) pixels[l++];
0851:                        }
0852:                        encodeRLE4(bipixels, scanlineBytes);
0853:                    } else {
0854:                        for (int j = 0; j < scanlineBytes / 2; j++) {
0855:                            pixel = (pixels[l++] << 4) | pixels[l++];
0856:                            bpixels[k++] = (byte) pixel;
0857:                        }
0858:                        // Put the last pixel of odd-length lines in the 4 MSBs
0859:                        if ((scanlineBytes % 2) == 1) {
0860:                            pixel = pixels[l] << 4;
0861:                            bpixels[k++] = (byte) pixel;
0862:                        }
0863:                        stream.write(bpixels, 0, (scanlineBytes + 1) / 2);
0864:                    }
0865:                    break;
0866:
0867:                case 8:
0868:                    if (compressionType == BMPConstants.BI_RLE8) {
0869:                        for (int h = 0; h < scanlineBytes; h++) {
0870:                            bpixels[h] = (byte) pixels[l++];
0871:                        }
0872:                        encodeRLE8(bpixels, scanlineBytes);
0873:                    } else {
0874:                        for (int j = 0; j < scanlineBytes; j++) {
0875:                            bpixels[j] = (byte) pixels[l++];
0876:                        }
0877:                        stream.write(bpixels, 0, scanlineBytes);
0878:                    }
0879:                    break;
0880:
0881:                case 16:
0882:                    if (spixels == null)
0883:                        spixels = new short[scanlineBytes / numBands];
0884:                    /*
0885:                     * We expect that pixel data comes in RGB order.
0886:                     * We will assemble short pixel taking into account
0887:                     * the compression type:
0888:                     *
0889:                     * BI_RGB        - the RGB order should be maintained.
0890:                     * BI_BITFIELDS  - use bitPos array that was built
0891:                     *                 according to bitfields masks.
0892:                     */
0893:                    for (int j = 0, m = 0; j < scanlineBytes; m++) {
0894:                        spixels[m] = 0;
0895:                        if (compressionType == BMPConstants.BI_RGB) {
0896:                            /*
0897:                             * please note that despite other cases,
0898:                             * the 16bpp BI_RGB requires the RGB data order
0899:                             */
0900:                            spixels[m] = (short) (((0x1f & pixels[j]) << 10)
0901:                                    | ((0x1f & pixels[j + 1]) << 5) | ((0x1f & pixels[j + 2])));
0902:                            j += 3;
0903:                        } else {
0904:                            for (int i = 0; i < numBands; i++, j++) {
0905:                                spixels[m] |= (((pixels[j]) << bitPos[i]) & bitMasks[i]);
0906:                            }
0907:                        }
0908:                    }
0909:                    stream.writeShorts(spixels, 0, spixels.length);
0910:                    break;
0911:
0912:                case 24:
0913:                    if (numBands == 3) {
0914:                        for (int j = 0; j < scanlineBytes; j += 3) {
0915:                            // Since BMP needs BGR format
0916:                            bpixels[k++] = (byte) (pixels[l + 2]);
0917:                            bpixels[k++] = (byte) (pixels[l + 1]);
0918:                            bpixels[k++] = (byte) (pixels[l]);
0919:                            l += 3;
0920:                        }
0921:                        stream.write(bpixels, 0, scanlineBytes);
0922:                    } else {
0923:                        // Case where IndexColorModel had > 256 colors.
0924:                        int entries = icm.getMapSize();
0925:
0926:                        byte r[] = new byte[entries];
0927:                        byte g[] = new byte[entries];
0928:                        byte b[] = new byte[entries];
0929:
0930:                        icm.getReds(r);
0931:                        icm.getGreens(g);
0932:                        icm.getBlues(b);
0933:                        int index;
0934:
0935:                        for (int j = 0; j < scanlineBytes; j++) {
0936:                            index = pixels[l];
0937:                            bpixels[k++] = b[index];
0938:                            bpixels[k++] = g[index];
0939:                            bpixels[k++] = b[index];
0940:                            l++;
0941:                        }
0942:                        stream.write(bpixels, 0, scanlineBytes * 3);
0943:                    }
0944:                    break;
0945:
0946:                case 32:
0947:                    if (ipixels == null)
0948:                        ipixels = new int[scanlineBytes / numBands];
0949:                    if (numBands == 3) {
0950:                        /*
0951:                         * We expect that pixel data comes in RGB order.
0952:                         * We will assemble int pixel taking into account
0953:                         * the compression type.
0954:                         *
0955:                         * BI_RGB        - the BGR order should be used.
0956:                         * BI_BITFIELDS  - use bitPos array that was built
0957:                         *                 according to bitfields masks.
0958:                         */
0959:                        for (int j = 0, m = 0; j < scanlineBytes; m++) {
0960:                            ipixels[m] = 0;
0961:                            if (compressionType == BMPConstants.BI_RGB) {
0962:                                ipixels[m] = ((0xff & pixels[j + 2]) << 16)
0963:                                        | ((0xff & pixels[j + 1]) << 8)
0964:                                        | ((0xff & pixels[j]));
0965:                                j += 3;
0966:                            } else {
0967:                                for (int i = 0; i < numBands; i++, j++) {
0968:                                    ipixels[m] |= (((pixels[j]) << bitPos[i]) & bitMasks[i]);
0969:                                }
0970:                            }
0971:                        }
0972:                    } else {
0973:                        // We have two possibilities here:
0974:                        // 1. we are writing the indexed image with bitfields
0975:                        //    compression (this covers also the case of BYTE_BINARY)
0976:                        //    => use icm to get actual RGB color values.
0977:                        // 2. we are writing the gray-scaled image with BI_BITFIELDS
0978:                        //    compression
0979:                        //    => just replicate the level of gray to color components.
0980:                        for (int j = 0; j < scanlineBytes; j++) {
0981:                            if (icm != null) {
0982:                                ipixels[j] = icm.getRGB(pixels[j]);
0983:                            } else {
0984:                                ipixels[j] = pixels[j] << 16 | pixels[j] << 8
0985:                                        | pixels[j];
0986:                            }
0987:                        }
0988:                    }
0989:                    stream.writeInts(ipixels, 0, ipixels.length);
0990:                    break;
0991:                }
0992:
0993:                // Write out the padding
0994:                if (compressionType == BMPConstants.BI_RGB
0995:                        || compressionType == BMPConstants.BI_BITFIELDS) {
0996:                    for (k = 0; k < padding; k++) {
0997:                        stream.writeByte(0);
0998:                    }
0999:                }
1000:            }
1001:
1002:            private void encodeRLE8(byte[] bpixels, int scanlineBytes)
1003:                    throws IOException {
1004:
1005:                int runCount = 1, absVal = -1, j = -1;
1006:                byte runVal = 0, nextVal = 0;
1007:
1008:                runVal = bpixels[++j];
1009:                byte[] absBuf = new byte[256];
1010:
1011:                while (j < scanlineBytes - 1) {
1012:                    nextVal = bpixels[++j];
1013:                    if (nextVal == runVal) {
1014:                        if (absVal >= 3) {
1015:                            /// Check if there was an existing Absolute Run
1016:                            stream.writeByte(0);
1017:                            stream.writeByte(absVal);
1018:                            incCompImageSize(2);
1019:                            for (int a = 0; a < absVal; a++) {
1020:                                stream.writeByte(absBuf[a]);
1021:                                incCompImageSize(1);
1022:                            }
1023:                            if (!isEven(absVal)) {
1024:                                //Padding
1025:                                stream.writeByte(0);
1026:                                incCompImageSize(1);
1027:                            }
1028:                        } else if (absVal > -1) {
1029:                            /// Absolute Encoding for less than 3
1030:                            /// treated as regular encoding
1031:                            /// Do not include the last element since it will
1032:                            /// be inclued in the next encoding/run
1033:                            for (int b = 0; b < absVal; b++) {
1034:                                stream.writeByte(1);
1035:                                stream.writeByte(absBuf[b]);
1036:                                incCompImageSize(2);
1037:                            }
1038:                        }
1039:                        absVal = -1;
1040:                        runCount++;
1041:                        if (runCount == 256) {
1042:                            /// Only 255 values permitted
1043:                            stream.writeByte(runCount - 1);
1044:                            stream.writeByte(runVal);
1045:                            incCompImageSize(2);
1046:                            runCount = 1;
1047:                        }
1048:                    } else {
1049:                        if (runCount > 1) {
1050:                            /// If there was an existing run
1051:                            stream.writeByte(runCount);
1052:                            stream.writeByte(runVal);
1053:                            incCompImageSize(2);
1054:                        } else if (absVal < 0) {
1055:                            // First time..
1056:                            absBuf[++absVal] = runVal;
1057:                            absBuf[++absVal] = nextVal;
1058:                        } else if (absVal < 254) {
1059:                            //  0-254 only
1060:                            absBuf[++absVal] = nextVal;
1061:                        } else {
1062:                            stream.writeByte(0);
1063:                            stream.writeByte(absVal + 1);
1064:                            incCompImageSize(2);
1065:                            for (int a = 0; a <= absVal; a++) {
1066:                                stream.writeByte(absBuf[a]);
1067:                                incCompImageSize(1);
1068:                            }
1069:                            // padding since 255 elts is not even
1070:                            stream.writeByte(0);
1071:                            incCompImageSize(1);
1072:                            absVal = -1;
1073:                        }
1074:                        runVal = nextVal;
1075:                        runCount = 1;
1076:                    }
1077:
1078:                    if (j == scanlineBytes - 1) { // EOF scanline
1079:                        // Write the run
1080:                        if (absVal == -1) {
1081:                            stream.writeByte(runCount);
1082:                            stream.writeByte(runVal);
1083:                            incCompImageSize(2);
1084:                            runCount = 1;
1085:                        } else {
1086:                            // write the Absolute Run
1087:                            if (absVal >= 2) {
1088:                                stream.writeByte(0);
1089:                                stream.writeByte(absVal + 1);
1090:                                incCompImageSize(2);
1091:                                for (int a = 0; a <= absVal; a++) {
1092:                                    stream.writeByte(absBuf[a]);
1093:                                    incCompImageSize(1);
1094:                                }
1095:                                if (!isEven(absVal + 1)) {
1096:                                    //Padding
1097:                                    stream.writeByte(0);
1098:                                    incCompImageSize(1);
1099:                                }
1100:
1101:                            } else if (absVal > -1) {
1102:                                for (int b = 0; b <= absVal; b++) {
1103:                                    stream.writeByte(1);
1104:                                    stream.writeByte(absBuf[b]);
1105:                                    incCompImageSize(2);
1106:                                }
1107:                            }
1108:                        }
1109:                        /// EOF scanline
1110:
1111:                        stream.writeByte(0);
1112:                        stream.writeByte(0);
1113:                        incCompImageSize(2);
1114:                    }
1115:                }
1116:            }
1117:
1118:            private void encodeRLE4(byte[] bipixels, int scanlineBytes)
1119:                    throws IOException {
1120:
1121:                int runCount = 2, absVal = -1, j = -1, pixel = 0, q = 0;
1122:                byte runVal1 = 0, runVal2 = 0, nextVal1 = 0, nextVal2 = 0;
1123:                byte[] absBuf = new byte[256];
1124:
1125:                runVal1 = bipixels[++j];
1126:                runVal2 = bipixels[++j];
1127:
1128:                while (j < scanlineBytes - 2) {
1129:                    nextVal1 = bipixels[++j];
1130:                    nextVal2 = bipixels[++j];
1131:
1132:                    if (nextVal1 == runVal1) {
1133:
1134:                        //Check if there was an existing Absolute Run
1135:                        if (absVal >= 4) {
1136:                            stream.writeByte(0);
1137:                            stream.writeByte(absVal - 1);
1138:                            incCompImageSize(2);
1139:                            // we need to exclude  last 2 elts, similarity of
1140:                            // which caused to enter this part of the code
1141:                            for (int a = 0; a < absVal - 2; a += 2) {
1142:                                pixel = (absBuf[a] << 4) | absBuf[a + 1];
1143:                                stream.writeByte((byte) pixel);
1144:                                incCompImageSize(1);
1145:                            }
1146:                            // if # of elts is odd - read the last element
1147:                            if (!(isEven(absVal - 1))) {
1148:                                q = absBuf[absVal - 2] << 4 | 0;
1149:                                stream.writeByte(q);
1150:                                incCompImageSize(1);
1151:                            }
1152:                            // Padding to word align absolute encoding
1153:                            if (!isEven((int) Math.ceil((absVal - 1) / 2))) {
1154:                                stream.writeByte(0);
1155:                                incCompImageSize(1);
1156:                            }
1157:                        } else if (absVal > -1) {
1158:                            stream.writeByte(2);
1159:                            pixel = (absBuf[0] << 4) | absBuf[1];
1160:                            stream.writeByte(pixel);
1161:                            incCompImageSize(2);
1162:                        }
1163:                        absVal = -1;
1164:
1165:                        if (nextVal2 == runVal2) {
1166:                            // Even runlength
1167:                            runCount += 2;
1168:                            if (runCount == 256) {
1169:                                stream.writeByte(runCount - 1);
1170:                                pixel = (runVal1 << 4) | runVal2;
1171:                                stream.writeByte(pixel);
1172:                                incCompImageSize(2);
1173:                                runCount = 2;
1174:                                if (j < scanlineBytes - 1) {
1175:                                    runVal1 = runVal2;
1176:                                    runVal2 = bipixels[++j];
1177:                                } else {
1178:                                    stream.writeByte(01);
1179:                                    int r = runVal2 << 4 | 0;
1180:                                    stream.writeByte(r);
1181:                                    incCompImageSize(2);
1182:                                    runCount = -1;/// Only EOF required now
1183:                                }
1184:                            }
1185:                        } else {
1186:                            // odd runlength and the run ends here
1187:                            // runCount wont be > 254 since 256/255 case will
1188:                            // be taken care of in above code.
1189:                            runCount++;
1190:                            pixel = (runVal1 << 4) | runVal2;
1191:                            stream.writeByte(runCount);
1192:                            stream.writeByte(pixel);
1193:                            incCompImageSize(2);
1194:                            runCount = 2;
1195:                            runVal1 = nextVal2;
1196:                            // If end of scanline
1197:                            if (j < scanlineBytes - 1) {
1198:                                runVal2 = bipixels[++j];
1199:                            } else {
1200:                                stream.writeByte(01);
1201:                                int r = nextVal2 << 4 | 0;
1202:                                stream.writeByte(r);
1203:                                incCompImageSize(2);
1204:                                runCount = -1;/// Only EOF required now
1205:                            }
1206:
1207:                        }
1208:                    } else {
1209:                        // Check for existing run
1210:                        if (runCount > 2) {
1211:                            pixel = (runVal1 << 4) | runVal2;
1212:                            stream.writeByte(runCount);
1213:                            stream.writeByte(pixel);
1214:                            incCompImageSize(2);
1215:                        } else if (absVal < 0) { // first time
1216:                            absBuf[++absVal] = runVal1;
1217:                            absBuf[++absVal] = runVal2;
1218:                            absBuf[++absVal] = nextVal1;
1219:                            absBuf[++absVal] = nextVal2;
1220:                        } else if (absVal < 253) { // only 255 elements
1221:                            absBuf[++absVal] = nextVal1;
1222:                            absBuf[++absVal] = nextVal2;
1223:                        } else {
1224:                            stream.writeByte(0);
1225:                            stream.writeByte(absVal + 1);
1226:                            incCompImageSize(2);
1227:                            for (int a = 0; a < absVal; a += 2) {
1228:                                pixel = (absBuf[a] << 4) | absBuf[a + 1];
1229:                                stream.writeByte((byte) pixel);
1230:                                incCompImageSize(1);
1231:                            }
1232:                            // Padding for word align
1233:                            // since it will fit into 127 bytes
1234:                            stream.writeByte(0);
1235:                            incCompImageSize(1);
1236:                            absVal = -1;
1237:                        }
1238:
1239:                        runVal1 = nextVal1;
1240:                        runVal2 = nextVal2;
1241:                        runCount = 2;
1242:                    }
1243:                    // Handle the End of scanline for the last 2 4bits
1244:                    if (j >= scanlineBytes - 2) {
1245:                        if (absVal == -1 && runCount >= 2) {
1246:                            if (j == scanlineBytes - 2) {
1247:                                if (bipixels[++j] == runVal1) {
1248:                                    runCount++;
1249:                                    pixel = (runVal1 << 4) | runVal2;
1250:                                    stream.writeByte(runCount);
1251:                                    stream.writeByte(pixel);
1252:                                    incCompImageSize(2);
1253:                                } else {
1254:                                    pixel = (runVal1 << 4) | runVal2;
1255:                                    stream.writeByte(runCount);
1256:                                    stream.writeByte(pixel);
1257:                                    stream.writeByte(01);
1258:                                    pixel = bipixels[j] << 4 | 0;
1259:                                    stream.writeByte(pixel);
1260:                                    int n = bipixels[j] << 4 | 0;
1261:                                    incCompImageSize(4);
1262:                                }
1263:                            } else {
1264:                                stream.writeByte(runCount);
1265:                                pixel = (runVal1 << 4) | runVal2;
1266:                                stream.writeByte(pixel);
1267:                                incCompImageSize(2);
1268:                            }
1269:                        } else if (absVal > -1) {
1270:                            if (j == scanlineBytes - 2) {
1271:                                absBuf[++absVal] = bipixels[++j];
1272:                            }
1273:                            if (absVal >= 2) {
1274:                                stream.writeByte(0);
1275:                                stream.writeByte(absVal + 1);
1276:                                incCompImageSize(2);
1277:                                for (int a = 0; a < absVal; a += 2) {
1278:                                    pixel = (absBuf[a] << 4) | absBuf[a + 1];
1279:                                    stream.writeByte((byte) pixel);
1280:                                    incCompImageSize(1);
1281:                                }
1282:                                if (!(isEven(absVal + 1))) {
1283:                                    q = absBuf[absVal] << 4 | 0;
1284:                                    stream.writeByte(q);
1285:                                    incCompImageSize(1);
1286:                                }
1287:
1288:                                // Padding
1289:                                if (!isEven((int) Math.ceil((absVal + 1) / 2))) {
1290:                                    stream.writeByte(0);
1291:                                    incCompImageSize(1);
1292:                                }
1293:
1294:                            } else {
1295:                                switch (absVal) {
1296:                                case 0:
1297:                                    stream.writeByte(1);
1298:                                    int n = absBuf[0] << 4 | 0;
1299:                                    stream.writeByte(n);
1300:                                    incCompImageSize(2);
1301:                                    break;
1302:                                case 1:
1303:                                    stream.writeByte(2);
1304:                                    pixel = (absBuf[0] << 4) | absBuf[1];
1305:                                    stream.writeByte(pixel);
1306:                                    incCompImageSize(2);
1307:                                    break;
1308:                                }
1309:                            }
1310:
1311:                        }
1312:                        stream.writeByte(0);
1313:                        stream.writeByte(0);
1314:                        incCompImageSize(2);
1315:                    }
1316:                }
1317:            }
1318:
1319:            private synchronized void incCompImageSize(int value) {
1320:                compImageSize = compImageSize + value;
1321:            }
1322:
1323:            private boolean isEven(int number) {
1324:                return (number % 2 == 0 ? true : false);
1325:            }
1326:
1327:            private void writeFileHeader(int fileSize, int offset)
1328:                    throws IOException {
1329:                // magic value
1330:                stream.writeByte('B');
1331:                stream.writeByte('M');
1332:
1333:                // File size
1334:                stream.writeInt(fileSize);
1335:
1336:                // reserved1 and reserved2
1337:                stream.writeInt(0);
1338:
1339:                // offset to image data
1340:                stream.writeInt(offset);
1341:            }
1342:
1343:            private void writeInfoHeader(int headerSize, int bitsPerPixel)
1344:                    throws IOException {
1345:                // size of header
1346:                stream.writeInt(headerSize);
1347:
1348:                // width
1349:                stream.writeInt(w);
1350:
1351:                // height
1352:                if (isTopDown == true)
1353:                    stream.writeInt(-h);
1354:                else
1355:                    stream.writeInt(h);
1356:
1357:                // number of planes
1358:                stream.writeShort(1);
1359:
1360:                // Bits Per Pixel
1361:                stream.writeShort(bitsPerPixel);
1362:            }
1363:
1364:            private void writeSize(int dword, int offset) throws IOException {
1365:                stream.skipBytes(offset);
1366:                stream.writeInt(dword);
1367:            }
1368:
1369:            public void reset() {
1370:                super .reset();
1371:                stream = null;
1372:            }
1373:
1374:            static int getCompressionType(String typeString) {
1375:                for (int i = 0; i < BMPConstants.compressionTypeNames.length; i++)
1376:                    if (BMPConstants.compressionTypeNames[i].equals(typeString))
1377:                        return i;
1378:                return 0;
1379:            }
1380:
1381:            private void writeEmbedded(IIOImage image, ImageWriteParam bmpParam)
1382:                    throws IOException {
1383:                String format = compressionType == BMPConstants.BI_JPEG ? "jpeg"
1384:                        : "png";
1385:                Iterator iterator = ImageIO.getImageWritersByFormatName(format);
1386:                ImageWriter writer = null;
1387:                if (iterator.hasNext())
1388:                    writer = (ImageWriter) iterator.next();
1389:                if (writer != null) {
1390:                    if (embedded_stream == null) {
1391:                        throw new RuntimeException(
1392:                                "No stream for writing embedded image!");
1393:                    }
1394:
1395:                    writer
1396:                            .addIIOWriteProgressListener(new IIOWriteProgressAdapter() {
1397:                                public void imageProgress(ImageWriter source,
1398:                                        float percentageDone) {
1399:                                    processImageProgress(percentageDone);
1400:                                }
1401:                            });
1402:
1403:                    writer
1404:                            .addIIOWriteWarningListener(new IIOWriteWarningListener() {
1405:                                public void warningOccurred(ImageWriter source,
1406:                                        int imageIndex, String warning) {
1407:                                    processWarningOccurred(imageIndex, warning);
1408:                                }
1409:                            });
1410:
1411:                    ImageOutputStream emb_ios = ImageIO
1412:                            .createImageOutputStream(embedded_stream);
1413:                    writer.setOutput(emb_ios);
1414:                    ImageWriteParam param = writer.getDefaultWriteParam();
1415:                    //param.setDestinationBands(bmpParam.getDestinationBands());
1416:                    param.setDestinationOffset(bmpParam.getDestinationOffset());
1417:                    param.setSourceBands(bmpParam.getSourceBands());
1418:                    param.setSourceRegion(bmpParam.getSourceRegion());
1419:                    param.setSourceSubsampling(
1420:                            bmpParam.getSourceXSubsampling(), bmpParam
1421:                                    .getSourceYSubsampling(), bmpParam
1422:                                    .getSubsamplingXOffset(), bmpParam
1423:                                    .getSubsamplingYOffset());
1424:                    writer.write(null, image, param);
1425:                    emb_ios.flush();
1426:                } else
1427:                    throw new RuntimeException(I18N.getString("BMPImageWrite5")
1428:                            + " " + format);
1429:
1430:            }
1431:
1432:            private int firstLowBit(int num) {
1433:                int count = 0;
1434:                while ((num & 1) == 0) {
1435:                    count++;
1436:                    num >>>= 1;
1437:                }
1438:                return count;
1439:            }
1440:
1441:            private class IIOWriteProgressAdapter implements 
1442:                    IIOWriteProgressListener {
1443:
1444:                public void imageComplete(ImageWriter source) {
1445:                }
1446:
1447:                public void imageProgress(ImageWriter source,
1448:                        float percentageDone) {
1449:                }
1450:
1451:                public void imageStarted(ImageWriter source, int imageIndex) {
1452:                }
1453:
1454:                public void thumbnailComplete(ImageWriter source) {
1455:                }
1456:
1457:                public void thumbnailProgress(ImageWriter source,
1458:                        float percentageDone) {
1459:                }
1460:
1461:                public void thumbnailStarted(ImageWriter source,
1462:                        int imageIndex, int thumbnailIndex) {
1463:                }
1464:
1465:                public void writeAborted(ImageWriter source) {
1466:                }
1467:            }
1468:
1469:            /*
1470:             * Returns preferred compression type for given image.
1471:             * The default compression type is BI_RGB, but some image types can't be 
1472:             * encoded with using default compression without changing color resolution.
1473:             * For example, BufferedImage.TYPE_USHORT_555_RGB and
1474:             * BufferedImage.TYPE_USHORT_565_RGB may be encoded only by using the
1475:             * BI_BITFIELDS compression type.
1476:             *
1477:             * NB: we probably need to extend this method if we encounter other image 
1478:             * types which can not be encoded with BI_RGB compression type. 
1479:             */
1480:            static int getPreferredCompressionType(ColorModel cm, SampleModel sm) {
1481:                ImageTypeSpecifier imageType = new ImageTypeSpecifier(cm, sm);
1482:                return getPreferredCompressionType(imageType);
1483:            }
1484:
1485:            static int getPreferredCompressionType(ImageTypeSpecifier imageType) {
1486:                int biType = imageType.getBufferedImageType();
1487:                if (biType == BufferedImage.TYPE_USHORT_565_RGB
1488:                        || biType == BufferedImage.TYPE_USHORT_555_RGB) {
1489:                    return BI_BITFIELDS;
1490:                }
1491:                return BI_RGB;
1492:            }
1493:
1494:            /*
1495:             * Check whether we can encode image of given type using compression method in question.
1496:             *
1497:             * For example, TYPE_USHORT_565_RGB can be encodeed with BI_BITFIELDS compression only.
1498:             *
1499:             * NB: method should be extended if other cases when we can not encode 
1500:             *     with given compression will be discovered.
1501:             */
1502:            protected boolean canEncodeImage(int compression, ColorModel cm,
1503:                    SampleModel sm) {
1504:                ImageTypeSpecifier imgType = new ImageTypeSpecifier(cm, sm);
1505:                return canEncodeImage(compression, imgType);
1506:            }
1507:
1508:            protected boolean canEncodeImage(int compression,
1509:                    ImageTypeSpecifier imgType) {
1510:                ImageWriterSpi spi = this .getOriginatingProvider();
1511:                if (!spi.canEncodeImage(imgType)) {
1512:                    return false;
1513:                }
1514:                int bpp = imgType.getColorModel().getPixelSize();
1515:                if (compressionType == BI_RLE4 && bpp != 4) {
1516:                    // only 4bpp images can be encoded as BI_RLE4
1517:                    return false;
1518:                }
1519:                if (compressionType == BI_RLE8 && bpp != 8) {
1520:                    // only 8bpp images can be encoded as BI_RLE8
1521:                    return false;
1522:                }
1523:                if (bpp == 16) {
1524:                    /*
1525:                     * Technically we expect that we may be able to
1526:                     * encode only some of SinglePixelPackedSampleModel
1527:                     * images here.
1528:                     *
1529:                     * In addition we should take into account following:
1530:                     *
1531:                     * 1. BI_RGB case, according to the MSDN description:
1532:                     *
1533:                     *     The bitmap has a maximum of 2^16 colors. If the
1534:                     *     biCompression member of the BITMAPINFOHEADER is BI_RGB,
1535:                     *     the bmiColors member of BITMAPINFO is NULL. Each WORD
1536:                     *     in the bitmap array represents a single pixel. The
1537:                     *     relative intensities of red, green, and blue are
1538:                     *     represented with five bits for each color component.
1539:                     *
1540:                     * 2. BI_BITFIELDS case, according ot the MSDN description:
1541:                     *
1542:                     *     Windows 95/98/Me: When the biCompression member is
1543:                     *     BI_BITFIELDS, the system supports only the following
1544:                     *     16bpp color masks: A 5-5-5 16-bit image, where the blue
1545:                     *     mask is 0x001F, the green mask is 0x03E0, and the red mask
1546:                     *     is 0x7C00; and a 5-6-5 16-bit image, where the blue mask
1547:                     *     is 0x001F, the green mask is 0x07E0, and the red mask is
1548:                     *     0xF800.
1549:                     */
1550:                    boolean canUseRGB = false;
1551:                    boolean canUseBITFIELDS = false;
1552:
1553:                    SampleModel sm = imgType.getSampleModel();
1554:                    if (sm instanceof  SinglePixelPackedSampleModel) {
1555:                        int[] sizes = ((SinglePixelPackedSampleModel) sm)
1556:                                .getSampleSize();
1557:
1558:                        canUseRGB = true;
1559:                        canUseBITFIELDS = true;
1560:                        for (int i = 0; i < sizes.length; i++) {
1561:                            canUseRGB &= (sizes[i] == 5);
1562:                            canUseBITFIELDS &= ((sizes[i] == 5) || (i == 1 && sizes[i] == 6));
1563:                        }
1564:                    }
1565:
1566:                    return (((compressionType == BI_RGB) && canUseRGB) || ((compressionType == BI_BITFIELDS) && canUseBITFIELDS));
1567:                }
1568:                return true;
1569:            }
1570:
1571:            protected void writeMaskToPalette(int mask, int i, byte[] r,
1572:                    byte[] g, byte[] b, byte[] a) {
1573:                b[i] = (byte) (0xff & (mask >> 24));
1574:                g[i] = (byte) (0xff & (mask >> 16));
1575:                r[i] = (byte) (0xff & (mask >> 8));
1576:                a[i] = (byte) (0xff & mask);
1577:            }
1578:
1579:            private int roundBpp(int x) {
1580:                if (x <= 8) {
1581:                    return 8;
1582:                } else if (x <= 16) {
1583:                    return 16;
1584:                }
1585:                if (x <= 24) {
1586:                    return 24;
1587:                } else {
1588:                    return 32;
1589:                }
1590:            }
1591:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.