About java ByteArrayOutputStream class - java

BufferedImage bufferedImage = ImageIO.read(new File("/...icon.jpg"));
// this writes the bufferedImage into a byte array called resultingBytes
ByteArrayOutputStream byteArrayOut = new ByteArrayOutputStream();
ImageIO.write(bufferedImage, "jpg", byteArrayOut);
byte[] resultingBytes = byteArrayOut.toByteArray();
I use the above code to get a JEPG image as a byte array. I want to know what exactly is in this byte array. Does this array contain any file header information or just pixel values? And for example, if I want to reverse this image's color, what is a good way to do so?
Thanks so much!

It's a complete JPEG file, in memory.
EDIT: If you want to manipulate pixel data as an array, you may find Raster more helpful:
E.g.:
Raster raster = bufferedImage.getData();
You can then call one of the Raster.getPixels methods.

The ByteArrayOutputStream contains whatever you wrote to it. Nothing more, nothing less. So your question is really about ImageIO.write(). Which writes out an encoding of an image according to the encoding type you supply. Which was JPEG.

Here is how you read real pixel values. The JPEG information is much harder to do anything with!
public static void main(String... args) throws IOException {
String u = "http://blog.stackoverflow.com/wp-content/uploads/stackoverflow-logo-300.png";
BufferedImage old = ImageIO.read(new URL(u));
BufferedImage inverted = new BufferedImage(old.getWidth(),
old.getHeight(),
BufferedImage.TYPE_INT_RGB);
for (int y = 0; y < old.getHeight(); y++) {
for (int x = 0; x < old.getWidth(); x++) {
Color oldColor = new Color(old.getRGB(x, y));
// reverse all but the alpha channel
Color invertedColor = new Color(255 - oldColor.getRed(),
255 - oldColor.getGreen(),
255 - oldColor.getBlue());
inverted.setRGB(x, y, invertedColor.getRGB());
}
}
ImageIO.write(inverted, "png", new File("test.png"));
}

Related

Manipulating the Alpha value of BufferedImage

In the code i'm setting the alpha value of a pixel to 100 for entire image and I want the Alpha value to be 100 while reading the image. But at the retrieving part it gives me 255(Default Value) . What is wrong ? and how to solve it ? Any Help would be appreciated...
class Demo
{
Demo()
{
try
{
BufferedImage im2 = new BufferedImage(width,height,BufferedImage.TYPE_INT_ARGB);
File f2 = new File("test2.jpg");
im2 = ImageIO.read(f2);
int width1 = im2.getWidth();
int height1 = im2.getHeight();
for(int i=0;i<height1;i++)
{
for(int j=0;j<width1;j++)
{
Color c = new Color(50,0,0,100); //Set the alpha value to 100
im2.setRGB(j,i,c.getRGB()); // for every pixel
}
}
File f = new File("Demo_copy.jpg");
ImageIO.write(im2,"jpg",f);
// Retrieving.........
BufferedImage im1;
File f1 = new File("Demo_copy.jpg");
im1 = ImageIO.read(f1);
int width = im1.getWidth();
int height = im1.getHeight();
for(int i=0;i<height;i++)
{
for(int j=0;j<width;j++)
{
int pixel = im1.getRGB(j,i);
Color c = new Color(pixel,true);
int a = c.getAlpha();
System.out.println("Alpha value is :"+a); // Printing Alpha : 255 for every pixel
}
}
}catch(Exception e){}
}
public static void main(String [] ar)
{
new Demo();
}
}
The new BufferedImage(...) you assign to im2 is just thrown away (garbage collected) after you assign a new value from ImageIO.read(..). As the new value is a JPEG and doesn't have alpha, it does not matter what alpha values you set. They will always stay 255 (completely opaque).
Instead, you probably want to do something like this:
// Read opaque image...
BufferedImage img = ImageIO.read(new File("test2.jpg"));
// ...convert image to TYPE_INT_ARGB...
BufferedImage im2 = new BufferedImage(img.getWidth(), img.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics2D g = im2.createGraphics();
try {
g.drawImage(img, 0, 0, null);
}
finally {
g.dispose();
}
// ... loop over and change alpha in im2 as before
Finally, you should write the image in a format that supports lossless alpha, like PNG instead of JPEG, to be sure you get the values you expect:
ImageIO.write(im2,"PNG", new File("Demo_copy.png"));
PS: It might just work using JPEG too, as the built-in Java ImageIO JPEG plugin supports reading/writing JPEGs with alpha values. However, most other software will misinterpret these as CMYK JPEGs, and the colors will look all wrong. Also, JPEG is lossy, so you will most likely not see the exact alpha value (100) as you would expect on the receiving end. That's why I suggest using PNG. TIFF or other format that supports alpha would also work, but requires extra plugins.

create png/jpg from random byte[]

I was wondering if it is possible to create a byte array that can be decoded to a Bitmap.
For example, suppose I have a byte array of 100 elements. Could I somehow transform it into an image? I read about headers and whatnots for png, and markers for jpges, but I'm still rather clueless ...
Maybe take 4 bytes at a time and create pixels?
Your question: "create png/jpg from random byte[]"; literally possible though not directly:
You will have to use your own logic first to create a Bitmap Object from that byte[]. But along with the byte[] you will also need to have the bitmaps width, height and bytes per pixel (Bitmap.Config) predefined. You will also have to ensure the size of the byte[] matches the predefined values or accept the blank space in the Bitmap, i.e.:
byte[] b = new byte[width*height*bytesPerPixel];
...so 100 bytes could give you a 5 X 5 pixel bitmap with 4 bytes per pixel. Then you create a Bitmap Object:
Bitmap bitmap = Bitmap.create(width, height, Bitmap.Config.<whatever>)
...where <whatever> will depend on bytes per pixel. Example for 4 bytes per pixel it would be ARGB_8888.
Then run through every pixel in bitmap using two for loops, and pull out bytesPerPixel (assuming 4 now) number of bytes from b, generate a pixel colour and draw the pixel to it:
// Create a Canvas Object;
Canvas c = new Canvas(bitmap);
// Value to index the byte[];
int bI = 0;
// Paint Object for drawing the pixel;
Paint p = new Paint();
// Iterate through the pixel rows;
for(int i = 0; i < height; i++) {
// Iterate through the pixels in the row;
for(int j = 0; j < width; j++) {
// Pull out 4 bytes and generate colour int;
// This entire statement depends on bytesPerPixel;
int colorInt = Color.argb(b[bI++], b[bI++], b[bI++], b[bI++]);
// Set the colour on the Paint;
p.setColor(colorInt);
// Draw the pixel;
c.drawPoint(j, i, p);
}
}
Now your Bitmap will be present in memory so to save it to a file:
try {
// Create a File Object;
File file = new File(<file path>)
// Ensure that the file exists and can be written to;
if(!file.exists()) {
file.createNewFile();
}
// Create a FileOutputStream Object;
FileOutputStream fos = new FileOutputStream(file);
// Write the Bitmap to the File, 100 is max quality but
// it is ignored for PNG since that is lossless;
bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos)
// Clear the output stream;
fos.flush();
// Close the output stream;
fos.close();
} catch (Exception e) {}

Change in color while using ImageIO.read()

I am trying to read images from external directory and for that I am using
bufferedImage image=ImageIO.read(new File(imagefile));
jlabel.seticon(new imageicon(image));
and getting a drastic change in colors. I tried many other things like:
bufferedImage image=ImageIO.read(new File(imagefile));
bufferedImage img=new bufferedImage(image.getWidth(),image.getHeight(),bufferedImage.TYPE_INT_RGB);
and I tried:
img.setData(image.getData();
jlabel.seticon(new imageicon(image));
and I tried:
Iterator readers = ImageIO.getImageReadersByFormatName("JPEG");
ImageReader reader = null;
while(readers.hasNext()) {
reader = (ImageReader)readers.next();
if(reader.canReadRaster()) {
break;
}
}
ImageInputStream input = ImageIO.createImageInputStream(f);
reader.setInput(input);
Raster raster = reader.readRaster(0, null);
BufferedImage bi = new BufferedImage(raster.getWidth(), raster.getHeight(),
BufferedImage.TYPE_4BYTE_ABGR);
bi.getRaster().setRect(raster);
but result are still same
http://i.stack.imgur.com/jNVm0.jpg
Here is an example of the issue:
The minimal code for viewing is:
bufferedImage image=ImageIO.read(new File(imagefile));
jlabel.seticon(new imageicon(image));
lbitem.setIcon(im);
and for storing
File f = new File(s);
long size=f.length();
FileInputStream fis1=new FileInputStream(f);
FileOutputStream fos2=new FileOutputStream("src/image/"+tfpn.getText()+".jpg");
byte b[]=new byte[1000];
int r=0;
long count=0;
while(true)
{
r=fis1.read(b,0,1000);
fos2.write(b,0,1000);
count = count+r;
if(count==size)
break;
System.out.println(count);
}
What could be causing the bad colors?
This problem is cause by a mismatch between reading/writing (creating/using) an image
that contains alpha (transparency) but you are expecting it to contain no alpha (or the inverse).
For example, if your image is BufferedImage.TYPE_4BYTE_ABGR and you output it
to a file type that does not support alpha (transparency) , or you writer does not
support alpha, it will look like your sample after reading and displaying it.
Use type PNG (supports alpha channel) not JPG (does not support alpha channel)

Convert/display byte array to bmp/jpeg image

First of all, im asking this specific question, because i've already read many examples around this topic, but none of them really helped.
My problem is that i'd like to convert and display a jpg image. I don't have the original image, it is on a server. The data comes through a stream (socket) and it is given in a byte array. In this byte array, every 4 bytes represents information about a pixel. I managed to get the RGBs and convert/save them into a bmp image, however i couldn't find a working solution to make a jpg.
On the other hand, i have a BMP :) how can i display it in a JLabel or JPanel? I also read abou imageicon ImageIO etc. but it doesn't work for me. I use ScheduleExecutorSystem btw. Maybe that is the problem?
Here's the encoder code (Copyright (C) 2013 Philipp C. Heckel ):
public static void encodeToBitmap(byte[] srcBytes, OutputStream destStream)
throws IOException {
int imageWidth = 1024;
int imageHeight = 1080;
int imageBytes = imageWidth * imageHeight * 3;
int filesizeBytes = imageBytes + BMP_SIZE_HEADER;
byte[] header = BMP_HEADER.clone(); // Clone bitmap header template, and
// overwrite with fields
header = writeIntLE(header, BMP_OFFSET_FILESIZE_BYTES, filesizeBytes);
header = writeIntLE(header, BMP_OFFSET_IMAGE_WIDTH, imageWidth);
header = writeIntLE(header, BMP_OFFSET_IMAGE_HEIGHT, imageHeight);
header = writeIntLE(header, BMP_OFFSET_IMAGE_DATA_BYTES, 0);
header = writeIntLE(header, BMP_OFFSET_PAYLOAD_LENGTH,
(int) srcBytes.length);
// WRITE TO STREAM
// Add payload
destStream.write(header, 0, header.length);
for (int offset = imageBytes - imageWidth * 3; offset >= 0; offset -= imageWidth * 3) {
for (int i = 0; i < (imageWidth) * 3; i++) {
destStream.write(srcBytes[offset + i]);
}
}
destStream.close();
}
And the code, how i use it:
BitmapEncoder.encodeToBitmap(RGBvalues, new FileOutputStream("path to file"));
RGBvalues - bytes of 3, with the RGB values (i don't say!! :P )
image width and Height is fix for debug purpose
I have a JPanel and a JLabel within, and i added a default ImageIcon to the JLabel (a jpg image), and it works fine.
After i saved the image, i try :
ImageIcon icon = new ImageIcon("path to file");
pictureLabel.setIcon(icon);
It only makes the default disappear. Am i forgetting to set something?
Is this the fastest way, to do it?
The ImageIcon class only directly supports reading PNG, GIF and JPEG types. You need to use ImageIO to read your bitmap into a generic Image object (which is supported by ImageIcon) and then pass that to ImageIcon. Here's how I'd modify your code to work:
File imgFile = new File("path to file");
Image image = javax.imageio.ImageIO.read(imgFile);
ImageIcon icon = new ImageIcon(image);
pictureLabel.setIcon(icon);
Note that you can also use ImageIO to convert your bitmap to JPEG format.

Write to 16 bit BufferedImage TYPE_USHORT_GRAY

I'm trying to write 16 bit grayscale imagedata to a png using BufferedImage.TYPE_USHORT_GRAY. Normally I write to an image like so:
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
then:
image.setRGB(x,y,Color.getRGB);
to set the pixels, and finally:
ImageIO.write(image, "png", new File(path + ".png"));
to write to a png image.
But now I have this as image:
BufferedImage imageGray = new BufferedImage(width, height, BufferedImage.TYPE_USHORT_GRAY);
How do I go about saving pixels to that format? Using setRGB() with a 16 bit integer doesn't seem to work, when I open the saved png file I see a lot of banding happening.
I tried saving a simple gradient from 0 to 65535 and then using the setRGB() on the grayscale image, and checked the results in Photoshop. I can see the image consists of smaller gradients every 256 rows. I'm guessing either setRGB() or imageIO doesn't work as I would like it to.
Are there workarounds for this? Does imageIO even support the BufferedImage.TYPE_USHORT_GRAY format? Or can it only save 8 bit data? And if it can save 16bit data, how would I go about saving pixel data, preferably in a way like setRGB() works (so for a certain x,y coordinate)?
As pst already commented below my question:
Try using the Raster directly?
Accessing the Raster directly solved the problem :
BufferedImage bi = BufferedImage(width, height, BufferedImage.TYPE_USHORT_GRAY)
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
Short s = shortData[x][y]
bi.getRaster().setDataElements(x, y, Short[] {s})
}
}
From BufferedImage you can read
public static final int TYPE_USHORT_GRAY
Represents an unsigned short grayscale image, non-indexed). This image has a ComponentColorModel with a CS_GRAY ColorSpace.
So try instantiating your own ColorSpace with the CS_GRAY type (ColorSpace.getInstance(ColorSpace.CS_GRAY) should do it I suppose). This object has a method called fromRGB which you should be able to use...
You probably need to widen the signed 16bit shorts to ints and remove the sign:
int ushort = (int)(shortData[x][y]) & 0xFFFF;
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_USHORT_GRAY);
short[] dataArray = ((DataBufferUShort)image.getRaster().getDataBuffer()).getData();
dataArray[y*width+x] = color;
ImageIO.write(image, "png", new File(path + ".png"));

Categories