How to increase Graphics2D text quality?

Sway picture Sway · Nov 24, 2012 · Viewed 9.3k times · Source

I have a question concerning printing additional information on barcodes. I am using http://barbecue.sourceforge.net/ to create my barcodes.

After I created my barcodes I want to add some additional information. At the moment i do this with the following way! For example:

Graphics2D g2d5 = container4Barcode.createGraphics();
g2d5.setBackground(Color.WHITE);
g2d5.clearRect(0, 33, 200, 200);
g2d5.setColor(Color.BLACK);
g2d5.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
    RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
g2d5.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
    RenderingHints.VALUE_TEXT_ANTIALIAS_GASP);
g2d5.setFont(new Font("Arial", Font.PLAIN, 8));
g2d5.drawString(barcode, 8, 40);
g2d5.drawString(generateRandomNumber(ekPreis), 57, 40);
String datumResult = datum;
g2d5.drawString(location, 98, 40);
g2d5.drawString(datum.substring(2), 114, 40);
g2d5.dispose();

The output is in a pdf the following: enter image description here

As you can see is the quality of my text (above and under the barcode) is really bad ... How can I increase the quality of the text to make the text more smoother and not that pixelated?!

(When I print my barcodes, the barcodes look very pixelated ...)

Any tips?

UPDATE:

So, I added here the a picture of my latest outcome ... When I print out these barcodes they look horrible! So here is the code what I did:

Graphics2D g2d6 = container4Barcode.createGraphics();
g2d6.setColor(Color.black);
g2d6.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
    RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
g2d6.setFont(new Font("Verdana", Font.BOLD, 7));
g2d6.drawString("FLORETT", 9, 20);
g2d6.drawString("50-521-60", 57, 20);
Graphics2D g2d4 = container4Barcode.createGraphics();
g2d4.setColor(Color.black);
g2d4.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
    RenderingHints.VALUE_TEXT_ANTIALIAS_ON); 
g2d4.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, 
    RenderingHints.VALUE_FRACTIONALMETRICS_ON);
g2d4.setFont(new Font("Verdana", Font.BOLD, 11));
g2d4.drawString("SSYYS", 105, 19);
g2d4.dispose();

With that Code I get the best results! Of course I played with "Metrics, AA_GASP, LCS_HRGB, different fonts (Verdana is the best in my opinion) ..." and a lot more, but some of them I couldn't use, because then my barcode got blurred! So actioally I am forcing the problem that I am unable to improve the quality of my text-quality of the drawstring from graphics2d!

So, I want to ask if there is a possibility to let the "SSYYS" (Font Size 11) and the "FLORETT" (Font Size 7) look much nicer! Is there a possibility in JAVA to draw "smooth" text on an image with a font size less than "12" ? Is there a workaround to to that ? As you can see in the picture the letters "S and Y" look very awful...

2nd Update:

Some Example code so far... Please be sure that the following folder exists: C:\TestBarcodes\

Hope I reduced my code to the minimum that you can imagine what my problem is...

package generator;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.io.FileOutputStream;
import java.io.IOException;

import net.sourceforge.barbecue.Barcode;
import net.sourceforge.barbecue.BarcodeException;
import net.sourceforge.barbecue.BarcodeFactory;
import net.sourceforge.barbecue.output.OutputException;

import org.apache.pdfbox.exceptions.COSVisitorException;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.edit.PDPageContentStream;
import org.apache.pdfbox.pdmodel.graphics.xobject.PDJpeg;
import org.apache.pdfbox.pdmodel.graphics.xobject.PDXObjectImage;

public class BarcodeGen {

  // sets the picWidth
  private static int picWidth = 149;
  // sets the picHeigth
  private static int picHeigth = 60;

  public static void main(String[] args) 
      throws BarcodeException, OutputException, COSVisitorException, IOException {
    generateBarcode("11138500");
  }

  public static void generateBarcode(String barcode) 
      throws IOException, COSVisitorException, BarcodeException, OutputException {

    Barcode barcode2 = BarcodeFactory.createCode39(barcode, false);
    int gw = barcode2.getWidth();
    // change this to suit if you want higher, default 50
    // barcode2.setBarWidth(50);
    // this sets DPI
    barcode2.setResolution(100);
    // barcode2.setFont(font);
    int gh = barcode2.getHeight();
    // change this if you want a coloured background
    // image = new BufferedImage(t, s, BufferedImage.TYPE_INT_RGB)
    BufferedImage image = new BufferedImage(gw, gh, BufferedImage.TYPE_INT_RGB);

    Graphics2D g2 = (Graphics2D) image.getGraphics();
    // default is black so draw a white box first
    // change type to INT_RGB if you want a coloured background
    g2.setColor(Color.white);
    g2.fillRect(0, 0, gw, gh);
    barcode2.draw(g2, 0, 0);

    // CREATE ADDITIONAL INFORMATION ON BARCODE

    BufferedImage container4Barcode = new BufferedImage(
        picWidth, picHeigth, image.getType());
    Graphics2D g2d = container4Barcode.createGraphics();

    g2d.setBackground(Color.WHITE);
    g2d.clearRect(0, 0, picWidth, picHeigth);
    g2d.setColor(Color.black);
    g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
        RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB);
    g2d.drawImage(image, 8, 21, 130, 18, null);
    g2d.dispose();

    Graphics2D g2d6 = container4Barcode.createGraphics();
    g2d6.setColor(Color.black);
    g2d6.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
        RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
    g2d6.setFont(new Font("Verdana", Font.BOLD, 7));

    g2d6.drawString("FLORETT", 9, 20);
    g2d6.drawString("50-521-60", 57, 20);

    Graphics2D g2d4 = container4Barcode.createGraphics();
    g2d4.setColor(Color.black);
    g2d4.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
        RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
    g2d4.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS,
        RenderingHints.VALUE_FRACTIONALMETRICS_ON);
    g2d4.setFont(new Font("Verdana", Font.BOLD, 11));
    g2d4.drawString("SSYYS", 105, 19);
    g2d4.dispose();

    // PRINT PDF

    int ver = 782;

    PDDocument doc = new PDDocument();
    PDPage page = new PDPage(PDPage.PAGE_SIZE_A4);
    doc.addPage(page);

    PDXObjectImage image2 = new PDJpeg(doc, container4Barcode);
    PDPageContentStream content = new PDPageContentStream(doc, page);
    content.drawImage(image2, 5, ver);
    content.close();

    doc.save(new FileOutputStream("C:\\TestBarcodes\\barcode.pdf"));

    // opens the pdf file
    Process p = Runtime
        .getRuntime()
        .exec("rundll32 url.dll,FileProtocolHandler C:\\TestBarcodes\\barcode.pdf");
    try {
      p.waitFor();
    } catch (InterruptedException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
  }
}

enter image description here

Answer

vladimir83 picture vladimir83 · Oct 8, 2013

If someone wants to use pixel images in such cases, and not vector, then image should be upscaled for better printing quality:

static final int PIXELS_PER_POINT = 4; // 4x

Then define all dimensions in points, not in pixels:

// Image size in points
static final int IMAGE_WIDTH = 150;
static final int IMAGE_HEIGHT = 60;
// Font size in points
static final int FONT_SIZE = 11;

Now, when do any drawing, always use points converted to pixels:

static int toPixels(int value) {
    return value * PIXELS_PER_POINT;
}

BufferedImage draw() {
    BufferedImage image = 
        new BufferedImage(toPixels(IMAGE_WIDTH), toPixels(IMAGE_HEIGHT), TYPE_INT_ARGB);
    Graphics2D g = image.createGraphics();
    // <graphics init code goes here>

    Font font = new Font("Arial", Font.PLAIN, toPixels(FONT_SIZE));
    g.setFont(font);
    g.drawString("Grapes", toPixels(5), toPixels(40)); // coordinates are in points

    g.dispose()
    return image;
}

So, with this approach you can operate with 'standard' dimentions. This approach works quite well for me for low- and medium complexity drawings.

You can go further and convert PIXELS_PER_POINT to a parameter: use 1x for images on web-pages with ordinary display, 2x for Retina displays and 4x for printing!