On Mon, 11 Mar 2024 13:54:02 GMT, Alexander Scherbatiy <alex...@openjdk.org> 
wrote:

> The fix provides ability to print Black & White pages on macOS.
> 
> Cocoa API has 
> [PMSetColorMode](https://developer.apple.com/documentation/applicationservices/core_printing/1805783-pmsetcolormode)
>  function but it is marked as deprecated and really does nothing.
> 
> There is no replacement; this function was included to facilitate porting 
> legacy applications to macOS, 
> but it serves no useful purpose.
> 
> Dumping `NSPrintInfo` print settings which were set by the native print 
> dialog on macOS shows that the keys and values used for Black & White 
> printing depend on the used printer type.
> For example, the tested 
> `HP Color LaserJet MFP M180n` printer uses `ColorModel` key and`Gray` value, 
> and
> `HP Ink Tank 110 series` uses `HPColorMode` key and `grayscale` value.
> 
> Printing all `NSPrintInfo` presets shows that they do not contain key/value 
> pairs  for Black&White settings.
> This is the code snippet used to print `NSPrintInfo` presets:
> 
>     PMPrinter pr;
>     PMPrintSession printSession = (PMPrintSession)[printInfo PMPrintSession];
>     OSStatus status = PMSessionGetCurrentPrinter(printSession, &pr);
>     CFArrayRef presetsList = nil;
>     status = PMPrinterCopyPresets(pr, &presetsList);
>     CFIndex arrayCount = CFArrayGetCount(presetsList);
> 
>     for (CFIndex index = 0; index < arrayCount; index++) {
>         PMPreset preset = (PMPreset)CFArrayGetValueAtIndex(presetsList, 
> index);
>         CFStringRef presetName = nil;
>         if (PMPresetCopyName(preset, &presetName) == noErr && 
> CFStringGetLength(presetName) > 0) {
>             NSLog(@"  presetName: '%@'", presetName);
>             NSDictionary* dict = nil;
>             if (PMPresetGetAttributes(preset, (CFDictionaryRef*)(&dict)) == 
> noErr) {
>                    // print preset dict
> 
> 
> The idea of the proposed fix is to store printer dependent key/value pairs in 
> the `<jdk-home>/conf/printer.properties` property file.
> 
> The property file has the format:
> 
> print-attribute.print-attribute-value.key=value
> 
> where `print-attribute` is the java print attribute, `print-attribute-value` 
> is the corresponding attribute value, and `key` and `value` is the key/value 
> pair used by a specific printer.
> 
> For example, for `Chromaticity` attribute the property file could look like:
> 
> Chromaticity.MONOCHROME.ColorModel=Gray
> Chromaticity.COLOR.ColorModel=CMYK
> Chromaticity.MONOCHROME.HPColorMode=grayscale
> Chromaticity.COLOR.HPColorMode=color
> 
> where `Chromaticity.MONOCHROME` key prefix corresponds to 
> `Chromaticity.MONOCHOROME` print attribute constant  with  (...

Since the user can always select greyscale in the user dialog, I presume you 
have some requirement
to do this printing without user intervention. Perhaps there's no user there 
(server-side printing), or
the app would like to make sure the user always defaults to B&W.

As far as I can tell, this isn't supported via any kind of API on macOS, so it 
is not a Java problem.
You could be printing from an Objective-C app written directly to Cocoa APIs 
and still have the same problem.
So a Java-specific workaround like this seems inappropriate.

I've poked around to help me understand what is going on.

When I do "Print to File" on macOS - meaning use the native printer dialog's 
"Save as PDF" option,
then the generated PDF is always colour even if I select the printer dialog's 
"Grayscale Printing" option.
This isn't just true for Java apps, the same happens if I print a web page from 
Safari.

And when I query the  Chromaticity support for a couple of colour printers - 
one Canon, one HP,
both report they support it but only the value COLOR.

So I conclude the grayscale printing option is something handled by the printer 
driver at the time it is converted to
the printer-specific format and sent to the physical printer and it isn't 
changing the rendering.

So in general without an API, to get greyscale it requires the end-user to set 
an option in a print dialog
and as mentioned above, what you are trying  o enable isn't possible even if 
you wrote the app in
Objective-C or Swift directly as a macOS native app.

But what works for me to get greyscale by default is to set that up as the 
default for the print queue.
It is easy to add a printer twice - with two queues for it.
One has the default set to greyscale, the other to colour. Then the app just 
needs to select the required queue.
This is clearly more site-specific than having the app just specify MONOCHROME 
but is a lot lower cost all round.

I don't understand why PMSetColorMode is deprecated and non-functional since it 
seems like it would
be the right option here, but then internally macOS would need to be able to 
map it to the right option.
Doubtless that would be easier if MONOCHROME were supported by all these 
drivers and I don't understand
that omission either. In fact if it were we probably could just specify that 
directly without macOS needing
to understand anything - like  I expect it doesn't understand the key/value 
pairs your code is sending it.
I note that you send ALL known key/value pairs and hope one works .. and that 
points out that all
it takes is some vendor API change or a different printer and it just won't 
work again.
These points and the implied maintenance cost are some of my bigger concerns 
with this.

Perhaps you should engage with Apple and get them to properly support 
MONOCHROME.
Or maybe it would be enough if the printer vendors do ?
FWIW, I don't think it is an Apple-specific issue, the free drivers for Linux 
behave similarly.
Perhaps there's a clue in there somewhere. But similarly you can set up a 
separate queue.

The other idea that crossed my mind is that instead of relying on a printing 
solution, we could
explicitly render in greyscale. Then we could always declare MONOCHROME support 
and just emulate it.
But I am not sure if this is really possible - it would require changes to the 
rendering code and
I'm not sure if or how if we'd be able to do that properly and safely. And the 
risks of that clearly extend beyond printing.

-------------

PR Comment: https://git.openjdk.org/jdk/pull/18195#issuecomment-2043813832

Reply via email to