converting gif image to pixels and then back to gif - java

My real goal is to read the values from a graph in GIF format, into some meaningful data structure but in order to get started I need to be able to read the colour of each pixel of the GIF in question.
In order to test this i want to save the segment of the GIF i am reading to file for visual analysis, but am having trouble.
after reading this post I attempted to do something similar, however my output GIF always comes out completely black.
can anyone tell me what i've misunderstood?
BufferedImage bi = ImageIO.read(new URL("http://upload.wikimedia.org/wikipedia/commons/3/36/Sunflower_as_GIF.gif"));
int x = 100;
int y = 100;
int width = 100;
int height = 100;
int[] data = grabPixels(bi, x, y, width, height);
BufferedImage img = createImage(data, width, height);
ImageIO.write(img, "gif", new File("part.gif"));
...
private int[] grabPixels(BufferedImage img, int x, int y, int width, int height)
{
try
{
PixelGrabber pg = new PixelGrabber(img, x, y, width, height, true);
pg.grabPixels();
if ((pg.getStatus() & ImageObserver.ABORT) != 0)
throw new RuntimeException("image fetch aborted or errored");
return convertPixels((int[]) pg.getPixels(), width, height);
}
catch (InterruptedException e)
{
throw new RuntimeException("interrupted waiting for pixels", e);
}
}
public int[] convertPixels(int[] pixels, int width, int height)
{
int[] newPix = new int[width * height * 3];
int n = 0;
for (int j = 0; j < height; j++)
{
for (int i = 0; i < width; i++)
{
int pixel = pixels[j * width + i];
newPix[n++] = (pixel >> 16) & 0xff;
newPix[n++] = (pixel >> 8) & 0xff;
newPix[n++] = (pixel) & 0xff;
}
}
return newPix;
}
private BufferedImage createImage(int[] pixels, int width, int height)
{
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
WritableRaster raster = (WritableRaster) image.getData();
raster.setPixels(0, 0, width, height, pixels);
return image;
}

All black sounds like zeros, as if the image hadn't loaded yet. You might check the result returned by grabPixels() or specify a timeout. Once you have a BufferedImage, you could use getRaster() and work with the WritableRaster.

Related

How to display a 48 bit RGB image (16 bit per channel) in JavaFX?

I'm using JavaFX and I have a 16bit grayscale image that I'm able to show with the following code:
public Image createNewImageFromArrayPixels(int[][] pixels) {
int width = pixels.length;
int height = pixels[0].length;
int[] buffer = from2DArrayTo1DArray(pixels);
ColorModel colorModel = new ComponentColorModel(
ColorSpace.getInstance(ColorSpace.CS_GRAY), //we have grayscale images
new int[]{16}, //bit depth: 16 bit per pixel
false,
false,
Transparency.OPAQUE,
DataBuffer.TYPE_INT); //every pixel has an integer intensity
WritableRaster raster = colorModel.createCompatibleWritableRaster(height, width);
DataBufferInt buff = (DataBufferInt) raster.getDataBuffer();
int[] bufferData = buff.getData();
System.arraycopy(buffer, 0, bufferData, 0, (buffer.length < bufferData.length ? buffer.length : bufferData.length));
BufferedImage bm = new BufferedImage(colorModel, raster, colorModel.isAlphaPremultiplied(), null);
Image img = SwingFXUtils.toFXImage(bm, null);
return img;
}
Now I want to transform it in a 48bit RGB image (16bit per channel), but I can't understand how.
At the moment I'm able to create a RGB 24bit image (8 bit per channel) by taking the int value of a pixel from the grayscale image and building manually the bytes that will compose the pixels with the following code:
private Image createRGBImageFromGrayPixels(int[][] pixels) {
int width = pixels.length;
int height = pixels[0].length;
BufferedImage bm = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
int converted = from16to8(pixels[y][x]);
System.out.println("original " + pixels[y][x] + " = " + converted + " = " + from8to16(converted));
int rgb = converted;
rgb = (rgb << 8) + converted;
rgb = (rgb << 8) + converted;
bm.setRGB(x, y, rgb);
}
}
Image img = SwingFXUtils.toFXImage(bm, null);
return img;
}
private int from16to8(int value) {
int originalStart = 0;
int originalEnd = 65535;
int newStart = 0;
int newEnd = 255;
double scale = (double)(newEnd - newStart) / (originalEnd - originalStart);
double res = newStart + ((value - originalStart) * scale);
System.out.println(res);
int result = Math.round(Math.round(res));
return result;
}
Similarly, I'm also able to create the same structure for 16bits obtaining the desired rgb value, but it is a long and is not accepted by the setRGB() method, so I'm not able to create the bufferedImage, whose type I can't specify.
Can anyone help me with this final steps, please? Thank you in advance.
private Image createRGBImageFromGrayPixels_16(int[][] pixels) {
int width = pixels.length;
int height = pixels[0].length;
BufferedImage bm = new BufferedImage(width, height, BufferedImage...); //BufferedImage.TYPE ???
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
long rgb = pixels[y][x];
rgb = (rgb << 16) + pixels[y][x];
rgb = (rgb << 16) + pixels[y][x];
System.out.println(pixels[y][x] + "\t->\t" + rgb);
System.out.println();
bm.setRGB(x, y, rgb); //ERROR: long type for rgb is not accepted!
}
}
Image img = SwingFXUtils.toFXImage(bm, null);
return img;
}
If needed, I can also install external jar libraries (obviously, only if opersource) that can help me achieving this goal.

Converting subimage to RGB-A

I am working on a 2D platform game and I have a sprite sheet which includes the sprites of tiles and blocks.
I noticed that there was a pink-ish background behind the transparent sprites so I thought that Java wasn't loading the sprites as PNG and I tried to re-draw the sprite on a new bufferedImage, pixel by pixel checking if the pixel was R=255, G=63, B=52 but unfortunately, the code wasn't able to detect that either and at this point I have no more options left to try.
I made sure that the "pink" color values are correct by using a color picker.
original spritesheet (transparent):
The class that loads the sprite(s) is:
public class SpriteSheet {
private BufferedImage image;
public SpriteSheet(BufferedImage image) {
this.image = image;
}
public BufferedImage grabImage(int col, int row, int width, int height) {
BufferedImage alpha = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
BufferedImage img = image.getSubimage(
(col * width) - width,
(row * height) - height,
width,
height);
int w = img.getWidth();
int h = img.getHeight();
for(int y = 0; y < h; y++) {
for(int x = 0; x < w; x++) {
int pixel = img.getRGB(x, y);
int red, green, blue;
red = (pixel >> 16) & 0xff;
green = (pixel >> 8) & 0xff;
blue = (pixel) & 0xff;
if(red == 255 && green == 63 && blue == 52)
alpha.setRGB(x, y, new Color(0, 0, 0, 0).getRGB());
else
alpha.setRGB(x, y, pixel);
}
}
return alpha;
}
}
the class that loads the sprite sheet is:
public class Texture {
SpriteSheet bs, ss;
private BufferedImage block_sheet = null;
public BufferedImage[] block = new BufferedImage[3];
public Texture() {
BufferedImageLoader loader = new BufferedImageLoader();
try {
block_sheet = loader.loadImage("/tiles.png");
} catch(Exception e) {
e.printStackTrace();
}
bs = new SpriteSheet(block_sheet);
getTextures();
}
private void getTextures() {
block[0] = bs.grabImage(1, 1, 32, 32);
block[1] = bs.grabImage(2, 1, 32, 32);
block[2] = bs.grabImage(4, 1, 32, 32);
}
}
How do I get rid of the pink-ish background and keep transparency?
I dont understand why you're using subImage.
try {
BufferedImage img = ImageIO.read(new File("D:/image.png"));
for (int i = 0; i < img.getWidth(); i++) {
for (int j = 0; j < img.getHeight(); j++) {
Color pixelcolor = new Color(img.getRGB(i, j));
int r = pixelcolor.getRed();
int g = pixelcolor.getGreen();
int b = pixelcolor.getBlue();
if (r == 255 && g == 63 && b == 52) {
int rgb = new Color(255, 255, 255).getRGB();
img.setRGB(i, j, rgb);
}
}
}
ImageIO.write(img, "png", new File("D:/transparent.png"));
} catch (Exception e) {
System.err.println(e.getMessage());
}
cough, It worked all along, I had forgotten to disable the test blocks which was representing the blocks. Realized this after some time.
So the transparency was working fine. I just saw the rectangle i was drawing behind it.

Java BufferedImage changes the RGB that I assign

I'm trying to create a program that, when selecting an image, reverses the colors of the image.
But when I run the code, my BufferedImage changes the RGB I assigned earlier.
I leave you the code that reverses the image.
image is a static BufferedImage.
public static void saveImage(File input, File output) throws IOException{
image = ImageIO.read(input);
for (int x = 0; x < image.getWidth(); x++) {
for (int y = 0; y < image.getHeight(); y++) {
boolean isTransparent = isTransparent(x, y);
if (!isTransparent) {
Color color = new Color(image.getRGB(x, y));
int r = 255 - color.getRed();
int g = 255 - color.getGreen();
int b = 255 - color.getBlue();
color = new Color(r, g, b);
int rgb = color.getRGB();
image.setRGB(x, y, rgb);
System.out.println(rgb+" --> "+image.getRGB(x, y));
}
}
}
ImageIO.write(image, "png", output);
}
public static boolean isTransparent(int x, int y) {
int pixel = image.getRGB(x, y);
return (pixel >> 24) == 0x00;
}

get RGB-YCbCr components of image

I want to show the jpeg image R_G_B channels as separated images in jlabel and the Y-Cb-Cr channels as well, I got the arrays but don't know how to convert them to images
///
Edit:
thanX very much , this is the method I'm writing ,Now It can display just the upper left quarter of the image ,and show it in a blue color whatever the color channel was?
public void getRGB_YCC(int width,int height,String inFileName) {
R=new int[height][width];G=new int[height][width];
B=new int[height][width];Y=new int[height][width];
Cb1=new int[height][width];Cr1=new int[height][width];
final int values[] = new int[width * height];
int r, g, b, Y_ch,Cb,Cr, y, x;
final PixelGrabber grabber = new PixelGrabber(image.getSource(), 0, 0,width,height, values, 0, width);
try {
if (grabber.grabPixels() != true) {
try {
throw new AWTException("Grabber returned false: " + grabber.getStatus());
} catch (final Exception e) {};
}
} catch (final InterruptedException e) {};
int index = 0;
for (y = 0; y < height; ++y) {
for (x = 0; x < width; ++x) {
r = values[index] >> 16 & 0xff;
g = values[index] >> 8 & 0xff;
b = values[index] & 0xff;
Y_ch= (int)(0.299 * r + 0.587 * g + 0.114 * b);
Cb= 128 + (int) (-0.16874 * r - 0.33126 * g + 0.5 * b);
Cr= 128 + (int)(0.5 * r - 0.41869 * g - 0.08131 * b);
R [y][x]=r;
G [y][x]=g;
B [y][x]=b;
Y [y][x]=Y_ch;
Cb1[y][x]=Cb;
Cr1[y][x]=Cr;
index++;
}
}
BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
int[] pixels = ((DataBufferInt)img.getRaster().getDataBuffer()).getData();
for( y=0;y<height;y++)
{
for( x=0;x<width;x++)
{
pixels[x + y*width] =R[y][x]<<16;
}
}
jLabel15.setIcon(new ImageIcon(img));
}
A simple and fast way to get an array of pixels into an image is using BufferedImage:
This example creates a grayscale 8 bit image and retrieves a 'pixel buffer' for it:
BufferedImage img = new BufferedImage(w, h, BufferedImage.TYPE_BYTE_GRAY);
byte[] pixels = ((DataBufferByte)img.getRaster().getDataBuffer()).getData();
This also works with RGB:
BufferedImage img = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
int[] pixels = ((DataBufferInt)img.getRaster().getDataBuffer()).getData();
You now can set pixels by just writing to the pixels array like pixels[x + y * w] = value and the results are instantly visible.

How to initialize BufferedImage fast in Java?

I have the following Java code:
public static BufferedImage createImage(byte[] data, int width, int height)
{
BufferedImage res = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY);
byte[] rdata = ((DataBufferByte)res.getRaster().getDataBuffer()).getData();
for (int y = 0; y < height; y++) {
int yi = y * width;
for (int x = 0; x < width; x++) {
rdata[yi] = data[yi];
yi++;
}
}
return res;
}
Is there a faster way to do this?
In C++ I would use memcpy, but in Java?
Or maybe it is possible to initialize the result image with the passed data directly?
Well, to copy the array quickly you can use System.arraycopy:
System.arraycopy(data, 0, rdata, 0, height * width);
I don't know about initializing the BufferedImage to start with though, I'm afraid.
Have you tried:
res.getRaster().setDataElements(0, 0, width, height, data);
?

Categories