package ij.io;
import java.io.*;
import ij.*; import ij.process.ImageProcessor;
public class ImageWriter {
private FileInfo fi;
private boolean showProgressBar=true;
public ImageWriter (FileInfo fi) {
this.fi = fi;
}
private void showProgress(double progress) {
if (showProgressBar)
IJ.showProgress(progress);
}
void write8BitImage(OutputStream out, byte[] pixels) throws IOException {
int bytesWritten = 0;
int size = fi.width*fi.height;
int count = 8192;
while (bytesWritten<size) {
if ((bytesWritten + count)>size)
count = size - bytesWritten;
out.write(pixels, bytesWritten, count);
bytesWritten += count;
showProgress((double)bytesWritten/size);
}
}
void write8BitStack(OutputStream out, Object[] stack) throws IOException {
showProgressBar = false;
for (int i=0; i<fi.nImages; i++) {
IJ.showStatus("Writing: " + (i+1) + "/" + fi.nImages);
write8BitImage(out, (byte[])stack[i]);
IJ.showProgress((double)(i+1)/fi.nImages);
}
}
void write8BitVirtualStack(OutputStream out, VirtualStack virtualStack) throws IOException {
showProgressBar = false;
boolean flip = "FlipTheseImages".equals(fi.fileName);
for (int i=1; i<=fi.nImages; i++) {
IJ.showStatus("Writing: " + i + "/" + fi.nImages);
ImageProcessor ip = virtualStack.getProcessor(i);
if (flip) ip.flipVertical();
byte[] pixels = (byte[])ip.getPixels();
write8BitImage(out, pixels);
IJ.showProgress((double)i/fi.nImages);
}
}
void write16BitImage(OutputStream out, short[] pixels) throws IOException {
long bytesWritten = 0L;
long size = 2L*fi.width*fi.height;
int count = 8192;
byte[] buffer = new byte[count];
while (bytesWritten<size) {
if ((bytesWritten + count)>size)
count = (int)(size-bytesWritten);
int j = (int)(bytesWritten/2L);
int value;
if (fi.intelByteOrder)
for (int i=0; i < count; i+=2) {
value = pixels[j];
buffer[i] = (byte)value;
buffer[i+1] = (byte)(value>>>8);
j++;
}
else
for (int i=0; i < count; i+=2) {
value = pixels[j];
buffer[i] = (byte)(value>>>8);
buffer[i+1] = (byte)value;
j++;
}
out.write(buffer, 0, count);
bytesWritten += count;
showProgress((double)bytesWritten/size);
}
}
void write16BitStack(OutputStream out, Object[] stack) throws IOException {
showProgressBar = false;
for (int i=0; i<fi.nImages; i++) {
IJ.showStatus("Writing: " + (i+1) + "/" + fi.nImages);
write16BitImage(out, (short[])stack[i]);
IJ.showProgress((double)(i+1)/fi.nImages);
}
}
void write16BitVirtualStack(OutputStream out, VirtualStack virtualStack) throws IOException {
showProgressBar = false;
boolean flip = "FlipTheseImages".equals(fi.fileName);
for (int i=1; i<=fi.nImages; i++) {
IJ.showStatus("Writing: " + i + "/" + fi.nImages);
ImageProcessor ip = virtualStack.getProcessor(i);
if (flip) ip.flipVertical();
short[] pixels = (short[])ip.getPixels();
write16BitImage(out, pixels);
IJ.showProgress((double)i/fi.nImages);
}
}
void writeRGB48Image(OutputStream out, Object[] stack) throws IOException {
short[] r = (short[])stack[0];
short[] g = (short[])stack[1];
short[] b = (short[])stack[2];
int size = fi.width*fi.height;
int count = fi.width*6;
byte[] buffer = new byte[count];
for (int line=0; line<fi.height; line++) {
int index2 = 0;
int index1 = line*fi.width;
int value;
if (fi.intelByteOrder) {
for (int i=0; i<fi.width; i++) {
value = r[index1];
buffer[index2++] = (byte)value;
buffer[index2++] = (byte)(value>>>8);
value = g[index1];
buffer[index2++] = (byte)value;
buffer[index2++] = (byte)(value>>>8);
value = b[index1];
buffer[index2++] = (byte)value;
buffer[index2++] = (byte)(value>>>8);
index1++;
}
} else {
for (int i=0; i<fi.width; i++) {
value = r[index1];
buffer[index2++] = (byte)(value>>>8);
buffer[index2++] = (byte)value;
value = g[index1];
buffer[index2++] = (byte)(value>>>8);
buffer[index2++] = (byte)value;
value = b[index1];
buffer[index2++] = (byte)(value>>>8);
buffer[index2++] = (byte)value;
index1++;
}
}
out.write(buffer, 0, count);
}
}
void writeFloatImage(OutputStream out, float[] pixels) throws IOException {
long bytesWritten = 0L;
long size = 4L*fi.width*fi.height;
int count = 8192;
byte[] buffer = new byte[count];
int tmp;
while (bytesWritten<size) {
if ((bytesWritten + count)>size)
count = (int)(size-bytesWritten);
int j = (int)(bytesWritten/4L);
if (fi.intelByteOrder)
for (int i=0; i < count; i+=4) {
tmp = Float.floatToRawIntBits(pixels[j]);
buffer[i] = (byte)tmp;
buffer[i+1] = (byte)(tmp>>8);
buffer[i+2] = (byte)(tmp>>16);
buffer[i+3] = (byte)(tmp>>24);
j++;
}
else
for (int i=0; i < count; i+=4) {
tmp = Float.floatToRawIntBits(pixels[j]);
buffer[i] = (byte)(tmp>>24);
buffer[i+1] = (byte)(tmp>>16);
buffer[i+2] = (byte)(tmp>>8);
buffer[i+3] = (byte)tmp;
j++;
}
out.write(buffer, 0, count);
bytesWritten += count;
showProgress((double)bytesWritten/size);
}
}
void writeFloatStack(OutputStream out, Object[] stack) throws IOException {
showProgressBar = false;
for (int i=0; i<fi.nImages; i++) {
IJ.showStatus("Writing: " + (i+1) + "/" + fi.nImages);
writeFloatImage(out, (float[])stack[i]);
IJ.showProgress((double)(i+1)/fi.nImages);
}
}
void writeFloatVirtualStack(OutputStream out, VirtualStack virtualStack) throws IOException {
showProgressBar = false;
boolean flip = "FlipTheseImages".equals(fi.fileName);
for (int i=1; i<=fi.nImages; i++) {
IJ.showStatus("Writing: " + i + "/" + fi.nImages);
ImageProcessor ip = virtualStack.getProcessor(i);
if (flip) ip.flipVertical();
float[] pixels = (float[])ip.getPixels();
writeFloatImage(out, pixels);
IJ.showProgress((double)i/fi.nImages);
}
}
void writeRGBImage(OutputStream out, int[] pixels) throws IOException {
long bytesWritten = 0L;
long size = 3L*fi.width*fi.height;
int count = fi.width*24;
byte[] buffer = new byte[count];
while (bytesWritten<size) {
if ((bytesWritten+count)>size)
count = (int)(size-bytesWritten);
int j = (int)(bytesWritten/3L);
for (int i=0; i<count; i+=3) {
buffer[i] = (byte)(pixels[j]>>16); buffer[i+1] = (byte)(pixels[j]>>8); buffer[i+2] = (byte)pixels[j]; j++;
}
out.write(buffer, 0, count);
bytesWritten += count;
showProgress((double)bytesWritten/size);
}
}
void writeRGBStack(OutputStream out, Object[] stack) throws IOException {
showProgressBar = false;
for (int i=0; i<fi.nImages; i++) {
IJ.showStatus("Writing: " + (i+1) + "/" + fi.nImages);
writeRGBImage(out, (int[])stack[i]);
IJ.showProgress((double)(i+1)/fi.nImages);
}
}
void writeRGBVirtualStack(OutputStream out, VirtualStack virtualStack) throws IOException {
showProgressBar = false;
boolean flip = "FlipTheseImages".equals(fi.fileName);
for (int i=1; i<=fi.nImages; i++) {
IJ.showStatus("Writing: " + i + "/" + fi.nImages);
ImageProcessor ip = virtualStack.getProcessor(i);
if (flip) ip.flipVertical();
int[] pixels = (int[])ip.getPixels();
writeRGBImage(out, pixels);
IJ.showProgress((double)i/fi.nImages);
}
}
public void write(OutputStream out) throws IOException {
if (fi.pixels==null && fi.virtualStack==null)
throw new IOException("ImageWriter: fi.pixels==null");
if (fi.nImages>1 && fi.virtualStack==null && !(fi.pixels instanceof Object[]))
throw new IOException("ImageWriter: fi.pixels not a stack");
if (fi.width*fi.height*fi.getBytesPerPixel()<26214400)
showProgressBar = false; switch (fi.fileType) {
case FileInfo.GRAY8:
case FileInfo.COLOR8:
if (fi.nImages>1 && fi.virtualStack!=null)
write8BitVirtualStack(out, fi.virtualStack);
else if (fi.nImages>1)
write8BitStack(out, (Object[])fi.pixels);
else
write8BitImage(out, (byte[])fi.pixels);
break;
case FileInfo.GRAY16_SIGNED:
case FileInfo.GRAY16_UNSIGNED:
if (fi.nImages>1 && fi.virtualStack!=null)
write16BitVirtualStack(out, fi.virtualStack);
else if (fi.nImages>1)
write16BitStack(out, (Object[])fi.pixels);
else
write16BitImage(out, (short[])fi.pixels);
break;
case FileInfo.RGB48:
writeRGB48Image(out, (Object[])fi.pixels);
break;
case FileInfo.GRAY32_FLOAT:
if (fi.nImages>1 && fi.virtualStack!=null)
writeFloatVirtualStack(out, fi.virtualStack);
else if (fi.nImages>1)
writeFloatStack(out, (Object[])fi.pixels);
else
writeFloatImage(out, (float[])fi.pixels);
break;
case FileInfo.RGB:
if (fi.nImages>1 && fi.virtualStack!=null)
writeRGBVirtualStack(out, fi.virtualStack);
else if (fi.nImages>1)
writeRGBStack(out, (Object[])fi.pixels);
else
writeRGBImage(out, (int[])fi.pixels);
break;
default:
}
}
}