| Printer Demo #1 | Lab Report |
Purpose
The purpose of this project was to explore printing
in Delphi, especially the various ways to print an image. The various Windows
printer "Device Capabilities" are also to be studied.
Materials and Equipment
Software Requirements
Windows 95/98/2000
Delphi 3/4/5 (to recompile)
PrinterDemo1.EXEHardware Requirements
VGA display
Windows printer
Procedure
Data
Printers
| Pixels | LogPixelsX | PhysicalOffset | ||||
| Printer | Type | Width | Height | LogPixelsY | X/Y | Comments/Features |
| Canon BJC-620 | Color ink jet | 3750 | 2879 | 360 | 167/90 | Good color. Not much difference between StretchDraw and StretchDIBits. "CopyRect Enigma" present in "normal" orientation. Because of the large PhysicalOffsetX value, the image runs off the right margin (unlike most ink jets that "hug" the left margin). |
| Epson Stylus Color 850 | Color ink jet | 7440 | 5952 | 720 [What about the marketing claim of 1440 x 720 DPI? See notes below.] |
84/84 |
Excellent color, especially with photo-quality paper. "CopyRect Enigma" is present in "flipped" orientation but is missing in the "normal" orientation. Transparent "Blue O" is yellow for Draw and StretchDraw (not sure why). |
| HP DeskJet 682C | Color ink jet | 3112 | 2400 | 300 | 12/75 | StretchDIBits is much better than StretchDraw. No "CopyRect Enigma," except for slight color shift in "Flipped" orientation. |
| HP DeskJet 870C | Color ink jet | 3150 | 2400 | 300 | 12/75 | StretchDIBits is much better than StretchDraw. No "CopyRect Enigma," except for slight color shift in "Flipped" orientation. |
| HP DesignJet 750C | Color ink jet "plotter" | 6481 | 4698 | 600 | 59/200 | Excellent color. StretchDIBits is much better than StretchDraw. GetDeviceCaps values such as LOGPIXELSX are for a "logical" inch, which may be 2 physical inches. |
| HP LaserJet III | Black/ White laser | 3150 | 2425 | 300 | 75/75 | StretchDIBits is much better than StretchDraw. No "CopyRect Enigma" at all! "Draw" of spectrum does not appear. |
| HP LaserJet 5 | Black/ White laser | 6352 | 4896 | 600 | 124/102 | StretchDIBits is much better than StretchDraw. StretchDraw
is very bad using Raster Graphics mode. "CopyRect Enigma" sometimes present in
"normal" orientation. "Draw" of spectrum does not appear. "Banding" in spectrum images. Sometimes Draw doesn't result in any image. GDI GPFs under Windows 98 are sometimes observed during the transparency test. |
| IBM 4039 | Black/ White laser | 3158 | 2408 | 300 | 75/79 | No difference between StretchDraw and StretchDIBits. No "CopyRect Enigma" at all! |
| Lexmark 4039 Plus | Black/ White laser | 3163 | 2413 | 300 | 71/75 | No difference between StretchDraw and StretchDIBits. "CopyRect Enigma" in both "normal" and "flipped" orientation. |
| Lexmark Z31 | Color ink jet | 6260 | 4800 | 600 | 600 | "Normal" Copyrect doesn't work, but "Flipped" Copyrect does. No difference between StrechDraw and StretchDIBits. |
| Okidata 192 | Black/ White dot matrix | 1584 | 2376 | 144 x 288 | 0/0 | Draw image is twice as wide as normal due to ratio of LOGPIXELSY to LOGPIXELSX. StretchDraw show a "weak" image. StretchDIBits does not work at all. |
Discussion
Here is pseudocode for this program:
Draw rectangle to show margins and printable area.
Display labels and Date
Show Delphi Printer and Page Properties
Show Printer Device Capabilities
Draw "Blue O" eight different ways: "regular" and "transparent" images printed using Draw, StretchDraw, StretchDIBits and CopyRect
Show Spectrum Images: Draw, CopyRect, StretchDraw, StretchDIBits
Show KC Fox: Draw, StretchDraw, StretchDIBits
Show Hue-Saturation Color Circle: StretchDraw, StretchDIBits (from in-memory, computed bitmap)
Show Sine Curve (the "CopyRect Enigma")
Show List of Fonts. (Print font name in its own font -- can be a viewing problem for symbol fonts)
Draw and StretchDraw use the StretchBlt API call.
The "CopyRect Enigma" is so named because of a problem in initially getting CopyRect to work at all with a HP LaserJet 5. When I accidentally coded the "flipped" image, I noticed the graphics were wrong and "corrected" the image. But with the "correct" orientation, the image would not print at all! (Note: the sine curve initially goes "down" when the direction of the "Y" axis is reversed.) [Is it possible this is caused by a pfDevice PixelFormat? I need to check this. 1 Dec 98, efg]
In a few observed cases with a LaserJet 5, the use of "Draw" in Delphi 1did not result in any image. The same program in Delphi 2 or later resulted in a small image being drawn.
Physical Page Versus Logical Page
The dimensions of the physical page (GetDeviceCaps values PHYSICALWIDTH and PHYSICALHEIGHT in dots) are larger the the logical page (GetDeviceCaps values HORZRES and VERTRES in dots, or HORZSIZE and VERTSIZE in millimeters). There doesn't seem to be much of a "pattern" in what manufacturers use for the left and top margins (PhysicalOffsetX and PhysicalOffsetY). Often the Logical Page is not even centered horizontally and vertically within the Physical page. Often with InkJet printers there is much as a 0.5-inch gap at the bottom of a page in portrait orientation, or the right of the page in landscape orientation.
Important GetDeviceCaps Values
| GetDeviceCaps Parameter | Description |
| HORZSIZE | horizontal size [mm] |
| VERTSIZE | vertical size [mm] |
| HORZRES | horizontal resolution [dots] |
| VERTRES | vertical resolution [dots] |
| LOGPIXELSX | horizontal dot density [dots/inch] |
| LOGPIXELSY | vertical dot density [dots/inch] |
| PHYSICALWIDTH | page width [dots] |
| PHYSICALHEIGHT | page height [dots] |
| PHYSICALOFFSETX | horizontal offset from physical page edge to logical page edge [dots] |
| PHYSICALOFFSETY | vertical offset from physical page edge to logical page edge [dots] |
Here's a brief description of some of the relationships among the GetDeviceCaps values:
Horizontal Dimension
(not drawn to scale)
PHYSICALWIDTH |
||
| PHYSICALOFFSETX | HORZRES | gap |
Horizontal gap (or margin at the right) = PHYSICALWIDTH - PHYSICALOFFSETX - HORZRES
Example: Epson Color Stylus 850 in Landscape Orientation, 8.5-by-11" paper:
| GetDeviceCaps Value | Dots | Inches Dots/LOGPIXELSX |
Millimeters Inches * 25.4 |
| PHYSICALWIDTH | 7920 | 11.00 | 279.4 |
| PHYSICALOFFSETX | 84 | 0.12 | 3.0 |
| HORZRES | 7440 | 10.33 | 262.5 |
| gap | 7920 - 84 - 7440 = 396 | 0.55 | 14.0 |
Ideally, the gap would be the same as the PHYSICALOFFSETX value to center the logical page within the physical page. A horizontal "gap" of 84 dots would have centered the logical page within the physical page horizontally. So the page is positioned 396 - 84 = 312 dots from being centered. (On the Epson this is 312/720 = 0.43 inch.) Since printing outside of the logical page is impossible, there is no way to print anything in this "gap" area. As mentioned earlier, many inkjet printers have a significant "gap" in the longer dimension.
Vertical Dimension
(not drawn to scale)
| PHYSICALHEIGHT | PHYSICALOFFSETY |
| VERTRES | |
| gap |
Vertical gap (or margin at the bottom) = PHYSICALHEIGHT - PHYSICALOFFSETY - VERTRES
Example: Epson Color Stylus 850 in Landscape Orientation, 8.5-by-11" paper:
| GetDeviceCaps Value | Dots | Inches Dots/LOGPIXELSY |
Millimeters Inches * 25.4 |
| PHYSICALHEIGHT | 6120 | 8.50 | 215.9 |
| PHYSICALOFFSETY | 84 | 0.12 | 3.0 |
| VERTRES | 5952 | 8.27 | 210.0 |
| gap | 6120 - 84 - 5952 = 84 | 0.12 | 3.0 |
With the vertical gap the same as the PHYSICALOFFSETY, the logical page is centered vertically within the physical page.
Other GetDeviceCaps issues
Epson claims a 1440-by-720 DPI on printers such as the Epson 850 Color Stylus. Neither the LOGPIXELSX nor LOGPIXELSY value is ever 1440! Is this marketing hype?
We tend to think that DotsPerInch = PixelsPerInch. Sometimes
they do not. The Epson can print slightly
overlapping dots of different colors to create a "pixel". There may be
1440 dots in an inch, but there are only 720 pixels. I know that's kinda hard to put into
concept. (and be happy that the driver reports a "square pixel" as you have seen
the problems that both the VCL (and the GDI) can have when dealing with a surface that
does not have a 1:1 aspect ratio. [Thanks to Joe Hecht for this information.]
Transparency
The Epson Stylus Color 850 was the first printer found to have a problem with transparency. For some unexplained reason, Draw or StretchDraw with transparency seems to create an inverted image with this Epson printer. The "Blue O" test was added to this demo program as a result. This transparency test will sometimes cause GDI.EXE GPFs in Windows 98. [See Joe Hecht's notes about why Transparency on printers is not guaranteed -- see Item 11 on the Delphi Printing Info and Links page.]
DIB vs DDB and the Sine Curve
Ulrich Strautz reports (October 2000) with his Olivetti JP170 Bubble-Jet printer that the sine curve prints correctly ONLY when a PixelFormat statement is added:
OffScreenBitmap := TBitMap.Create;
OFFScreenBitmap.PixelFormat:=pf24bit; // here is the missing line
The bitmap becomes a DIB (device independent bitmap) when the PixelFormat statement is added, and apparently at least with the Olivetti printer, the sine curve prints correctly with a DIB but not a DDB. (Bitmaps were DDBs in Delphi 1 and 2, and can be either a DIB or a DDB in Delphi 3 or later.)
Miscellaneous
Why use StretchDIBits? See Blitting Between DCs for Different Devices Is Unsupported (MS Q195830).
Conclusions
Getting the "same" printout on a variety of
Windows printers is almost impossible! (This is a Windows issue, not a Delphi problem.)
Almost always use StretchDIBits to print images.
When isn't StretchDIBits the best way to go? If you need to use transparency (Transparent := TRUE), then you must use Draw or StretchDraw. BUT, transparency is not guaranteed. [See Joe Hecht's notes about why Transparency on printers is not guaranteed -- see Item 11 on the Delphi Printing Info and Links page.]
Future
A "Print Preview" would be a nice addition to
this demonstration program to show how to draw on a canvas, whether the screen or the
printer, in a device independent way.
Keywords
Delphi printing, Draw, StretchDraw, StretchDIBits, CopyRect, GetDeviceCaps, Pixels
Per Inch, Aspect Ratio, Fonts, Scanline, HSVtoRGB, TextOut, Rect, sorting using
TStringList, Transparency
Files
Delphi 3/4/5 Source and EXE (218 KB): PrinterDemo1.ZIP
Delphi Conversion Notes
No changes are needed to compile in D3-D5.
Size of Delphi 3 EXE: 345 KB
Size of Delphi 4 EXE: 441 KB
Size of Delphi 5 EXE: 460 KB
Because of the use of Scanline, this program no longer works in D1 or D2, but some of the conditional compilation statements for D1/D2 are still present in the code.
Thomas Bornhaupt's Printer Demo 1 project that creates a preview version of the page that is to be printed. (Delete RzButton, RzPanel, TMultiP, ToolWin from Uses to compile.)
This is a very interesting modification to Printer Demo 1. Because of the huge bitmap that is created to allow a print preview, this program may only reliably work in Windows NT/2000 and may have problems in Win 95/98.
Updated 18 Feb 2002
since 1 Nov 1998