-
-
Notifications
You must be signed in to change notification settings - Fork 15
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
createGlyphVector prints in worse quality than drawString #45
Comments
@tresf - 11.0.6 was just released, are you able to try that (both regular and adoptopenjdk.net/upstream.html versions). |
Identical results with AdoptOpenJDK 11.0.6+10 x64. This bug has existed for a while, my Oracle JDK8 environment exposes it as well. |
Can you confirm that antialiasing definitely does not work and is not a viable solution. I think I have produced a tighter reproducer of the issue as follows. As can be seen from the images, antialiasing does seem to have an effect and produce something readable.
|
Setting
It appears to be slightly visually improved for a format (such as PNG) which supports sub-pixel interpolation, however thermal printers don't support this. Furthemore, your antialias output is much different than the image created from In contrast to the aliasing suggestion, techniques which force aliasing off and nearest-neighbor on are often preferred when readability is needed on a thermal printer... e.g: https:/qzind/tray/blob/b3e364028c6694e6fd571c08a44468948190d7e8/src/qz/printer/action/PrintPixel.java#L174-L180 Since the Apache library uses As Tillman observes in his tests, the issue is very hard to observe at a high-dpi, which is probably why it's gone so long unnoticed (or perhaps more accurately, unreported). |
You will have to bear with me as I am not familiar with this area so I am probably going off on red herrings. So I followed the steps to reproduce the issue. I noticed that I get acceptable results if I use
Do we have a link to the code where the apache library is drawing the GlyphVector to see how it is using it? |
The PDFBox library is not using "drawGlyphVector", it is drawing / filling the shapes it gets from decoding the font The "drawGlyphVector" thing was created as a simple example to show that for some mysterious reason, fonts drawn with the font drawing methods are OK but no longer when their shapes are drawn directly, but only for small font sizes. |
Yeah, Maruan (another PDFBox committer) tested on Linux and it was OK there. The original issue has my thoughts on that. |
I'm quoting the conversation that you're referencing incase it offers any more context to the problem. @THausherr do you have any idea where to start looking for this? I know it sounds small and specific, but I feel the scope is quite large when thinking of how many real-world implementations of Apache PDFBOX are out there using this with 180 or 203 DPI printers (as well as any other projects leveraging similar Java code for printing).
|
The real question is: what is done with the curves in the printer driver, why the loss of precision? I changed the initial code here to have a font size of 4 and set my default printer to "print to PDF" and here is the result With font size 8 the effect is harder to see but still here: |
An interesting write-up I found on stackoverflow: https://stackoverflow.com/a/18484397/3196753 Quoting...
Unfortunately, my attempts to render at a larger size and then shrink explicitly using |
I also tried to create a default transform and render everything at a larger size and the bug still occurs, nearly identically... // Snag the old transform so we can use it for scaling
AffineTransform backup = ((Graphics2D) graphics).getTransform();
// Reset to a default transform
((Graphics2D) graphics).setTransform(new AffineTransform());
double fontSize = 8;
double patchedSize = fontSize * backup.getScaleX();
graphics2D.setFont(new Font("Times New Roman", Font.PLAIN, (int)patchedSize));
GlyphVector gv = graphics2D.getFont().createGlyphVector(frc, "Thermal test [GlyphVector]"); I even tried coercing the After a bunch of digging I had a suspicion that the bug was rooted in // REMIND: We will allow this test to pass silently on Windows
// (when OGL is not enabled) until we fix the GDI pipeline so that
// its stroked/filled GeneralPaths match our software loops (see
// 6322554). This check should be removed when 6322554 is fixed.
GraphicsConfiguration gc = frame.getGraphicsConfiguration();
if (gc.getClass().getSimpleName().startsWith("Win")) {
System.out.println("GDI pipeline detected: " +
"test considered PASSED");
frame.dispose();
return;
} So I looked up
So I kept digging... I found reference to another issue, This issue has a much better writeup and although it contains information specific to Swing drawing routines and double-buffering, I feel it may be applicable as it reads very similar to what we're observing. I'll quote the whole thing as I feel it's all relevant...
So am I getting close? Is there a way to force quality over performance using the information provided in |
Thanks, @tresf - @johnoliver can you take a look at the code samples in those two OpenJDK bug reports and see if you can repro? |
This issue seems to be caused by precision loss in WPrinterJob.lineTo which maps to wingdi.h LineTo. In all of the jni functions, floats are passed, but in native, only ints and longs are accepted. This causes each node to 'snap to' an integer value, this includes bezier curve control points. The Unfortunately this issue seems to be caused by limitations within windgi rather than a flaw in its java implementation. I do not know much about the topic, but perhaps an alternative could be used. |
@tresf - I saw an old note that setting |
@karianna, |
@tresf This was written without thinking much. I looked at our current code, one would first have to get the the font stream and then open it with Java (not all types of valid fonts can be opened in java). This is what PDFBox 1.8 was doing. So I did it with your "drug-print.pdf" test file on jdk14 and there are many error messages, java can't open the font and uses another font instead. (That is the reason why we have our own font engine that does the complete rendering) Try the PDFBOX 1.8 app jar on your printer to see what you get... My output didn't really look good at 300dpi. |
Hmm... well, 1.8 didn't have the rendering hints added yet, would that impact it? I'll see what it draws like on the emulator. |
The emulator's results for 1.8 confirm @THausherr's suspicions that it may not help a whole lot for the PDF that inspired the bug report. One could argue that 1.8 is slightly better, but I would say it's marginal. Here're my results. And here's the results printing to a PDF printer, zoomed in to illustrate the inaccuracies that are created: @THausherr this is quite different from what the |
I've recompiled and added 3 rendering hint commands before the drawString() command and it is a bit better. I'm going to sleep soon so if you want to test this, get the source, search for Pagedrawer.java and add these 3 lines before "font.drawString"
or whatever else you think might help. |
It may be marginally better, but since the rounding issues:
I'm inclined to believe that the underlying rounding issues that are plaguing Windows won't be fixed using 1.8 (or more accurately, won't be fixed by reverting to 1.8's logic) . Evidence of this is here. These same artifacts do not occur when using |
Our primary JDK support provider has attempted and failed to fix this issue through GDI by working directly with Microsoft. As a result they've reached out to the openjdk mailing list for advice on how to fix this moving forward: https://mail.openjdk.java.net/pipermail/2d-dev/2020-September/011071.html Our secondary JDK support provider is taking a different approach by adding a System property to Java which allows switching to GDI+. This impacts quite a bit of code due to API changes between GDI and GDI+. Results already look promising although I'm not certain as to the chances of this being accepted upstream (if not, the project requiring this will be on a forked release for eternity as a result of this change). I'll provide updates as I receive them. |
Good news, testing our secondary JDK support provider's code, @lite1979 and I were able to achieve near-identical results to Ubuntu, but using Windows 10 and a custom JDK. This isn't as good as Adobe, but it's more readable than the current JDK and the vendor was able to do so both with GDI and GDI+ to near identical results. The current plan is to submit the pure-GDI patch to openjdk for approval. Currently, the setting is toggled using a system property, which we'll share when the feature is closer to landing upstream. |
Despite the "good news" from previous post, it turns out that neither GDI nor GDI+ really help improve this to even come close to CUPS/Adobe, so the vendor has taken a second approach. This new approach is to scale the content 1000x so that when GDI transforms it, it maintains most of the quality. Although instinct would say to only do this for small fonts, I've been able to visually see these artifacts even on higher DPI printers (600dpi, 1200dpi). For example, if a PDF is printed to a HP Laserjet 4000 series and if I look closely, I can see the artifacts. So I'm quite confident that this technique will be welcomed by all print jobs -- albeit not necessarily needed for readability for the larger unit-tests, should be welcomed from a quality perspective. 🚀 The vendor has a JDK patch ready, we'll be testing shortly. |
The vendor's patch was tested with mixed results. Although the shapes improve, the lack of outer stroke causes them to still suffer from quality issues. Adding a stroke causes them to be too bold. The vendor is still working towards a palatable solution. |
Upstream PR created: openjdk/jdk#1183. This doesn't entirely fix the problem, something with the missing text outline when using fill just never achieves the same quality as drawString. So in addition to this bug, we're looking into patching PDFBOX downstream per @THausherr recommendation in
|
The PDFBOX downstream bug report has been documented here, and can be tracked as such: https://issues.apache.org/jira/browse/PDFBOX-5093 I'm leaving this bug report open since JDK-8256264 hasn't landed on any of the Adopt builds, as it hasn't been backported to any versions offered on the downloads page yet. If interested, EA builds directly from openjdk should contain the first half of the patch. |
Quoting our JDK provider:
Since the remaining components are related to https://issues.apache.org/jira/browse/PDFBOX-5093, we'll continue tracking those there. Closing. :) |
Platform and architecture
Windows 10 x64
Java version
AdoptOpenJDK 11.0.4+11 HotSpot
Summary
Per Apache
PDFBOX-4709
, printing usingGlyphVector
produces poorer quality output versus usingGraphics.drawString(...)
. There's a significant quality difference -- especially on low-dpi (e.g. thermal) printers printing printing withcreateGlyphVector
versusdrawString
. LeveragingRenderingHints
does not appear to help.✅
drawString
🚫
createGlyphVector
Details
Quoting the PDFBOX developer Tilman Hausherr:
Steps
(Note, these steps include installing a proprietary printer driver to visually observe the issue, but the Apache PDFBOX developer was able to observe it without the proprietary driver and printing to a PDF instead)
ZDesigner TLP 2884-Z
although any ZPL driver should technically work.127.0.0.1
(the OS took a long time to timeout and allow me to finish the port addition, but it does eventually let you.4x6 inches
(otherwise our example will throw PrinterException("Paper's imageable height is too small.");The text was updated successfully, but these errors were encountered: