Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

BufferedImage and int[] array

1,081 views
Skip to first unread message

Rick C. Hodgin

unread,
Apr 21, 2017, 11:29:07 AM4/21/17
to
I'm using JDK 1.8 on Linux.

I have a PNG file which is ARGB when I load it in GIMP, and would like
to obtain an array of int pixels to alter its contents directly from
within my app.

I am able to obtain byte[], but I don't know how to translate it to
int[] for direct 4-byte access per pixel.

I read on Stack Overflow that they aren't compatible unless the img
created is ARGB as well, meaning the ImageIO.read(new File("myfile.png"))
may have returned only a 24-bit RGB image, and not with the transparency
layer/channel. I also see on Stack Overflow that this may be a known
bug as other people have had this same issue in the past.

If true, how would I force it to read in and create it as an ARGB layer
even if it doesn't think the alpha channel is there? And if I cannot,
do I read it in in whatever format it's in, create a second image of the
same size but with 32-bit ARGB for the color depth, and then do some kind
of BitBlt operation to paint the pixel bits into the other image?

I come from a Win32 GDI and C/C++ background where I handle most of the
low-level drawing through custom functions. I'm not sure what the
equivalent operation is in Java.

-----
I am basically trying to load an image, obtain an array to the raw
pixel data so I can manipulate each pixel directly in various ways,
including a colorize() algorithm, invert(), putBorder(), etc.

Thank you,
Rick C. Hodgin

Eric Douglas

unread,
Apr 21, 2017, 11:54:16 AM4/21/17
to
On Friday, April 21, 2017 at 11:29:07 AM UTC-4, Rick C. Hodgin wrote:
> -----
> I am basically trying to load an image, obtain an array to the raw
> pixel data so I can manipulate each pixel directly in various ways,
> including a colorize() algorithm, invert(), putBorder(), etc.
>
> Thank you,
> Rick C. Hodgin

I've never had a problem dealing with images and only using byte[] array. I didn't even know images could or should be referenced as int[] array. So I'd need specifics on what you're trying to do, either some code you wrote that's not working and/or the stackoverflow post you mentioned. Otherwise I can only assume you're looking for this:
https://stackoverflow.com/questions/12154090/creating-8-bit-image-from-byte-array

Rick C. Hodgin

unread,
Apr 21, 2017, 12:03:19 PM4/21/17
to
The underlying data in the byte[] array should already be in that
exact int[] format. If I could cast the byte[] array into an int[],
then I could reference it as an int 4-bytes at a time.

Basically, I'm trying to do that without having to convert it as
the Stack Overflow link above indicates, because I want to be able
to access the byte[] data as that int[] form at any time.

Here's a reference on Stack Overflow:

http://stackoverflow.com/questions/20852641/bufferedimage-int-pixels-and-rendering-how-do-they-work-they-work-together

It uses this code:

int[] pixels = ((DataBufferInt)image.getRaster().getDataBuffer()).getData();

That apparently works when you have a 4-byte color depth, but if it's
not 4-bytes (32-bit) it doesn't work. That's understandable, so I
need to know how to convert whatever format is loaded with the
IoImage.read() to then create a BufferedImage that is in 4-byte form?

Eric Douglas

unread,
Apr 21, 2017, 1:41:28 PM4/21/17
to
On Friday, April 21, 2017 at 12:03:19 PM UTC-4, Rick C. Hodgin wrote:
> That apparently works when you have a 4-byte color depth, but if it's
> not 4-bytes (32-bit) it doesn't work. That's understandable, so I
> need to know how to convert whatever format is loaded with the
> IoImage.read() to then create a BufferedImage that is in 4-byte form?
>
> Thank you,
> Rick C. Hodgin

Here again it would help if you have some source code that's not working to debug. I'm going to guess the image bytes you have are file bytes.

final byte[] contents;
InputStream myFileInputStream;
File myImgFile = new File("c:/image.png");
myFileInputStream = new FileInputStream(myImgFile);
contents = new byte[myFileInputStream.available()];
myFileInputStream.read(contents);
myFileInputStream.close();

Then you can get an image from those bytes.

ByteArrayInputStream myByteArrayInputStream;
BufferedImage myBufferedImage = null;
myByteArrayInputStream = new ByteArrayInputStream(contents);
final MemoryCacheImageInputStream mciis = new MemoryCacheImageInputStream(myByteArrayInputStream);
myBufferedImage = ImageIO.read(mciis);

Then you can grab the int[] reference.
int[] pixels = ((DataBufferInt)myBufferedImage.getRaster().getDataBuffer()).getData();

There is no casting the byte[]. I think that stackoverflow you linked explains the int[] well. What else are you missing?

Eric Douglas

unread,
Apr 21, 2017, 1:47:01 PM4/21/17
to
On Friday, April 21, 2017 at 1:41:28 PM UTC-4, Eric Douglas wrote:
> final byte[] contents;
> InputStream myFileInputStream;
> File myImgFile = new File("c:/image.png");
> myFileInputStream = new FileInputStream(myImgFile);
> contents = new byte[myFileInputStream.available()];
> myFileInputStream.read(contents);
> myFileInputStream.close();

While using .available() to read the entire stream often just works on local files, or files embedded in the jar, there is a more reliable stream method.

public static byte[] getStreamBytes(final InputStream is) throws IOException {
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
int bytesRead = 0;
while (bytesRead > -1) {
bytesRead = Math.max(is.available(), 1);
final byte[] buf = new byte[bytesRead];
bytesRead = is.read(buf);
if (bytesRead > 0) {
baos.write(buf, 0, bytesRead);
}
}
baos.flush();
baos.close();
return baos.toByteArray();
}

Rick C. Hodgin

unread,
Apr 21, 2017, 2:13:45 PM4/21/17
to
On Friday, April 21, 2017 at 1:41:28 PM UTC-4, Eric Douglas wrote:
> On Friday, April 21, 2017 at 12:03:19 PM UTC-4, Rick C. Hodgin wrote:
> > That apparently works when you have a 4-byte color depth, but if it's
> > not 4-bytes (32-bit) it doesn't work. That's understandable, so I
> > need to know how to convert whatever format is loaded with the
> > IoImage.read() to then create a BufferedImage that is in 4-byte form?
> >
> > Thank you,
> > Rick C. Hodgin
>
> Here again it would help if you have some source code that's not working
> to debug. I'm going to guess the image bytes you have are file bytes.

I'm using NetBeans 8.0.2 on Linux, and here's my source code:

http://www.libsf.org:8990/projects/LIB/repos/libsf/browse/king/keyboard_driver/gui

It didn't save the project apparently, so you can't just load it, but
here is the exact source file:

Line 180:
pixels = ((DataBufferInt)img.getRaster().getDataBuffer()).getData();
http://www.libsf.org:8990/projects/LIB/repos/libsf/browse/king/keyboard_driver/gui/src/gui/BufferedImage3.java

Throws an exception saying DataBufferByte cannot be cast to DataBufferInt.

> final byte[] contents;
> InputStream myFileInputStream;
> File myImgFile = new File("c:/image.png");
> myFileInputStream = new FileInputStream(myImgFile);
> contents = new byte[myFileInputStream.available()];
> myFileInputStream.read(contents);
> myFileInputStream.close();
>
> Then you can get an image from those bytes.
>
> ByteArrayInputStream myByteArrayInputStream;
> BufferedImage myBufferedImage = null;
> myByteArrayInputStream = new ByteArrayInputStream(contents);
> final MemoryCacheImageInputStream mciis = new MemoryCacheImageInputStream(myByteArrayInputStream);
> myBufferedImage = ImageIO.read(mciis);
>
> Then you can grab the int[] reference.
> int[] pixels = ((DataBufferInt)myBufferedImage.getRaster().getDataBuffer()).getData();
>
> There is no casting the byte[]. I think that stackoverflow you linked
> explains the int[] well. What else are you missing?

The way I have applied it (using another Stack Overflow link, and one
of several that I've looked at) doesn't work.

Eric Douglas

unread,
Apr 21, 2017, 3:12:53 PM4/21/17
to
On Friday, April 21, 2017 at 2:13:45 PM UTC-4, Rick C. Hodgin wrote:
>
> The way I have applied it (using another Stack Overflow link, and one
> of several that I've looked at) doesn't work.
>
> Thank you,
> Rick C. Hodgin

Well, if you Google that problem, the first result looks like they did the same thing.
http://stackoverflow.com/questions/15839223/java-awt-image-databufferbyte-cannot-be-cast-to-java-awt-image-databufferint

So I test your code with a transparent PNG and it does show the ImageIO.read() statement returned a type 6.
http://docs.oracle.com/javase/8/docs/api/constant-values.html#java.awt.image.BufferedImage.TYPE_3BYTE_BGR

So if you want to manipulate ints it seems you need a TYPE_INT (1,2,3,4).
So what do you get if you convert it?
Insert this code right after the ImageIO.read().
final GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
final GraphicsDevice gd = ge.getDefaultScreenDevice();
final GraphicsConfiguration gc = gd.getDefaultConfiguration();
final BufferedImage newimg = gc.createCompatibleImage(img.getWidth(), img.getHeight(), BufferedImage.TYPE_INT_ARGB);
// Draw the image on to the buffered image
final Graphics2D myImageGraphics = newimg.createGraphics();
myImageGraphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
myImageGraphics.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
myImageGraphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
myImageGraphics.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
myImageGraphics.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
myImageGraphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
myImageGraphics.fillRect(0, 0, img.getWidth(), img.getHeight());
myImageGraphics.setComposite(AlphaComposite.SrcOver);
myImageGraphics.drawImage(img, 0, 0, null);
myImageGraphics.dispose();
img = newimg;

and of course modify your imports
import java.awt.AlphaComposite;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;

Eric Douglas

unread,
Apr 21, 2017, 4:24:47 PM4/21/17
to
On Friday, April 21, 2017 at 2:13:45 PM UTC-4, Rick C. Hodgin wrote:
> http://www.libsf.org:8990/projects/LIB/repos/libsf/browse/king/keyboard_driver/gui/src/gui/BufferedImage3.java
>

I tested with the change I suggested and it got past your error so I assume that fixes the problem you're asking about here, though I crashed on the ImageIO.write() because I didn't have valid file names in there.
I put in valid local files to test that. The first write worked fine, the other 2 failed, so there appears to be something wrong with your rgba() method.
With a real lack of comments in your code I'm not sure what each section is trying to accomplish.
Taking a guess your invert method wants to turn the image upside down, I googled that and found this working code.

public void invert(final BufferedImage img) {
WritableRaster raster = img.getRaster();
int h = raster.getHeight();
int w = raster.getWidth();
int x0 = raster.getMinX();
int y0 = raster.getMinY();
for (int x = x0; x < x0 + w; x++){
for (int y = y0; y < y0 + h / 2; y++){
int[] pix1 = new int[4];
pix1 = raster.getPixel(x, y, pix1);
int[] pix2 = new int[4];
pix2 = raster.getPixel(x, y0 + h - 1 - (y - y0), pix2);
raster.setPixel(x, y, pix2);
raster.setPixel(x, y0 + h - 1 - (y - y0), pix1);
}
}
return;

Either I'm missing something, or you need to fix your argb method, or you need to get rid of that and change the other methods to do something like the invert code here.

Rick C. Hodgin

unread,
Apr 21, 2017, 4:37:47 PM4/21/17
to
On Friday, April 21, 2017 at 4:24:47 PM UTC-4, Eric Douglas wrote:
> With a real lack of comments in your code I'm not sure what each
> section is trying to accomplish.
> Taking a guess your invert method wants to turn the image upside down,
> I googled that and found this working code.

That code was all written last night and when I ran into the issue
with reading in a transparent enabled PNG file and it losing the
alpha channel I sort of stopped.

The algorithm is inverting the color. This line reverses the color
of each pixel color channel:

Line 275:
pixels[offset] = rgba(255 - red, 255 - grn, 255 - blu, 0);
http://www.libsf.org:8990/projects/LIB/repos/libsf/browse/king/keyboard_driver/gui/src/gui/BufferedImage3.java

The 255 - red computes the inverted color of the red channel, and
it repeats for green, blue, and sets the alpha channel to 0, which
is a bug and should be using the originally derived alp value on
line 220, once it's copied down into that function. :-)

I'll look at your solution. I'm really thinking I don't need to
do anything other than load in the PNG as a 3-byte BGR format,
and then create a second PNG in the 4-byte ARGB format, and then
obtain WritableRaster objects and draw the image from one to the
other, which should handle the translation, and then delete the
3-byte BGR version.

Do you feel so inclined to write code to test that method out?
I only ask because you've been far more helpful than I would've
expected someone to be on Usenet. :-) I plan on working on it
tonight. I've only programmed in Java one time previously back
in 2011 on a project used to automate tests on hardware:

Office Productivity Benchmark
https://github.com/RickCHodgin/opbm

A lot of code written mostly from May-July 2011. I'm sure it
has lots of errors in it, but I was on my own in trying to do
everything. I used Stack Overflow and the javadoc help files.

That one was written in NetBeans 8.0 I believe.

Rick C. Hodgin

unread,
Apr 21, 2017, 4:40:18 PM4/21/17
to
On Friday, April 21, 2017 at 4:37:47 PM UTC-4, Rick C. Hodgin wrote:
> ...I've only programmed in Java one time previously back
> in 2011 on a project used to automate tests on hardware:
>
> Office Productivity Benchmark
> https://github.com/RickCHodgin/opbm
>
> A lot of code written mostly from May-July 2011. I'm sure it
> has lots of errors in it, but I was on my own in trying to do
> everything. I used Stack Overflow and the javadoc help files.

I don't mean lots of errors, but I mean that I did lots of things
in non-standard ways, or ways other Java devs would not code in.

I did it that way from my predominately C/C++ background.

Eric Douglas

unread,
Apr 21, 2017, 4:54:43 PM4/21/17
to
On Friday, April 21, 2017 at 4:37:47 PM UTC-4, Rick C. Hodgin wrote:
> That code was all written last night and when I ran into the issue
> with reading in a transparent enabled PNG file and it losing the
> alpha channel I sort of stopped.
>
> The algorithm is inverting the color. This line reverses the color
> of each pixel color channel:
>

I believe I did figure out the invert was trying to invert the colors not the horizontal. Change the pixels line in the invert to pass the actual alpha:
pixels[offset] = rgba(255 - red, 255 - grn, 255 - blu, (rgba & 0xff000000) >> 24);

Then change the rgba method to just add them.
return(red + (grn << 8) + (blu << 16) + (alp << 24));

Eric Douglas

unread,
Apr 21, 2017, 4:58:24 PM4/21/17
to
On Friday, April 21, 2017 at 4:37:47 PM UTC-4, Rick C. Hodgin wrote:
>
> Do you feel so inclined to write code to test that method out?
> I only ask because you've been far more helpful than I would've
> expected someone to be on Usenet. :-) I plan on working on it
> tonight. I've only programmed in Java one time previously back
> in 2011 on a project used to automate tests on hardware:

We won't "do your homework for you" but I do love a good puzzle.

>
> Office Productivity Benchmark
> https://github.com/RickCHodgin/opbm
>
> A lot of code written mostly from May-July 2011. I'm sure it
> has lots of errors in it, but I was on my own in trying to do
> everything. I used Stack Overflow and the javadoc help files.
>
> That one was written in NetBeans 8.0 I believe.
>
I use Eclipse. We have 2 developers in a small company. I write all the Java.

Rick C. Hodgin

unread,
Apr 21, 2017, 4:59:49 PM4/21/17
to
LOL! Well, they should be OR operations, not AND:

return (red | (grn << 8) | (blu << 16) | <alp << 24);

I code like that all of the time. I know what I'm intending, but it
literally gets translated out of my fingers differently than what's
in my mind. It's very frustrating at times. A symptom of dylsexia
and the associated family of the spectrum. :-)

Rick C. Hodgin

unread,
Apr 21, 2017, 5:06:35 PM4/21/17
to
On Friday, April 21, 2017 at 4:58:24 PM UTC-4, Eric Douglas wrote:
> On Friday, April 21, 2017 at 4:37:47 PM UTC-4, Rick C. Hodgin wrote:
> >
> > Do you feel so inclined to write code to test that method out?
> > I only ask because you've been far more helpful than I would've
> > expected someone to be on Usenet. :-) I plan on working on it
> > tonight. I've only programmed in Java one time previously back
> > in 2011 on a project used to automate tests on hardware:
>
> We won't "do your homework for you" but I do love a good puzzle.

I'm 47 years old. I have written all of the bitmap algorithms
already in C/C++. I'm very close to using JNI to complete this
task as well:

http://www.libsf.org:8990/projects/LIB/repos/libsf/browse/source/vjr/source/bitmaps
http://www.visual-freepro.org/wiki/index.php/Rick_C._Hodgin

> > Office Productivity Benchmark
> > https://github.com/RickCHodgin/opbm
> >
> > A lot of code written mostly from May-July 2011. I'm sure it
> > has lots of errors in it, but I was on my own in trying to do
> > everything. I used Stack Overflow and the javadoc help files.
> >
> > That one was written in NetBeans 8.0 I believe.
> >
> I use Eclipse. We have 2 developers in a small company. I write
> all the Java.

I work predominately in Visual FoxPro and C/C++ for a company with
about 50 employees, though there are only seven in my division.

Knute Johnson

unread,
Apr 22, 2017, 12:28:42 PM4/22/17
to
What you want is a RescaleOp. In test6 I create an image with three
bars of red, green and blue. Using test5 I invert the pixel values as
you specified further down in these posts with a RescaleOp and the
result is an image with three bars of cyan, magenta and yellow.

import java.awt.*;
import java.awt.image.*;
import java.io.*;
import javax.imageio.*;

public class test6 {
public static void main(String... args) throws Exception {
BufferedImage img =
new BufferedImage(640,480,BufferedImage.TYPE_INT_RGB);
Graphics2D g = img.createGraphics();
g.setColor(Color.RED);
g.fillRect(0,0,213,480);
g.setColor(Color.GREEN);
g.fillRect(214,0,214,480);
g.setColor(Color.BLUE);
g.fillRect(428,0,213,480);
g.dispose();
ImageIO.write(img,"JPEG",new File("bars.jpg"));
}
}

import java.awt.image.*;
import javax.imageio.*;
import java.io.*;

public class test5 {
public static void main(String... args) throws Exception {
BufferedImage img = ImageIO.read(new File("bars.jpg"));
RescaleOp op = new RescaleOp(-1.0f,255f,null);
BufferedImage chg = op.filter(img,null);
ImageIO.write(chg,"JPEG",new File("bars2.jpg"));
}
}


--

Knute Johnson

Rick C. Hodgin

unread,
Apr 24, 2017, 10:34:16 AM4/24/17
to
Is this for the color invert operation? I notice it creates a new
BufferedImage. Is there a way to apply the operation on the bits
within the original image directly?

Eric Douglas

unread,
Apr 24, 2017, 11:04:43 AM4/24/17
to
test6 creates a dummy image, the input for test5, which just modifies an existing image.

Rick C. Hodgin

unread,
Apr 24, 2017, 11:17:20 AM4/24/17
to
On Saturday, April 22, 2017 at 12:28:42 PM UTC-4, Knute Johnson wrote:
Would it be possible to do this?

import java.awt.*;
import java.awt.image.*;
import java.io.*;
import javax.imageio.*;

public class test6 {
public static void main(String... args) throws Exception {
RescaleOp op = new RescaleOp(-1.0f,255f,null);
BufferedImage img =
new BufferedImage(640,480,BufferedImage.TYPE_INT_RGB);
Graphics2D g = img.createGraphics();
g.setColor(Color.RED);
g.fillRect(0,0,213,480);
g.setColor(Color.GREEN);
g.fillRect(214,0,214,480);
g.setColor(Color.BLUE);
g.fillRect(428,0,213,480);
g.dispose();

===> Something like this, where the input img bits are updated directly:
img = op.filter(img,null);
// Maintain img, now altered, as it was before
}
}

That's what I'm trying to do with my algorithms. Receive an existing
image and then process it in some way which directly updates its bits
without copying or creating a new image for output in the process.

Knute Johnson

unread,
Apr 24, 2017, 12:26:01 PM4/24/17
to
Yes however I'm pretty sure that if you use null as the second argument
to BufferredImageOp.filter that it creates a new BufferedImage. I think
if you put the same reference in the call to filter it is the same image
modified in place.

import java.awt.*;
import java.awt.image.*;
import java.io.*;
import javax.imageio.*;

public class test6 {
public static void main(String... args) throws Exception {
BufferedImage img =
new BufferedImage(640,480,BufferedImage.TYPE_INT_RGB);
Graphics2D g = img.createGraphics();
g.setColor(Color.RED);
g.fillRect(0,0,213,480);
g.setColor(Color.GREEN);
g.fillRect(213,0,214,480);
g.setColor(Color.BLUE);
g.fillRect(427,0,213,480);
g.dispose();

RescaleOp op = new RescaleOp(-1.0f,255f,null);
BufferedImage gmi = op.filter(img,img);
System.out.println(gmi.equals(img));
}
}

In this case the output is true. If you put null in the second argument
the output is false. I don't know if it is any faster, the cost of
creating a small BufferedImage is not that great.


--

Knute Johnson
0 new messages