/* * Copyright (c) 2001 Sun Microsystems, Inc. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * -Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * -Redistribution in binary form must reproduct the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of Sun Microsystems, Inc. or the names of contributors may * be used to endorse or promote products derived from this software without * specific prior written permission. * * This software is provided "AS IS," without a warranty of any kind. ALL * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY * IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR * NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS SHALL NOT BE * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING * OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS * LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, * INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER * CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF * OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * * You acknowledge that Software is not designed,licensed or intended for use in * the design, construction, operation or maintenance of any nuclear facility. */ package com.fr.third.JAI; import java.io.OutputStream; import java.io.IOException; import java.awt.image.Raster; import java.awt.image.DataBuffer; import java.awt.image.RenderedImage; import java.awt.image.SampleModel; import java.awt.Rectangle; import java.awt.image.ColorModel; import java.awt.image.IndexColorModel; /** * An ImageEncoder for the various versions of the BMP image file format. * * Unless specified otherwise by the BMPDecodeParam object passed to the * constructor, Version 3 will be the default version used. * *

If the image to be encoded has an IndexColorModel and can be encoded * using upto 8 bits per pixel, the image will be written out as a Palette * color image with an appropriate number of bits per pixel. For example an * image having a 256 color IndexColorModel will be written out as a Palette * image with 8 bits per pixel while one with a 16 color palette will be * written out as a Palette image with 4 bits per pixel. For all other images, * the 24 bit image format will be used. * * */ public class BMPImageEncoder extends ImageEncoderImpl { private OutputStream output; private int version; private boolean isCompressed, isTopDown; private int w, h; private int compImageSize = 0; /** * An ImageEncoder for the BMP file format. * * @param output The OutputStream to write to. * @param param The BMPEncodeParam object. */ public BMPImageEncoder(OutputStream output, ImageEncodeParam param) { super(output, param); this.output = output; BMPEncodeParam bmpParam; if (param == null) { // Use default valued BMPEncodeParam bmpParam = new BMPEncodeParam(); } else { bmpParam = (BMPEncodeParam)param; } this.version = bmpParam.getVersion(); this.isCompressed = bmpParam.isCompressed(); if(isCompressed && !(output instanceof SeekableOutputStream)){ throw new IllegalArgumentException(JaiI18N.getString("BMPImageEncoder6")); } this.isTopDown = bmpParam.isTopDown(); } /** * Encodes a RenderedImage and writes the output to the * OutputStream associated with this ImageEncoder. */ public void encode(RenderedImage im) throws IOException { // Get image dimensions int minX = im.getMinX(); int minY = im.getMinY(); w = im.getWidth(); h = im.getHeight(); // Default is using 24 bits per pixel. int bitsPerPixel = 24; boolean isPalette = false; int paletteEntries = 0; IndexColorModel icm = null; SampleModel sm = im.getSampleModel(); int numBands = sm.getNumBands(); ColorModel cm = im.getColorModel(); if (numBands != 1 && numBands != 3) { throw new IllegalArgumentException(JaiI18N.getString("BMPImageEncoder1")); } int sampleSize[] = sm.getSampleSize(); if (sampleSize[0] > 8) { throw new RuntimeException(JaiI18N.getString("BMPImageEncoder2")); } for (int i=1; i= minY; row -= 8) { // Number of rows being read int rows = Math.min(8, row - minY + 1); // Get the pixels Raster src = im.getData(new Rectangle(minX, row - rows + 1, w, rows)); src.getPixels(minX, row - rows + 1, w, rows, pixels); l = 0; // Last possible position in the pixels array int max = scanlineBytes * rows - 1; for (int i=0; i 0) { pixel = 0; for (int j=0; j 256 colors. int entries = icm.getMapSize(); byte r[] = new byte[entries]; byte g[] = new byte[entries]; byte b[] = new byte[entries]; icm.getReds(r); icm.getGreens(g); icm.getBlues(b); int index; for (int j=0; j= 3 ){ /// Check if there was an existing Absolute Run output.write(0); output.write(absVal); incCompImageSize(2); for(int a=0; a -1){ /// Absolute Encoding for less than 3 /// treated as regular encoding /// Do not include the last element since it will /// be inclued in the next encoding/run for (int b=0;b 1){ /// If there was an existing run output.write(runCount); output.write(runVal); incCompImageSize(2); } else if (absVal < 0){ // First time.. absBuf[++absVal] = runVal; absBuf[++absVal] = nextVal; } else if (absVal < 254){ // 0-254 only absBuf[++absVal] = nextVal; } else { output.write(0); output.write(absVal+1); incCompImageSize(2); for(int a=0; a<=absVal;a++){ output.write(absBuf[a]); incCompImageSize(1); } // padding since 255 elts is not even output.write(0); incCompImageSize(1); absVal = -1; } runVal = nextVal; runCount = 1; } if (j == scanlineBytes-1){ // EOF scanline // Write the run if (absVal == -1){ output.write(runCount); output.write(runVal); incCompImageSize(2); runCount = 1; } else { // write the Absolute Run if(absVal >= 2){ output.write(0); output.write(absVal+1); incCompImageSize(2); for(int a=0; a<=absVal;a++){ output.write(absBuf[a]); incCompImageSize(1); } if (!isEven(absVal+1)){ //Padding output.write(0); incCompImageSize(1); } } else if(absVal > -1){ for (int b=0;b<=absVal;b++){ output.write(1); output.write(absBuf[b]); incCompImageSize(2); } } } /// EOF scanline output.write(0); output.write(0); incCompImageSize(2); } } } private void encodeRLE4(byte[] bipixels, int scanlineBytes) throws IOException { int runCount=2, absVal=-1, j=-1, pixel=0, q=0; byte runVal1=0, runVal2=0, nextVal1=0, nextVal2=0; byte[] absBuf = new byte[256]; runVal1 = bipixels[++j]; runVal2 = bipixels[++j]; while (j < scanlineBytes-2){ nextVal1 = bipixels[++j]; nextVal2 = bipixels[++j]; if (nextVal1 == runVal1 ) { //Check if there was an existing Absolute Run if(absVal >= 4){ output.write(0); output.write(absVal - 1); incCompImageSize(2); // we need to exclude last 2 elts, similarity of // which caused to enter this part of the code for(int a=0; a -1){ output.write(2); pixel = (absBuf[0] << 4) | absBuf[1]; output.write(pixel); incCompImageSize(2); } absVal = -1; if (nextVal2 == runVal2){ // Even runlength runCount+=2; if(runCount == 256){ output.write(runCount-1); pixel = ( runVal1 << 4) | runVal2; output.write(pixel); incCompImageSize(2); runCount =2; if(j< scanlineBytes - 1){ runVal1 = runVal2; runVal2 = bipixels[++j]; } else { output.write(01); int r = runVal2 << 4 | 0; output.write(r); incCompImageSize(2); runCount = -1;/// Only EOF required now } } } else { // odd runlength and the run ends here // runCount wont be > 254 since 256/255 case will // be taken care of in above code. runCount++; pixel = ( runVal1 << 4) | runVal2; output.write(runCount); output.write(pixel); incCompImageSize(2); runCount = 2; runVal1 = nextVal2; // If end of scanline if (j < scanlineBytes -1){ runVal2 = bipixels[++j]; }else { output.write(01); int r = nextVal2 << 4 | 0; output.write(r); incCompImageSize(2); runCount = -1;/// Only EOF required now } } } else{ // Check for existing run if (runCount > 2){ pixel = ( runVal1 << 4) | runVal2; output.write(runCount); output.write(pixel); incCompImageSize(2); } else if (absVal < 0){ // first time absBuf[++absVal] = runVal1; absBuf[++absVal] = runVal2; absBuf[++absVal] = nextVal1; absBuf[++absVal] = nextVal2; } else if (absVal < 253){ // only 255 elements absBuf[++absVal] = nextVal1; absBuf[++absVal] = nextVal2; } else { output.write(0); output.write(absVal+1); incCompImageSize(2); for(int a=0; a= scanlineBytes-2 ) { if (absVal == -1 && runCount >= 2){ if (j == scanlineBytes-2){ if(bipixels[++j] == runVal1){ runCount++; pixel = ( runVal1 << 4) | runVal2; output.write(runCount); output.write(pixel); incCompImageSize(2); } else { pixel = ( runVal1 << 4) | runVal2; output.write(runCount); output.write(pixel); output.write(01); pixel = bipixels[j]<<4 |0; output.write(pixel); int n = bipixels[j]<<4|0; incCompImageSize(4); } } else { output.write(runCount); pixel =( runVal1 << 4) | runVal2 ; output.write(pixel); incCompImageSize(2); } } else if(absVal > -1){ if (j == scanlineBytes-2){ absBuf[++absVal] = bipixels[++j]; } if (absVal >=2){ output.write(0); output.write(absVal+1); incCompImageSize(2); for(int a=0; a> 8); } public void writeDWord(int dword) throws IOException { output.write(dword & 0xff); output.write((dword & 0xff00) >> 8); output.write((dword & 0xff0000) >> 16); output.write((dword & 0xff000000) >> 24); } private void writeSize(int dword, int offset) throws IOException { ((SeekableOutputStream)output).seek(offset); writeDWord(dword); } }