As a Delphi programmer I'm a bit of a hack - learned bits and pieces along the way, mostly self taught.
I'm working on a program for fun that's a database for an out of print card game. Has info of the cards and links to a JPG of the card image.
Was talking to someone about it and they said "Wouldn't it be cool if you could render multiple card images on a page at 2.5 x 3.5 inches and print them".
Legal issues aside (I won't be distributing this without express permission from the former publisher), I wanted to see if it could be done as an exercise to teach me how to use TCanvas. Unfortunately I've really got no idea how to do this.
I'm working with an 8.5 x 11 inch page, so I'd want a 2.3 x 3.5 card image which gives me about an inch to play with that's not taken up by card images, so like 0.25 inches page margins all around and .25 inches between each image. This would put 9 cards on the page.
For what I have written in my program so far, I can drop a TImage on a form and read the associated jpg file for any given card from disk and show it on the form.
Assume I have built a deck of these cards and want to print the images of my "deck". How do I then take that associated image for each card, resize it so that it would fit into a 2.5 x 3.5 space on a canvas and then continue loading images until I've got 9 on the page. Then I'd want to move to a new page and do it again until I've printed the cards in my deck (usually around 50 of them - so about 6 pages).
I've been doing some searching and I'm not sure how to deal with these aspects
The current images are (for the most part) 390 x 546 pixels. (which is the correct ratio for 2.5 x 3.5 inches).
Also, in order to try to preserve ink & paper, is there a way to "preview" the canvas before you send it to the printer (a print preview if you will), or is it just a huge trial and error thing until you get it right.
While specific code example would be preferred, I'm willing to do some legwork if I could even get a pointer to a website that showed how to work with these objects.
About 15 years ago I mucked around with putting Text onto a TCanvas and printing it, but I'm not sure how to make this work with a JPG after reading from disk and then resizing it to print to the scale I want here.
Anyone able to offer some pointers for me here ?
Oh if it matters, I'm working with Delphi XE3 Enterprise / Windows 10.
Thanks.
There is some rude way to make it work.
First of all, I see at least two ways to make it:
Which of them the better one? I don't know. I'd prefer second because it will take less RAM I suppose.
uses ...,jpeg, SysUtils, Graphics;
...
const CARD_WIDTH:integer = /*your card width*/;
const CARD_HEIGHT:integer = /*your card height*/;
const MARGIN_X:integer = 0; //you can change it if you want to
const MARGIN_Y:integer = 0; //you can change it if you want to
...
//Load images. You can call it from button's OnClick event;
function LoadImages(aWidth, aHeight:integer):TBitmap;
var i:integer;
lImage:TJpegImage;
lResizedBmp:TBitmap;
lPosX,lPosY:integer; //it can be TPoint as well
begin
result := TBitmap.Create;
lPosX := MARGIN_X;
lPosY := MARGIN_Y;
try
result.Width := aWidth;
result.Height := aHeight;
//I don't know how you will get filenames, so I'll make some dummy code
for i := 0 to 10 do
begin
lImage := TJpegImage.Create;
lResizedBmp := nil;
try
lImage.LoadFromFile('C:\' + inttostr(i) + '.jpg'); //it's bad code just to demonstrate the way we load file. I don't remember if "i.toString()" is acceptable in XE3.
lResizedBmp := ResizeJpeg(lImage, CARD_WIDTH, CARD_HEIGHT);
result.Canvas.Draw(lPosX, lPosY, lResizedBmp);
//let's calculate next card position
lPosX := lPosX + CARD_WIDTH + MARGIN_X;
if (lPosX + CARD_WIDTH + MARGIN_X > aWidth) then
begin
lPosX := MARGIN_X;
lPosY := lPosY + MARGIN_Y + CARD_HEIGHT;
end;
finally
FreeAndNil(lImage);
if assigned(lResizedBmp) then
FreeAndNil(lResizedBmp)
end;
end;
except
on (e:Exception) do
begin
FreeAndNil(result);
raise e;
end;
end;
end;
//Resize image and convert it into Bitmap
function ResizeJpeg(aJpg:TJpegImage; aWidth, aHeight:integer):TBitmap;
var lProxyBmp:TBitmap;
begin
result := TBitmap.Create;
try
result.Width := aWidth;
result.Height := aHeight;
lProxyBmp := TBitmap.Create;
try
lProxyBmp.Assign(aJpg);
result.Canvas.StretchDraw(result.Canvas.ClipRect, lProxyBmp);
finally
FreeAndNil(lProxyBmp);
end;
except
on e:Exception do
begin
FreeAndNil(result);
raise e;
end;
end;
end;
So, you have all procedures to make your page. Just make Form, place TImage and two buttons on in. Set TImage's Stretched
and Proportional
properties to true
. Set buttons' captions
to Load
and Print
. Don't forget to add unit with procedures to uses
or make them as Form's methods. Add private field _bmp:TBitmap
to your Form
;
For Load
button:
//Page preview.
procedure TForm1.Button1Click(Sender:TObject)
begin
if assigned(_bmp) then
FreeAndnIl(_bmp);
_bmp := LoadImages(2000,3000);
Image1.Picture.Assign(_bmp);
end;
For Print
button:
procedure TForm1.Button2Click(Sender:TObject)
begin
if not assigned(_bmp) then
begin
ShowMessage('Click "Load" first');
Exit;
end;
with TPrintDialog.Create(nil) do
try
if not Execute then
Exit;
finally
Free;
end;
Printer.BeginDoc;
try
Printer.Canvas.Draw(0,0,_bmp);
finally
Printer.EndDoc;
end;
end;
After I checked this code on Delphi 10.1 using PDF printer I got my pdf file.
I've tried to make it as simple as possible, but there is plenty of code. I could miss something, but I'm ready to help. All constants can be made as variables and passed as function's params, it's up to you.