DrawPageAt to bitmap, metafile

General TRichView support forum. Please post your questions here
Post Reply
Lucian
Posts: 56
Joined: Fri Aug 01, 2014 9:52 am

DrawPageAt to bitmap, metafile

Post by Lucian »

Hi Sergey,

I am trying to print preview. Our reporting engine works like this. It uses and informational device context (CreateIC) compatible with the default printer. Than all output methods are overridden in such way, that the actual "output" happens in a memory stream. So the DC is only used for measuring draw items.

To connect the engine with TRichView control, I decided to output the content into a bitmap (I also tried with a metafile) than, I would "Draw" the bitmap with our reporting engine. Thus, I should get an image of the richview at the coordinates computed in the printing engine. However the image is not coming out at all. To debug, intermediary I printed the image to some external file (bmp, emf) and I found out that the text is very very small

I do not know what I am doing wrong. This is how I implemented it:

I create a TRVReportHelper object, load its RichView from a database blob (LoadRVFFromStream):
- call Helper.Init(SomeCanvas, DocWidth), somecanvas is either a tbitmap.canvas or a TMetafileCanvas;
- call Helper.FormatNextPage(DocHeight)
- call Helper.DrawPageAt(0, 0, PageNo, somecanvas, True, DocHeight);

Any idea what I may be doing wrong. For example I understand that in DrawPageAt I should use true for Preview parameter and also that the Canvas should be a "true" output Canvas (like RV_GetPrinterDC or for a bitmap, TBitmap.Canvas)...?

Thx
Sergey Tkachenko
Site Admin
Posts: 17557
Joined: Sat Aug 27, 2005 10:28 am
Contact:

Post by Sergey Tkachenko »

Make sure that Canvas.Font.PixelsPerInch is set correctly to GetDeviceCaps(Canvas.Handle, LOGPIXELSY)
Lucian
Posts: 56
Joined: Fri Aug 01, 2014 9:52 am

Post by Lucian »

All right, it started to work. Now I have another problem. For me, FormatNextPage always returns true, even though the full content for the richview fits on the first page. Here is a piece from how I coded it (you'll the WHILE loop should break when FormatNextPage would return false, however it never happens for me):

while TRUE do
begin
if fPrinter.LinesLeft < 6 then
fPrinter.NewPage;
Inc(PageNo);

DocTop := fPrinter.CursorYPos;
DocHeight := DocBottom - DocTop;

G := PrintWithMeta(fPrinter.Canvas.Handle);
if Assigned(G) then
try
ImageBounds := Rect(DocLeft, DocTop, DocLeft+DocWidth, DocTop+lRVHelper.EndAt);
fPrinter.StretchDraw(ImageBounds, G);
NewPos := fPrinter.XD2U(lRVHelper.EndAt);
fPrinter.YPos := fPrinter.YPos + NewPos;
finally
FreeAndNil(G);
end
else
BREAK;
end;

function PrintWithMeta(DC: HDC): TBitmap;
var
M: TMetafile;
MC: TMetafileCanvas;
begin
Result := nil;
M := TMetafile.Create;
try
M.Height := DocHeight;
M.Width := DocWidth;

MC := TMetafileCanvas.Create(M, DC);
try
MC.Font.PixelsPerInch := GetDeviceCaps(DC, LOGPIXELSY);

lRVHelper.Init(MC, DocWidth);
if not lRVHelper.FormatNextPage(DocHeight) then
EXIT
else
lRVHelper.DrawPageAt(0, 0, PageNo, MC, True, DocHeight);
finally
MC.Free;
end;
Result := GetImage(M);
finally
M.Free;
end;
end;

function GetImage(Drawing: TGraphic): TBitmap;
begin
Result := TBitmap.Create;
Result.Width := DocWidth;
Result.Height := lRVHelper.EndAt;
Result.Canvas.Draw(0, 0, Drawing);
//Result.SaveToFile('p:\test.bmp');
end;
Lucian
Posts: 56
Joined: Fri Aug 01, 2014 9:52 am

forget about last question

Post by Lucian »

I think I got it. The Init call must happen only once, I call it for page one, but than since I "print" to TMetafileCanvas I must update PrinterCanvas property, new code something like:

TReportRVData(TReportRichView(lRVHelper.RichView).RVData).PrinterCanvas := MC;

Pretty ugly looks this :-), do you have a nicer suggestion Sergey?

Thx,
Lucian
Sergey Tkachenko
Site Admin
Posts: 17557
Joined: Sat Aug 27, 2005 10:28 am
Contact:

Post by Sergey Tkachenko »

It's not necessary to reassign canvas, but you must not destroy this canvas until you finish working with document formatted by the last call of Init.
Lucian
Posts: 56
Joined: Fri Aug 01, 2014 9:52 am

Post by Lucian »

I have to reassign it. After I the output of the richview, there are other things to be printed and there may be a NewPage happening, different height available for the richview, a different metafile, different canvas... no?
Sergey Tkachenko
Site Admin
Posts: 17557
Joined: Sat Aug 27, 2005 10:28 am
Contact:

Post by Sergey Tkachenko »

The canvas passed in Init is not necessary the same canvas as used for DrawPage. They should only be compatible.

For example, in the demo Demos\DelphiUnicode\Assorted\ToImage\, Init is called for the form's Canvas, while DrawPage is called for a metafile or a bitmap canvas.
Lucian
Posts: 56
Joined: Fri Aug 01, 2014 9:52 am

It started to work

Post by Lucian »

His Sergey,

It works for small data. However I have a 2-3 pages piece which doesn't work correctly. It only shows last page with my code. On the first page, the data should start at about 8 cm from the top of the page, than, the eventual other pages should start at about 3.5 cm. For whatever reason, the TRVReportHelper doesn't want to start with the beginning of the data (not sure how to explain). My code is something like this.

function PrintWithMeta(DC: HDC): TGraphic;
var
M: TMetafile;
MC: TMetafileCanvas;
begin
Result := nil;
M := TMetafile.Create;
try
M.Height := DocHeight; // 4786
M.Width := DocWidth; // 3922

MC := TMetafileCanvas.Create(M, DC);
try
MC.Font.PixelsPerInch := GetDeviceCaps(DC, LOGPIXELSY); // 600

if PageNo = 1 then
lRVHelper.Init(MC, DocWidth);

if not lRVHelper.FormatNextPage(DocHeight) then
EXIT
else
lRVHelper.DrawPageAt(0, 0, PageNo, MC, True, DocHeight);

(*
the problem seems to be that after first run of this method,
lRVHelper.EndAt is still 0, as if nothing fits
*)
finally
MC.Free;
end;

// use another metafile with correct height
Result := TMetafile.Create;
Result.Height := lRVHelper.EndAt;
Result.Width := DocWidth;
MC := TMetafileCanvas.Create(TMetafile(Result), DC);
try
MC.Draw(0, 0, M);
finally
MC.Free;
end;

finally
M.Free;
end;
end;

Any ideas?
Thx
Lucian
Lucian
Posts: 56
Joined: Fri Aug 01, 2014 9:52 am

Post by Lucian »

I got it to work. It's all fine if I don't rely on "EndAt". If I use the Height that I know, it's ok.

So I don't know why after a successful call to FormatNextPage, the EndAt call returns 0. Is it a bug?
Sergey Tkachenko
Site Admin
Posts: 17557
Joined: Sat Aug 27, 2005 10:28 am
Contact:

Post by Sergey Tkachenko »

EndAt can be used only for the last page, when all FormatNextPage are called.
It's better to use GetLastPageHeight instead of EndAt, it includes all necessary margins and indents.
Post Reply