Java encode raw bytes into image simple image fomat/ file - java

I am very new to image encoding and would rather not learn a whole lot about it. Basically I'm taking greyscale byte array where each byte equals one pixel. I'm getting this data from mnist where I get 28x28 byte images. Anyway, bellow is my code, so you understand what I'm trying to accomplish.
private def getImages = {
val filePath = getClass.getResource("/mnist/train-images.idx3-ubyte").getPath
val fis = new FileInputStream(filePath)
var bytes = new Array[Byte](4)
fis.read(bytes)
println((ByteBuffer.wrap(bytes).getInt()))
fis.read(bytes)
println((ByteBuffer.wrap(bytes).getInt()))
fis.read(bytes)
var rows = ByteBuffer.wrap(bytes).getInt()
println("Number of rows: " + rows)
fis.read(bytes)
var cols = ByteBuffer.wrap(bytes).getInt()
println("Number of cols: " + cols)
var imageBytes = new Array[Byte](rows * cols)
fis.read(imageBytes)
imageBytes.foreach(println(_))
// I created a byte array input stream to feed into ImageIO
// which should create my image
val b = new ByteArrayInputStream(imageBytes)
// This is where your helpful answer would be placed
// What is the code to encode this into jpeg, gif, or whatever?
// This returns null because I have not encoded the bytes
// in the proper format
val img = ImageIO.read(b)
// Errors out because img is null
ImageIO.write(img, "gif", new File("/home/dev/woot.gif"))
}
The format is just consecutive pixel bytes laid next to each other. My question is what Java library or function is available to convert these raw bytes into jpeg, gif, or whatever format I need?

Before you write it out with ImageIO, create a BufferedImage first. It can be as simple as using the setRGB methods, and has the added benefit of allowing you to observe the image before writing it out.

Related

From image to BufferedImage to image

I'm trying to read a 256x256 image using ImageIO.read, transform it into a ByteArray, then into a BufferedImage, and back into an image file using ImageIO.write. It all seems to work as it should, but the final image is quite corrupted (although clearly still based on the original image. I can't find what's wrong in the process, I am suspicious of the scansize parameter, which I don't completely understand.
The idea is to manipulate pixels in between the reading and writing, but at the moment I can't even recreate the original image back into itself.
I attach the original image and the processed one below:
import java.awt.image.BufferedImage
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.IOException
import javax.imageio.ImageIO
fun main(args: Array<String>) {
val bImage = ImageIO.read(File("original.tiff"))
val bos = ByteArrayOutputStream()
ImageIO.write(bImage, "tiff", bos)
val data = bos.toByteArray()
val width = 256
val height = 256
val bytesPerPixel = 3
val len = width * height * bytesPerPixel
val image = BufferedImage(width, height, BufferedImage.TYPE_INT_RGB)
val arr = IntArray(len)
for (i in 0 until len) arr[i] = data.get(i).toInt()
image.setRGB(0, 0, width, height, arr, 0, 256) // Seems like something is wrong here
try {
ImageIO.write(image, "jpg", File("converted-grayscale-002.jpg"))
} catch (e: IOException) {
System.err.println("IOException: $e")
}
}
This line is not returning the RGB image data:
val data = bos.toByteArray()
it is returning the compressed stream of the image in tiff format, surely it is not the correct image.
To get the pixels, use Image.getPixel(), alternatively you can get the buffer of the image directly, but to this you need to know what is the underlying buffer type - this is broad topic.
Take a look at this answer, it should give you idea how to do it: convert a RGB image to grayscale Image reducing the memory in java

Compressing a multi-page tiff image with lossy jpeg

I need to compress a tif file that has several gray 16bit images (multi-page). I have tried working with ImageIO as here: Tiff compression using Java ImageIO Initially, each image that will be in the tif file comes from another tiff file. When I want to use the compressors, I have the following options:
CCITT RLE, CCITT T.4, CCITT T.6: They give me the error: "javax.imageio.IIOException: I/O error writing TIFF file!"
LZW. I cannot use it. My images are 16bit and LZW increases the size of 16bit images
JPEG. Not possible for 16bit images.
ZLIB. It only reduces 10% even if I specify setCompressionQuality(0.0f);
PackBits. Does not compress.
Deflate. Like ZLIB.
EXIF JPEG. It gives me the error: "javax.imageio.IIOException: Old JPEG compression not supported!"
Does any know any other alternative? I saw an apache imaging library but the tif compression only support the above or less options. Does anyone know about JPEG2000 compressor? Any other kind of alternative?
PNG compresses 16-bit images losslessly. Libraries and utilities are widely available. JPEG2000 has a lossy 16-bit mode, but you'd have to find some software that supports it. Open JPEG might.
However I'd have to ask: what are your criteria for when you have acceptable image quality and when you do not? If it is visual, then you likely end up at normal JPEG anyway, with a good bit less than 8 bits per pixel effective.
Reducing the image 16 bit to 8 bit. Consider that you have a byte[] variable plane16 where you have all the pixels of your image.
Note: My byte[] plane16 gets the data from a 16bit image but byte is 8bit=1byte. Therefore, 2 elements in row of this array are 2byte = 16bit. That is why I convert it to a short[] before operating. If you start from a short[], ommit "ByteBuffer.wrap(plane16).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().get(shorts);"
byte[] plane16; //Fill it with your image!!!
//Do stuff with imageIO. Set writer and compresion method
ImageIO.scanForPlugins();
TIFFImageWriterSpi tiffspi = new TIFFImageWriterSpi();
javax.imageio.ImageWriter writerIO = tiffspi.createWriterInstance();
ImageWriteParam param = writerIO.getDefaultWriteParam();
param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
param.setCompressionType("ZLib");
param.setCompressionQuality(0.5f);
File fOutputFile = new File(route+".tif");
ImageOutputStream ios = ImageIO.createImageOutputStream(fOutputFile);
writerIO.setOutput(ios);
//Reducing 16bit to 8bit
short[] shorts = new short[plane16.length/2];
ByteBuffer.wrap(plane16).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().get(shorts);
int max = 0;
int min = 999999;
for (int v = 0; v<shorts.length;v++){
if (max<shorts[v]) max = shorts[v];
if (min>shorts[v]) min = shorts[v];
}
double range = 255./(max-min);
byte[] plane8 = new byte[shorts.length];
for (int v = 0; v<plane8.length;v++){
plane8[v] = (byte) ((shorts[v]+min)*range - 128);
}
//16bit:
/*BufferedImage convertedGrayscale = new BufferedImage(width,
heigth, BufferedImage.TYPE_USHORT_GRAY);
convertedGrayscale.getRaster().setDataElements(0, 0, width,
heigth, shorts);*/
//8bit:
BufferedImage convertedGrayscale = new BufferedImage(width,
heigth, BufferedImage.TYPE_BYTE_GRAY);
convertedGrayscale.getRaster().setDataElements(0, 0, width,
heigth, plane8);
//Save image
//If you have a stack of images in tiff, do this trick. "image" is the image number you are setting inside the tiff. If you only have 1 image, remove the if and take the expression from the else.
if (image!=0){
writerIO.writeInsert(image, new IIOImage(convertedGrayscale, null, null), param);
}else{
writerIO.write(null, new IIOImage(convertedGrayscale, null, null), param);
}
//do the next only after the last image to be saved
writerIO.dispose();
ios.flush();
ios.close();

Java - Convert Data URI to File [duplicate]

I have a Data-URL from an image file and have to pass it through to another function. Along this path from Data-URL to the BufferedImage it needs to be a byteArray.
my approach was the following:
String dataUrl;
byte[] imageData = dataUrl.getBytes();
// pass the byteArray along the path
// create BufferedImage from byteArray
BufferedImage inputImage = ImageIO.read(new ByteArrayInputStream(imageData));
// If the picture is null, then throw an unsupported image exception.
if (inputImage == null) {
throw new UnknownImageFormatException();
}
The problem is, it always throws the UnknownImageFormatException Exception, which means inputImage is null, which means, the ImageIO.read did not recognize the imagetype.
I've used ImageIO.getReaderFormatNames() to get the supported Filenames and got the following list:
Supported Formats:
jpg, BMP, bmp, JPG, jpeg, wbmp, png, JPEG, PNG, WBMP, GIF, gif
The dataURLs I try to pass are like: data:image/png;base64,... or data:image/jpg;base64,...
As far as I understand, those are in the supported filelist and therefor should be recognized.
What else could cause the inputImage to be null in this case? And more interesting, how do I solve it?
As the comments already said the image data is Base64 encoded. To retrieve the binary data you have to strip the type/encoding headers, then decode the Base64 content to binary data.
String encodingPrefix = "base64,";
int contentStartIndex = dataUrl.indexOf(encodingPrefix) + encodingPrefix.length();
byte[] imageData = Base64.decodeBase64(dataUrl.substring(contentStartIndex));
I use org.apache.commons.codec.binary.Base64 from apaches common-codec, other Base64 decoders should work as well.
The only one problem with RFC2397 string is its specification with everything before data but data: and , optional:
data:[<mediatype>][;base64],<data>
So pure Java 8 solution accounting this would be:
final int dataStartIndex = dataUrl.indexOf(",") + 1;
final String data = dataUrl.substring(dataStartIndex);
byte[] decoded = java.util.Base64.getDecoder().decode(data);
Of course dataStartIndex should be checked.
I think, a simple regex replace would be better and more conform to the RFC2397:
java.util.Base64.getDecoder().decode(b64DataString.replaceFirst("data:.+,", ""))
The RFC states that the data: and the , are the required prefixes for a data url, therefore it is wise to match for them.

convert raw image bytes to multipage tiff using java and vice versa

I have a requirement where i have set of base64 strings each string is one tiff file, i need to combine all these base64 strings and provide this full tiff data as base64 string, so end user can create a tiff file from the combined base64 strings.
I tried all the ways shared below but each time in my output tiff only one page is coming but i am passing 2 base64 strings.
Any inputs greatly appreciated.
Iam using this code
ArrayList al = new ArrayList();
//this is repetative so i am adding all the base64 strings to arraylist
byte[] imgBytes = Base64.decodeBase64(imageObject.get("image").toString());
al.add(imgBytes);
//writing all base64 strings to a new tiff file //here it is showing only the first page but in the top i am adding two pages.
BufferedImage imag=ImageIO.read(new ByteArrayInputStream(toByteArray(al)));
ImageIO.write(imag, "tif", new File(processedFilesFolder,"combined.tif"));
public static byte[] toByteArray(List<byte[]> bytesList)
{
int size = 0;
for (byte[] bytes : bytesList)
{
size += bytes.length;
}
ByteBuffer byteBuffer = ByteBuffer.allocate(size);
for (byte[] bytes : bytesList)
{
byteBuffer.put(bytes);
}
return byteBuffer.array();
}
ByteArrayOutputStream outputStream = new ByteArrayOutputStream( );
outputStream.write( data ); // this line is repetative
byte c[] = outputStream.toByteArray( );
try (OutputStream stream = new FileOutputStream("C:\\Users\\XYZ\\Desktop\\EID_Image_Desktop‌​Scan_mod.tiff")) { stream.write(c); } catch(Exception e){}
Regards,
Meerasaaheb Mohmmad

Store animated GIF image in a Java program

In a Java program you can store images like .png, .jpg and such in a BufferedImage. I don't think it works for animated gif images as it seems to lose its animation.
Currently I get normal images like:
BufferedImage image = ImageIO.read(new URL(images.get(x)));
String type = images.get(x).substring(images.get(x).length() - 3, images.get(x).length());
ImageIO.write(image, type, new File(title + "/" + filename));
Where images is a String[] of URLs.
As for gif's I'm getting them by:
byte[] b = new byte[1];
URL url = new URL(images.get(x));
URLConnection urlConnection = url.openConnection();
urlConnection.connect();
DataInputStream di = new DataInputStream(urlConnection.getInputStream());
FileOutputStream fo = new FileOutputStream(title + "/" + filename);
while (-1 != di.read(b, 0, 1) && downloading)
fo.write(b, 0, 1);
di.close();
fo.close();
But I want to store them in the program and write them to a file another time. How do I store a GIF without writing it to a file but while keeping its animation?
If you are only interested in storing the gif in memory, and not in having it display from the java program. You could write the data you've received into a ByteArrayOutputStream rather than a FileOutputStream, and then take the resulting byte array and write that to a FileOutputStream at a later time.
If you would like to display the animated gif, you might want to check out the top answer in this post, although the first comment on the answer seems to be having a problem similar to yours.

Categories

Resources