Obtaining the printer DPI in Windows

I’ve put together a little demo to show you how to obtain the DPI of the printer that you are currently printing to in windows.

https://www.dropbox.com/s/tiod5twkggb9t0x/PrinterDPI.xojo_binary_project?dl=1

Notes:

  1. Some printer drivers don’t return DPI for certain axis so you’ll need to best use what you are given.

  2. dmCopies isn’t being set inside the DEVMODE structure (there may be other things but I’ve not really looked), but you can read that from Graphics.Copies anyway so not a deal breaker.

  3. There is currently a bug (<https://xojo.com/issue/51489>) where by if you open a PrinterSetup.PageSetupDialog and pass the results of that to the OpenPrinterDialog the information inside the DEVMODE structure won’t be updated so you will only see the information for the default printer, NOT the selected printer that you are printing to (if that is different from default), hopefully Xojo will fix that for the next release.

However, if you call OpenPrinterDialog with a brand new uninitialised PrinterSetup as I have in the demo then it will work because it seems there’s another bug (?) where by if you send an uninitialised PrinterSetup to OpenPrinterDialog then 0,0 is in the top left corner of the paper which makes it super easy for placing things exactly where you want on the page. PrinterSetup.PageLeft and PrinterSetup.PageTop will show your left and top margins respectively so you can calculate where you can print as these will be set to the minimum margins for the printer. However, there is another bug (?) that is placing things ever so slightly up and right on the page, this is probably a rounding issue but it seems to be uniform across prints.

To get around this you will need to provide a method to your users to tweak the vertical and horizontal offset a bit if you want to hit calculated positions on pre-printed forms. I’ve not checked if this is a scaling issue so the discrepancy might alter across the print.

Let me know how you get on with the demo, if you want, print off a couple of test pages and measure the dots as accurately as you can and let me know if they are slightly off.

I can get it perfectly positioned in MS Word with every print and double checked with my digital calipers so its not my printer or printer driver that is causing the drift, I’ll post a feedback about it when I get a moment to collect my thoughts on it.

Call me Mr Silly, but :

if the page size is (eg) 8 inches at 300 dpi, the graphics object should be (eg) 2400 points across
Top left corner should be 0,0 so that we know exactly where our output is going to be on the page, regardless of the margins.

There should be leftmargin, topmargin, rightmargin, and bottommargin available
so we can respect the user’s choice of margins if we don’t have preprinted paperwork to line up with.

Since 2017, Xojo Windows does not provide the printer resolution. All methods systematically returns 96 dpi, and so does the printerSetup object. There is no apparent way to work around this since the implementation of Direct2D. Talking about breaking existing code…

The only Xojo way I can think of would be to create a small helper in 2016R3 which would communicate via IPCSocket, and be in charge of printing. It would open the printer setup, as well as the printer, and then simply take a picture for the actual printing. It seems fairly easy to create an elementary protocol to have the helper send all useful data, including setupstring, and once the printer is open, horizontal and vertical resolution.

Another approach would be to devise a DLL in VS, since for instance VB. Net does provide all the informations about the printer. I have used several time that workaround, to get features only VB. Net provided.

For your page margins, you can get or set a lot of such information in the printerSetup object. But even if you try to set to zero, the printing area is a physical limit you won’t be able to overcome.

On my printer things are shifted about two pixels to the right or 1/32". However printing to a PDF prints it correctly. I tried two different PDF printers.

[quote=375455:@Jeff Tullin]Call me Mr Silly, but :

if the page size is (eg) 8 inches at 300 dpi, the graphics object should be (eg) 2400 points across
Top left corner should be 0,0 so that we know exactly where our output is going to be on the page, regardless of the margins.[/quote]

That was the problem, the graphic object that you draw onto is now 96 DP so it would be 768 units for an 8" final print I in windows no matter what printer it was going to.

Even without knowing the DPI of the printer we always knew where to precisely position things, I don’t think everyone understood this though. The problem was that every seems to be sticking to standard integer based drawing routines rather than using Object2D which could be placed with double precision.

There’s only certain edge cases these days when you need to know the DPI of the target printer like calculate an image size so it comes out as a 1:1 when it hits the printer. Some drivers will convert D2D primitives into native internal elements anyway which should be crisp.

[quote=375455:@Jeff Tullin]There should be leftmargin, topmargin, rightmargin, and bottommargin available
so we can respect the user’s choice of margins if we don’t have preprinted paperwork to line up with.[/quote]

At the moment, because of the bug I mentioned above, there’s no way to play with margins and get the DPI of the printer if you happen to pick a different printer than default. However margins are just offsets that are applied to your graphics anyway which can be done in your own way if you make a UI for it (until the bug is fixed if you don’t want to implement your own margin UI). I.e. MS Word doesn’t use the stock page setup dialog for its margins.

Well it looks like Michel has set me on ignore because I allegedly don’t help people, shame, he was so convinced that Xojo wasn’t providing the DPI information. Someone might want to let him know that DPI can now be found because it seems that I can’t. /shrug

Thanks Neil, this is similar to what I was finding.

@JulianS

Thanks for all you help.I’m curious now if a printer setup string could be setup from scratch using the DevMode structure? I’d love to be able to create my own custom print dialog and set things such as printer to use, number of copies, orientation, and so forth.

As @JulianS 's demo shows it is possible to get the DPI info. It’s frustrating how this changed. It would be nice if Xojo provided a way that ‘average’ people could access it. For myself I wasn’t aware that DevMode info could be extracted from the printersetup string until @JulianS so nicely demonstrated it. It’s not something one would figure out by reading the Xojo documentation.

[quote=375494:@Neil Burkholder]@JulianS

Thanks for all you help.I’m curious now if a printer setup string could be setup from scratch using the DevMode structure? I’d love to be able to create my own custom print dialog and set things such as printer to use, number of copies, orientation, and so forth.[/quote]

No probs.

Technically yes, I don’t really know the full structure of the SetupString though as its 10000+ bytes of something so altering the DevModeStructure inside there might cause havoc, I don’t know though. PrintDlgEx takes in a LPPRINTDLGEX which has a DEVMODE structure inside which is used to initialize the controls on the property sheet, but I don’t think the Xojo framework allows this… yet :slight_smile:

Also, you can hook the Print Dialog and/or the PageSetup dialog to have custom stuff on there so you can do funky stuff. However, Xojo doesn’t allow us a way into the print pipeline so we’re stuck with what they expose for us to use at the moment.

Feature request party anyone? :slight_smile:

I appreciate and salute Julian’s efforts. Yet, Xojo 2017 and over indeed no longer natively provide the printer resolution that was accessible before the implementation of Direct2D.

A clever recourse to Devmode is a great workaround. Pity code has been broken for over a year without any solution.

+1

I’ve updated the source code at the link posted above because William has kindly pointed out that additional information is provided in the SetupString which I had overlooked in the excitement of actually finding the information in there in the first place. Doh!

This means that the bug mentioned above doesn’t exist, you can read the DPI of the default printer or a selected printer without issue.

However, I believe there is still a problem with the calculation of position on the page, I will look into this further and update this thread when I have some more information.

Very nice. Thank you :slight_smile:

I noticed that on my Epson XP-900 I obtain resolution 360 dpi for X and Y, just like on the HP Envy D410 I get 600 dpi for X and Y, whether an HP Laserjet Professional P1102 reports only dpiX = 600. dpiY = 0.

In these three case, though, it is possible to do a good job, since they all have square pixels.

But as I was shopping yesterday for a new 1200 x1200 printer on Amazon, I noticed there is a whole range of new printers with resolution 600 x 2400. Hopefully the driver will map that to square pixels, or that will be an interesting challenge to address to print with precision.

I have not yet decided if I should buy one to test on, though. I will cross my fingers and hope for the best with the software I currently have on the market based on 2016R3.