I'm currently working on a dynamic Animation Loader for Characters in a game and for that I'm in need of detecting if the current frame is completely blank in order to stop loading more sprites.
This is what I'm currently using to find out if the current image is blank:
public static boolean isBlankImage(BufferedImage b) {
byte[] pixels1 = getPixels(b);
byte[] pixels2 = getPixels(getBlankImage(b.getWidth(), b.getHeight()));
return Arrays.equals(pixels1, pixels2);
}
private static BufferedImage getBlankImage(int width, int height) {
return new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
}
private static byte[] getPixels(BufferedImage b) {
byte[] pixels = ((DataBufferByte) b.getRaster().getDataBuffer()).getData();
return pixels;
}
However, as soon as I run it, I get this annoying error:
Exception in thread "Thread-0" java.lang.ClassCastException:
java.awt.image.DataBufferInt cannot be cast to java.awt.image.DataBufferByte
I've tried switching the casting type but all I get in return is:
Exception in thread "Thread-0" java.lang.ClassCastException:
java.awt.image.DataBufferByte cannot be cast to java.awt.image.DataBufferInt
I've searched all over the place for an answer to no avail, so here's my question: Is there a better functional way to check if an image is fully transparent ?
Any help will be greatly appreciated.
The method must be return a byte array, you are trying convert a DataBuffer in a DataBufferByte.
I have changed the name getPixels to getByteArray. Since it is not the same.
Try this:
private static byte[] getByteArray(BufferedImage img) {
byte[] imageInByte = null;
String format = "jpeg"; //Needs a image TYPE
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(img, format, baos);
baos.flush();
imageInByte = baos.toByteArray();
baos.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return imageInByte;
}
The blank image's DataBuffer is indeed an instance of DataBufferInt while your original image has a buffer of type DataBufferByte.
You should create your empty image based on the type of the image to compare with:
private static BufferedImage getBlankImage(int width, int height, int type) {
return new BufferedImage(width, height, type);
}
and call it this way:
getBlankImage(b.getWidth(), b.getHeight(), b.getType())
Notice that in terms of performance and memory usage it may be better to create the empty image only once (or once for each image type which may occur).
Probably the image type and size are constant and written wherever the actual images are created.
Now you have a proper empty image and may test its equality as in Is there a simple way to compare BufferedImage instances?:
public static boolean compareImages(BufferedImage imgA, BufferedImage imgB) {
int width = imgA.getWidth();
int height = imgA.getHeight();
// Loop over every pixel.
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
// Compare the pixels for equality.
if (imgA.getRGB(x, y) != imgB.getRGB(x, y)) {
return false;
}
}
}
return true;
}
Related
This post is a follow up to :
ImageIO.read can't read ByteArrayInputStream (image processing)
Similar to the OP, I am getting a null pointer whenever I try to read from my ByteArrayInputStream (as it should, as explained by the top answer). Noticing this, I have implemented the code from the #haraldK 's answer from the post above in order to correct this issue, but I have run into another problem. I have the following code:
byte[] imageInByteArr = ...
// convert byte array back to BufferedImage
int width = 1085;
int height = 696;
BufferedImage convertedGrayScale = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY);
convertedGrayScale.getRaster().setDataElements(0, 0, width, height, imageInByteArr );
try {
ImageIO.write(convertedGrayScale, "jpg", new File("C:\\test.jpg"));
}
catch (IOException e) {
System.err.println("IOException: " + e);
}
Upon execution, I run into a java.lang.ArrayIndexOutOfBoundsException: null error on the line right before the try/catch block. My first thought was that this null pointer was arising for not having a file in my C drive called test.jpg. I adjusted to fix that worry, yet I am still getting the same null pointer issue at convertedGrayScale.getRaster().setDataElements(0, 0, width, height, imageInByteArr );. Why is this happening?
On another note, aside from writing the file uining ImageIO, is there ANY other way for me to convert the byte[] into a visual representation of an image? I have tried to just print the array onto a file and saving it as a '.jpg', but the file will not open. Any suggestions will help. To summarize, I am looking to convert a byte[] into an image and save it OR render it onto a browser. Whichever is easier/doable.
it appears that your imageInByteArr is too short. I was able to get the same error you get from this
public static void main(String[] args) {
int width = 1085;
int height = 696;
byte[] imageInByteArr = new byte[width ];
BufferedImage convertedGrayScale = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY);
convertedGrayScale.getRaster().setDataElements(0, 0, width, height, imageInByteArr);
}
when using width*height for size of imageInByteArr or anything bigger i get no error, but when it's smaller than the data you are trying to update it throws the exception.
I ideally need to have offline access to information of the altitude of the terrain of Mexico on an Android app I'm developing. I downloaded a .bil file and converted it to a .tif file with QGIS, and the resulting file is almost 900 MB.
I don'I know if it would work, I'm still learning to develop Android apps, but I was planning to store it in the SD card and I was wondering if it could be possible to access to a single pixel without reading the whole image, because I know that's impossible.
Can anyone tell me if it is possible? And if it is, how to do it? Or any other way to get the information I need maybe converting the .bil file to other format or something like that.
Thanks for answering.
Tiff has images stored as rows of bytes starting at defined offsets. So you can easily retrieve single pixel and certainly no need to load the full image.
If you open any tif file in hex editor you will see that first 4 bytes mark tiff by code. And next 4 bytes give offset for metadata about tif image.
Use random access file to open image tif file, then seek the offset and you land into metadata space.From here you can pick offset of required pixel. Then go and get it..
We have tiff for this purpose only. That is to access individual pixels. If we needed full load of image then jpeg or BMP was enough.
check this link for full code:- full example to decode tiff image
package com.tif;
import android.os.*;import android.content.*;import android.app.*;import android.widget.*;import android.view.*;
import android.view.View.*;import android.graphics.*;import java.io.*;import java.util.*;import android.util.*;
import java.lang.*;import java.nio.*;import java.nio.channels.*;
public class Main extends Activity
{
private static final int CLEAR_CODE = 256;
private static final int EOI_CODE = 257;
long bytesCount=0L;
ScrollView sv;TextView tv;ImageView iv;
List intList;
long[] stripOffs,stripBytes;
byte[] bytes,ubytes,bmpBytes;
ByteBuffer bBuff;
BitBuffer bitBuff;
int entries,type,tag;
long count,value,ifd,stripAt,stripCount,stripBytesAt,rows,cols;
String txt="Null",path="",decompressed="";
String[] info= {"width","length","bitsPerSample","Compression","PhotometricInterpretation","FillOrder","StripOffsets","SamplesPerPixel","RowsPerStrip"
,"StripBytes","XResolution","YResolution","PlanarConfig","ResolutionUnit","extra","NextIFD"};
Bitmap bmp=null;
class DotsView extends View
{
int i = 0;Bitmap bmp;Canvas cnv;Rect bounds;Paint p;int width,height;
int alfa,red,green,blue;
public DotsView(Context context ,int width ,int height)
{
super(context);
this.width = width;
this.height = height;
bmp = Bitmap.createBitmap(width,height,Bitmap.Config.ARGB_8888);
cnv = new Canvas(bmp);
bounds = new Rect(0 , 0, width,height);
p = new Paint();
}
#Override
protected void onDraw(Canvas c)
{
for(int i=0;i<width;i++)
for(int j=0;j<height;j++)
{
for(int pix=0;pix<3;pix++)
{
if(pix==0)blue=bmpBytes[i+j+pix];
if(pix==1)green=bmpBytes[i+j+pix];
if(pix==2)red=bmpBytes[i+j+pix];
}
p.setColor( Color.argb(255, red,green,blue) );
cnv.drawPoint(i,j, p);
}
c.drawBitmap(bmp, null, bounds , null);
invalidate();
}
}
public int myShort(short sh)
{ int i;
ByteBuffer shortBuff=ByteBuffer.allocate(4);
shortBuff.order(ByteOrder.BIG_ENDIAN);shortBuff.putShort(sh);shortBuff.rewind();
shortBuff.order(ByteOrder.LITTLE_ENDIAN);sh=shortBuff.getShort();
if(sh<0)i=(int)(sh+32768); else i=(int)sh;
return i;
}
public long myInt(int i)
{ long l=0L;
ByteBuffer intBuff=ByteBuffer.allocate(4);
intBuff.order(ByteOrder.BIG_ENDIAN);intBuff.putInt(i);intBuff.rewind();
intBuff.order(ByteOrder.LITTLE_ENDIAN); i=intBuff.getInt();
if(i<0)l=(long)(i+2147483648L); else l=(long)i;
return l;
}
public String tagInfo(int tag)
{ int i=0;
switch(tag)
{case 256: i=0;break;case 257: i=1;break;case 258: i=2;break;case 259: i=3;break;case 262: i=4;break;case 266: i=5;break;
case 273: i=6;break;case 277: i=7;break;case 278: i=8;break;case 279: i=9;break;case 282: i=10;break;case 283: i=11;break;
case 284: i=12;break;case 296: i=13;break;case 1496: i=14;break;case 0: i=15;break;
}
return info[i];
}
public void extractTif()
{
String taginfo="";String strVal="";
FileInputStream fis;BufferedInputStream bis;DataInputStream dis;
path=Environment.getExternalStorageDirectory().getPath();
path=path+"/DCIM"+"/kpd.tif";
try {
fis=new FileInputStream(path);bis=new BufferedInputStream(fis);dis=new DataInputStream(bis);
dis.skip(4);ifd=myInt(dis.readInt());
txt="TIFF-IFD: "; txt=txt+ifd;
dis.skip(ifd-8); entries=myShort(dis.readShort());
txt=txt+"\nNo.OfEntries="+entries;
for(int i=0;i<=entries;i++)
{ tag=myShort( dis.readShort() );taginfo=tagInfo(tag);
type=myShort( dis.readShort() );count=myInt( dis.readInt() );value=myInt( dis.readInt() );
if(type==3)strVal="Value="; else strVal="Offset=";
if( strVal.equals("Offset=") )
{
if( taginfo.equals("StripOffsets") ){stripAt=value;stripCount=count;}
if( taginfo.equals("StripBytes") ){stripBytesAt=value;}
}
if( taginfo.equals("width") ){cols=value;}
if( taginfo.equals("length") ){rows=value;}
txt=txt+"\ntag="+tag+" "+tagInfo(tag)+",type="+type+",count="+count+strVal+value;
}
dis.close();bis.close();fis.close();
}catch(Exception e) {txt=txt+"\nerror="+e.toString();}
txt=txt+"\nNo.OfStrips="+stripCount+",array of strip locations at: "+stripAt+" and array of bytesPerStrip at "+stripBytesAt ;
extractBMP();
}
public void extractBMP()
{try{ File f=new File(path);RandomAccessFile raf=new RandomAccessFile(f,"r");
raf.seek(stripAt);stripOffs=new long[(int)stripCount];
txt=txt+"\nArray Of Image Offsets=";
for(int i=0;i<stripCount;i++){stripOffs[i]=myInt( raf.readInt() ); txt=txt+","+stripOffs[i]; }
raf.seek(stripBytesAt); stripBytes=new long[(int)stripCount];
txt=txt+"\nArray Of Strip Bytes =";
for(int i=0;i<stripCount;i++){stripBytes[i]=myInt(raf.readInt()); txt=txt+","+stripBytes[i];bytesCount+=stripBytes[i];}
txt=txt+stripBytes;
bBuff =ByteBuffer.allocate((int)(rows*cols*3));
for(int i=0;i<stripCount;i++)
{
bytes =new byte[(int)stripBytes[i]];
raf.seek(stripOffs[i]);
raf.read(bytes);
bBuff.put(lzwUncompress(bytes));
bytes=null;
}
txt=txt+"\nBuffered Image Bytes Size="+bBuff.position();
bBuff.rewind();
bmpBytes=new byte[bBuff.remaining()];
bmpBytes=bBuff.array();
txt=txt+"\nCount of bmpBytes="+bmpBytes.length;
bmp=BitmapFactory.decodeByteArray(bmpBytes,0,bmpBytes.length);
SystemClock.sleep(5000);
txt=txt+"Bitmap Object, bmp="+bmp;
if(bmp!=null){iv.setImageBitmap(bmp);sv.addView(iv);}
raf.close();
}catch(Exception e){txt=txt+"\nerror="+e.toString();}
}
public void lzw()
{
//String[] table=new String[4096];
byte b;char ch;String s;String pre="";short sh;
//List strTable=Arrays.asList(table);
//for(int i=0;i<255;i++)table[i]=Character.toString((char)i);
for(int i=0;i<100;i++)
{
b=bytes[i];
if(b<0)sh=(short)(128+b);
else sh=(short)b;
//ch=(char)b;
s=String.valueOf(sh);
//s=s+pre;
//if(strTable.contains(s)){pre=s;}
//else{ }
txt=txt+"Byte No."+i+"="+s+" ";
}
}
public void onCreate(Bundle bnd)
{
super.onCreate(bnd);
extractTif();
//sv=new ScrollView(this);
//tv=new TextView(this);
//iv=new ImageView(this);
//tv.setTextSize(7);
//sv.addView(tv);
//sv.addView(iv);
//tv.setText(txt);
//setContentView(sv);
Point res=new Point(); getWindowManager().getDefaultDisplay().getSize(res);
DotsView myView = new DotsView(this,res.x,res.y);
setContentView(myView);
}
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.
What I'm trying to do is create a BufferedImage from a byte array. Here is what I'm doing now:
try {
ByteArrayInputStream in = new ByteArrayInputStream(bytearray);
BufferedImage bImageFromConvert = ImageIO.read(in);
Color color = new Color(bImageFromConvert.getRGB((int) local_car.x, (int) local_car.z));
System.out.println("R :: "+color.getRed() + " B :: "+color.getBlue() + " G :: "+color.getGreen());
} catch (IOException e) {
e.printStackTrace();
}
}
The documentation of ImageIO.read says:
Returns a BufferedImage as the result of decoding a supplied URL with an ImageReader chosen automatically from among those currently registered. An InputStream is obtained from the URL, which is wrapped in an ImageInputStream. If no registered ImageReader claims to be able to read the resulting stream, null is returned.
I'm receiving a null pointer exception from ImageIO.read() returning null. I am sending my bytearray in the form of RGBA. Why is ImageIO.read returning null?
The ImageIO functions are for reading files and expect the input stream to be in one of the file formats such as PNG or JPG, not for reading simple arrays of rgba. To read in a simple array try something like:
int width = 256;
int height = 256;
final int bytes_per_pixel = 4;
byte[] raw = new byte[width * height * bytes_per_pixel];
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
IntBuffer intBuf
= ByteBuffer.wrap(raw)
.order(ByteOrder.LITTLE_ENDIAN)
.asIntBuffer();
int[] array = new int[intBuf.remaining()];
intBuf.get(array);
image.setRGB(0, 0, width, height, array, 0, width);
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"));
}