/*
* 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);
}
}