Skip to main content

How to keep the rasterizer at bay when printing?

17 replies [Last post]
Anonymous

I am tring to print charts in Java 1.6 on Windows and getting poor results
(blurry images) There seems to be no way to force rasterization to be done
in the printer rather than by Java, even sun.java2d.print.pipeline=pdl has
no effect. I could not find an authoritative list of which features of
Java2D must be avoided so that the rasterizer will not be called; I only
know that, e.g., alpha color is one of them. So, where can I find a list?

Furthermore it seems this decision reflects late 1990s thinking re. the
capabilities and speed of some printers. Isn't it time to revisit?

Regards,

-- O.L.

===========================================================================
To unsubscribe, send email to listserv@java.sun.com and include in the body
of the message "signoff JAVA2D-INTEREST". For general help, send email to
listserv@java.sun.com and include in the body of the message "help".

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
Olivier Lefevre

Just a quick update on this: painting using the print method to a
streaming Graphics2D object that writes SVG/PostScript/PDF/whatever
to file will give the "correct" results, i.e., not a bitmap, provided
print is used correctly (i.e., printComponent and printBorder in the
widget tree may need to be overridden and customized). However to get
"correct" results when actually printing to a printer you do have to
set the sun.java2d.print.pipeline property to pdl. Thus I think it
might be useful to bring that property out in the open, so to speak,
and stop regarding it as a private testing back-end.

Regards,

-- O.L.

===========================================================================
To unsubscribe, send email to listserv@java.sun.com and include in the body
of the message "signoff JAVA2D-INTEREST". For general help, send email to
listserv@java.sun.com and include in the body of the message "help".

Phil Race

I refer the honourable gentleman to the answer I gave earlier ..

> So specifying PDL is either a no-op, or is possibly going to
> cause a failure at runtime since you are forcing an inappropriate path.

In short : do not do this.

If this actually had any effect in your case this that means you have :
1) not yet spotted where it lead to incorrect results.
and
2) been lucky so far not to get a RuntimeException thrown.

-phil.

Olivier Lefevre wrote:
> Just a quick update on this: painting using the print method to a
> streaming Graphics2D object that writes SVG/PostScript/PDF/whatever
> to file will give the "correct" results, i.e., not a bitmap, provided
> print is used correctly (i.e., printComponent and printBorder in the
> widget tree may need to be overridden and customized). However to get
> "correct" results when actually printing to a printer you do have to
> set the sun.java2d.print.pipeline property to pdl. Thus I think it
> might be useful to bring that property out in the open, so to speak,
> and stop regarding it as a private testing back-end.
>
> Regards,
>
> -- O.L.
>

===========================================================================
To unsubscribe, send email to listserv@java.sun.com and include in the body
of the message "signoff JAVA2D-INTEREST". For general help, send email to
listserv@java.sun.com and include in the body of the message "help".

Olivier Lefevre

> I refer the honourable gentleman to the answer I gave earlier ..
>
>> So specifying PDL is either a no-op, or is possibly going to
>> cause a failure at runtime since you are forcing an inappropriate path.
>
> In short : do not do this.
>
> If this actually had any effect in your case this that means you have :
> 1) not yet spotted where it lead to incorrect results.
> and
> 2) been lucky so far not to get a RuntimeException thrown.

We are talking past each other. The pdl path right now is what it is but by
"bringing it out into the open" I was suggesting fixing the above problems,
precisely. About the RuntimeException: it's entirely up to you to implement
it so that it does not throw. About the incorrect results: by that I assume
you refer to the features like certain transparency or shading effects that
would not be supported. If so, have you ever heard of graceful degradation?
You could skip those instructions, pick the closest implemented rendering,
whatever; you do not have to throw. It is routine for page rendering engines
(think browsers with HTML + CSS or SVG) to have limitations and implement
only a subset of a given spec. Where would we be if, say, browsers decided
to bomb every time they encounter an unimplemented SVG instruction? That is
no way to implement this kind of product.

>From my perspective it would be much better to get high-quality (i.e., not
raster) translation of a more limited set of instructions than a raster
version of the full set. At least it would be useful to have the choice
but at the moment that option is denied to us.

Regards,

-- O.L.

===========================================================================
To unsubscribe, send email to listserv@java.sun.com and include in the body
of the message "signoff JAVA2D-INTEREST". For general help, send email to
listserv@java.sun.com and include in the body of the message "help".

Phil Race

Olivier,

Olivier Lefevre wrote:
>> I refer the honourable gentleman to the answer I gave earlier ..
>>
>>> So specifying PDL is either a no-op, or is possibly going to
>>> cause a failure at runtime since you are forcing an inappropriate path.
>> In short : do not do this.
>>
>> If this actually had any effect in your case this that means you have :
>> 1) not yet spotted where it lead to incorrect results.
>> and
>> 2) been lucky so far not to get a RuntimeException thrown.
>
> We are talking past each other. The pdl path right now is what it is but by
> "bringing it out into the open" I was suggesting fixing the above problems,
> precisely. About the RuntimeException: it's entirely up to you to implement
> it so that it does not throw.

The runtime exception can occur ONLY when you specify this property
(which perhaps I should just delete), and even then only in cases where
its wholly inappropriate. Applications behaving properly will never see it.

About the incorrect results: by that I assume
> you refer to the features like certain transparency or shading effects that
> would not be supported. If so, have you ever heard of graceful degradation?
> You could skip those instructions, pick the closest implemented rendering,
> whatever; you do not have to throw. It is routine for page rendering engines
> (think browsers with HTML + CSS or SVG) to have limitations and implement
> only a subset of a given spec. Where would we be if, say, browsers decided
> to bomb every time they encounter an unimplemented SVG instruction? That is
> no way to implement this kind of product.

We do not bomb. We have "graceful degradation". We've had it for many years.

And it makes no sense for Java 2D printing to implement only a subset of our own API.

>
> From my perspective it would be much better to get high-quality (i.e., not
> raster) translation of a more limited set of instructions than a raster
> version of the full set. At least it would be useful to have the choice
> but at the moment that option is denied to us.

So what you want is that explicit setting of this internal property
to "pdl" to mean skip any output it cannot render.
I don't see that as desirable or truly useful and its obviously completely
non-standard.

-phil.
>
> Regards,
>
> -- O.L.
>
> ===========================================================================
> To unsubscribe, send email to listserv@java.sun.com and include in the body
> of the message "signoff JAVA2D-INTEREST". For general help, send email to
> listserv@java.sun.com and include in the body of the message "help".

===========================================================================
To unsubscribe, send email to listserv@java.sun.com and include in the body
of the message "signoff JAVA2D-INTEREST". For general help, send email to
listserv@java.sun.com and include in the body of the message "help".

Olivier Lefevre

> And it makes no sense for Java 2D printing to implement only a subset of our
> own API.

When rendering onto a target (i.e., a printer driver) that makes it
inordinately
difficult to support certain features and forces drastic trade-offs, I think it
could make sense.

> I don't see that as desirable or truly useful and its obviously completely
> non-standard.

But blurry rasters are not useful either and it _is_ standard behaviour for
software acting on markup or page descriptors to skip unprocessable
instructions.

-- O.L.

===========================================================================
To unsubscribe, send email to listserv@java.sun.com and include in the body
of the message "signoff JAVA2D-INTEREST". For general help, send email to
listserv@java.sun.com and include in the body of the message "help".

Phil Race

Olivier Lefevre wrote:
>> And it makes no sense for Java 2D printing to implement only a subset of our
>> own API.
>
> When rendering onto a target (i.e., a printer driver) that makes it
> inordinately
> difficult to support certain features and forces drastic trade-offs, I think it
> could make sense.
>
>> I don't see that as desirable or truly useful and its obviously completely
>> non-standard.
>
> But blurry rasters are not useful either and it _is_ standard behaviour for
> software acting on markup or page descriptors to skip unprocessable
> instructions.

The "blurry" raster is solely because you tried to send a screen resolution
swing ui to the printer. ie print a lo-res image scaled up massively.
The printing rasterisation is high quality.

-phil

===========================================================================
To unsubscribe, send email to listserv@java.sun.com and include in the body
of the message "signoff JAVA2D-INTEREST". For general help, send email to
listserv@java.sun.com and include in the body of the message "help".

Olivier Lefevre

> The "blurry" raster is solely because you tried to send a screen resolution
> swing ui to the printer. ie print a lo-res image scaled up massively.
> The printing rasterisation is high quality.

Yes I know but in order to send data to the printer at the printer res I
would need to implement a complement different painting path: the image
is complex enough that I cache a lot of information instead of computing
it on the fly within paintComponent. Now with a pdl path (e.g., when
saving to PDF or using the "forbidden" pdl pipeline) I can simply apply
a scaling factor and get mostly correct results (slight mismatches with
fonts at most) whereas with a raster path I'd need to keep 2 copies of
the plot around: one for for the screen and one for the printer, or else
implement 2 modes: one with caching, another without. So it's a bother.

-- O.L.

===========================================================================
To unsubscribe, send email to listserv@java.sun.com and include in the body
of the message "signoff JAVA2D-INTEREST". For general help, send email to
listserv@java.sun.com and include in the body of the message "help".

Phil Race

No, you wouldn't. It makes no difference. No one is asking *you* to
create a raster.
The implementation creates the raster in a way that is completely
transparent to your code.
Its an implementation detail of the graphics instance and its
relationship to the surface
to which you are drawing.

-phil
.
Olivier Lefevre wrote:
>> The "blurry" raster is solely because you tried to send a screen resolution
>> swing ui to the printer. ie print a lo-res image scaled up massively.
>> The printing rasterisation is high quality.
>>
>
> Yes I know but in order to send data to the printer at the printer res I
> would need to implement a complement different painting path: the image
> is complex enough that I cache a lot of information instead of computing
> it on the fly within paintComponent. Now with a pdl path (e.g., when
> saving to PDF or using the "forbidden" pdl pipeline) I can simply apply
> a scaling factor and get mostly correct results (slight mismatches with
> fonts at most) whereas with a raster path I'd need to keep 2 copies of
> the plot around: one for for the screen and one for the printer, or else
> implement 2 modes: one with caching, another without. So it's a bother.
>
> -- O.L.
>
> ===========================================================================
> To unsubscribe, send email to listserv@java.sun.com and include in the body
> of the message "signoff JAVA2D-INTEREST". For general help, send email to
> listserv@java.sun.com and include in the body of the message "help".
>

===========================================================================
To unsubscribe, send email to listserv@java.sun.com and include in the body
of the message "signoff JAVA2D-INTEREST". For general help, send email to
listserv@java.sun.com and include in the body of the message "help".

Olivier Lefevre

> No, you wouldn't. It makes no difference. No one is asking *you* to
> create a raster.

Misunderstanding. Let us say I have a line plot with a thousand points,
many tick etc. I have a to convert their coordinates from whatever "data
space" they come from to actual pixel positions on the device (the
screen). Now because it's a lot of computation I save these positions.
If suddenly I am requested to paint the plot onto a device with a different
size/resolution I cannot simply use the state backing what is on the
screen, for obvious reasons. One possibility is to simply apply a scaling
factor in the Graphics2D object to the saved positions but that is exactly
the strategy that fails with raster images. Thus either I must create a
second, invisible copy of the widget with the appropriate backing state
and paint _that_ to the printer or else I must keep around a second version
of paintComponent that does not use the saved pre-computed positions but
computes them on the fly. Is it clear now?

The bottom line is that being unable to simply scale the drawing and
having to paint it at its "real" size/resolution does put a burden
on the developer.

-- O.L.

===========================================================================
To unsubscribe, send email to listserv@java.sun.com and include in the body
of the message "signoff JAVA2D-INTEREST". For general help, send email to
listserv@java.sun.com and include in the body of the message "help".

Phil Race

Olivier Lefevre wrote:
>> No, you wouldn't. It makes no difference. No one is asking *you* to
>> create a raster.
>>
>
> Misunderstanding.
Yes. You are misunderstanding. The printer "raster" path is at the same
resolution as the pdl path
Both will be different than the screen resolution which you are
hardcoding to.

-phil.

> Let us say I have a line plot with a thousand points,
> many tick etc. I have a to convert their coordinates from whatever "data
> space" they come from to actual pixel positions on the device (the
> screen). Now because it's a lot of computation I save these positions.
> If suddenly I am requested to paint the plot onto a device with a different
> size/resolution I cannot simply use the state backing what is on the
> screen, for obvious reasons. One possibility is to simply apply a scaling
> factor in the Graphics2D object to the saved positions but that is exactly
> the strategy that fails with raster images. Thus either I must create a
> second, invisible copy of the widget with the appropriate backing state
> and paint _that_ to the printer or else I must keep around a second version
> of paintComponent that does not use the saved pre-computed positions but
> computes them on the fly. Is it clear now?
>
> The bottom line is that being unable to simply scale the drawing and
> having to paint it at its "real" size/resolution does put a burden
> on the developer.
>
> -- O.L.
>
>

===========================================================================
To unsubscribe, send email to listserv@java.sun.com and include in the body
of the message "signoff JAVA2D-INTEREST". For general help, send email to
listserv@java.sun.com and include in the body of the message "help".

Olivier Lefevre

Why is this so difficult? I know full well that the raster and pdl path are
at the same resolution. The difference is that with pdl I can simply scale
whatever I was drawing onto the screen and still get good results because pdl
instructions are intrinsically scalable whereas with raster I cannot because
when you scale an image get a blurry one. Hence, as I explained at length,
I have to take extra steps to draw directly at the appropriate scale.

-- O.L.

===========================================================================
To unsubscribe, send email to listserv@java.sun.com and include in the body
of the message "signoff JAVA2D-INTEREST". For general help, send email to
listserv@java.sun.com and include in the body of the message "help".

Phil Race

Olivier Lefevre wrote:
> I am tring to print charts in Java 1.6 on Windows and getting poor results
> (blurry images) There seems to be no way to force rasterization to be done
> in the printer rather than by Java, even sun.java2d.print.pipeline=pdl has
> no effect. I could not find an authoritative list of which features of
> Java2D must be avoided so that the rasterizer will not be called; I only
> know that, e.g., alpha color is one of them. So, where can I find a list?
>
http://java.sun.com/products/java-media/2D/reference/faqs/index.html#Q_W...

Since (surprise) 'pdl' didn't help try 'raster', which is the opposite
of what you think is helpful but might be interesting.

Failing that you'd need to submit a small self-contained test case along
with printer driver info etc.

> Furthermore it seems this decision reflects late 1990s thinking re. the
> capabilities and speed of some printers. Isn't it time to revisit?
>

No, its the late eighties Microsoft APIs that limit what we can do.

-phil.
> Regards,
>
> -- O.L.
>
> ===========================================================================
> To unsubscribe, send email to listserv@java.sun.com and include in the body
> of the message "signoff JAVA2D-INTEREST". For general help, send email to
> listserv@java.sun.com and include in the body of the message "help".
>

===========================================================================
To unsubscribe, send email to listserv@java.sun.com and include in the body
of the message "signoff JAVA2D-INTEREST". For general help, send email to
listserv@java.sun.com and include in the body of the message "help".

Olivier Lefevre

> Since (surprise) 'pdl' didn't help try 'raster', which is the opposite
> of what you think is helpful but might be interesting.

Thanks for the answer but I think the sarcasm is misplaced. Pease google
"sun.java2d.print.pipeline" and see for yourself how much information
you get. I could not find a list the possible values nor an explanation
of what they do, only a hint that pdl might be a good idea.

>> Furthermore it seems this decision reflects late 1990s thinking re. the
>> capabilities and speed of some printers. Isn't it time to revisit?
>
> No, its the late eighties Microsoft APIs that limit what we can do.

How do the MS APIs come into the picture? Unless we are talking about
so-called Windows printers that render on the desktop and thus using GDI,
I would not think they are involved. To be sure they are an important
use case but they are not even the majority of printers.

In any case the point is not just printers: you can "print" or "paint"
to Graphics2D instances that generate PostScript, PDF, SVG or whatever
and it is extremely unhelpful when they are sent a bitmap instead of
the expected graphics instructions that you put in your code. There
ought to be a switch to turn off rasterization *unconditionally* and
ensure graphics command are sent exactly as they are written. As it
is, the only way I could find to do that is to bypass the high-level
print/paint methods and call paintCompoment and paintBorder directly.
That works but then I have to perform nested widget placment, background
printing etc manually, which is quite a bother. Is there a better way
that I have overlooked?

Regards,

-- O.L.

===========================================================================
To unsubscribe, send email to listserv@java.sun.com and include in the body
of the message "signoff JAVA2D-INTEREST". For general help, send email to
listserv@java.sun.com and include in the body of the message "help".

Phil Race

Olivier Lefevre wrote:
>> Since (surprise) 'pdl' didn't help try 'raster', which is the opposite
>> of what you think is helpful but might be interesting.
>
> Thanks for the answer but I think the sarcasm is misplaced. Pease google
> "sun.java2d.print.pipeline" and see for yourself how much information
> you get. I could not find a list the possible values nor an explanation
> of what they do, only a hint that pdl might be a good idea.

Well since this is internal implementation of the Sun JDK, and not in fact
a standard property its not surprising its not documented.
Its principle use is internal testing.

Generating "PDL" graphics instructions ie NOT a rasterised bitmap
is what the JDK does by default and strives to do whenever it can.

So specifying PDL is either a no-op, or is possibly going to
cause a failure at runtime since you are forcing an inappropriate path.

>
>>> Furthermore it seems this decision reflects late 1990s thinking re. the
>>> capabilities and speed of some printers. Isn't it time to revisit?
>> No, its the late eighties Microsoft APIs that limit what we can do.
>
> How do the MS APIs come into the picture? Unless we are talking about
> so-called Windows printers that render on the desktop and thus using GDI,
> I would not think they are involved. To be sure they are an important
> use case but they are not even the majority of printers.

I don't know what you are driving at.
The standard way to print graphics on windows is via GDI,
unless perhaps you are a .NET app, but even then I'll bet its
translated into GDI under the covers as that's what the windows
printer driver API wants.

And GDI doesn't have an API to create a translucent color

Color c = new Color(255,255,255,128);

simply isn't available.

So things like that force a bitmap but I am doubtful its relevant
to your case :

>
> In any case the point is not just printers: you can "print" or "paint"
> to Graphics2D instances that generate PostScript, PDF, SVG or whatever
> and it is extremely unhelpful when they are sent a bitmap instead of
> the expected graphics instructions that you put in your code. There
> ought to be a switch to turn off rasterization *unconditionally* and
> ensure graphics command are sent exactly as they are written. As it
> is, the only way I could find to do that is to bypass the high-level
> print/paint methods and call paintCompoment and paintBorder directly.
> That works but then I have to perform nested widget placment, background
> printing etc manually, which is quite a bother. Is there a better way
> that I have overlooked?

Ah! I suspect this is your application bug.

Are you seeing this only when printing a Swing UI?
How are you printing?

Are you calling "component.paint(printerGraphics) on the printer graphics.

Remember that Swing is double-buffered by default so
it does all its painting to an off screen image and that
"printerGraphics" for the printer sees only the resulting image.
So its nothing to do with the printing implementation.

You need to call Component.print() or Component.printAll() in which
case Swing renders directly to the printer graphics.

-phil.

>
> Regards,
>
> -- O.L.
>

===========================================================================
To unsubscribe, send email to listserv@java.sun.com and include in the body
of the message "signoff JAVA2D-INTEREST". For general help, send email to
listserv@java.sun.com and include in the body of the message "help".

Olivier Lefevre

> I could not find a list the possible values nor an explanation
> of what they do, only a hint that pdl might be a good idea.

It now occurs to me that PDL must stand for Page Description Language,
i.e., just what I wanted but you say it's normally a no-op.

> I don't know what you are driving at [with you remarks on Windows printers]

I am vague on the architecture of Windows printing. I was hoping that in the
case of "real" printers (i.e., with their own rasterizers) applications are
talking directly to the printer driver that is installed with the printer,
not to some generic Windows printer driver. If that's not the case maybe
for high-quaklity printing you are better off generating PostScript and
sending that directly to the printer? A few printers also understand PDF.

> Are you seeing this only when printing a Swing UI? How are you printing?

Yes, I was printing a JPanel with plots in it, i.e., just text ad line art
but with some transparency.

> Are you calling "component.paint(printerGraphics) on the printer graphics.

No I was calling print and I even turned off Swing buffering manually but
I was still getting bitmaps. However now that you told me that print never
rasterizes I went back and I realized the problem is that a sub-widget was
doing its own buffering for performance reasons and I was not turning off
_that_. It seems to work fine now. Thanks!

While we are talkinmg, I have a subsidiary question. When printing or saving
to file the print size is not necessarily what is shown on the screen. One
can simply apply a scaling transform to the graphics object or one can keep
around a private, non-displayable copy of the widget and resize that one
before printing it. The first solution is simpler but are there any gotchas
with rescaling that I am not aware of?

Regards,

-- O.L.

===========================================================================
To unsubscribe, send email to listserv@java.sun.com and include in the body
of the message "signoff JAVA2D-INTEREST". For general help, send email to
listserv@java.sun.com and include in the body of the message "help".

Phil Race

Olivier Lefevre wrote:
>> I could not find a list the possible values nor an explanation
>> of what they do, only a hint that pdl might be a good idea.
>>
>
> It now occurs to me that PDL must stand for Page Description Language,
> i.e., just what I wanted but you say it's normally a no-op.
>
>
>> I don't know what you are driving at [with you remarks on Windows printers]
>>
>
> I am vague on the architecture of Windows printing. I was hoping that in the
> case of "real" printers (i.e., with their own rasterizers) applications are
> talking directly to the printer driver that is installed with the printer,
> not to some generic Windows printer driver. If that's not the case maybe
> for high-quaklity printing you are better off generating PostScript and
> sending that directly to the printer? A few printers also understand PDF.
>

Postscript also doesn't support translucency except in some unlikely and
esoteric implementations
and whilst windows provides a way to see if a printer is a postscript
one it provides no such API for determining
if its a PDF printer.

>
>> Are you seeing this only when printing a Swing UI? How are you printing?
>>
>
> Yes, I was printing a JPanel with plots in it, i.e., just text ad line art
> but with some transparency.
>
>
>> Are you calling "component.paint(printerGraphics) on the printer graphics.
>>
>
> No I was calling print and I even turned off Swing buffering manually but
> I was still getting bitmaps. However now that you told me that print never
> rasterizes I went back and I realized the problem is that a sub-widget was
> doing its own buffering for performance reasons and I was not turning off
> _that_. It seems to work fine now. Thanks!
>
> While we are talkinmg, I have a subsidiary question. When printing or saving
> to file the print size is not necessarily what is shown on the screen. One
> can simply apply a scaling transform to the graphics object or one can keep
> around a private, non-displayable copy of the widget and resize that one
> before printing it. The first solution is simpler but are there any gotchas
> with rescaling that I am not aware of?
>
>

I can't say what you are not aware of until you tell me everything you
are aware of.

Image rescaling will work but be blurry like you complained about to
begin with.
One common mistake is to assume that text scales linearly from screen to
printer.
It doesn't.

If you scale the graphics 4x then a specific piece of text might scale
by 3.87 or 4.23, or 3.95 , or ..

you can only measure text in the right context. So code that supports
printing of a layed
out component needs to use the screen FontRenderContext for the text.

-phil.
> Regards,
>
> -- O.L.
>
>

===========================================================================
To unsubscribe, send email to listserv@java.sun.com and include in the body
of the message "signoff JAVA2D-INTEREST". For general help, send email to
listserv@java.sun.com and include in the body of the message "help".

Olivier Lefevre

> I can't say what you are not aware of until you tell me everything you
> are aware of.

OK, poor wording; I was just asking for any known gotchas. I know images
will be blurred but the charts I am printing are pure vector art + text
and I though that ought to work.

> One common mistake is to assume that text scales linearly from screen to
> printer. It doesn't. If you scale the graphics 4x then a specific piece
> of text might scale by 3.87 or 4.23, or 3.95 , or ..

I didn't know about that. I knew fonts sizes are not linear but I thought
scaling the Graphics2D would scale the font outlines "exactly", not ask
the font manager for the next best font size. And indeed my labels sometimes
overlap after scaling. This may be the reason or it may be a font metrics
problem since AWT and PDF fonts don't always match. I must investigate.

Thanks again for the help,

-- O.L.

===========================================================================
To unsubscribe, send email to listserv@java.sun.com and include in the body
of the message "signoff JAVA2D-INTEREST". For general help, send email to
listserv@java.sun.com and include in the body of the message "help".