jonwcroft
asked on
Printing bitmaps in Delphi 4
I can't seem to be able to print bitmaps reliably in Delphi 4. My code is as follows:
procedure TForm1.BitBtn1Click(Sender : TObject);
var
i : integer;
bm : tbitmap;
begin
printer.BeginDoc;
for i := 1 to 20 do
begin
bm := tbitmap.create;
try
bm.handletype := bmDIB;
bm.pixelformat := pf32bit;
bm.width := 1000;
bm.height := 100;
bm.canvas.font.color := clBlack;
bm.canvas.font.size := 40;
bm.canvas.font.name := 'ARIAL';
bm.canvas.textout(0, 0, 'Using tbitmap ' +inttostr(i));
printer.canvas.textout(100 0, 100 + 100*i, 'Using textout ' + inttoStr(i));
printer.Canvas.Draw(100,10 0 + 100 * i,bm);
finally
bm.free;
end;
end;
printer.EndDoc;
end;
The printout should have two columns, the first with text printed via a tbitmap, the second with text printed directly. However, bitmaps in the first column seem to randomly go missing. I've tried using an HP Laserjet 6L and an IBM 4039 LaserPrinter Plus both with the same result. Using Acrobat 2.11 writer causes a GPF.
Is there something wierd going on here, or am I being totally stupid?
Any help would be greatly appreciated.
Regards,
Jon.
procedure TForm1.BitBtn1Click(Sender
var
i : integer;
bm : tbitmap;
begin
printer.BeginDoc;
for i := 1 to 20 do
begin
bm := tbitmap.create;
try
bm.handletype := bmDIB;
bm.pixelformat := pf32bit;
bm.width := 1000;
bm.height := 100;
bm.canvas.font.color := clBlack;
bm.canvas.font.size := 40;
bm.canvas.font.name := 'ARIAL';
bm.canvas.textout(0, 0, 'Using tbitmap ' +inttostr(i));
printer.canvas.textout(100
printer.Canvas.Draw(100,10
finally
bm.free;
end;
end;
printer.EndDoc;
end;
The printout should have two columns, the first with text printed via a tbitmap, the second with text printed directly. However, bitmaps in the first column seem to randomly go missing. I've tried using an HP Laserjet 6L and an IBM 4039 LaserPrinter Plus both with the same result. Using Acrobat 2.11 writer causes a GPF.
Is there something wierd going on here, or am I being totally stupid?
Any help would be greatly appreciated.
Regards,
Jon.
ASKER
RBertora:
Thank-you for your comment.
The crash is a white box "An error has occurred in your application" job. Certainly not trapped by "try except" & "on except do"
The line that causes the crash is the "printer.canvas.draw(100, 100 + 100 * i, bm)" - I know this because the program does not crash when the line is removed. Don't forget that the program only crashes when printing to Acrobat - bitmaps dissappear when printing to normal printers.
This is only a simple little program that you can cut and paste into a new delphi 3/4 application - why don't you try it?
Regards,
Jon.
Thank-you for your comment.
The crash is a white box "An error has occurred in your application" job. Certainly not trapped by "try except" & "on except do"
The line that causes the crash is the "printer.canvas.draw(100, 100 + 100 * i, bm)" - I know this because the program does not crash when the line is removed. Don't forget that the program only crashes when printing to Acrobat - bitmaps dissappear when printing to normal printers.
This is only a simple little program that you can cut and paste into a new delphi 3/4 application - why don't you try it?
Regards,
Jon.
I could not even run this in Run mode. I had to step through it. The first time, it showed 2-6 and 12-20. The second time, I got 2-20. Some process is not quite finished after the Create. I added a Application.Processmessage s; line after the create and all worked fine.
ASKER
CalvinDay:
Thank-you for your answer.
I tried your suggestion and got it to work only by adding "processmessages" before and after the printer.canvas.draw line.
I want to reopen this question because I'm sure that there must be a better answer than just chucking in processmessages everywhere (particularly as this will routine will become part of a very large multithreading application) and I'm not totally convinced that it will work with a large veriety of bitmaps.
Obviously the VCL does not work completely propperly when printing DIBS: do Borland fix bugs like these and supply patches?
If no-one comes up with a better answer within a few days then I will give you the points.
Thank-you for your answer.
I tried your suggestion and got it to work only by adding "processmessages" before and after the printer.canvas.draw line.
I want to reopen this question because I'm sure that there must be a better answer than just chucking in processmessages everywhere (particularly as this will routine will become part of a very large multithreading application) and I'm not totally convinced that it will work with a large veriety of bitmaps.
Obviously the VCL does not work completely propperly when printing DIBS: do Borland fix bugs like these and supply patches?
If no-one comes up with a better answer within a few days then I will give you the points.
Good point. I have seen this happen when the setting the pallete. It seems to trigger a flurry of messages.
ASKER
Epsylon:
Thank-you for your comment.
In fact I have tried something simillar using StretchDIBits with some success.
But what is the point of setting TBITMAP.HANDLETYPE to bmDIB if not so that you can print reliably? I have checked the VCL source and can not find any trace of StretchDIBits.
Lets face it: this is a dirty great big omission in the VCL: bmDIBs have not been implemented propperly in the TBITMAP.DRAW method.
I shall award the points to CALVINDAY unless someone can explain the point of HANDLETYPE=bmDIB, or can deny or confirm that this is a VCL omission/bug.
Thank-you for your comment.
In fact I have tried something simillar using StretchDIBits with some success.
But what is the point of setting TBITMAP.HANDLETYPE to bmDIB if not so that you can print reliably? I have checked the VCL source and can not find any trace of StretchDIBits.
Lets face it: this is a dirty great big omission in the VCL: bmDIBs have not been implemented propperly in the TBITMAP.DRAW method.
I shall award the points to CALVINDAY unless someone can explain the point of HANDLETYPE=bmDIB, or can deny or confirm that this is a VCL omission/bug.
Quoted from the Delphi help:
TBitmap.HandleType "Indicates whether the bitmap is a DDB, Device Dependent Bitmap, or a DIB, Device Independent Bitmap."
bmDDB:
This means that the actual data stored in the bitmap is in a format that is asociated with a certain device. Some devices can handle it, others not.
bmDIB:
This means that the actual data stored in the bitmap is universal. Whatever device wants to use the bitmap should convert it for its own use. TPrinter provides a canvas for that purpose.
Did you try TCanvas.StretchDraw?
See TBitmap.PixelFormat := pfDevice too....
Epsylon.
TBitmap.HandleType "Indicates whether the bitmap is a DDB, Device Dependent Bitmap, or a DIB, Device Independent Bitmap."
bmDDB:
This means that the actual data stored in the bitmap is in a format that is asociated with a certain device. Some devices can handle it, others not.
bmDIB:
This means that the actual data stored in the bitmap is universal. Whatever device wants to use the bitmap should convert it for its own use. TPrinter provides a canvas for that purpose.
Did you try TCanvas.StretchDraw?
See TBitmap.PixelFormat := pfDevice too....
Epsylon.
ASKER
Epsylon:
Thank-you for your comment. Yes, I have read the same section of help several times myself.
A note for Borland:
Why should I care how bitmaps are stored? I just want them to work.
I understood that the practical upshot of using bmDIBs are that they print correctly, and that bmDDBs are faster.
I would have thought that the tbitmap should be able to detect an incompatible canvas and convert itself to a DIB should it need to. Whatever they should always work.
This not my question. My problem is that even bmDIBs, randomly don't work! Also when trying StretchDraw, or whatever pixelformat.
CalvinDay:
Repost your orriginal answer tomorrow, and I'll give you the points.
Thank-you for your comment. Yes, I have read the same section of help several times myself.
A note for Borland:
Why should I care how bitmaps are stored? I just want them to work.
I understood that the practical upshot of using bmDIBs are that they print correctly, and that bmDDBs are faster.
I would have thought that the tbitmap should be able to detect an incompatible canvas and convert itself to a DIB should it need to. Whatever they should always work.
This not my question. My problem is that even bmDIBs, randomly don't work! Also when trying StretchDraw, or whatever pixelformat.
CalvinDay:
Repost your orriginal answer tomorrow, and I'll give you the points.
Is this question closed? I mean: has a solution already been found?
Alx
Alx
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
simonet,
The question is still really not answered. I just gave jonwcroft a hack (application.processmessag es) to keep his problem from happening. I don't think we really know why it happens.
The question is still really not answered. I just gave jonwcroft a hack (application.processmessag
Give this one a shot. It uses GetDIBSizes and GetDIB:
procedure PrintBitmap(BitmapOut : TBitmap);
var
Info: PBitmapInfo;
InfoSize: Integer;
Image: Pointer;
ImageSize: DWORD;
YPos : integer;
begin
inherited;
with BitmapOut do
begin
{ Call GetDIBSizes to get the Info header and image size }
GetDIBSizes(Handle, InfoSize, ImageSize);
{ Allocate memory for the info header }
Info := AllocMem(InfoSize);
try
{ Allocate memory for the Image }
Image := AllocMem(ImageSize);
try
{ Retrieve the bitmap bits in device-independent format, the
palette adn the Info header }
GetDIB(Handle, Palette, Info^, Image^);
with Info^.bmiHeader do begin
{ Call StretchDIBits to print the bitmap }
Printer.title := 'Resistências dos Materiais - Diagramas';
Printer.BeginDoc;
Printer.title := 'Resistências dos Materiais - Diagramas';
YPos := PrintHeader;
try
StretchDIBits(Printer.Canv as.Handle, 0, YPos, Printer.PageWidth,
Printer.PageHeight - YPos, 0, 0, biWidth, biHeight, Image, Info^,
DIB_RGB_COLORS, SRCCOPY);
finally
Printer.EndDoc;
end;
end;
finally
FreeMem(Image, ImageSize); // Free the memory allocated
end;
finally
FreeMem(Info, InfoSize);
end;
end;
end;
Cheers,
Epsylon.
procedure PrintBitmap(BitmapOut : TBitmap);
var
Info: PBitmapInfo;
InfoSize: Integer;
Image: Pointer;
ImageSize: DWORD;
YPos : integer;
begin
inherited;
with BitmapOut do
begin
{ Call GetDIBSizes to get the Info header and image size }
GetDIBSizes(Handle, InfoSize, ImageSize);
{ Allocate memory for the info header }
Info := AllocMem(InfoSize);
try
{ Allocate memory for the Image }
Image := AllocMem(ImageSize);
try
{ Retrieve the bitmap bits in device-independent format, the
palette adn the Info header }
GetDIB(Handle, Palette, Info^, Image^);
with Info^.bmiHeader do begin
{ Call StretchDIBits to print the bitmap }
Printer.title := 'Resistências dos Materiais - Diagramas';
Printer.BeginDoc;
Printer.title := 'Resistências dos Materiais - Diagramas';
YPos := PrintHeader;
try
StretchDIBits(Printer.Canv
Printer.PageHeight - YPos, 0, 0, biWidth, biHeight, Image, Info^,
DIB_RGB_COLORS, SRCCOPY);
finally
Printer.EndDoc;
end;
end;
finally
FreeMem(Image, ImageSize); // Free the memory allocated
end;
finally
FreeMem(Info, InfoSize);
end;
end;
end;
Cheers,
Epsylon.
Epsylon,
The reason I asked if this question had already been answered is because I was planning on posting that code you just posted.
That's code I wrote for an application I developed years ago and had just used it to answer another similar question. You didn't even bother to remove the sentences that are in Portuguese and make up the header on the printed bitmap.
I relly resent you posting this code.
Alex
The reason I asked if this question had already been answered is because I was planning on posting that code you just posted.
That's code I wrote for an application I developed years ago and had just used it to answer another similar question. You didn't even bother to remove the sentences that are in Portuguese and make up the header on the printed bitmap.
I relly resent you posting this code.
Alex
You are right, Alex, I should have at least have mentioned your name. But as you say this question is CalvinDay's and I was just collecting stuff on this subject to get it all solved. I'm sorry about it. Hope you are not to mad at me.
Jon, please treat that comment as if it came from Alex.
ASKER
Thanks for your help guys.
In the end I used the StretchDIBits thing, and got it to work reliably.
As far as HANDLETYPE = bmDIB is concerned, I shall lodge a bug report with Borland.... (I wonder if they'll take any notice).
Oh bugger, I guess I'll have to help loads of other people before I can post another tricky one..
In the end I used the StretchDIBits thing, and got it to work reliably.
As far as HANDLETYPE = bmDIB is concerned, I shall lodge a bug report with Borland.... (I wonder if they'll take any notice).
Oh bugger, I guess I'll have to help loads of other people before I can post another tricky one..
You can't use points you get by answering questions for asking your own questions.
ASKER
eh?
So what is the point of the points system? Can you cash your points in for money or something?
So what is the point of the points system? Can you cash your points in for money or something?
Nope!
except on excetption do
begin
showmessage('haha!');
end;
end;
forget the finally freeing for now... if haha is displayed then use the trace to see which line is bombing out...
if this is the case then write another comment and tell us which one...