## TPrintPreview: Supply the page EMF files directly?

Please post bug reports, feature requests, or any question regarding the DELPHI AREA projects here.

### TPrintPreview: Supply the page EMF files directly?

In my application I'm displaying a few special pages first, then I have 6 EMF files that represent replacement manual pages to be printed (they're print images of printouts from Word captured as EMF files). The 6 EMF files total about 500 KB. Currently I am simply using PaintGraphicEx() to paint the existing EMF files onto the canvas for each page. This works but is rather slow (about 2 seconds per page) and has HUGE memory requirements (the temp file created is over 100 MB and the process memory is almost as big).

I'm wondering if it's possible to somehow stuff the existing EMF files into TPrintPreview without reprocessing them? Since I know how big the EMF files need to be I assume its the act of painting them onto the canvas that converts them to simple bitmaps and consuming all the memory.

In a quick look at the code, it appears that if I expose the TPrintPreview.FPages as a property that I could then use the .Add() method to add metafiles directly. Is there a better way to do this that doesn't require changing the source? Are there any problems I'll encounter by doing this?

Thanks for any suggestions!
sbussinger
Active Member

Posts: 10
Joined: July 2nd, 2004, 7:55 pm

I decided to give what I described a try and it appears to work on the screen, but printing the added pages just results in a blank sheet.
sbussinger
Active Member

Posts: 10
Joined: July 2nd, 2004, 7:55 pm

You should draw the images, because they need to be scaled to the printer's resolution.

Kambiz

Posts: 2430
Joined: March 7th, 2003, 7:10 pm

But the EMF files I'm using are already a scalable vector image that's resolution independent, right? That's why you use them yourself. All I'm trying to do is eliminate the step of converting an EMF to a bitmap to draw it into a EMF so that TPrintPreview can convert it to a bitmap again for printing.

Like I mentioned, this process is both slow and is very resource intensive. I'm going from less than half a megabyte of source files to over 100 megabytes of temp file and on older systems, it really has an effect.

My simple changes work fine on the screen, it's just printing that's failing. I'll play with it a bit and see if I can figure out why they don't print.
sbussinger
Active Member

Posts: 10
Joined: July 2nd, 2004, 7:55 pm

I just noticed this comment in the change log for TPrintPreview:

Version 4.34 (December 8, 2003) Now, a page on the preview can be altered by assigning a metafile to it.

This is precisely what I needed and I didn't need any other changes to TPrintPreview. I just created empty pages and then assigned my EMF file with something like MyTPrintPreview[x].Assign(MyTMetafile).

The only problem is that it doesn't really work right. The metafile isn't StretchDrawn correctly onto the page. Are there some particular requirements for the Metafile that is assigned?

If it's in FastPrint mode, the output looks OK, but it's not stretched to the printer printable area (i.e. if the MMHeight and MMWidth are larger than the printable area on the current printer, then the output is cropped rather than shrunk to fit). If it's not in FastPrint mode, the output page is blank. I think this is because the X,Y coordinates are not in the same units as the EMF file but I'm still playing with this a bit as I have time.
sbussinger
Active Member

Posts: 10
Joined: July 2nd, 2004, 7:55 pm

OK, I found the problems I was having. The first was that I got no printout if FastPrint was false. The problem is in BltBitmapAsDIB():
Code: Select all
procedure BltBitmapAsDIB(DestDc : hdc;   {Handle of where to blt}                          x : word;       {Bit at x}                          y : word;       {Blt at y}                          Width : word;   {Width to stretch}                          Height : word;  {Height to stretch}                          bm : TBitmap);  {the TBitmap to Blt}

The X and Y parameters are defined as words and are being passed negative values. The reason is that the X and Y parameters when printing ultimately come from the GetPrinterPageBounds() routine:
Code: Select all
  function GetPrinterPageBounds: TRect;  begin    Result.Left := 0;    Result.Top := 0;    if UsePrinterOptions then    begin      Result.Right := GetDeviceCaps(Printer.Handle, PHYSICALWIDTH);      Result.Bottom := GetDeviceCaps(Printer.Handle, PHYSICALHEIGHT);    end    else    begin      Result.Right := ConvertUnits(FPageExt.X,        GetDeviceCaps(Printer.Handle, LOGPIXELSX), FUnits, mmPixel);      Result.Bottom := ConvertUnits(FPageExt.Y,        GetDeviceCaps(Printer.Handle, LOGPIXELSY), FUnits, mmPixel);    end;    OffsetRect(Result,       -GetDeviceCaps(Printer.Handle, PHYSICALOFFSETX),       -GetDeviceCaps(Printer.Handle, PHYSICALOFFSETY));  end;

Result.Left and Result.Top will always be negative coming out of this routine because of the OffsetRect() call. The values get converted to large positive values because of the WORD declarations and the bitmap gets printed way off the page. Changing the declarations to INTEGER seems to work OK.

My second problem was also related to GetPrinterPageBounds() routine. It returns values based on the physical size of the page rather than the logical size of the page. In my case that's an issue, but it may be better the way it is for everyone else. My problem arises because inkjets tend to have much larger bottom margins than laser printers and my output was getting cropped. I'd like to propose this change to GetPrinterPageBounds():
Code: Select all
Replace      Result.Right := GetDeviceCaps(Printer.Handle, PHYSICALWIDTH);      Result.Bottom := GetDeviceCaps(Printer.Handle, PHYSICALHEIGHT);with      Result.Right := GetDeviceCaps(Printer.Handle, HORZRES);      Result.Bottom := GetDeviceCaps(Printer.Handle, VERTRES);

This would mean that if UsePrinterOptions is true, that the page size is based on the printable area of the page rather than on the full size of the page in question. Any thoughts?

Thanks again for a great component set!
sbussinger
Active Member

Posts: 10
Joined: July 2nd, 2004, 7:55 pm

Thanks for the valuable information you provided.

Just for your information, TPrintPreview doesn't convert metafiles to bitmap, except FastPrint property is False and the metafile has at least one DDB bitmap as meta data (EMR_BITBLT and EMR_STRETCHBLT meta records).

Regarding to using HORZRES and VERTRES instead of PHYSICALWIDTH and PHYSICALHEIGHT I think could be some problems, because HORZRES and VERTRES are in pixels, however PHYSICALWIDTH and PHYSICALHEIGHT in logical units. I'll investigate it.

Kambiz

Posts: 2430
Joined: March 7th, 2003, 7:10 pm

Please forgive me, pixel and logical unit are identical here.

Kambiz

Posts: 2430
Joined: March 7th, 2003, 7:10 pm

Just for your information, TPrintPreview doesn't convert metafiles to bitmap, except FastPrint property is False and the metafile has at least one DDB bitmap as meta data (EMR_BITBLT and EMR_STRETCHBLT meta records).

Actually I was referring to the process I was performing before finding out I could assign a TMetafile directly to the TPrintPreview. I did a BeginDoc, a PaintGraphicEx to put my EMF file on the page, then EndDoc sort of sequence and went from a nice tidy EMF file to a huge bitmap. It wasn't TPrintPreview's fault at all, it makes sense that it did it that way. But that's why I needed a way to just assign the EMF directly.

Regarding to using HORZRES and VERTRES instead of PHYSICALWIDTH and PHYSICALHEIGHT I think could be some problems, because HORZRES and VERTRES are in pixels, however PHYSICALWIDTH and PHYSICALHEIGHT in logical units. I'll investigate it.

Thanks! I'm not entirely sure what affect this change will have on the normal cases. I haven't done a great deal of printing so I'm not entirely sure how this change would affect existing users.

Be seeing you.
sbussinger
Active Member

Posts: 10
Joined: July 2nd, 2004, 7:55 pm