I'm trying to save an image in bmp format, but it doesn't create any file.
If I use "png" instead, everything works fine.
Any ideas?
//This works fine:
ImageIO.write(bi, "png", new File("D:\\MyImage.png"));
//This does not work:
ImageIO.write(bi, "bmp", new File("D:\\MyImage.bmp"));
ImageIO.getWriterFormatNames() gives me "jpg", "bmp", "jpeg" and some others..
Thanks in advance.
Jakob
I just finished debugging a similar problem and I thought I will present my reasoning here, although Jakob has gone ahead with the PNG format.
First, always check the return value of ImageIO.write(...). It will return false if no appropriate writer can be found and that's what should have happened when Jakob tried writing it as a bitmap. This happens when the actual image format of the file does not match what is given in the 'format name' argument. No exception is thrown in this case. Check out the docs at http://docs.oracle.com/javase/7/docs/api/javax/imageio/ImageIO.html#write(java.awt.image.RenderedImage, java.lang.String, java.io.File)
Second, check the image type of the BufferedImage object by using the BufferedImage#getType() method. Check out the possible return values at http://docs.oracle.com/javase/7/docs/api/java/awt/image/BufferedImage.html#getType(). For example, If you get the type as TYPE_INT_ARGB from your BufferedImage object (which represents a PNG with a alpha component) you wont have success using ImageIO.write(bi, "BMP", new File("D:\\test.bmp")) and the method would return false, even though you can see BMP/bmp in the list of entries obtained using ImageIO.getWriterFormatNames(). You might have to work on the encoding and transform your image to the desired format.
Third, when facing such problems which can be a pain sometimes, it always helps to use an image editor such as GIMP to check out your image properties in detail.
#Green arrow, a minor note... you can use either "bmp" or "BMP" as the image format value. The same applies for other formats as well. It does not matter.
As #bincob says, if write returns false, you can redraw the source image like this
BufferedImage newBufferedImage = new BufferedImage(bufferedImage.getWidth(),
bufferedImage.getHeight(), BufferedImage.TYPE_INT_RGB);
newBufferedImage.createGraphics().drawImage(bufferedImage, 0, 0, Color.WHITE, null);
And then you can write again.
Using BufferedImage.TYPE_INT_RGB encoding works for "gif","png","tif" as well as "jpg" and "bmp":
static void saveBufferedImageToFileTest(){
String[] types = new String[] {"gif","png","tif","jpg","bmp"};
//JPEG and BMP needs BufferedImage.TYPE_INT_RGB. See https://mkyong.com/java/convert-png-to-jpeg-image-file-in-java/
//BufferedImage.TYPE_INT_RGB for all `types`
int biType = BufferedImage.TYPE_INT_RGB; // BufferedImage.TYPE_INT_ARGB does not work for "bmp" and "jpeg"
BufferedImage bi = new BufferedImage(200 ,200, biType);
Graphics g = bi.getGraphics();
g.fillRect(50, 50, 100, 100);
g.dispose();
try {
for(String type : types){
boolean success = ImageIO.write(bi,type,new File("test_image."+type));
System.out.println(type + (success ? " file created" : " file NOT created") );
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
didn't try but I think the format should be "BMP" and not "bmp" actually.
Please try with
ImageIO.write(bi, "BMP", new File("D:\\MyImage.bmp"));
and see what happens.
We can't see how your bi is build.
BufferedImage bufferedImage = new BufferedImage(w,h,BufferedImage.TYPE_INT_RGB);
Is the encodingType is set properly ?
I think your bi is corrupted, that's work perfectly for me.
BufferedImage bi = new BufferedImage(50,50,BufferedImage.TYPE_INT_RGB);
Graphics gd = bi.getGraphics();
gd.drawRect(0, 0, 10, 10);
try {
ImageIO.write(bi, "BMP", new File("C:\\test.bmp"));
ImageIO.write(bi, "PNG", new File("C:\\test.png"));
} catch (IOException e) {
System.out.println("error "+e.getMessage());
}
An oldie, but BMPs are still useful occasionally and the answers above all skirt the best solution: do it yourself. That way it works for any type of bitmap.
static void writeBMP(BufferedImage image, File f) throws IOException {
OutputStream out = new BufferedOutputStream(new FileOutputStream(f));
int width = image.getWidth();
int height = image.getHeight();
int row = (width * 3 + 3) / 4 * 4;
out.write('B');
out.write('M');
writeInt(out, 14 + 40 + row * height); // file size
writeInt(out, 0);
writeInt(out, 14 + 40); // bitmap offset
writeInt(out, 40); // size
writeInt(out, width); // width
writeInt(out, height); // weight
writeInt(out, (24<<16) | 1); // planes, bpp
writeInt(out, 0); // compression
writeInt(out, row * height); // bitmap size
writeInt(out, 0); // resx
writeInt(out, 0); // resy
writeInt(out, 0); // used colors
writeInt(out, 0); // important colors
for (int y=height-1;y>=0;y--) {
for (int x=0;x<width;x++) {
int rgba = image.getRGB(x, y);
out.write(rgba & 0xFF); // b
out.write(rgba >> 8); // g
out.write(rgba >> 16); // r
}
for (int x=width*3;x%4!=0;x++) { // pad to 4 bytes
out.write(0);
}
}
out.close();
}
private static void writeInt(OutputStream out, int v) throws IOException {
out.write(v);
out.write(v >> 8);
out.write(v >> 16);
out.write(v >> 24);
}
Related
I have used BufferedImage class to generate images from pdf. I am getting 8-bit RGBA by using the below-mentioned snippet, but I was unable to convert it to 16 bpc RGBA.
int page = 0;
BufferedImage bim = new BufferedImage(100, 100, BufferedImage.TYPE_USHORT_565_RGB);
bim = pdfRenderer.renderImage(page);
String fileName = OUTPUT_DIR + "image-" + page + ".png";
ImageIOUtil.writeImage(bim, fileName, 1);
To create a 16 bit per sample (or channel) BufferedImage and store it as a PNG, you can use the following code:
ComponentColorModel colorModel = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB), true, false, Transparency.TRANSLUCENT, DataBuffer.TYPE_USHORT);
BufferedImage image = new BufferedImage(colorModel, colorModel.createCompatibleWritableRaster(100, 100), colorModel.isAlphaPremultiplied(), null);
if (!ImageIO.write(image, "PNG", new File("test.png"))) {
System.err.println("Could not write PNG: " + image);
}
From the code, I'm assuming you are using PDFBox. If you are using PDFBox, you can use ImageIOUtil.writeImage instead of ImageIO.write. But you probably want to set the DPI to something more reasonable than 1... 😉
Also note that image = pdfRenderer.renderImage(page) in your code will replace the image, so you can't use that. Try using the renderPageToGraphics(int, Graphics2D)method instead:
ComponentColorModel colorModel = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB), true, false, Transparency.TRANSLUCENT, DataBuffer.TYPE_USHORT);
BufferedImage image = new BufferedImage(colorModel, colorModel.createCompatibleWritableRaster(100, 100), colorModel.isAlphaPremultiplied(), null);
Graphics2D g = image.createGraphics();
try {
pdfRenderer.renderPageToGraphics(page, g);
}
finally {
g.dispose();
}
if (!ImageIOUtil.writeImage(image, test.png, 72))) {
System.err.println("Could not write PNG: " + image);
}
I am working with Java and combine two images. I save the combined image and want to delete the overlay, but it seems there are still streams open. And i don't know which and how to close them.
f_overlay and f_image are both Files.
// load source images
BufferedImage image = null;
BufferedImage overlay = null;
try {
log.debug(f_image.getAbsolutePath());
log.debug(f_overlay.getAbsolutePath());
image = ImageIO.read(f_image);
overlay = ImageIO.read(f_overlay);
} catch (IOException e) {
log.error(e.getMessage());
}
// create the new image, canvas size is the max. of both image sizes
int w = Math.max(image.getWidth(), overlay.getWidth());
int h = Math.max(image.getHeight(), overlay.getHeight());
BufferedImage combined = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
// paint both images, preserving the alpha channels
Graphics g = combined.getGraphics();
g.drawImage(image, 0, 0, null);
g.drawImage(overlay, 0, 0, null);
// Save as new image
try {
ImageIO.write(combined, "PNG", f_image);
} catch (IOException e) {
log.error(e.getMessage());
}
// we can delete the overlay now
log.debug("Delete overlay: " + f_overlay.delete());
Are there any suggestions?
I can't see anything wrong in your code.
However, I would only delete the file f_overlay if the reading was successful. Important, after you call delete() on the file object, you must not use the object for anything else, so best is to assign f_overlay=null
boolean state = f_overlay.delete();
f_overlay=null;
log.debug("Delete ... "+state);
I'm trying to save an image in bmp format, but it doesn't create any file.
If I use "png" instead, everything works fine.
Any ideas?
//This works fine:
ImageIO.write(bi, "png", new File("D:\\MyImage.png"));
//This does not work:
ImageIO.write(bi, "bmp", new File("D:\\MyImage.bmp"));
ImageIO.getWriterFormatNames() gives me "jpg", "bmp", "jpeg" and some others..
Thanks in advance.
Jakob
I just finished debugging a similar problem and I thought I will present my reasoning here, although Jakob has gone ahead with the PNG format.
First, always check the return value of ImageIO.write(...). It will return false if no appropriate writer can be found and that's what should have happened when Jakob tried writing it as a bitmap. This happens when the actual image format of the file does not match what is given in the 'format name' argument. No exception is thrown in this case. Check out the docs at http://docs.oracle.com/javase/7/docs/api/javax/imageio/ImageIO.html#write(java.awt.image.RenderedImage, java.lang.String, java.io.File)
Second, check the image type of the BufferedImage object by using the BufferedImage#getType() method. Check out the possible return values at http://docs.oracle.com/javase/7/docs/api/java/awt/image/BufferedImage.html#getType(). For example, If you get the type as TYPE_INT_ARGB from your BufferedImage object (which represents a PNG with a alpha component) you wont have success using ImageIO.write(bi, "BMP", new File("D:\\test.bmp")) and the method would return false, even though you can see BMP/bmp in the list of entries obtained using ImageIO.getWriterFormatNames(). You might have to work on the encoding and transform your image to the desired format.
Third, when facing such problems which can be a pain sometimes, it always helps to use an image editor such as GIMP to check out your image properties in detail.
#Green arrow, a minor note... you can use either "bmp" or "BMP" as the image format value. The same applies for other formats as well. It does not matter.
As #bincob says, if write returns false, you can redraw the source image like this
BufferedImage newBufferedImage = new BufferedImage(bufferedImage.getWidth(),
bufferedImage.getHeight(), BufferedImage.TYPE_INT_RGB);
newBufferedImage.createGraphics().drawImage(bufferedImage, 0, 0, Color.WHITE, null);
And then you can write again.
Using BufferedImage.TYPE_INT_RGB encoding works for "gif","png","tif" as well as "jpg" and "bmp":
static void saveBufferedImageToFileTest(){
String[] types = new String[] {"gif","png","tif","jpg","bmp"};
//JPEG and BMP needs BufferedImage.TYPE_INT_RGB. See https://mkyong.com/java/convert-png-to-jpeg-image-file-in-java/
//BufferedImage.TYPE_INT_RGB for all `types`
int biType = BufferedImage.TYPE_INT_RGB; // BufferedImage.TYPE_INT_ARGB does not work for "bmp" and "jpeg"
BufferedImage bi = new BufferedImage(200 ,200, biType);
Graphics g = bi.getGraphics();
g.fillRect(50, 50, 100, 100);
g.dispose();
try {
for(String type : types){
boolean success = ImageIO.write(bi,type,new File("test_image."+type));
System.out.println(type + (success ? " file created" : " file NOT created") );
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
didn't try but I think the format should be "BMP" and not "bmp" actually.
Please try with
ImageIO.write(bi, "BMP", new File("D:\\MyImage.bmp"));
and see what happens.
We can't see how your bi is build.
BufferedImage bufferedImage = new BufferedImage(w,h,BufferedImage.TYPE_INT_RGB);
Is the encodingType is set properly ?
I think your bi is corrupted, that's work perfectly for me.
BufferedImage bi = new BufferedImage(50,50,BufferedImage.TYPE_INT_RGB);
Graphics gd = bi.getGraphics();
gd.drawRect(0, 0, 10, 10);
try {
ImageIO.write(bi, "BMP", new File("C:\\test.bmp"));
ImageIO.write(bi, "PNG", new File("C:\\test.png"));
} catch (IOException e) {
System.out.println("error "+e.getMessage());
}
An oldie, but BMPs are still useful occasionally and the answers above all skirt the best solution: do it yourself. That way it works for any type of bitmap.
static void writeBMP(BufferedImage image, File f) throws IOException {
OutputStream out = new BufferedOutputStream(new FileOutputStream(f));
int width = image.getWidth();
int height = image.getHeight();
int row = (width * 3 + 3) / 4 * 4;
out.write('B');
out.write('M');
writeInt(out, 14 + 40 + row * height); // file size
writeInt(out, 0);
writeInt(out, 14 + 40); // bitmap offset
writeInt(out, 40); // size
writeInt(out, width); // width
writeInt(out, height); // weight
writeInt(out, (24<<16) | 1); // planes, bpp
writeInt(out, 0); // compression
writeInt(out, row * height); // bitmap size
writeInt(out, 0); // resx
writeInt(out, 0); // resy
writeInt(out, 0); // used colors
writeInt(out, 0); // important colors
for (int y=height-1;y>=0;y--) {
for (int x=0;x<width;x++) {
int rgba = image.getRGB(x, y);
out.write(rgba & 0xFF); // b
out.write(rgba >> 8); // g
out.write(rgba >> 16); // r
}
for (int x=width*3;x%4!=0;x++) { // pad to 4 bytes
out.write(0);
}
}
out.close();
}
private static void writeInt(OutputStream out, int v) throws IOException {
out.write(v);
out.write(v >> 8);
out.write(v >> 16);
out.write(v >> 24);
}
I am trying to write a method that takes an image, and saves a 100 by 100 thumbnail of that image. However, when I save the file, it comes out as an unreadable 0 byte image (with the error "Error interpreting JPEG image file (Improper call to JPEG library in state 200)") in Ubuntu's ImageViewer. My code is as follows:
public boolean scale(){
String file = filename.substring(filename.lastIndexOf(File.separator)+1);
File out = new File("data"+File.separator+"thumbnails"+File.separator+file);
if( out.exists() ) return false;
BufferedImage bi;
try{
bi = ImageIO.read(new File(filename));
}
catch(IOException e){
return false;
}
Dimension imgSize = new Dimension(bi.getWidth(), bi.getHeight());
Dimension bounds = new Dimension(100, 100);
int newHeight = imgSize.height;
int newWidth = imgSize.width;
if( imgSize.width > bounds.width ){
newWidth = bounds.width;
newHeight = (newWidth*imgSize.height)/imgSize.width;
}
if( imgSize.height > bounds.width ){
newHeight = bounds.height;
newWidth = (newHeight*imgSize.width)/imgSize.height;
}
Image img = bi.getScaledInstance(newWidth, newHeight, BufferedImage.SCALE_SMOOTH);
BufferedImage thumb = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_4BYTE_ABGR);
Graphics2D g2d = thumb.createGraphics();
g2d.drawImage(img, 0, 0, null);
g2d.dispose();
try{
ImageIO.write(thumb, "jpg", out);
}
catch(IOException e){
return false;
}
return true;
}
Where "filename" is a global variable for the class housing this method, representing the path to the original image. My main issue is that I do not see why I'm creating a 0 byte image.
So, the issue was this. I'm working in OpenJDK. OpenJDK doesn't have a JPEG encoder, apparently, so while the file was being created by
ImageIO.write(thumb, "jpg", out);
it wasn't actually creating anything for the file to save; hence the empty 0 byte unreadable file. Changing the ImageIO argument to "png" (and adjusting the new File() extension, appropriately) successfully created the desired image with the above code.
I experienced the same issue even though the JVM had a JPG encoder and it was caused by using an unsupported type of BufferImage underneath. I had used BufferedImage.TYPE_USHORT_GRAY which is evidently not supported and gave no error messages but produced a 0 byte file. When I switched to BufferedImage.TYPE_BYTE_GRAY it worked perfectly.
JPG have no alpha channel, ImageIO.write() will fail silently (just return false) one way is to copy your image into another one
BufferedImage newBufferedImage = new BufferedImage(bufferedImage.getWidth(),
bufferedImage.getHeight(), BufferedImage.TYPE_INT_RGB);
newBufferedImage.getGraphics().drawImage(bufferedImage, 0, 0, null);
boolean write = ImageIO.write(newBufferedImage, extension, outputfile);
if (!write) {
// do something
}
I am trying to save an image to JPEG. The code below works fine when image width is a multiple of 4, but the image is skewed otherwise. It has something to do with padding. When I was debugging I was able to save the image as a bitmap correctly, by padding each row with 0s. However, this did not work out with the JPEG.
Main point to remember is my image is represented as bgr (blue green red 1 byte each) byte array which I receive from a native call.
byte[] data = captureImage(OpenGLCanvas.getLastFocused().getViewId(), x, y);
if (data.length != 3*x*y)
{
// 3 bytes per pixel
return false;
}
// create buffered image from raw data
DataBufferByte buffer = new DataBufferByte(data, 3*x*y);
ComponentSampleModel csm = new ComponentSampleModel(DataBuffer.TYPE_BYTE, x, y, 3, 3*x, new int[]{0,1,2} );
WritableRaster raster = Raster.createWritableRaster(csm, buffer, new Point(0,0));
BufferedImage buff_image = new BufferedImage(x, y, BufferedImage.TYPE_INT_BGR); // because windows goes the wrong way...
buff_image.setData(raster);
//save the BufferedImage as a jpeg
try
{
File file = new File(file_name);
FileOutputStream out = new FileOutputStream(file);
JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
JPEGEncodeParam param = encoder.getDefaultJPEGEncodeParam(buff_image);
param.setQuality(1.0f, false);
encoder.setJPEGEncodeParam(param);
encoder.encode(buff_image);
out.close();
// or JDK 1.4
// ImageIO.write(image, "JPEG", out);
}
catch (Exception ex)
{
// Write permissions on "file_name"
return false;
}
I also looked on creating the JPEG in C++ but there was even less material on that, but it is still an option.
Any help greatly apprecieated.
Leon
Thanks for your suggestions, but I have managed to work it out.
To capture the image I was using WINGDIAPI HBITMAP WINAPI CreateDIBSection in C++, then OpenGL would draw to that bitmap. Unbeknown to be, there was padding added to the bitmap automatically the width was not a multiple of 4.
Therefore Java was incorrectly interpreting the byte array.
Correct way is to interpret bytes is
byte[] data = captureImage(OpenGLCanvas.getLastFocused().getViewId(), x, y);
int x_padding = x%4;
BufferedImage buff_image = new BufferedImage(x, y, BufferedImage.TYPE_INT_RGB);
int val;
for (int j = 0; j < y; j++)
{
for (int i = 0; i < x; i++)
{
val = ( data[(i + j*x)*3 + j*x_padding + 2]& 0xff) +
((data[(i + j*x)*3 + j*x_padding + 1]& 0xff) << 8) +
((data[(i + j*x)*3 + j*x_padding + 0]& 0xff) << 16);
buff_image.setRGB(i, j, val);
}
}
//save the BufferedImage as a jpeg
try
{
File file = new File(file_name);
FileOutputStream out = new FileOutputStream(file);
JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
JPEGEncodeParam param = encoder.getDefaultJPEGEncodeParam(buff_image);
param.setQuality(1.0f, false);
encoder.setJPEGEncodeParam(param);
encoder.encode(buff_image);
out.close();
}
The JPEG standard is extremely complex. I am thinking it may be an issue with padding the output of the DCT somehow. The DCT is done to transform the content from YCrCb 4:2:2 to signal space with one DCT for each channel, Y,Cr, and Cb. The DCT is done on a "Macroblock" or "minimum coded block" depending on your context. JPEG usually has 8x8 macroblocks. When on the edge and there are not enough pixel it clamps the edge value and "drags it across" and does a DCT on that.
I am not sure if this helps, but it sounds like a non standard conforming file. I suggest you use JPEGSnoop to find out more. There are also several explanations about how JPEG compression works.
One possibility is that the sample rate may be encoded incorrectly. It might be something exotic such as 4:2:1 So you might be pulling twice as many X samples as there really are, thus distorting the image.
it is an image I capture from the screen
Maybe the Screen Image class will be easier to use.