package ij.plugin;
import ij.*;
import ij.io.*;
import ij.process.*;
import java.awt.*;
import java.io.*;
import java.awt.image.*;
public class BMP_Writer implements PlugIn {
private final static int BITMAPFILEHEADER_SIZE = 14;
private final static int BITMAPINFOHEADER_SIZE = 40;
private byte bitmapFileHeader [] = new byte [14];
private byte bfType [] = {(byte)'B', (byte)'M'};
private int bfSize = 0;
private int bfReserved1 = 0;
private int bfReserved2 = 0;
private int bfOffBits = BITMAPFILEHEADER_SIZE + BITMAPINFOHEADER_SIZE;
private byte bitmapInfoHeader [] = new byte [40];
private int biSize = BITMAPINFOHEADER_SIZE;
private int biWidth = 0;
private int padWidth = 0;
private int biHeight = 0;
private int biPlanes = 1;
private int biBitCount = 24;
private int biCompression = 0;
private int biSizeImage = 0;
private int biXPelsPerMeter = 0x0;
private int biYPelsPerMeter = 0x0;
private int biClrUsed = 0;
private int biClrImportant = 0;
private int intBitmap [];
private byte byteBitmap [];
private FileOutputStream fo;
private BufferedOutputStream bfo;
ImagePlus imp;
public void run(String path) {
IJ.showProgress(0);
imp = WindowManager.getCurrentImage();
if (imp==null)
{IJ.noImage(); return;}
try {
writeImage(imp, path);
} catch (Exception e) {
String msg = e.getMessage();
if (msg==null || msg.equals(""))
msg = ""+e;
IJ.error("BMP Writer", "An error occured writing the file.\n \n" + msg);
}
IJ.showProgress(1);
IJ.showStatus("");
}
void writeImage(ImagePlus imp, String path) throws Exception {
if(imp.getBitDepth()==24)
biBitCount = 24;
else {
biBitCount = 8;
LookUpTable lut = imp.createLut();
biClrUsed=lut.getMapSize(); bfOffBits+=biClrUsed*4;
}
if (path==null || path.equals("")) {
String prompt = "Save as " + biBitCount + " bit BMP";
SaveDialog sd = new SaveDialog(prompt, imp.getTitle(), ".bmp");
if(sd.getFileName()==null)
return;
path = sd.getDirectory()+sd.getFileName();
}
imp.startTiming();
saveBitmap (path, imp.getImage(), imp.getWidth(), imp.getHeight() );
}
public void saveBitmap (String parFilename, Image parImage, int parWidth, int parHeight) throws Exception {
fo = new FileOutputStream (parFilename);
bfo = new BufferedOutputStream(fo);
save (parImage, parWidth, parHeight);
bfo.close();
fo.close ();
}
private void save (Image parImage, int parWidth, int parHeight) throws Exception {
convertImage (parImage, parWidth, parHeight);
writeBitmapFileHeader ();
writeBitmapInfoHeader ();
if(biBitCount == 8)
writeBitmapPalette ();
writeBitmap ();
}
private void writeBitmapPalette() throws Exception {
LookUpTable lut = imp.createLut();
byte[] g = lut.getGreens();
byte[] r = lut.getReds();
byte[] b = lut.getBlues();
for(int i = 0;i<lut.getMapSize();i++) {
bfo.write(b[i]);
bfo.write(g[i]);
bfo.write(r[i]);
bfo.write(0x00);
}
}
private boolean convertImage (Image parImage, int parWidth, int parHeight) {
int pad;
if(biBitCount == 24)
intBitmap = (int[]) imp.getProcessor().getPixels();
else
byteBitmap = (byte[]) imp.getProcessor().convertToByte(true).getPixels();
biWidth = parWidth;
biHeight = parHeight;
if(biBitCount==24)
pad = 4 - ((biWidth * 3) % 4);
else
pad = 4 - ((biWidth) % 4);
if (pad == 4) pad = 0; padWidth = biWidth*(biBitCount==24?3:1)+pad;
return (true);
}
private void writeBitmap () throws Exception {
int value;
int i;
int pad;
byte rgb [] = new byte [3];
if(biBitCount==24)
pad = 4 - ((biWidth * 3) % 4);
else
pad = 4 - ((biWidth) % 4);
if (pad == 4) pad = 0;
int counter=0;
for(int row = biHeight; row>0; row--) {
if (row%20==0)
IJ.showProgress((double)(biHeight-row)/biHeight);
for(int col = 0; col<biWidth; col++) {
if(biBitCount==24) {
value = intBitmap [(row-1)*biWidth + col ];
rgb [0] = (byte) (value & 0xFF);
rgb [1] = (byte) ((value >> 8) & 0xFF);
rgb [2] = (byte) ((value >> 16) & 0xFF);
bfo.write(rgb);
} else
bfo.write(byteBitmap [(row-1)*biWidth + col ]);
++counter;
}
for (i = 1; i <= pad; i++)
bfo.write (0x00);
counter += pad;
}
}
private void writeBitmapFileHeader() throws Exception {
fo.write (bfType);
bfSize = bfOffBits+padWidth*biHeight;
fo.write (intToDWord (bfSize));
fo.write (intToWord (bfReserved1));
fo.write (intToWord (bfReserved2));
fo.write (intToDWord (bfOffBits));
}
private void writeBitmapInfoHeader () throws Exception {
fo.write (intToDWord (biSize));
fo.write (intToDWord (biWidth));
fo.write (intToDWord (biHeight));
fo.write (intToWord (biPlanes));
fo.write (intToWord (biBitCount));
fo.write (intToDWord (biCompression));
fo.write (intToDWord (biSizeImage));
fo.write (intToDWord (biXPelsPerMeter));
fo.write (intToDWord (biYPelsPerMeter));
fo.write (intToDWord (biClrUsed));
fo.write (intToDWord (biClrImportant));
}
private byte [] intToWord (int parValue) {
byte retValue [] = new byte [2];
retValue [0] = (byte) (parValue & 0x00FF);
retValue [1] = (byte) ((parValue >> 8) & 0x00FF);
return (retValue);
}
private byte [] intToDWord (int parValue) {
byte retValue [] = new byte [4];
retValue [0] = (byte) (parValue & 0x00FF);
retValue [1] = (byte) ((parValue >> 8) & 0x000000FF);
retValue [2] = (byte) ((parValue >> 16) & 0x000000FF);
retValue [3] = (byte) ((parValue >> 24) & 0x000000FF);
return (retValue);
}
}