I am trying to convert a PNG image to a JPEG image following this tutorial. But I encounter a problem. The resulting image has a pink layer.
Does anyone have a solution for this problem? Or what code should I use in order to convert the image into the desired format?
Thanks in advance!
Create a BufferedImage of desired size, e.g.:
BufferedImage img = new BufferedImage(w,h,BufferedImage.TYPE_INT_RGB)
fill it with a proper background color:
img.getGraphics().fillRect(....)
Call drawImage on the image's graphics atop of that background:
img.getGraphics().drawImage(image, 0, 0, null);
then write down your image as JPG as usual.
Which color mode are you using? While you create buffered image object, try adding the type like this option.
File newFile = new File(path + fileName + "." + Strings.FILE_TYPE);
Image image = null;
try {
image = ImageIO.read(url); // I was using an image from web
} catch (IOException e1) {
e1.printStackTrace();
}
image = image.getScaledInstance(width, height, Image.SCALE_SMOOTH);
try {
BufferedImage img = toBufferedImage(image);
ImageIO.write(img, "jpg", newFile);
} catch (IOException e) {
e.printStackTrace();
}
}
private static BufferedImage toBufferedImage(Image src) {
int w = src.getWidth(null);
int h = src.getHeight(null);
int type = BufferedImage.TYPE_INT_RGB; // other options
BufferedImage dest = new BufferedImage(w, h, type);
Graphics2D g2 = dest.createGraphics();
g2.drawImage(src, 0, 0, null);
g2.dispose();
return dest;
}
Related
I am trying to resize jpg Image files in Java. For this I am using Scalr.
I have around 16MB image with 6000x4000 Resolution and 350 dpi.
When I resize it to 4500 width, it downscales the DPI also to 96.
This is the code I am using:
Scalr.resize(img, Scalr.Method.ULTRA_QUALITY, 4500, Scalr.OP_ANTIALIAS);
I tried it without any library with the code as:
private static BufferedImage resizeImageWithHint(BufferedImage originalImage, int type, int IMG_WIDTH,
int IMG_HEIGHT) {
BufferedImage resizedImage = new BufferedImage(IMG_WIDTH, IMG_HEIGHT, type);
Graphics2D g = resizedImage.createGraphics();
g.drawImage(originalImage, 0, 0, IMG_WIDTH, IMG_HEIGHT, null);
g.dispose();
g.setComposite(AlphaComposite.Src);
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
return resizedImage;
}
But the result was same. So how can I resize the images with dpi around 150 if possible and same 350 dpi if not possible.
To store the DPI in an image implies that you want to save the image. (this wasn't clear in your question.) You need to specify the metadata directly in the encoder. Here's the JPEG version. I saw it's possible to PNG too it needs different metadata tree nodes.
[Edit] I found a way that doesn't rely on proprietary classes.
import org.w3c.dom.Element;
ImageWriter writer = ImageIO.getImageWritersByFormatName("jpeg").next();
ImageWriteParam param = writer.getDefaultWriteParam();
param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
param.setCompressionQuality(0.95f);
IIOMetadata metadata = writer.getDefaultImageMetadata(ImageTypeSpecifier.createFromRenderedImage(image), param);
Element tree = (Element)metadata.getAsTree("javax_imageio_jpeg_image_1.0");
Element jfif = (Element)tree.getElementsByTagName("app0JFIF").item(0);
jfif.setAttribute("Xdensity", Integer.toString(350));
jfif.setAttribute("Ydensity", Integer.toString(350));
jfif.setAttribute("resUnits", "1"); // In pixels-per-inch units
metadata.mergeTree("javax_imageio_jpeg_image_1.0", tree);
try (FileImageOutputStream output = new FileImageOutputStream(new File(filename))) {
writer.setOutput(output);
IIOImage iioImage = new IIOImage(image, null, metadata);
writer.write(metadata, iioImage, param);
writer.dispose();
}
Adapted from source
PNG version here
this work for me, jpg 72 -> 300
public static void handleDpi(File file, int xDensity, int yDensity) {
try {
BufferedImage image = ImageIO.read(file);
JPEGImageEncoder jpegEncoder = JPEGCodec.createJPEGEncoder(new FileOutputStream(file));
JPEGEncodeParam jpegEncodeParam = jpegEncoder.getDefaultJPEGEncodeParam(image);
jpegEncodeParam.setDensityUnit(JPEGEncodeParam.DENSITY_UNIT_DOTS_INCH);
jpegEncoder.setJPEGEncodeParam(jpegEncodeParam);
jpegEncodeParam.setQuality(0.75f, false);
jpegEncodeParam.setXDensity(xDensity);
jpegEncodeParam.setYDensity(yDensity);
jpegEncoder.encode(image, jpegEncodeParam);
image.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
I am adding text to an image using this code in Android :
public Bitmap drawTextToBitmap(Context gContext, Bitmap image, String gText) {
Resources resources = gContext.getResources();
float scale = resources.getDisplayMetrics().density;
android.graphics.Bitmap.Config bitmapConfig =
image.getConfig();
// set default bitmap config if none
if(bitmapConfig == null) {
bitmapConfig = android.graphics.Bitmap.Config.ARGB_8888;
}
// resource bitmaps are imutable,
// so we need to convert it to mutable one
Bitmap bitmap = null;
try{
bitmap = image.copy(bitmapConfig, true);
image.recycle();
Canvas canvas = new Canvas(bitmap);
// new antialised Paint
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
// text color - #3D3D3D
paint.setColor(Color.WHITE);
// text size in pixels
paint.setTextSize((int) (50 * scale));
// text shadow
paint.setShadowLayer(1f, 0f, 1f, Color.BLACK);
// draw text to the Canvas center
Rect bounds = new Rect();
paint.getTextBounds(gText, 0, gText.length(), bounds);
int padding = bounds.height()/2;
int x = bitmap.getWidth() - (bounds.width()+padding);
int y = (bitmap.getHeight() - (bounds.height()+padding));
canvas.drawText(gText, x, y, paint);
}catch (Throwable e){
AppLog.e("DrawingBitmap","error while adding timestamp",e);
}
return bitmap;
}
Then I create a new File with the transformed bitmap
storeImage(newBitmap, newFileName);
private File storeImage(Bitmap image, String nameFile) {
File pictureFile = new File(getExternalCacheDir(), nameFile);
try {
FileOutputStream fos = new FileOutputStream(pictureFile);
image.compress(Bitmap.CompressFormat.JPEG, 100, fos);
fos.close();
} catch (FileNotFoundException e) {
AppLog.e("error creating bitmap", "File not found: " + e.getMessage());
} catch (IOException e) {
AppLog.e("error creating bitmap", "Error accessing file: " + e.getMessage());
}
return pictureFile;
}
I send the file to my server, I receive an input stream, I create a File, I scale it and I create a new File with the scaled image :
ImageWriter.write(metadata, new IIOImage(image, null, metadata), param);
I get an IIOException:
javax.imageio.IIOException: Missing Huffman code table entry
at com.sun.imageio.plugins.jpeg.JPEGImageWriter.writeImage(Native Method)
at com.sun.imageio.plugins.jpeg.JPEGImageWriter.writeOnThread(JPEGImageWriter.java:1067)
at com.sun.imageio.plugins.jpeg.JPEGImageWriter.write(JPEGImageWriter.java:363)
at com.twelvemonkeys.imageio.plugins.jpeg.JPEGImageWriter.write(JPEGImageWriter.java:162)
if I don't call drawTextToBitmap() from android I don't get that error.
If someone can help me ... thx
EDIT : here is the way I use to get metadata from my file
private static IIOMetadata readMetaData(File source) {
try {
ImageInputStream stream = ImageIO.createImageInputStream(source);
Iterator<ImageReader> readers = ImageIO.getImageReaders(stream);
IIOMetadata metadata = null;
if (readers.hasNext()) {
ImageReader reader = readers.next();
reader.setInput(stream);
metadata = reader.getImageMetadata(0);
}
return metadata;
}catch (Exception e){
_logger.error(e);
e.printStackTrace();
}
return null;
}
Edit 2 :
Using jpegParams.setOptimizeHuffmanTables(true); works but it resets all metadata and I want to keep them like gps location ...
ImageWriteParam param = writer.getDefaultWriteParam();
param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
param.setCompressionQuality(quality);
if (param instanceof JPEGImageWriteParam) {
((JPEGImageWriteParam) param).setOptimizeHuffmanTables(true);
}
IIOImage image = new IIOImage(reader.read(0), null, reader.getImageMetadata(0));
writer.write(null, image, param);
here's my code, which keeps the metadata of image, and get rid of "missing huffman code table" stuff.
I have this code:
public void draw(File image, int number, File destination) {
BufferedImage img = null;
try {
img = ImageIO.read(image);
//create graphic object
Graphics2D graphicImg = img.createGraphics();
//select the font
Font font = new Font("TimesRoman", Font.BOLD, 96);
graphicImg.setFont(font);
//draw the text
graphicImg.drawString(String.valueOf(number), 100, 100);
//save on disk
ImageIO.write(img, "jpg", destination);
} catch (Exception e) {
System.out.println("Error while trying to write on image!");
}
}
I pass a File (which will be an image) as first parameter, an int and a File(which will represent the destination) of the file.
The method should draw a number on this file.
The problem is that the image size of the new image will be lower than original. For example, if I give a image with 3Mb as first parameter, the saved image will have around 1.5Mb. Why the size are so different and how I can fix it?
Thank you
I'm trying to make a picture fit a JLabel. I wish to reduce the picture dimensions to something more appropriate for my Swing JPanel.
I tried with setPreferredSize but it doesn't work.
I'm wondering if there is a simple way to do it? Should I scale the image for this purpose?
Outline
Here are the steps to follow.
Read the picture as a BufferedImage.
Resize the BufferedImage to another BufferedImage that's the size of the JLabel.
Create an ImageIcon from the resized BufferedImage.
You do not have to set the preferred size of the JLabel. Once you've scaled the image to the size you want, the JLabel will take the size of the ImageIcon.
Read the picture as a BufferedImage
BufferedImage img = null;
try {
img = ImageIO.read(new File("strawberry.jpg"));
} catch (IOException e) {
e.printStackTrace();
}
Resize the BufferedImage
Image dimg = img.getScaledInstance(label.getWidth(), label.getHeight(),
Image.SCALE_SMOOTH);
Make sure that the label width and height are the same proportions as the original image width and height. In other words, if the picture is 600 x 900 pixels, scale to 100 X 150. Otherwise, your picture will be distorted.
Create an ImageIcon
ImageIcon imageIcon = new ImageIcon(dimg);
You can try it:
ImageIcon imageIcon = new ImageIcon(new ImageIcon("icon.png").getImage().getScaledInstance(20, 20, Image.SCALE_DEFAULT));
label.setIcon(imageIcon);
Or in one line:
label.setIcon(new ImageIcon(new ImageIcon("icon.png").getImage().getScaledInstance(20, 20, Image.SCALE_DEFAULT)));
The execution time is much more faster than File and ImageIO.
I recommend you to compare the two solutions in a loop.
public static void main(String s[])
{
BufferedImage image = null;
try
{
image = ImageIO.read(new File("your image path"));
} catch (Exception e)
{
e.printStackTrace();
}
ImageIcon imageIcon = new ImageIcon(fitimage(image, label.getWidth(), label.getHeight()));
jLabel1.setIcon(imageIcon);
}
private Image fitimage(Image img , int w , int h)
{
BufferedImage resizedimage = new BufferedImage(w,h,BufferedImage.TYPE_INT_RGB);
Graphics2D g2 = resizedimage.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2.drawImage(img, 0, 0,w,h,null);
g2.dispose();
return resizedimage;
}
The best and easy way for image resize using Java Swing is:
jLabel.setIcon(new ImageIcon(new javax.swing.ImageIcon(getClass().getResource("/res/image.png")).getImage().getScaledInstance(200, 50, Image.SCALE_SMOOTH)));
For better display, identify the actual height & width of image and resize based on width/height percentage
i have done the following and it worked perfectly
try {
JFileChooser jfc = new JFileChooser();
jfc.showOpenDialog(null);
File f = jfc.getSelectedFile();
Image bi = ImageIO.read(f);
image1.setText("");
image1.setIcon(new ImageIcon(bi.getScaledInstance(int width, int width, int width)));
} catch (Exception e) {
}
Or u can do it this way. The function u put the below 6 lines will throw an IOException. And will take your JLabel as a parameter.
BufferedImage bi=new BufferedImage(label.width(),label.height(),BufferedImage.TYPE_INT_RGB);
Graphics2D g=bi.createGraphics();
Image img=ImageIO.read(new File("path of your image"));
g.drawImage(img, 0, 0, label.width(), label.height(), null);
g.dispose();
return bi;
public void selectImageAndResize(){
int returnVal = jFileChooser.showOpenDialog(this); //open jfilechooser
if (returnVal == jFileChooser.APPROVE_OPTION) { //select image
File file = jFileChooser.getSelectedFile(); //get the image
BufferedImage bi;
try {
//
//transforms selected file to buffer
//
bi=ImageIO.read(file);
ImageIcon iconimage = new ImageIcon(bi);
//
//get image dimensions
//
BufferedImage bi2 = new BufferedImage(iconimage.getIconWidth(), iconimage.getIconHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics g = bi.createGraphics();
iconimage.paintIcon(null, g, 0,0);
g.dispose();
//
//resize image according to jlabel
//
BufferedImage resizedimage=resize(bi,jLabel2.getWidth(), jLabel2.getHeight());
ImageIcon resizedicon=new ImageIcon(resizedimage);
jLabel2.setIcon(resizedicon);
} catch (Exception ex) {
System.out.println("problem accessing file"+file.getAbsolutePath());
}
}
else {
System.out.println("File access cancelled by user.");
}
}
Assign your image to a string.
Eg image
Now set icon to a fixed size label.
image.setIcon(new javax.swing.ImageIcon(image.getScaledInstance(50,50,WIDTH)));
I'm getting images from clipboard using this:
if(Toolkit.getDefaultToolkit().getSystemClipboard().isDataFlavorAvailable(DataFlavor.imageFlavor)){
ImageIcon IMG = new ImageIcon((BufferedImage) Toolkit.getDefaultToolkit().getSystemClipboard().getData(DataFlavor.imageFlavor));
}
Now I want to save this image in disk using ImageIO.write;
How can I find image format (JPG,PNG,GIF,...) to use in ImageIO.write as formatName ?
Thanks
The mime type of the content of the clipboard when checked via
.isDataFlavorAvailable(DataFlavor.imageFlavor)
is image/x-java-image (but OS vendors do not need to follow MIME types for clipboards).
I found two ways to supposedly get an image from a clipboard and write it to a file:
Using a helper method found in this blog post: The nightmares of getting images from the Mac OS X clipboard using Java.
Clipboard clip = Toolkit.getDefaultToolkit().getSystemClipboard()
ImageIcon IMG = new ImageIcon((BufferedImage)
clip.getData(DataFlavor.imageFlavor));
BufferedImage bImage = getBufferedImage(IMG.getImage());
ImageIO.write(bImage, "png", new File("/tmp/test.png"));
The getBufferedImage method looks like this:
public static BufferedImage getBufferedImage(Image img) {
if (img == null) {
return null;
}
int w = img.getWidth(null);
int h = img.getHeight(null);
// draw original image to thumbnail image object and
// scale it to the new size on-the-fly
BufferedImage bufimg = new BufferedImage(w, h,
BufferedImage.TYPE_INT_RGB);
Graphics2D g2 = bufimg.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2.drawImage(img, 0, 0, w, h, null);
g2.dispose();
return bufimg;
}
Via Transferable. Note that this runs on OS X but produces an empty image of the correct size:
Clipboard clip = Toolkit.getDefaultToolkit().getSystemClipboard()
Transferable content =
clip.getContents(null);
BufferedImage img = (BufferedImage) content.getTransferData(
DataFlavor.imageFlavor);
ImageIO.write(img, "png", new File("/tmp/test.png"));