-
Type:
Bug
-
Resolution: Unresolved
-
Priority:
P3
-
Affects Version/s: 25, 26
-
Component/s: client-libs
-
x86_64
-
windows_10
ADDITIONAL SYSTEM INFORMATION :
The described problem occurs with 25.0.1 and 23.0.5, but not with 21.0.8 or 17.0.15.
It only occurs when printing on windows on a real printer. Using a PDF printer (without non-printable area) does not lead to the problem, as there is no non-printable area on these printer.
A DESCRIPTION OF THE PROBLEM :
There are obviously 2 print modes in sun.print.RasterPrinterJob.printPage() as sun.awt.windows.WPrinterJob.createPathGraphics() creates no PathGraphics when compositing is used.
This leads to a different printout when printing a semi transparent text somewhere on the page.
In java 17.0.15 I even had the problem, that pdfs were printed with a shift, but I cannot make a short reproducable code to demonstrate it.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Execute the test case code. Use a real printer with non-printable area. Two pages will be printed.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The corner on the printout should be the same. The only exception should be the text.
ACTUAL -
The corners are cut off at the printout with the semi transparent text (although they are not at the printout area)
---------- BEGIN SOURCE ----------
package de.empic.printerproblem;
import java.awt.*;
import java.awt.print.*;
public class PrinterProblemMain {
static boolean withCompositeGraphics = false;
public static void main(String[] args) {
try {
VirtualPageable virtualPageable = new VirtualPageable();
PrinterJob job = PrinterJob.getPrinterJob();
job.setPageable(virtualPageable);
if (job.printDialog()) {
job.print();
withCompositeGraphics = true;
job.print();
}
} catch (Exception e) {
e.printStackTrace();
}
}
static class VirtualPageable implements Pageable {
private final Printable printable = new VirtualPrintable();
@Override
public int getNumberOfPages() {
return 1;
}
@Override
public PageFormat getPageFormat(int pageIndex) throws IndexOutOfBoundsException {
PageFormat returnValue = new PageFormat();
returnValue.setOrientation(PageFormat.REVERSE_LANDSCAPE);
return returnValue;
}
@Override
public Printable getPrintable(int pageIndex) throws IndexOutOfBoundsException {
return pageIndex == 0 ? printable : null;
}
}
static class VirtualPrintable implements Printable {
@Override
public int print(Graphics graphics, PageFormat pageFormat, int pageIndex) throws PrinterException {
// Only a single page should be printed
if (pageIndex > 0 || graphics == null) {
return NO_SUCH_PAGE;
}
Graphics2D g2 = (Graphics2D) graphics;
double ix = pageFormat.getImageableX();
double iy = pageFormat.getImageableY();
double iw = pageFormat.getImageableWidth();
double ih = pageFormat.getImageableHeight();
double offset = 1.0;
double d = 20.0;
// Draw circles and numbers 1..4 centered in each circle
Point[] centersOfCornerCircles = new Point[]{
new Point((int) Math.round(ix + offset + d / 2.0), (int) Math.round(iy + offset + d / 2.0)), // top-left
new Point((int) Math.round(ix + iw - offset - d / 2.0), (int) Math.round(iy + offset + d / 2.0)), // top-right
new Point((int) Math.round(ix + offset + d / 2.0), (int) Math.round(iy + ih - offset - d / 2.0)), // bottom-left
new Point((int) Math.round(ix + iw - offset - d / 2.0), (int) Math.round(iy + ih - offset - d / 2.0)) // bottom-right
};
Font originalFont = g2.getFont();
Font font = originalFont.deriveFont(12f);
g2.setFont(font);
g2.setStroke(new BasicStroke(1.0f));
g2.setColor(Color.BLACK);
for (int i = 0; i < centersOfCornerCircles.length; i++) {
Point c = centersOfCornerCircles[i];
int x = (int) Math.round(c.x - d / 2.0);
int y = (int) Math.round(c.y - d / 2.0);
// Circle
g2.drawOval(x, y, (int) Math.round(d), (int) Math.round(d));
// Number centered
String text = String.valueOf(i + 1);
FontMetrics fm = g2.getFontMetrics();
int textWidth = fm.stringWidth(text);
int textAscent = fm.getAscent();
int textDescent = fm.getDescent();
int tx = (int) Math.round(c.x - textWidth / 2.0);
int ty = (int) Math.round(c.y + (textAscent - textDescent) / 2.0);
g2.drawString(text, tx, ty);
}
// The bug happens, when a composite graphics element is rendered
if (withCompositeGraphics) {
Graphics2D gAlpha = (Graphics2D) g2.create();
try {
gAlpha.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
gAlpha.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.25f));
String centerText = "Composite Graphics";
int baseSize = 48;
Font centerFont = originalFont.deriveFont(Font.BOLD, baseSize);
gAlpha.setFont(centerFont);
FontMetrics cfm = gAlpha.getFontMetrics();
int textWidth = cfm.stringWidth(centerText);
double maxWidth = iw * 0.8;
if (textWidth > maxWidth && textWidth > 0) {
float scaledSize = (float) (baseSize * (maxWidth / textWidth));
scaledSize = Math.max(18f, scaledSize);
centerFont = originalFont.deriveFont(Font.BOLD, scaledSize);
gAlpha.setFont(centerFont);
cfm = gAlpha.getFontMetrics();
textWidth = cfm.stringWidth(centerText);
}
int textAscent = cfm.getAscent();
int textDescent = cfm.getDescent();
int cx = (int) Math.round(ix + iw / 2.0);
int cy = (int) Math.round(iy + ih / 2.0);
int tx = (int) Math.round(cx - textWidth / 2.0);
int ty = (int) Math.round(cy + (textAscent - textDescent) / 2.0);
gAlpha.setColor(Color.BLACK);
gAlpha.drawString(centerText, tx, ty);
} finally {
gAlpha.dispose();
}
}
return PAGE_EXISTS;
}
}
}
---------- END SOURCE ----------
The described problem occurs with 25.0.1 and 23.0.5, but not with 21.0.8 or 17.0.15.
It only occurs when printing on windows on a real printer. Using a PDF printer (without non-printable area) does not lead to the problem, as there is no non-printable area on these printer.
A DESCRIPTION OF THE PROBLEM :
There are obviously 2 print modes in sun.print.RasterPrinterJob.printPage() as sun.awt.windows.WPrinterJob.createPathGraphics() creates no PathGraphics when compositing is used.
This leads to a different printout when printing a semi transparent text somewhere on the page.
In java 17.0.15 I even had the problem, that pdfs were printed with a shift, but I cannot make a short reproducable code to demonstrate it.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Execute the test case code. Use a real printer with non-printable area. Two pages will be printed.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The corner on the printout should be the same. The only exception should be the text.
ACTUAL -
The corners are cut off at the printout with the semi transparent text (although they are not at the printout area)
---------- BEGIN SOURCE ----------
package de.empic.printerproblem;
import java.awt.*;
import java.awt.print.*;
public class PrinterProblemMain {
static boolean withCompositeGraphics = false;
public static void main(String[] args) {
try {
VirtualPageable virtualPageable = new VirtualPageable();
PrinterJob job = PrinterJob.getPrinterJob();
job.setPageable(virtualPageable);
if (job.printDialog()) {
job.print();
withCompositeGraphics = true;
job.print();
}
} catch (Exception e) {
e.printStackTrace();
}
}
static class VirtualPageable implements Pageable {
private final Printable printable = new VirtualPrintable();
@Override
public int getNumberOfPages() {
return 1;
}
@Override
public PageFormat getPageFormat(int pageIndex) throws IndexOutOfBoundsException {
PageFormat returnValue = new PageFormat();
returnValue.setOrientation(PageFormat.REVERSE_LANDSCAPE);
return returnValue;
}
@Override
public Printable getPrintable(int pageIndex) throws IndexOutOfBoundsException {
return pageIndex == 0 ? printable : null;
}
}
static class VirtualPrintable implements Printable {
@Override
public int print(Graphics graphics, PageFormat pageFormat, int pageIndex) throws PrinterException {
// Only a single page should be printed
if (pageIndex > 0 || graphics == null) {
return NO_SUCH_PAGE;
}
Graphics2D g2 = (Graphics2D) graphics;
double ix = pageFormat.getImageableX();
double iy = pageFormat.getImageableY();
double iw = pageFormat.getImageableWidth();
double ih = pageFormat.getImageableHeight();
double offset = 1.0;
double d = 20.0;
// Draw circles and numbers 1..4 centered in each circle
Point[] centersOfCornerCircles = new Point[]{
new Point((int) Math.round(ix + offset + d / 2.0), (int) Math.round(iy + offset + d / 2.0)), // top-left
new Point((int) Math.round(ix + iw - offset - d / 2.0), (int) Math.round(iy + offset + d / 2.0)), // top-right
new Point((int) Math.round(ix + offset + d / 2.0), (int) Math.round(iy + ih - offset - d / 2.0)), // bottom-left
new Point((int) Math.round(ix + iw - offset - d / 2.0), (int) Math.round(iy + ih - offset - d / 2.0)) // bottom-right
};
Font originalFont = g2.getFont();
Font font = originalFont.deriveFont(12f);
g2.setFont(font);
g2.setStroke(new BasicStroke(1.0f));
g2.setColor(Color.BLACK);
for (int i = 0; i < centersOfCornerCircles.length; i++) {
Point c = centersOfCornerCircles[i];
int x = (int) Math.round(c.x - d / 2.0);
int y = (int) Math.round(c.y - d / 2.0);
// Circle
g2.drawOval(x, y, (int) Math.round(d), (int) Math.round(d));
// Number centered
String text = String.valueOf(i + 1);
FontMetrics fm = g2.getFontMetrics();
int textWidth = fm.stringWidth(text);
int textAscent = fm.getAscent();
int textDescent = fm.getDescent();
int tx = (int) Math.round(c.x - textWidth / 2.0);
int ty = (int) Math.round(c.y + (textAscent - textDescent) / 2.0);
g2.drawString(text, tx, ty);
}
// The bug happens, when a composite graphics element is rendered
if (withCompositeGraphics) {
Graphics2D gAlpha = (Graphics2D) g2.create();
try {
gAlpha.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
gAlpha.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.25f));
String centerText = "Composite Graphics";
int baseSize = 48;
Font centerFont = originalFont.deriveFont(Font.BOLD, baseSize);
gAlpha.setFont(centerFont);
FontMetrics cfm = gAlpha.getFontMetrics();
int textWidth = cfm.stringWidth(centerText);
double maxWidth = iw * 0.8;
if (textWidth > maxWidth && textWidth > 0) {
float scaledSize = (float) (baseSize * (maxWidth / textWidth));
scaledSize = Math.max(18f, scaledSize);
centerFont = originalFont.deriveFont(Font.BOLD, scaledSize);
gAlpha.setFont(centerFont);
cfm = gAlpha.getFontMetrics();
textWidth = cfm.stringWidth(centerText);
}
int textAscent = cfm.getAscent();
int textDescent = cfm.getDescent();
int cx = (int) Math.round(ix + iw / 2.0);
int cy = (int) Math.round(iy + ih / 2.0);
int tx = (int) Math.round(cx - textWidth / 2.0);
int ty = (int) Math.round(cy + (textAscent - textDescent) / 2.0);
gAlpha.setColor(Color.BLACK);
gAlpha.drawString(centerText, tx, ty);
} finally {
gAlpha.dispose();
}
}
return PAGE_EXISTS;
}
}
}
---------- END SOURCE ----------