提交 c349278f 编写于 作者: M mcherkas

8132890: Text Overlapping on Dot Matrix Printers

Reviewed-by: serb
上级 a78d8263
......@@ -494,24 +494,48 @@ final class WPathGraphics extends PathGraphics {
*/
float fontSize = font.getSize2D();
double devResX = wPrinterJob.getXRes();
double devResY = wPrinterJob.getYRes();
double fontDevScaleY = devResY / DEFAULT_USER_RES;
int orient = getPageFormat().getOrientation();
if (orient == PageFormat.LANDSCAPE ||
orient == PageFormat.REVERSE_LANDSCAPE)
{
double tmp = devResX;
devResX = devResY;
devResY = tmp;
}
double devScaleX = devResX / DEFAULT_USER_RES;
double devScaleY = devResY / DEFAULT_USER_RES;
fontTransform.scale(1.0/devScaleX, 1.0/devScaleY);
Point2D.Double pty = new Point2D.Double(0.0, 1.0);
fontTransform.deltaTransform(pty, pty);
double scaleFactorY = Math.sqrt(pty.x*pty.x+pty.y*pty.y);
float scaledFontSizeY = (float)(fontSize * scaleFactorY);
float scaledFontSizeY = (float)(fontSize * scaleFactorY * fontDevScaleY);
Point2D.Double ptx = new Point2D.Double(1.0, 0.0);
fontTransform.deltaTransform(ptx, ptx);
double scaleFactorX = Math.sqrt(ptx.x*ptx.x+ptx.y*ptx.y);
float scaledFontSizeX = (float)(fontSize * scaleFactorX);
float awScale = getAwScale(scaleFactorX, scaleFactorY);
int iangle = getAngle(ptx);
ptx = new Point2D.Double(1.0, 0.0);
deviceTransform.deltaTransform(ptx, ptx);
double advanceScaleX = Math.sqrt(ptx.x*ptx.x+ptx.y*ptx.y);
pty = new Point2D.Double(0.0, 1.0);
deviceTransform.deltaTransform(pty, pty);
double advanceScaleY = Math.sqrt(pty.x*pty.x+pty.y*pty.y);
Font2D font2D = FontUtilities.getFont2D(font);
if (font2D instanceof TrueTypeFont) {
textOut(str, font, (TrueTypeFont)font2D, frc,
scaledFontSizeY, iangle, awScale,
deviceTransform, scaleFactorX,
advanceScaleX, advanceScaleY,
x, y, devpos.x, devpos.y, targetW);
} else if (font2D instanceof CompositeFont) {
/* Composite fonts are made up of multiple fonts and each
......@@ -542,7 +566,7 @@ final class WPathGraphics extends PathGraphics {
PhysicalFont slotFont = compFont.getSlotFont(slot);
textOut(substr, font, slotFont, frc,
scaledFontSizeY, iangle, awScale,
deviceTransform, scaleFactorX,
advanceScaleX, advanceScaleY,
userx, usery, devx, devy, 0f);
Rectangle2D bds = font.getStringBounds(substr, frc);
float xAdvance = (float)bds.getWidth();
......@@ -635,18 +659,42 @@ final class WPathGraphics extends PathGraphics {
*/
float fontSize = font.getSize2D();
double devResX = wPrinterJob.getXRes();
double devResY = wPrinterJob.getYRes();
double fontDevScaleY = devResY / DEFAULT_USER_RES;
int orient = getPageFormat().getOrientation();
if (orient == PageFormat.LANDSCAPE ||
orient == PageFormat.REVERSE_LANDSCAPE)
{
double tmp = devResX;
devResX = devResY;
devResY = tmp;
}
double devScaleX = devResX / DEFAULT_USER_RES;
double devScaleY = devResY / DEFAULT_USER_RES;
fontTransform.scale(1.0/devScaleX, 1.0/devScaleY);
Point2D.Double pty = new Point2D.Double(0.0, 1.0);
fontTransform.deltaTransform(pty, pty);
double scaleFactorY = Math.sqrt(pty.x*pty.x+pty.y*pty.y);
float scaledFontSizeY = (float)(fontSize * scaleFactorY);
float scaledFontSizeY = (float)(fontSize * scaleFactorY * fontDevScaleY);
Point2D.Double pt = new Point2D.Double(1.0, 0.0);
fontTransform.deltaTransform(pt, pt);
double scaleFactorX = Math.sqrt(pt.x*pt.x+pt.y*pt.y);
float scaledFontSizeX = (float)(fontSize * scaleFactorX);
Point2D.Double ptx = new Point2D.Double(1.0, 0.0);
fontTransform.deltaTransform(ptx, ptx);
double scaleFactorX = Math.sqrt(ptx.x*ptx.x+ptx.y*ptx.y);
float awScale = getAwScale(scaleFactorX, scaleFactorY);
int iangle = getAngle(pt);
int iangle = getAngle(ptx);
ptx = new Point2D.Double(1.0, 0.0);
deviceTransform.deltaTransform(ptx, ptx);
double advanceScaleX = Math.sqrt(ptx.x*ptx.x+ptx.y*ptx.y);
pty = new Point2D.Double(0.0, 1.0);
deviceTransform.deltaTransform(pty, pty);
double advanceScaleY = Math.sqrt(pty.x*pty.x+pty.y*pty.y);
int numGlyphs = gv.getNumGlyphs();
int[] glyphCodes = gv.getGlyphCodes(0, numGlyphs, null);
......@@ -705,8 +753,7 @@ final class WPathGraphics extends PathGraphics {
* rotation element of the deviceTransform.
*/
AffineTransform advanceTransform =
new AffineTransform(deviceTransform);
advanceTransform.rotate(iangle*Math.PI/1800.0);
AffineTransform.getScaleInstance(advanceScaleX, advanceScaleY);
float[] glyphAdvPos = new float[glyphPos.length];
advanceTransform.transform(glyphPos, 0, //source
......@@ -784,8 +831,7 @@ final class WPathGraphics extends PathGraphics {
Font font, PhysicalFont font2D,
FontRenderContext frc,
float deviceSize, int rotation, float awScale,
AffineTransform deviceTransform,
double scaleFactorX,
double scaleFactorX, double scaleFactorY,
float userx, float usery,
float devx, float devy, float targetW) {
......@@ -826,8 +872,7 @@ final class WPathGraphics extends PathGraphics {
* See earlier comment in printGlyphVector() for details.
*/
AffineTransform advanceTransform =
new AffineTransform(deviceTransform);
advanceTransform.rotate(rotation*Math.PI/1800.0);
AffineTransform.getScaleInstance(scaleFactorX, scaleFactorY);
float[] glyphAdvPos = new float[glyphPos.length];
advanceTransform.transform(glyphPos, 0, //source
......@@ -841,11 +886,11 @@ final class WPathGraphics extends PathGraphics {
/* If 2D and GDI agree on the advance of the string we do not
* need to explicitly assign glyph positions.
* If we are to use the GDI advance, require it to agree with
* JDK to a precision of <= 0.2% - ie 1 pixel in 500
* JDK to a precision of <= 1.0% - ie 1 pixel in 100
* discrepancy after rounding the 2D advance to the
* nearest pixel and is greater than one pixel in total.
* ie strings < 500 pixels in length will be OK so long
* as they differ by only 1 pixel even though that is > 0.02%
* ie strings < 100 pixels in length will be OK so long
* as they differ by only 1 pixel even though that is > 1%
* The bounds from 2D are in user space so need to
* be scaled to device space for comparison with GDI.
* scaleX is the scale from user space to device space needed for this.
......@@ -863,7 +908,7 @@ final class WPathGraphics extends PathGraphics {
if (ratio < 1) {
ratio = 1/ratio;
}
return diff <= 1 || ratio < 1.002;
return diff <= 1 || ratio < 1.01;
}
return true;
}
......
<!--
Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
This code is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License version 2 only, as
published by the Free Software Foundation.
This code is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
version 2 for more details (a copy is included in the LICENSE file that
accompanied this code).
You should have received a copy of the GNU General Public License version
2 along with this work; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
or visit www.oracle.com if you need additional information or have any
questions.
-->
<html>
<body>
<applet code="PrintTextTest.class" width=400 height=100></applet>
This tests that printed text renders similarly to on-screen,
under a variety of APIs and graphics and font transforms
Print to your preferred printer. Collect the output.
Refer to the onscreen buttons to cycle through the on-screen
content
For each page, confirm that the printed content corresponds to
the on-screen rendering for that *same* page.
Some cases may look odd but its intentional. Verify
it looks the same on screen and on the printer.
Note that text does not scale linearly from screen to printer
so some differences are normal and not a bug.
The easiest way to spot real problems is to check that
any underlines are the same length as the underlined text
and that any rotations are the same in each case.
Note that each on-screen page is printed in both portrait
and landscape mode
So for example, Page 1/Portrait, and Page 1/Landscape when
rotated to view properly, should both match Page 1 on screen.;
</body>
</html>
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* @test
* @bug 6425068 7157659 8132890
* @summary Confirm that text prints where we expect to the length we expect.
* @run applet/manual=yesno PrintTextTest.html
*/
import java.awt.*;
import java.awt.event.*;
import java.text.*;
import java.util.*;
import java.awt.font.*;
import java.awt.geom.*;
import java.awt.print.*;
import javax.swing.*;
public class PrintTextTest extends JApplet {
public void start() {
StandalonePrintTextTest.main(null);
}
}
class StandalonePrintTextTest extends Component implements Printable {
static int preferredSize;
Font textFont;
AffineTransform gxTx;
String page;
boolean useFM;
public static void main(String args[]) {
PrinterJob pjob = PrinterJob.getPrinterJob();
PageFormat portrait = pjob.defaultPage();
portrait.setOrientation(PageFormat.PORTRAIT);
preferredSize = (int)portrait.getImageableWidth();
PageFormat landscape = pjob.defaultPage();
landscape.setOrientation(PageFormat.LANDSCAPE);
Book book = new Book();
JTabbedPane p = new JTabbedPane();
int page = 1;
Font font = new Font("Dialog", Font.PLAIN, 18);
String name = "Page " + new Integer(page++);
StandalonePrintTextTest ptt = new StandalonePrintTextTest(name, font, null, false);
p.add(name, ptt);
book.append(ptt, portrait);
book.append(ptt, landscape);
font = new Font("Dialog", Font.PLAIN, 18);
name = "Page " + new Integer(page++);
ptt = new StandalonePrintTextTest(name, font, null, true);
p.add(name, ptt);
book.append(ptt, portrait);
book.append(ptt, landscape);
font = new Font("Lucida Sans", Font.PLAIN, 18);
name = "Page " + new Integer(page++);
ptt = new StandalonePrintTextTest(name, font, null, false);
p.add(name, ptt);
book.append(ptt, portrait);
book.append(ptt, landscape);
font = new Font("Lucida Sans", Font.PLAIN, 18);
AffineTransform rotTx = AffineTransform.getRotateInstance(0.15);
rotTx.translate(60,0);
name = "Page " + new Integer(page++);
ptt = new StandalonePrintTextTest(name, font, rotTx, false);
p.add(name, ptt);
book.append(ptt, portrait);
book.append(ptt, landscape);
font = new Font("Dialog", Font.PLAIN, 18);
AffineTransform scaleTx = AffineTransform.getScaleInstance(1.25, 1.25);
name = "Page " + new Integer(page++);
ptt = new StandalonePrintTextTest(name, font, scaleTx, false);
p.add(name, ptt);
book.append(ptt, portrait);
book.append(ptt, landscape);
font = new Font("Dialog", Font.PLAIN, 18);
scaleTx = AffineTransform.getScaleInstance(-1.25, 1.25);
scaleTx.translate(-preferredSize/1.25, 0);
name = "Page " + new Integer(page++);
ptt = new StandalonePrintTextTest(name, font, scaleTx, false);
p.add(name, ptt);
book.append(ptt, portrait);
book.append(ptt, landscape);
font = new Font("Dialog", Font.PLAIN, 18);
scaleTx = AffineTransform.getScaleInstance(1.25, -1.25);
scaleTx.translate(0, -preferredSize/1.25);
name = "Page " + new Integer(page++);
ptt = new StandalonePrintTextTest(name, font, scaleTx, false);
p.add(name, ptt);
book.append(ptt, portrait);
book.append(ptt, landscape);
font = font.deriveFont(rotTx);
name = "Page " + new Integer(page++);
ptt = new StandalonePrintTextTest(name, font, null, false);
p.add(ptt, BorderLayout.CENTER);
p.add(name, ptt);
book.append(ptt, portrait);
book.append(ptt, landscape);
font = new Font("Monospaced", Font.PLAIN, 12);
name = "Page " + new Integer(page++);
ptt = new StandalonePrintTextTest(name, font, null, false);
p.add(ptt, BorderLayout.CENTER);
p.add(name, ptt);
book.append(ptt, portrait);
book.append(ptt, landscape);
Font xfont = font.deriveFont(AffineTransform.getScaleInstance(1.5, 1));
name = "Page " + new Integer(page++);
ptt = new StandalonePrintTextTest(name, xfont, null, false);
p.add(ptt, BorderLayout.CENTER);
p.add(name, ptt);
book.append(ptt, portrait);
book.append(ptt, landscape);
Font yfont = font.deriveFont(AffineTransform.getScaleInstance(1, 1.5));
name = "Page " + new Integer(page++);
ptt = new StandalonePrintTextTest(name, yfont, null, false);
p.add(ptt, BorderLayout.CENTER);
p.add(name, ptt);
book.append(ptt, portrait);
book.append(ptt, landscape);
if (System.getProperty("os.name").startsWith("Windows")) {
font = new Font("MS Gothic", Font.PLAIN, 12);
name = "Page " + new Integer(page++);
ptt = new PrintJAText(name, font, null, true);
p.add(ptt, BorderLayout.CENTER);
p.add(name, ptt);
book.append(ptt, portrait);
book.append(ptt, landscape);
font = new Font("MS Gothic", Font.PLAIN, 12);
name = "Page " + new Integer(page++);
rotTx = AffineTransform.getRotateInstance(0.15);
ptt = new PrintJAText(name, font, rotTx, true);
p.add(ptt, BorderLayout.CENTER);
p.add(name, ptt);
book.append(ptt, portrait);
book.append(ptt, landscape);
}
pjob.setPageable(book);
JFrame f = new JFrame();
f.add(BorderLayout.CENTER, p);
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {System.exit(0);}
});
f.pack();
f.show();
try {
if (pjob.printDialog()) {
pjob.print();
}
} catch (PrinterException e) {
throw new RuntimeException(e.getMessage());
}
}
public StandalonePrintTextTest(String page, Font font, AffineTransform gxTx,
boolean fm) {
this.page = page;
textFont = font;
this.gxTx = gxTx;
this.useFM = fm;
setBackground(Color.white);
}
public static AttributedCharacterIterator getIterator(String s) {
return new AttributedString(s).getIterator();
}
static String orient(PageFormat pf) {
if (pf.getOrientation() == PageFormat.PORTRAIT) {
return "Portrait";
} else {
return "Landscape";
}
}
public int print(Graphics g, PageFormat pf, int pageIndex) {
Graphics2D g2d = (Graphics2D)g;
g2d.translate(pf.getImageableX(), pf.getImageableY());
g.drawString(page+" "+orient(pf),50,20);
g.translate(0, 25);
paint(g);
return PAGE_EXISTS;
}
public Dimension getMinimumSize() {
return getPreferredSize();
}
public Dimension getPreferredSize() {
return new Dimension(preferredSize, preferredSize);
}
public void paint(Graphics g) {
/* fill with white before any transformation is applied */
g.setColor(Color.white);
g.fillRect(0, 0, getSize().width, getSize().height);
Graphics2D g2d = (Graphics2D) g;
if (gxTx != null) {
g2d.transform(gxTx);
}
if (useFM) {
g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS,
RenderingHints.VALUE_FRACTIONALMETRICS_ON);
}
g.setFont(textFont);
FontMetrics fm = g.getFontMetrics();
String s;
int LS = 30;
int ix=10, iy=LS+10;
g.setColor(Color.black);
s = "drawString(String str, int x, int y)";
g.drawString(s, ix, iy);
if (!textFont.isTransformed()) {
g.drawLine(ix, iy+1, ix+fm.stringWidth(s), iy+1);
}
iy += LS;
s = "drawString(AttributedCharacterIterator iterator, int x, int y)";
g.drawString(getIterator(s), ix, iy);
iy += LS;
s = "\tdrawChars(\t\r\nchar[], int off, int len, int x, int y\t)";
g.drawChars(s.toCharArray(), 0, s.length(), ix, iy);
if (!textFont.isTransformed()) {
g.drawLine(ix, iy+1, ix+fm.stringWidth(s), iy+1);
}
iy += LS;
s = "drawBytes(byte[], int off, int len, int x, int y)";
byte data[] = new byte[s.length()];
for (int i = 0; i < data.length; i++) {
data[i] = (byte) s.charAt(i);
}
g.drawBytes(data, 0, data.length, ix, iy);
Font f = g2d.getFont();
FontRenderContext frc = g2d.getFontRenderContext();
iy += LS;
s = "drawString(String s, float x, float y)";
g2d.drawString(s, (float) ix, (float) iy);
if (!textFont.isTransformed()) {
g.drawLine(ix, iy+1, ix+fm.stringWidth(s), iy+1);
}
iy += LS;
s = "drawString(AttributedCharacterIterator iterator, "+
"float x, float y)";
g2d.drawString(getIterator(s), (float) ix, (float) iy);
iy += LS;
s = "drawGlyphVector(GlyphVector g, float x, float y)";
GlyphVector gv = f.createGlyphVector(frc, s);
g2d.drawGlyphVector(gv, ix, iy);
Point2D adv = gv.getGlyphPosition(gv.getNumGlyphs());
if (!textFont.isTransformed()) {
g.drawLine(ix, iy+1, ix+(int)adv.getX(), iy+1);
}
iy += LS;
s = "GlyphVector with position adjustments";
gv = f.createGlyphVector(frc, s);
int ng = gv.getNumGlyphs();
adv = gv.getGlyphPosition(ng);
for (int i=0; i<ng; i++) {
Point2D gp = gv.getGlyphPosition(i);
double gx = gp.getX();
double gy = gp.getY();
if (i % 2 == 0) {
gy+=5;
} else {
gy-=5;
}
gp.setLocation(gx, gy);
gv.setGlyphPosition(i, gp);
}
g2d.drawGlyphVector(gv, ix, iy);
if (!textFont.isTransformed()) {
g.drawLine(ix, iy+1, ix+(int)adv.getX(), iy+1);
}
iy +=LS;
s = "drawString: \u0924\u094d\u0930 \u0915\u0948\u0930\u0947 End.";
g.drawString(s, ix, iy);
if (!textFont.isTransformed()) {
g.drawLine(ix, iy+1, ix+fm.stringWidth(s), iy+1);
}
iy += LS;
s = "TextLayout 1: \u0924\u094d\u0930 \u0915\u0948\u0930\u0947 End.";
TextLayout tl = new TextLayout(s, new HashMap(), frc);
tl.draw(g2d, ix, iy);
iy += LS;
s = "TextLayout 2: \u0924\u094d\u0930 \u0915\u0948\u0930\u0947 End.";
tl = new TextLayout(s, f, frc);
tl.draw(g2d, ix, iy);
}
}
class PrintJAText extends StandalonePrintTextTest {
public PrintJAText(String page, Font font, AffineTransform gxTx,
boolean fm) {
super(page, font, gxTx, fm);
}
private static final String TEXT =
"\u3042\u3044\u3046\u3048\u304a\u30a4\u30ed\u30cf" +
"\u30cb\u30db\u30d8\u30c8\u4e00\u4e01\u4e02\u4e05\uff08";
public void paint(Graphics g) {
/* fill with white before any transformation is applied */
g.setColor(Color.white);
g.fillRect(0, 0, getSize().width, getSize().height);
Graphics2D g2d = (Graphics2D) g;
if (gxTx != null) {
g2d.transform(gxTx);
}
if (useFM) {
g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS,
RenderingHints.VALUE_FRACTIONALMETRICS_ON);
}
String text = TEXT + TEXT + TEXT;
g.setColor(Color.black);
int y = 20;
float origSize = 7f;
for (int i=0;i<11;i++) {
float size = origSize+(i*0.1f);
g2d.translate(0, size+6);
Font f = textFont.deriveFont(size);
g2d.setFont(f);
FontMetrics fontMetrics = g2d.getFontMetrics();
int stringWidth = fontMetrics.stringWidth(text);
g.drawLine(0, y+1, stringWidth, y+1);
g.drawString(text, 0, y);
y +=10;
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册