I am trying to transform an image by flipping it horizontally and resizing it. The problem is that when the transformation is done the picture's colors are all weird, it has gotten this reddish tone. Is it possible to fix this somehow, I think I read somewhere that it might be some bug in the AWT library but I am not sure?
Here is the code:
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
public class LocalImageSizeFlip {
public static void main(String[] args) {
BufferedImage img = null;
try {
img = ImageIO.read(new File("C:\\picture.jpg"));
AffineTransform tx = AffineTransform.getScaleInstance(1, -1);
tx.translate(0, -img.getHeight(null));
AffineTransformOp op = new AffineTransformOp(tx, AffineTransformOp.TYPE_NEAREST_NEIGHBOR);
img = op.filter(img, null);
img = resize(img, 100, 75);
File newFile = new File("newPicture.jpg");
ImageIO.write(img, "JPEG", newFile);
} catch (IOException e) {
e.printStackTrace();
}
}
private static BufferedImage resize(BufferedImage image, int width, int height) {
BufferedImage resizedImage = new BufferedImage(width, height,
BufferedImage.TYPE_INT_ARGB);
Graphics2D g = resizedImage.createGraphics();
g.drawImage(image, 0, 0, width, height, null);
g.dispose();
return resizedImage;
}
}
Having an image develop a tint usually means the image is being rendered using the wrong colorspace, Adobe RGB vs. sRGB being a perennial favorite. Try changing TYPE_INT_ARGB to TYPE_INT_RGB in your code.
You can also try the following type: BufferedImage.TYPE_3BYTE_BGR
If you have any images already converted and those are almost pinkish/reddish.
You can convert those into RGB again.
try {
File folder = new File("photo/old");
File[] list = folder.listFiles();
for (File f : list) {
String url = f.getAbsolutePath();
String replce1 = url.replace('\\', '/');
File file = new File(replce1);
if (file.exists()) {
FileInputStream fis = new FileInputStream(file);
byte[] buff = new byte[fis.available()];
fis.read(buff);
BufferedImage bi = ImageIO.read(file);
BufferedImage biOriginal = new BufferedImage(1200, 800,
BufferedImage.TYPE_INT_RGB);
Graphics2D g = resizedImage.createGraphics();
g.drawImage(bi, 0, 0, 1200, 800, null);
g.dispose();
fis.close();
FileOutputStream fos2 = new FileOutputStream("photo/new/"+file.getName());
ByteArrayOutputStream baos2 = new ByteArrayOutputStream();
ImageIO.write(biOriginal, Main.extensionWithotDot, baos2);
baos2.flush();
byte[] imageInByte2 = baos2.toByteArray();
fos2.write(imageInByte2);
fos2.close();
}
}
} catch (Exception e) {
e.printStackTrace();
}
Related
I want to cut the pic to circle by using java graphics 2d, but the result is unsatisfying. I would like the final pic come as similar as the "object-fit: cover" comes out in css.
This is the original pic
original pic
Below are my codes and the final result.
BufferedImage testImage = ImageIO.read(new File("/Users/huangruixiang/Desktop/test.png"));
BufferedImage formatAvatarImage = new BufferedImage(200, 200, BufferedImage.TYPE_4BYTE_ABGR);
Graphics2D graphics = formatAvatarImage.createGraphics();
graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
Ellipse2D.Double shape = new Ellipse2D.Double(0, 0, 200, 200);
graphics.setClip(shape);
graphics.drawImage(testImage, 0, 0, 200, 200, null);
graphics.dispose();
ImageIO.write(formatAvatarImage,"png",new File("/Users/huangruixiang/Desktop/circle.png"));
resule
And the effect I want is similar to this
Expected effect
Here you go.
You have to use a different drawImage method than the one you used.
Here's the complete runnable code.
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.Ellipse2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
public class CenterCutImage {
public static void main(String[] args) {
CenterCutImage cci = new CenterCutImage();
BufferedImage image = cci.readImage("/do3kO.png");
BufferedImage croppedImage = cci.createCenterCut(image, new Dimension(200, 200));
String path = "D:\\Eclipse\\Eclipse-2020-workspace\\com.ggl.testing3\\resources";
cci.writeImage(croppedImage, path, "circle.png");
}
public BufferedImage createCenterCut(BufferedImage inputImage, Dimension d) {
BufferedImage image = new BufferedImage(d.width, d.height, BufferedImage.TYPE_4BYTE_ABGR);
Graphics2D g2d = (Graphics2D) image.getGraphics();
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
int x = (inputImage.getWidth() - d.width) / 2;
int y = (inputImage.getHeight() - d.height) / 2;
Ellipse2D.Double shape = new Ellipse2D.Double(0, 0, d.width, d.height);
g2d.setClip(shape);
g2d.drawImage(inputImage, 0, 0, d.width, d.height, x, y, x + d.width, y + d.height, null);
g2d.dispose();
return image;
}
public BufferedImage readImage(String filename) {
try {
return ImageIO.read(getClass().getResourceAsStream(filename));
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
public void writeImage(BufferedImage croppedImage, String path, String filename) {
try {
ImageIO.write(croppedImage, "png", new File(path + "/" + filename));
} catch (IOException e) {
e.printStackTrace();
}
}
}
I am trying to transform an image by flipping it horizontally and resizing it. The problem is that when the transformation is done the picture's colors are all weird, it has gotten this reddish tone. Is it possible to fix this somehow, I think I read somewhere that it might be some bug in the AWT library but I am not sure?
Here is the code:
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
public class LocalImageSizeFlip {
public static void main(String[] args) {
BufferedImage img = null;
try {
img = ImageIO.read(new File("C:\\picture.jpg"));
AffineTransform tx = AffineTransform.getScaleInstance(1, -1);
tx.translate(0, -img.getHeight(null));
AffineTransformOp op = new AffineTransformOp(tx, AffineTransformOp.TYPE_NEAREST_NEIGHBOR);
img = op.filter(img, null);
img = resize(img, 100, 75);
File newFile = new File("newPicture.jpg");
ImageIO.write(img, "JPEG", newFile);
} catch (IOException e) {
e.printStackTrace();
}
}
private static BufferedImage resize(BufferedImage image, int width, int height) {
BufferedImage resizedImage = new BufferedImage(width, height,
BufferedImage.TYPE_INT_ARGB);
Graphics2D g = resizedImage.createGraphics();
g.drawImage(image, 0, 0, width, height, null);
g.dispose();
return resizedImage;
}
}
Having an image develop a tint usually means the image is being rendered using the wrong colorspace, Adobe RGB vs. sRGB being a perennial favorite. Try changing TYPE_INT_ARGB to TYPE_INT_RGB in your code.
You can also try the following type: BufferedImage.TYPE_3BYTE_BGR
If you have any images already converted and those are almost pinkish/reddish.
You can convert those into RGB again.
try {
File folder = new File("photo/old");
File[] list = folder.listFiles();
for (File f : list) {
String url = f.getAbsolutePath();
String replce1 = url.replace('\\', '/');
File file = new File(replce1);
if (file.exists()) {
FileInputStream fis = new FileInputStream(file);
byte[] buff = new byte[fis.available()];
fis.read(buff);
BufferedImage bi = ImageIO.read(file);
BufferedImage biOriginal = new BufferedImage(1200, 800,
BufferedImage.TYPE_INT_RGB);
Graphics2D g = resizedImage.createGraphics();
g.drawImage(bi, 0, 0, 1200, 800, null);
g.dispose();
fis.close();
FileOutputStream fos2 = new FileOutputStream("photo/new/"+file.getName());
ByteArrayOutputStream baos2 = new ByteArrayOutputStream();
ImageIO.write(biOriginal, Main.extensionWithotDot, baos2);
baos2.flush();
byte[] imageInByte2 = baos2.toByteArray();
fos2.write(imageInByte2);
fos2.close();
}
}
} catch (Exception e) {
e.printStackTrace();
}
This question already has answers here:
Resizing an image in swing
(4 answers)
Closed 8 years ago.
I am loading an image in Java Swing and want to display it in JPanel..The problem I am facing is that despite of image being loaded, it is not showing in JPanel..I can say that image is successfully loaded because it is showing me the correct path of the loaded image in my label..
Here is my code..
private static final int IMG_WIDTH = 120;
private static final int IMG_HEIGHT = 120;
JLabel label;
ImageIcon photo;
WritableRaster raster;
DataBufferByte data;
File image;
JFileChooser chooser;
FileNameExtensionFilter filter;
chooser = new JFileChooser();
chooser.setCurrentDirectory(image);
filter = new FileNameExtensionFilter("jpeg, gif and png files", "jpg", "gif", "png");
chooser.addChoosableFileFilter(filter);
int i = chooser.showOpenDialog(this);
if (i == JFileChooser.APPROVE_OPTION) {
image = chooser.getSelectedFile();
jLabel8.setText(image.getAbsolutePath());
try {
BufferedImage originalImage = ImageIO.read(image);
int type = originalImage.getType() == 0 ? BufferedImage.TYPE_INT_ARGB : originalImage.getType();
BufferedImage resizeImageJpg = resizeImage(originalImage, type);
photo = new ImageIcon(toImage(resizeImageJpg));
jPanel2.removeAll();
label = new JLabel("", photo, JLabel.CENTER);
label.setIcon(photo);
jPanel2.add(label);
setVisible(true);
//converting buffered image to byte array
raster = resizeImageJpg.getRaster();
data = (DataBufferByte) raster.getDataBuffer();
} catch (IOException e) {
System.out.println(e.getMessage());
}
repaint();
chooser.setCurrentDirectory(image);
}
public Image toImage(BufferedImage bufferedImage) {
return Toolkit.getDefaultToolkit().createImage(bufferedImage.getSource());
}
private static BufferedImage resizeImage(BufferedImage originalImage, int type) {
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();
return resizedImage;
}
First, forget the toImage() method, BufferedImage already extends the Image class.
Then try to use
try {
BufferedImage originalImage = ImageIO.read( image );
int type = originalImage.getType() == 0 ? BufferedImage.TYPE_INT_ARGB : originalImage.getType();
BufferedImage resizeImageJpg = resizeImage( originalImage, type );
//forget the toImage() method, BufferedImage already extends the Image class.
photo = new ImageIcon( resizeImageJpg );
//And by the way, if you remove components and add new ones, use validate() instead.
//And don't remove the JLabel, just change the icon, it will repaint automatically.
label.setIcon(photo);
}
catch ( java.io.IOException iOException ) {
System.out.println(e.getMessage());
}
And for the resized BufferedImage, use AffineTransform to scale the image to the new size.
private static BufferedImage resizeImage(BufferedImage originalImage, int type) {
BufferedImage resizedImage = new BufferedImage(IMG_WIDTH, IMG_HEIGHT, type);
//Calculate de scale ratio;
double scaledDx = ((IMG_WIDTH*1.0d)/originalImage.getWidth());
double scaledDy = ((IMG_HEIGHT*1.0d)/originalImage.getHeight());
AffineTransform resizeAffine = AffineTransform.getScaleInstance( scaledDx, scaledDy );
BufferedImageOp buffResized = new AffineTransformOp( resizeAffine, null );
Graphics2D g2 = resizedImage.createGraphics();
g2.drawImage( resizedImage, buffResized, 0, 0 );
g2.dispose(); //Don't forget to dispose to release resources.
}
I hope I could help.
So I am trying to make a small game for a project in college. I have an image class that loads the images etc. I know this class works because I tested it all when I made it. But then I decided to use a form maker, in this case WindowsBuilder Pro to make a form that was better then I could code. I am now trying to call a function that in theory will load call the images class and load the image then add that image as an imageicon to a label within a jPanel. But I am getting nothing. Any help?
private void loadres(){
String PROGRAM_DIRECTORY = "E:/WordGame/bin/Images/";
Functions.Resources rs = new Functions.Resources();
rs.loadResources();
Functions.ImageLib iL = rs.getIL();
try {
BGImage = new JLabel(new ImageIcon(iL.mergeImages(iL.getImageArray(0),iL.getImage(PROGRAM_DIRECTORY + "Astroid1Image.png"))));
} catch (IOException e) {
e.printStackTrace();
}
BGImage.revalidate();
BGImage.repaint();
}
And here is the Image functions I am using:
public class ImageLib {
private ArrayList<BufferedImage> BIArray = new ArrayList<BufferedImage>();
public ImageLib(){
}
public BufferedImage getImage(String ref){
BufferedImage Bi = null;
try{
Bi = ImageIO.read(new File(ref));
}catch (Exception e) {
e.printStackTrace();
}
return Bi;
}
public BufferedImage resizeImage(BufferedImage Bi, int nW, int nH){
int w = Bi.getWidth();
int h = Bi.getHeight();
BufferedImage nBi = new BufferedImage(nW, nH, Bi.getType());
Graphics2D g = nBi.createGraphics();
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g.drawImage(Bi,0,0,nW,nH,0,0,w,h,null);
g.dispose();
return nBi;
}
public void addToArray(BufferedImage img){
BIArray.add(img);
}
public BufferedImage getImageArray(int index){
return (BufferedImage) BIArray.get(index);
}
public BufferedImage mergeImages(BufferedImage I1, BufferedImage I2) throws IOException{
int w = Math.max(I1.getWidth(), I2.getWidth());
int h = Math.max(I1.getHeight(), I2.getHeight());
BufferedImage combined = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
Graphics g = combined.getGraphics();
g.drawImage(I1, 0, 0, null);
g.drawImage(I2, 0, 0, null);
g.dispose();
return combined;
}
}
Here is my answer ^^
ClassLoader cldr = this.getClass().getClassLoader();
java.net.URL imageURL = cldr.getResource("path/to/your/images/picture.gif");
ImageIcon imgIcon = new ImageIcon(imageURL);
I am loading an image in bufferedimage and then writing some text on it .After I add text it makes image blurry and text distorted. I have TEXT ANTIALIASING ON . It can be seen as attached.
import java.awt.image.BufferedImage;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.imageio.*;
import java.io.*;
import javax.imageio.stream.ImageOutputStream;
import javax.imageio.plugins.jpeg.JPEGImageWriteParam;
import java.util.Locale;
class ImageCompressionDemo {
private BufferedImage originalImage;
private BufferedImage textImage;
private JPanel gui;
private JCheckBox antialiasing;
private JCheckBox rendering;
private JCheckBox fractionalMetrics;
private JCheckBox strokeControl;
private JCheckBox colorRendering;
private JCheckBox dithering;
private JComboBox textAntialiasing;
private JComboBox textLcdContrast;
private JLabel jpegLabel;
private JLabel pngLabel;
private JTextArea output;
private JSlider quality;
private int pngSize;
private int jpgSize;
final static Object[] VALUES_TEXT_ANTIALIASING = {
RenderingHints.VALUE_TEXT_ANTIALIAS_OFF,
RenderingHints.VALUE_TEXT_ANTIALIAS_ON,
RenderingHints.VALUE_TEXT_ANTIALIAS_GASP,
RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HBGR,
RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB,
RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_VBGR,
RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_VRGB
};
final static Object[] VALUES_TEXT_LCD_CONTRAST = {
new Integer(100),
new Integer(150),
new Integer(200),
new Integer(250)
};
ImageCompressionDemo() {
int width = 280;
int height = 100;
gui = new JPanel(new BorderLayout(3,4));
quality = new JSlider(JSlider.VERTICAL, 0, 100, 75);
quality.setSnapToTicks(true);
quality.setPaintTicks(true);
quality.setPaintLabels(true);
quality.setMajorTickSpacing(10);
quality.setMinorTickSpacing(5);
quality.addChangeListener( new ChangeListener(){
public void stateChanged(ChangeEvent ce) {
updateImages();
}
} );
gui.add(quality, BorderLayout.WEST);
originalImage = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);
textImage = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);
JPanel controls = new JPanel(new GridLayout(0,1,0,0));
antialiasing = new JCheckBox("Anti-aliasing", false);
rendering = new JCheckBox("Rendering - Quality", true);
fractionalMetrics = new JCheckBox("Fractional Metrics", true);
strokeControl = new JCheckBox("Stroke Control - Pure", false);
colorRendering = new JCheckBox("Color Rendering - Quality", true);
dithering = new JCheckBox("Dithering", false);
controls.add(antialiasing);
controls.add(fractionalMetrics);
textLcdContrast = new JComboBox(VALUES_TEXT_LCD_CONTRAST);
JPanel lcdContrastPanel = new JPanel(new FlowLayout(FlowLayout.LEADING));
lcdContrastPanel.add(textLcdContrast);
lcdContrastPanel.add(new JLabel("Text LCD Contrast"));
controls.add(lcdContrastPanel);
textAntialiasing = new JComboBox(VALUES_TEXT_ANTIALIASING);
controls.add(textAntialiasing);
controls.add(dithering);
controls.add(rendering);
controls.add(colorRendering);
controls.add(strokeControl);
ItemListener itemListener = new ItemListener(){
public void itemStateChanged(ItemEvent e) {
updateImages();
}
};
antialiasing.addItemListener(itemListener);
rendering.addItemListener(itemListener);
fractionalMetrics.addItemListener(itemListener);
strokeControl.addItemListener(itemListener);
colorRendering.addItemListener(itemListener);
dithering.addItemListener(itemListener);
textAntialiasing.addItemListener(itemListener);
textLcdContrast.addItemListener(itemListener);
Graphics2D g2d = originalImage.createGraphics();
GradientPaint gp = new GradientPaint(
0f, 0f, Color.red,
(float)width, (float)height, Color.orange);
g2d.setPaint(gp);
g2d.fillRect(0,0, width, height);
g2d.setColor(Color.blue);
for (int ii=0; ii<width; ii+=10) {
g2d.drawLine(ii, 0, ii, height);
}
g2d.setColor(Color.green);
for (int jj=0; jj<height; jj+=10) {
g2d.drawLine(0, jj, width, jj);
}
gui.add(controls, BorderLayout.EAST);
JPanel images = new JPanel(new GridLayout(0,1,2,2));
images.add(new JLabel(new ImageIcon(textImage)));
try {
pngLabel = new JLabel(new ImageIcon(getPngCompressedImage(textImage)));
images.add(pngLabel);
jpegLabel = new JLabel(new ImageIcon(getJpegCompressedImage(textImage)));
images.add(jpegLabel);
} catch(IOException ioe) {
}
gui.add(images, BorderLayout.CENTER);
output = new JTextArea(4,40);
output.setEditable(false);
gui.add(new JScrollPane(output), BorderLayout.SOUTH);
updateImages();
JOptionPane.showMessageDialog(null, gui);
}
private Image getPngCompressedImage(BufferedImage image) throws IOException {
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
ImageIO.write( image, "png", outStream );
pngSize = outStream.toByteArray().length;
BufferedImage compressedImage =
ImageIO.read(new ByteArrayInputStream(outStream.toByteArray()));
return compressedImage;
}
private Image getJpegCompressedImage(BufferedImage image) throws IOException {
float qualityFloat = (float)quality.getValue()/100f;
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
ImageWriter imgWriter = ImageIO.getImageWritersByFormatName( "jpg" ).next();
ImageOutputStream ioStream = ImageIO.createImageOutputStream( outStream );
imgWriter.setOutput( ioStream );
JPEGImageWriteParam jpegParams = new JPEGImageWriteParam( Locale.getDefault() );
jpegParams.setCompressionMode( ImageWriteParam.MODE_EXPLICIT );
jpegParams.setCompressionQuality( qualityFloat );
imgWriter.write( null, new IIOImage( image, null, null ), jpegParams );
ioStream.flush();
ioStream.close();
imgWriter.dispose();
jpgSize = outStream.toByteArray().length;
BufferedImage compressedImage = ImageIO.read(new ByteArrayInputStream(outStream.toByteArray()));
return compressedImage;
}
private void updateText() {
StringBuilder builder = new StringBuilder();
builder.append("Fractional Metrics: \t");
builder.append( fractionalMetrics.isSelected() );
builder.append("\n");
builder.append( textAntialiasing.getSelectedItem() );
builder.append("\nPNG size: \t");
builder.append(pngSize);
builder.append(" bytes\n");
builder.append("JPG size: \t");
builder.append(jpgSize);
builder.append(" bytes \tquality: ");
builder.append(quality.getValue());
output.setText(builder.toString());
}
private void updateImages() {
int width = originalImage.getWidth();
int height = originalImage.getHeight();
Graphics2D g2dText = textImage.createGraphics();
if (antialiasing.isSelected()) {
g2dText.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
} else {
g2dText.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_OFF);
}
if (rendering.isSelected()) {
g2dText.setRenderingHint(RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_QUALITY);
} else {
g2dText.setRenderingHint(RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_SPEED);
}
if (fractionalMetrics.isSelected()) {
g2dText.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS,
RenderingHints.VALUE_FRACTIONALMETRICS_ON);
} else {
g2dText.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS,
RenderingHints.VALUE_FRACTIONALMETRICS_OFF);
}
if (strokeControl.isSelected()) {
g2dText.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL,
RenderingHints.VALUE_STROKE_NORMALIZE);
} else {
g2dText.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL,
RenderingHints.VALUE_STROKE_PURE);
}
if (dithering.isSelected()) {
g2dText.setRenderingHint(RenderingHints.KEY_DITHERING,
RenderingHints.VALUE_DITHER_ENABLE);
} else {
g2dText.setRenderingHint(RenderingHints.KEY_DITHERING,
RenderingHints.VALUE_DITHER_DISABLE);
}
if (colorRendering.isSelected()) {
g2dText.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING,
RenderingHints.VALUE_COLOR_RENDER_QUALITY);
} else {
g2dText.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING,
RenderingHints.VALUE_COLOR_RENDER_SPEED);
}
g2dText.setRenderingHint(RenderingHints.KEY_TEXT_LCD_CONTRAST,
textLcdContrast.getSelectedItem());
g2dText.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
textAntialiasing.getSelectedItem());
g2dText.drawImage(originalImage, 0,0, null);
g2dText.setColor(Color.black);
g2dText.drawString("The quick brown fox jumped over the lazy dog.", 10,50);
try {
jpegLabel.setIcon(new ImageIcon(getJpegCompressedImage(textImage)));
pngLabel.setIcon(new ImageIcon(getPngCompressedImage(textImage)));
} catch(IOException ioe) {
}
gui.repaint();
updateText();
}
public static void main(String[] args) {
SwingUtilities.invokeLater( new Runnable() {
public void run() {
ImageCompressionDemo iwt = new ImageCompressionDemo();
}
} );
}
}
Screen shot
Typical outputs
Fractional Metrics: true
Nonantialiased text mode
PNG size: 7390 bytes
JPG size: 7036 bytes quality: 35
Fractional Metrics: true
Antialiased text mode
PNG size: 8741 bytes
JPG size: 8663 bytes quality: 55
Fractional Metrics: false
Antialiased text mode
PNG size: 8720 bytes
JPG size: 8717 bytes quality: 55
You should be able to control the text quality with the rendering hints that are shown in the other responses. I know that it works because I have done it a lot, so I think it must be something else that causes the quality degradation in this case.
How do you check the image quality? Do you paint the generated BufferedImage directly into a screen graphics in your java application or do you save to disk, i.e. as JPEG? If you save it to disk try to save it as PNG 24 and not as JPEG. I assume your desktop screen is running in True Color (32 or 24 bits color depth), right?
Are you sure that the image is actually created as BufferedImage.TYPE_INT_RGB? If you have no control over the creation of the BufferedImage in your code try to create a new BufferedImage with TYPE_INT_RGB and paint the source into this one and then draw the text into it.
Try setting the RenderingHints.KEY_DITHERING to RenderingHints.VALUE_DITHER_DISABLE (although this shouldn't be needed for true color images).
If this still doesn't help you to find the cause please provide some more information (VM version, operating system) and source code. The text rendering has become quite good with JDK 1.6 Update 10 but also earlier releases were able to produce clean text in images, it just didn't look as good because of less sophisticated antialiasing.
in response to your comment:
High contrast sharp edges as in text are a general problem with JPEG compression since it is not a lossless compression. If you really need to go with JPEG and can't switch to PNG, you can tune the compression quality of your saved image to find a better compromise between image quality and file size. See the following code on how to set the compression quality when you save a JPEG.
import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.plugins.jpeg.JPEGImageWriteParam;
import javax.imageio.stream.ImageOutputStream;
//----
float quality = 0.85f;
File outfile = new File( "MyImage.jpg" );
BufferedImage image = ...;
ImageWriter imgWriter = ImageIO.getImageWritersByFormatName( "jpg" ).next();
ImageOutputStream ioStream = ImageIO.createImageOutputStream( outfile );
imgWriter.setOutput( ioStream );
JPEGImageWriteParam jpegParams = new JPEGImageWriteParam( Locale.getDefault() );
jpegParams.setCompressionMode( ImageWriteParam.MODE_EXPLICIT );
jpegParams.setCompressionQuality( quality );
imgWriter.write( null, new IIOImage( image, null, null ), jpegParams );
ioStream.flush();
ioStream.close();
imgWriter.dispose();
try this:
public static void setGraphicsQuality(Graphics2D g2D) {
g2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2D.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
g2D.setRenderingHint(RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_QUALITY);
}
thats just java. simply turn off text anti aliasing.
or if you really need it, render the text on a separate image, if the text is black the get all pixels with color under about rgb(100,100,100) and set them to 0. then paint that buffer onto your main image.