1

I'm using javax.imageio to generate images from text strings on Windows and Linux, and I find the images are very different in quality (Linux = poor quality, small physical size, although same dimentions).

Linux (Ubunutu), 443 bytes

enter image description here

Windows 7, 1,242 bytes

enter image description here

I'm using the same font file (From Windows, uploaded to linux), and using this code to generate the images. Any idea how to improve the quality of the linux-generated images? Why are the generated images different in the first place?

I've tried setting explicit compression (via iwp.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);), but I'm getting an UnsupportedOperationException when I try that.

Update:

Here is an SSCCE. I've updated my example and removed the font, the results are consistent. They also happen if you do set the font on both systems.

import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;

public class Example {
    /**
     * <p>Create an image from text. <p/>
     * <p/>
     * http://stackoverflow.com/a/4437998/11236
     */
    public static void createFromText(String text, Path outputFile, int width, int height, Color color, int fontSize) {
        JLabel label = new JLabel(text, SwingConstants.CENTER);
        label.setSize(width, height);
        label.setForeground(color);

        BufferedImage image = new BufferedImage(
                label.getWidth(), label.getHeight(),
                BufferedImage.TYPE_INT_ARGB);

        Graphics g = null;
        try {
            // paint the html to an image
            g = image.getGraphics();
            g.setColor(Color.BLACK);
            label.paint(g);
        } finally {
            if (g != null) {
                g.dispose();
            }
        }

        // get the byte array of the image (as jpeg)
        try {
            ImageIO.write(image, "png", outputFile.toFile());
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public static void main(String[] args) {
        Path output = Paths.get("/tmp/foo.png");
        createFromText("Custom Text", output, 200, 40, Color.blue, 30);
    }
}
ripper234
  • 222,824
  • 274
  • 634
  • 905
  • *"I've tried.."* Try posting an [SSCCE](http://sscce.org/). But I recommend you factor out the `JLabel`, and instead draw the string directly to the graphics instance, using a `RenderingHints` map where you specify ..everything that can be specified. The latter will get around some of the different defaults that might be used. – Andrew Thompson Mar 04 '12 at 12:57
  • Also, you seem to be presuming the difference is in how the images are saved. I (& others, apparently) doubt that is the case. It would pay to pop the `JLabel` itself in a `JOptionPane` before you ever render it. Grab a screenshot and compare it to the screenshot from the other system. Do the initial `JLabel` instances even look the same? – Andrew Thompson Mar 04 '12 at 13:10
  • @AndrewThompson - I might have to produce a sccee indeed. I'll checkout RenderingHints. I can't easily preview the image on the linux system, I don't think it has a UI installed ... it's an EC2 ubuntu server. – ripper234 Mar 04 '12 at 13:17
  • @AndrewThompson - updated with a true SSCCE. – ripper234 Mar 04 '12 at 14:24
  • Well, I set all rendering hints I could find (updated SSCCE https://gist.github.com/1973391), and the images are a lot closer, but still not identical. I also noticed that the font I was using didn't have a BOLD version, just a PLAIN version. When I modified the code to output a PLAIN version, the images now look almost exactly the same ... still not binary identical. – ripper234 Mar 04 '12 at 14:58
  • What I would like to understand is why there's any difference between the two systems? What factors contribute to this, and can they be eliminated? – ripper234 Mar 04 '12 at 15:00
  • Ach! Java 7. I'm still using the Java 6 SDK, so cannot compile the code. :( – Andrew Thompson Mar 04 '12 at 15:20
  • @AndrewThompson - well, the difference between 6 and 7 is very minor, you should be able to port it with 2 minutes' work. – ripper234 Mar 04 '12 at 16:08

2 Answers2

3

Just a guess, but your images look like this could also come from different antialiasing behaviour when rendering the text to an image. Meaning that the difference is not caused during the compression or png encoding of the image, but already when rendering the text into the Image. If there is no text antialiasing, the image can be compressed to a smaller size because it contains less different colours, so that could also explain the difference in file size.

Try to experiment with explicitely specifiying antialising settings instead of relying on the system defaults, and see if that makes a difference. You can do this by adding RenderingHints to the Graphics2D object, e.g. the rendering hint text_antialising:

http://docs.oracle.com/javase/6/docs/api/java/awt/RenderingHints.html#KEY_TEXT_ANTIALIASING

Also see here for a discussion on font rendering behaviour:

Java Font Rendering

Community
  • 1
  • 1
Jan
  • 2,498
  • 1
  • 15
  • 6
  • This, and @AndrewThompson's comments were helpful. Still (see my comment replies to the question), I would like to understand why there's any difference between the two platforms? Some difference persists even after I set identical rendering hints. Why isn't this deterministic? – ripper234 Mar 04 '12 at 15:03
0

one time you say that you only want to make string images, then in the code you say you make images from html... please specify this

for only strings: Maybe on linux the label itself sets other properties for the graphics, so do it yourself and don't use the labels paint method... could be linked with linux's Window-UI

html: try to use the JTextPane, it should have advanced html settings... maybe this improves the quality

Thomas
  • 650
  • 9
  • 9