如何提高 Graphics2D 文本质量?

Posted

技术标签:

【中文标题】如何提高 Graphics2D 文本质量?【英文标题】:How to increase Graphics2D text quality? 【发布时间】:2012-11-12 13:01:38 【问题描述】:

我有一个关于在条形码上打印附加信息的问题。我正在使用http://barbecue.sourceforge.net/ 创建我的条形码。

创建条形码后,我想添加一些附加信息。目前我用以下方式做到这一点!例如:

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();

输出为 pdf 格式,如下所示:

如您所见,我的文字质量(条形码上方和下方)真的很差...如何提高文字质量以使文字更流畅而不是像素化?!

(当我打印条形码时,条形码看起来很像素化......)

有什么建议吗?

更新:

所以,我在这里添加了我最新结果的图片......当我打印出这些条形码时,它们看起来很糟糕!所以这是我所做的代码:

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();

使用该代码,我可以获得最好的结果!当然,我玩过“Metrics, AA_GASP, LCS_HRGB, different fonts (Verdana is the best in my opinion) ...”等等,但其中一些我无法使用,因为我的条形码变得模糊了!所以实际上我正在强迫我无法提高来自 graphics2d 的拉绳的文本质量的问题!

所以,我想问是否有可能让“SSYYS”(字体大小 11)和“FLORETT”(字体大小 7)看起来更好! JAVA 中是否有可能在字体大小小于“12”的图像上绘制“平滑”文本?有解决方法吗?正如您在图片中看到的那样,字母“S 和 Y”看起来非常糟糕......

第二次更新:

到目前为止的一些示例代码...请确保以下文件夹存在:C:\TestBarcodes\

希望我将代码减少到您可以想象我的问题的最低限度......

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();
    
  

【问题讨论】:

使用this answer上的代码,轻松尝试各种可能性。 感谢您的帖子,但这并没有帮助:/ 我玩了最后 5 天以提高文本质量......但我无法管理它......它是非常像素化!还有其他提高文本质量的机会吗?!除了 Graphics2D 之外的东西?!或者java不能处理这么小的字体?!我更新了我的帖子,你可以看到我到目前为止所拥有的,但即使是“SSYYS”(字体大小 13 非常像素化)...... 下一级帮助。如需尽快获得更好的帮助,请发帖SSCCE。 OK.. & pdfbox 与写明文有什么关系?当您在纯图像上绘制文字时,文字是否清晰?在这种情况下,问题是pdfbox 我不提供支持。如果不是,那么可以说pdfbox 与问题无关,应该被删除。删除与pdfbox 相关的代码的一个巨大优势是,人们将能够使用 J2SE 编译和运行代码,而无需第三方插件。我花了比平时更多的时间来解释如何发布代码,而且我几乎要放弃这个线程了。最后一次尝试。 您能否将文本作为实际文本写入 PDF 而不是图像?这样您就可以在最终结果中获得矢量格式的文本。 【参考方案1】:

如果有人想在这种情况下使用像素图像,而不是矢量,那么图像应该被放大以获得更好的打印质量:

static final int PIXELS_PER_POINT = 4; // 4x

然后定义所有尺寸以点为单位,而不是以像素为单位:

// 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;

现在,在进行任何绘图时,始终使用转换为像素的点:

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;

因此,通过这种方法,您可以使用“标准”尺寸进行操作。这种方法对我来说非常适合中低复杂度的图纸。

你可以更进一步,将PIXELS_PER_POINT转换为参数:1x用于普通显示网页上的图像,2x用于Retina显示器,4x用于打印!

【讨论】:

PIXELS_PER_POINT 不应该是 double 类型,计算方式如下:PIXELS_PER_POINT = 300./90。对于 300dpi 打印(假设标准显示器具有 90dpi)PIXELS_PER_POINT = 600./90。对于 600dpi 打印...等等【参考方案2】:

要修复 Graphics2d 中文本或形状中的锯齿状边缘,您需要设置 RenderingHint

Graphics2D g2d = bufferedImage.createGraphics();

    g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);

说明

典型的抗锯齿算法通过根据估计的形状的部分像素覆盖率将形状边界上像素的现有颜色与请求的填充油漆混合来工作。

文本抗锯齿提示键。 TEXT_ANTIALIASING 提示可以控制文本抗锯齿算法的使用,而与用于形状渲染的选择无关。通常,应用程序可能只想对文本使用抗锯齿,而不对其他形状使用。此外,用于减少文本混叠伪影的算法通常比为一般渲染开发的算法更复杂,因此此提示键提供了额外的值,可以控制某些特定于文本的算法的选择。如果保留在 DEFAULT 状态,此提示通常会遵循常规 KEY_ANTIALIASING 提示键的值。

【讨论】:

以上是关于如何提高 Graphics2D 文本质量?的主要内容,如果未能解决你的问题,请参考以下文章

在 Java Graphics2D 中,文本如何在 Rectangle 上居中对齐?

AWT 图形未正确翻译

通过 pytesseract 和 PIL 提高文本识别的准确性

浅谈如何提高产品质量?

怎么提高png图象的质量?

如何提高编码质量