Recent

Author Topic: Printer.XDPI and Printer.YDPI under OSX 10.9  (Read 15303 times)

jwdietrich

  • Hero Member
  • *****
  • Posts: 1232
    • formatio reticularis
Re: Printer.XDPI and Printer.YDPI under OSX 10.9
« Reply #15 on: March 25, 2015, 08:03:58 pm »
Your statements are correct and they don't contradict mine.
hmm, should I say then:
Gui applications work fine if launched from within a bundle via Terminal.

This would be incompatible with the sentence "They run when launched from Terminal, but they don't allow any interaction via Quartz."  ;)
function GetRandomNumber: integer; // xkcd.com
begin
  GetRandomNumber := 4; // chosen by fair dice roll. Guaranteed to be random.
end;

http://www.formatio-reticularis.de

Lazarus 2.2.6 | FPC 3.2.2 | PPC, Intel, ARM | macOS, Windows, Linux

jwdietrich

  • Hero Member
  • *****
  • Posts: 1232
    • formatio reticularis
Re: Printer.XDPI and Printer.YDPI under OSX 10.9
« Reply #16 on: March 25, 2015, 08:05:12 pm »
so I guess the only reason for the function to fail is that either: GetCurrentPrinter or PrintSettings returns faulty information.

Either these functions return faulty information or the values are reset to 72 afterwards.
function GetRandomNumber: integer; // xkcd.com
begin
  GetRandomNumber := 4; // chosen by fair dice roll. Guaranteed to be random.
end;

http://www.formatio-reticularis.de

Lazarus 2.2.6 | FPC 3.2.2 | PPC, Intel, ARM | macOS, Windows, Linux

skalogryz

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2770
    • havefunsoft.com
Re: Printer.XDPI and Printer.YDPI under OSX 10.9
« Reply #17 on: March 25, 2015, 08:14:27 pm »
This would be incompatible with the sentence "They run when launched from Terminal, but they don't allow any interaction via Quartz."  ;)
That's the point to make contradiction and inspire lelebass to run the app from terminal and get the error code!

skalogryz

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2770
    • havefunsoft.com
Re: Printer.XDPI and Printer.YDPI under OSX 10.9
« Reply #18 on: March 26, 2015, 01:55:35 am »
There're other APIs to get printers DPI since 10.0
PMPrinterGetPrinterResolutionCount
PMPrinterGetIndexedPrinterResolution.

Obviously it's used for printers that multiple printing sources (separate color and black-white drums?) or adjustable DPIs? Makes sense to be honest.
However LCL doesn't provide an interface to handle multiple DPIs for a printer. That's why the implementation (r48507) just grabs the first DPI available.
 
Also some sources online notes that PMPrinterGetOutputResolution is driver specific. Thus some printers would fail, until PMPrinterSetOutputResolution is called explicitly.

Anyway please update and test.

jesusr

  • Sr. Member
  • ****
  • Posts: 484
Re: Printer.XDPI and Printer.YDPI under OSX 10.9
« Reply #19 on: March 26, 2015, 06:38:48 am »
There're other APIs to get printers DPI since 10.0
PMPrinterGetPrinterResolutionCount
PMPrinterGetIndexedPrinterResolution.

Obviously it's used for printers that multiple printing sources (separate color and black-white drums?) or adjustable DPIs? Makes sense to be honest.
However LCL doesn't provide an interface to handle multiple DPIs for a printer. That's why the implementation (r48507) just grabs the first DPI available.
 
Also some sources online notes that PMPrinterGetOutputResolution is driver specific. Thus some printers would fail, until PMPrinterSetOutputResolution is called explicitly.

Anyway please update and test.

There is a problem with this change, the print job will be made with the first available resolution and not with the one picked by the user (in the print dialog).

The real problem is that if the user do not modify the output resolution (if available in print dialog), the function PMPrinterGetOutputResolution will return 72x72 dpi or fails (but IIRC it doesn't fail), even if the default resolution is set to 600x600 dpi, in any way the function CarbonPrinter.GetOutputResolution will return 72x72 dpi.  For example, in my case using a HP LaserJet 1200 printer, the Print Dialog shows 4 resolution values from which "Fastres 1200" is ticked by default so I guess that is the default resolution (BTW here "Fastres 1200" is really 600x600 dpi and not 1200x1200 weird no? :)), yet it will return 72x72 dpi if I don't modify the default selection.

I think the Print Dialog calls internally PMPrinterSetOutputResolution. Unfortunately I was not able to find a way to query the default output resolution when the user has not modified the default selection (again if it exists at all, some printers do not show a "quality" pane in Print Dialog). Probably if PMPrinterGetOutputResolution fails we could use the new functions in order to at least return a more appropriated value than 72x72, but most probably PMPrinterGetOutputResolution do not fails and so there is no way to know if the user has changed or not the output resolution in "quality" pane.  Indeed, I was about (at that time) to make XDPI and YDPI values user writable which in turn would use PMPrinterSetOutputResolution, the problem with that is that printers usually support a limited set of output resolutions and not arbitrary values, so I didn't implemented.

An impasse that leaded to the previous implementation.

skalogryz

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2770
    • havefunsoft.com
Re: Printer.XDPI and Printer.YDPI under OSX 10.9
« Reply #20 on: March 26, 2015, 01:11:36 pm »
There is a problem with this change, the print job will be made with the first available resolution and not with the one picked by the user (in the print dialog).
Print job would run with the selected one, XDPI and YDPI would return the first available.

I can agree that  PMPrinterGetOutputResolution should be used first. If it fails then indexes resolutions could be used.
However, the function itself should be loaded dynamically (in runtime), otherwise an app won't even start on OSX 10.4. The loader would just fail to find the function.

skalogryz

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2770
    • havefunsoft.com
Re: Printer.XDPI and Printer.YDPI under OSX 10.9
« Reply #21 on: March 27, 2015, 04:51:16 am »
ok, so how about this patch. It should satisfy everyone.
1) PMPrinterGetOutputResolution - get's priority. If the function return a value - it's used as DPI
2) PMPrinterGetOutputResolution - is loaded dynamically, thus no issues for OSX 10.4 (intel or ppc)
3) IndexesResolution would return the highest resolution available.
4) ... should the resolution by CGContextRef be added? (as suggested in dev ops). Of course it would return a value, when a job has been started.

Code: [Select]
Index: carbon/carbonprinters.inc
===================================================================
--- carbon/carbonprinters.inc (revision 48517)
+++ carbon/carbonprinters.inc (working copy)
@@ -2,7 +2,7 @@
 {**************************************************************
 Implementation for carbonprinter
 ***************************************************************}
-Uses InterfaceBase, LCLIntf, CarbonProc, LCLProc;
+Uses InterfaceBase, LCLIntf, CarbonProc, LCLProc, dl;
 
 
 { TCarbonPrinterContext }
@@ -335,20 +335,52 @@
   Validate;
 end;
 
+type
+ TPMPrinterGetOutputResolution = function( printer: PMPrinter;
+   printSettings: PMPrintSettings;
+   var resolutionP: PMResolution ): OSStatus; cdecl;
+
+var
+ _PMPrinterGetOutputResolution: TPMPrinterGetOutputResolution =  nil;
+ _PMPrinterGetOutputResolutionLoaded: Boolean;
+
 function TCarbonPrinter.GetOutputResolution: PMResolution;
 var
   res: OSStatus;
+  r  : PMresolution;
   prn: PMPrinter;
   cnt: UInt32;
+  i  : Integer;
 begin
   prn := GetCurrentPrinter;
-  PMPrinterGetPrinterResolutionCount(prn, cnt);
-  if cnt>0 then
-    //todo: get the first one or the highest one?
-    res:=PMPrinterGetIndexedPrinterResolution(prn, 1, Result)
+
+  if not _PMPrinterGetOutputResolutionLoaded then
+  begin
+    // loading in run-time, because the function isn't available on OSX 10.4
+    _PMPrinterGetOutputResolutionLoaded := true;
+    _PMPrinterGetOutputResolution := TPMPrinterGetOutputResolution(dlsym(RTLD_DEFAULT,'PMPrinterGetOutputResolution'));
+  end;
+  if Assigned(_PMPrinterGetOutputResolution) then
+    // the function might return kPMKeyNotFound, see function description in MacOSAll
+    res := _PMPrinterGetOutputResolution(prn,  PrintSettings, Result{%H-})
   else
-    res:=noErr+1;
+    res := noErr+1;
 
+  if res <> noErr then
+  begin
+   res := PMPrinterGetPrinterResolutionCount(prn, cnt{%H-});
+   if res = noErr then
+   begin
+     PMPrinterGetIndexedPrinterResolution(prn, 1, Result);
+     for i := 2 to cnt do
+     begin
+       if PMPrinterGetIndexedPrinterResolution(prn, i, r{%H-}) = noErr then
+         if (r.hRes > Result.hRes) and (r.vRes > Result.vRes) then
+           Result := r;
+     end;
+   end;
+  end;
+
   if res<>noErr then
   begin
     Result.vRes:=72;

jesusr

  • Sr. Member
  • ****
  • Posts: 484
Re: Printer.XDPI and Printer.YDPI under OSX 10.9
« Reply #22 on: March 28, 2015, 03:53:37 am »
I tried and it works ok here, IMO it should be applied.

With this method is possible to know whether or not the user has choosed a specific resolution. If he doesn't then it returns the best available resolution. Looks like an improvement to me.

point 4) looks interesting, how do you extract the resolution from the CGContextRef?, if this is possible, then we can use it only once BeginDoc has been called, and we should not call PMSetResolution?

Other way we can improve this is by trying to figure out ourselves what is the current default resolution by looking into the ppd file of the corresponding Printer. It could be something like this:

1. With PMPrinterGetPrinterResolutionCount we find if it only supports 1 resolution if it does, that is the default resolution.
2. If more than one, then we parse the ppd file looking for the default resolution and if successful use that,

I will try to do this and check the performance on parsing the ppd file.

For the moment your patch should be applied IMO.

skalogryz

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2770
    • havefunsoft.com
Re: Printer.XDPI and Printer.YDPI under OSX 10.9
« Reply #23 on: March 28, 2015, 05:48:39 am »
point 4) looks interesting, how do you extract the resolution from the CGContextRef?, if this is possible, then we can use it only once BeginDoc has been called, and we should not call PMSetResolution?
hmm. PMSetResolution and PMGetResolution are now deprecated. Apple suggests using CGContextScaleCTM instead.

applied - r48525
« Last Edit: March 28, 2015, 05:55:20 am by skalogryz »

skalogryz

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2770
    • havefunsoft.com
Re: Printer.XDPI and Printer.YDPI under OSX 10.9
« Reply #24 on: March 28, 2015, 06:00:31 am »
Other way we can improve this is by trying to figure out ourselves what is the current default resolution by looking into the ppd file of the corresponding Printer. It could be something like this:
...
I will try to do this and check the performance on parsing the ppd file.
I'm sure performance would not be an issue with parsing ppd files.

Apple could be the issue :) for following reasons:
* an app might not have rights to read system files (i.e. Sandbox-ed application)
* location of the files might change without notice in any OSX version. (btw, that's why dsym is using PDL_DEFAULT, rather than trying to load a Application Services framework)
* format of ppd file might change as well.

In the end if all these problems are handled properly and an app won't crash - it should work!

lelebass

  • New Member
  • *
  • Posts: 41
Re: Printer.XDPI and Printer.YDPI under OSX 10.9
« Reply #25 on: March 28, 2015, 11:25:46 pm »
This would be incompatible with the sentence "They run when launched from Terminal, but they don't allow any interaction via Quartz."  ;)
That's the point to make contradiction and inspire lelebass to run the app from terminal and get the error code!

Thank you all for the support!
I was able to launch app from Terminal as suggested by skalogryz and debug the PMPrinterGetOutputResolution call.
The value returned by the function is:

PMPrinterGetOutputResolution -9589

I'll try ASAP the proposed patch.

Dan

skalogryz

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2770
    • havefunsoft.com
Re: Printer.XDPI and Printer.YDPI under OSX 10.9
« Reply #26 on: March 29, 2015, 03:32:31 am »
PMPrinterGetOutputResolution -9589
a comment on this.
The "name" for the error is actually kPMKeyNotFound.
The description of PMPrinterGetOutputResolution suggests the following:
Quote
Some printers allow programmatic control of their hardware output resolution on a print job basis. The hardware resolution is determined by the combination of printer and print settings used for the print job. PMPrinterGetOutputResolution returns the best guess as to what printer resolution setting will be used for the destination print job. If the resolution setting cannot be reliably determined this function returns kPMKeyNotFound.                                                         

And that's exactly what's happening with this printer drivers. (despite of the fact it has only one DPI option).
Maybe playing with PrinterSettings could make the function to act more reliable, but it's always good to back it up with more reliable way of getting DPI.

jesusr

  • Sr. Member
  • ****
  • Posts: 484
Re: Printer.XDPI and Printer.YDPI under OSX 10.9
« Reply #27 on: March 30, 2015, 09:27:10 pm »
Gathering default resolution from printer's PPD data where available is now implemented, please test.

lelebass

  • New Member
  • *
  • Posts: 41
Re: Printer.XDPI and Printer.YDPI under OSX 10.9
« Reply #28 on: April 07, 2015, 10:40:33 pm »
I tried to test the code, please let me know if I followed the right procedure.

I downloaded the 5 files here:

http://svn.freepascal.org/cgi-bin/viewvc.cgi?view=revision&root=lazarus&revision=48542

Which seems to be the ones modified by jesusr.

Then I copied the files into the Lazarus folder in my installation.

If I build again my printing test project I run into the following error:

/Developer/lazarus/components/printers/carbon/carbonprinters_h.inc(86,15) Error: There is no method in an ancestor class to be overridden: "TCarbonPrinter.DoDestroy;"

If I comment out the override in the DoDestroy declaration in carbonprinters_h.inc:

Code: [Select]
   procedure DoDestroy; //override; 
and modify accordingly the TCarbonPrinter.DoDestroy procedure in carbonprinters.inc:

Code: [Select]
procedure TCarbonPrinter.DoDestroy;
begin
  FPrinterContext.Free;
 
  if FPrintSettings <> nil then PMRelease(PMObject(FPrintSettings));
  if FPageFormat <> nil then PMRelease(PMObject(FPageFormat));
  if FPrintSession <> nil then PMRelease(PMObject(FPrintSession));
 
  //inherited DoDestroy;
end;

then I am able to compile without errors, and it seems that XDPI and YDPI are returning the correct resolution.

Anyone can help me to understand what is going on?  :-[

Dan
« Last Edit: April 08, 2015, 01:14:09 pm by lelebass »

felipemdc

  • Administrator
  • Hero Member
  • *
  • Posts: 3538
Re: Printer.XDPI and Printer.YDPI under OSX 10.9
« Reply #29 on: April 08, 2015, 12:21:37 pm »
having this correct is critical for both Carbon and Cocoa widgets (the later doesn't have printers implemented yet).

Yes, it does =) I didn't test it yet, but I implemented the most basic printing in Cocoa as far as I remember.

 

TinyPortal © 2005-2018