Reputation: 610
Having some trouble with printing JPEG images via Delphi TCanvas. Anywhere between 30-50% of the time the JPEG will print out as a black square rather than as it should. Have tried changing many settings to see if there was a particular condition under which it would fail to print but as of the time of writing nothing has worked and the condition still exists - I am not able to tell when the printout may have a black JPEG or when it will print correctly.
Here is the code I am using to print the JPEG to the Canvas.
Screen.Cursor := crHourGlass;
try
// initialize image
//>>imgImage := TImage.Create(Self);
imgImage := TImage.Create(Application);
// load image from file
imgImage.Picture.LoadFromFile(sFileNameAndPath);
// set width and height to that of loaded image
////imgImage.Autosize := true;
////Printer.Orientation := poPortrait;
// Header
Printer.Canvas.Font.Height := MulDiv(GetDeviceCaps(Printer.Canvas.Handle, LOGPIXELSY), 12, 72);
Printer.Canvas.Font.Name := 'Courier New';
// Determine height and width of 1 printer-character
iDeltaW := Printer.Canvas.TextWidth('X');
iDeltaH := Printer.Canvas.TextHeight('X');
// ------------------------------
// Method #1 - columns and lines
// ------------------------------
// what column to printing from
iFromLeftMargin := iLeft * iDeltaW;
// what line to print from
iFromTopOfPage := iTop * iDeltaH;
// ------------------------------
// Method #2 - pixels
// ------------------------------
iPPW := Printer.PageWidth;
iPPH := Printer.PageHeight;
iIPW := imgImage.Picture.Width;
ePXW := iPPW / iInvImageWidth;
ePXH := iPPH / iInvImageHeight;
//~//iFromLeftMargin := Ceil(iLeft * pxW);
//~//iFromTopOfPage := Ceil(iTop * pxH);
iFromLeftMargin := Ceil(iLeft * ePXW);
iFromTopOfPage := Ceil(iTop * ePXH);
// Set printed bitmap width
iPrintedImageWidth := MulDiv(iPPW, iIPW, iInvImageWidth);
// Set printed bitmap height to maintain aspect ratio
iPrintedImageHeight := imgImage.Picture.Height * iPrintedImageWidth DIV
imgImage.Picture.Width; // maintain aspect ratio of bitmap
Bitmap := TBitmap.Create;
try
Bitmap.Width := imgImage.Picture.Width;
Bitmap.Height := imgImage.Picture.Height;
Bitmap.PixelFormat := pf24bit;
Bitmap.IgnorePalette := False;
// Convert JPEG (GIF, or whatever) to BMP
Bitmap.Canvas.Draw(0, 0, imgImage.Picture.Graphic);
// Print Image
PrintBitmap(Printer.Canvas,
Rect(iFromLeftMargin, iFromTopOfPage,
iFromLeftMargin + iPrintedImageWidth,
iFromTopOfPage + iPrintedImageHeight),
Bitmap);
finally
// free bitmap memory
Bitmap.Free;
end;
// free image memory
imgImage.Free;
finally
Screen.Cursor := crDefault;
end;
If anyone had any ideas it would be much appreciated!
Regards, James
EDIT: code for the PrintBitmap method below. I have taken the advice of saving the bitmap to disk to view it as it is being generated and the it is never saved as a black square even when the printed output is a black square. I hope this indicated the problem is in the PrintBitmap code below.
procedure PrintBitmap(Canvas: TCanvas; DestRect: TRect; Bitmap: TBitmap);
var
BitmapHeader: pBitmapInfo;
BitmapImage: POINTER;
HeaderSize: DWORD;
ImageSize: DWORD;
begin
GetDIBSizes(Bitmap.Handle, HeaderSize, ImageSize);
GetMem(BitmapHeader, HeaderSize);
GetMem(BitmapImage, ImageSize);
try
GetDIB(Bitmap.Handle, Bitmap.Palette, BitmapHeader^, BitmapImage^);
StretchDIBits(Canvas.Handle,
DestRect.Left, DestRect.Top, // Destination Origin
DestRect.Right - DestRect.Left, // Destination Width
DestRect.Bottom - DestRect.Top, // Destination Height
0, 0, // Source Origin
Bitmap.Width, Bitmap.Height, // Source Width & Height
BitmapImage,
TBitmapInfo(BitmapHeader^),
DIB_RGB_COLORS,
SRCCOPY);
finally
FreeMem(BitmapHeader);
FreeMem(BitmapImage);
end;
end; {PrintBitmap}
Unfortunately this code was written by someone who no longer works at my company and I am only trying to fix an existing issue.
Upvotes: 2
Views: 3605
Reputation: 21640
It's hard to tell with the snippet you posted. You should post some self sufficient working code (compilable and runnable).
There is no local var declaration for instance, no Begindoc/EndDoc.
Now, after adding the local declarations, there is a bunch of compiler warnings for Uninitialized Variables like iTop
or iLeft
. If those are left with random garbage, it could be that you don't draw where you think you do.
You also assume that you always have a pf24bit
format which is not guaranteed at all. As you don't specify if the same JPG can print OK or fail randomly, or if it is with different JPGs that you have problems, format conversion problems cannot be excluded.
I would also suggest that you install one of the free available Image Debug Visualizers, place a break point before PrintBitmap
and see if the local Bitmap
is correct before printing.
Then let us see what is in the PrintBitmap
procedure... Did you try to directly draw on the Printer Canvas?
Update:
The PrintBitmap
code seems legit except that it does not check for any return code:
if not GetDIB(...) then
raise [...];
if GDI_ERROR = StretchDIBits(...) then
RaiseLastOSError;
The problem might come from the Printer/Driver.
Did you try with another printer or with another driver?
Also, make sure your printer is ready...
Upvotes: 3