| BMP_Writer |

    package ij.plugin;
    import ij.*;
    import ij.io.*;
    import ij.process.*;
    import java.awt.*;
    import java.io.*;
    import java.awt.image.*;

    /** Implements the File/Save As/BMP command. Based on BMPFile class from
       http://www.javaworld.com/javaworld/javatips/jw-javatip60-p2.html */

    public class BMP_Writer implements PlugIn {
     //--- Private constants
     private final static int BITMAPFILEHEADER_SIZE = 14;
     private final static int BITMAPINFOHEADER_SIZE = 40;
     //--- Private variable declaration
     //--- Bitmap file header
     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;
     //--- Bitmap info header
     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;
     //--- Bitmap raw data
     private int intBitmap [];
     private byte byteBitmap [];
     //--- File section
     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(); // 8 bit color image may use less
         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 ();
     }

     /*
      *   The saveMethod is the main method of the process. This method
      *   will call the convertImage method to convert the memory image to
      *   a byte array; method writeBitmapFileHeader creates and writes
      *   the bitmap file header; writeBitmapInfoHeader creates the
      *   information header; and writeBitmap writes the image.
      *
      */
     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);
       }
     }

     /*
      * convertImage converts the memory image to the bitmap format (BRG).
      * It also computes some information for the bitmap info header.
      *
      */
     private boolean convertImage (Image parImage, int parWidth, int parHeight) {
       int pad;
       if(biBitCount == 24)
         intBitmap = (int[]) imp.getProcessor().getPixels();
       else
         byteBitmap = (byte[]) imp.getProcessor().getPixels();
       biWidth = parWidth;
       biHeight = parHeight;
       if(biBitCount==24)
         pad = 4 - ((biWidth * 3) % 4);
       else
         pad = 4 - ((biWidth) % 4);
       if (pad == 4)       // <==== Bug correction
         pad = 0;            // <==== Bug correction
       padWidth = biWidth*(biBitCount==24?3:1)+pad;
       return (true);
     }

     /*
      * writeBitmap converts the image returned from the pixel grabber to
      * the format required. Remember: scan lines are inverted in
      * a bitmap file!
      *
      * Each scan line must be padded to an even 4-byte boundary.
      */
     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)       // <==== Bug correction
         pad = 0;            // <==== Bug correction

       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;
       }
       // IJ.write("counter of bytes written = " + counter);
     }

     /*
      * writeBitmapFileHeader writes the bitmap file header to the file.
      *
      */
     private void writeBitmapFileHeader() throws Exception {
       fo.write (bfType);
       // calculate bfSize
       bfSize = bfOffBits+padWidth*biHeight;
       fo.write (intToDWord (bfSize));
       fo.write (intToWord (bfReserved1));
       fo.write (intToWord (bfReserved2));
       fo.write (intToDWord (bfOffBits));
       // IJ.write("biClrUsed = " + biClrUsed + " bfSize = " + bfSize + " bfOffBits=" + bfOffBits);
     }

     /*
      *
      * writeBitmapInfoHeader writes the bitmap information header
      * to the file.
      *
      */
     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));
     }

     /*
      *
      * intToWord converts an int to a word, where the return
      * value is stored in a 2-byte array.
      *
      */
     private byte [] intToWord (int parValue) {
       byte retValue [] = new byte [2];
       retValue [0] = (byte) (parValue & 0x00FF);
       retValue [1] = (byte) ((parValue >> 8) & 0x00FF);
       return (retValue);
     }

     /*
      *
      * intToDWord converts an int to a double word, where the return
      * value is stored in a 4-byte array.
      *
      */
     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);
     }
    }

| BMP_Writer |