Delphi - 如何将多个 JPG 图像添加到 TCanvas 并打印它们
Delphi - How to add multiple JPG images to a TCanvas and print them
作为一名 Delphi 程序员,我有点像黑客 - 一路上学到了点点滴滴,大部分是自学的。
我正在开发一个有趣的程序,它是绝版纸牌游戏的数据库。有卡片信息和卡片图像的 JPG 链接。
我和某人谈论过它,他们说“如果你能在 2.5 x 3.5 英寸的页面上渲染多个卡片图像并打印它们,那不是很酷吗”。
抛开法律问题(未经前出版商的明确许可,我不会分发此文件),我想看看是否可以将其作为练习来教我如何使用 TCanvas。不幸的是,我真的不知道该怎么做。
我正在使用 8.5 x 11 英寸的页面,所以我想要一张 2.3 x 3.5 的卡片图像,它给我大约一英寸的空间,卡片图像不会占用它,比如 0.25 英寸的页面每幅图像之间的四周和 0.25 英寸的边距。这将在页面上放置 9 张卡片。
到目前为止,对于我在程序中编写的内容,我可以将 TImage 放在表单上,然后从磁盘读取任何给定卡片的关联 jpg 文件,并将其显示在表单上。
假设我已经用这些卡片制作了一副牌并想要打印我的“牌组”的图像。然后我如何为每张卡片拍摄相关图像,调整它的大小以使其适合 canvas 上的 2.5 x 3.5 space 然后继续加载图像直到我在页面上有 9 .然后我想移动到一个新页面并再次执行此操作,直到我打印完我的套牌中的卡片(通常大约 50 张 - 所以大约 6 页)。
我一直在搜索,我不确定如何处理这些方面
- 阅读后调整 JPG 的大小
- 将它放在 canvas - 那里总共有 9 张图片
当前图像(大部分)为 390 x 546 像素。 (这是 2.5 x 3.5 英寸的正确比例)。
此外,为了尽量保护墨水和纸张,有没有一种方法可以在将 canvas 发送到打印机之前“预览”它(如果需要,可以进行打印预览),或者是在你做对之前,这只是一个巨大的反复试验。
虽然最好有具体的代码示例,但如果我能得到一个指向显示如何使用这些对象的网站的指针,我愿意做一些跑腿工作。
大约 15 年前,我把文本放到 TCanvas 上并打印它,但我不确定如何在从磁盘读取后使用 JPG 进行这项工作,然后调整它的大小以打印到我的比例想要这里
有谁能给我指点一下吗?
哦,如果重要的话,我正在使用 Delphi XE3 Enterprise / Windows 10.
谢谢。
有一些粗鲁的方法可以让它工作。
首先,我看到至少有两种制作方法:
- 将所有图像加载到数组或 ObjectList 中(我认为这更好),然后进行转换并在 canvas;
上绘制它们
- 一张一张地加载、转换和绘制图像;
他们中哪一个更好?我不知道。我更喜欢第二个,因为我想它会占用更少的内存。
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;
因此,您拥有制作页面的所有程序。只需制作Form,将TImage 和两个按钮放在其中。将TImage 的Stretched
和Proportional
属性设置为true
。将按钮的 captions
设置为 Load
和 Print
。不要忘记将带有过程的单元添加到 uses
或将它们作为 Form 的方法。将私有字段 _bmp:TBitmap
添加到您的 Form
;
对于 Load
按钮:
//Page preview.
procedure TForm1.Button1Click(Sender:TObject)
begin
if assigned(_bmp) then
FreeAndnIl(_bmp);
_bmp := LoadImages(2000,3000);
Image1.Picture.Assign(_bmp);
end;
对于 Print
按钮:
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;
我在 Delphi 10.1 上使用 PDF 打印机检查此代码后,我得到了我的 pdf 文件。
我已尽力使其尽可能简单,但代码很多。我可能会错过一些东西,但我随时准备提供帮助。所有常量都可以作为变量并作为函数的参数传递,由您决定。
作为一名 Delphi 程序员,我有点像黑客 - 一路上学到了点点滴滴,大部分是自学的。
我正在开发一个有趣的程序,它是绝版纸牌游戏的数据库。有卡片信息和卡片图像的 JPG 链接。
我和某人谈论过它,他们说“如果你能在 2.5 x 3.5 英寸的页面上渲染多个卡片图像并打印它们,那不是很酷吗”。
抛开法律问题(未经前出版商的明确许可,我不会分发此文件),我想看看是否可以将其作为练习来教我如何使用 TCanvas。不幸的是,我真的不知道该怎么做。
我正在使用 8.5 x 11 英寸的页面,所以我想要一张 2.3 x 3.5 的卡片图像,它给我大约一英寸的空间,卡片图像不会占用它,比如 0.25 英寸的页面每幅图像之间的四周和 0.25 英寸的边距。这将在页面上放置 9 张卡片。
到目前为止,对于我在程序中编写的内容,我可以将 TImage 放在表单上,然后从磁盘读取任何给定卡片的关联 jpg 文件,并将其显示在表单上。
假设我已经用这些卡片制作了一副牌并想要打印我的“牌组”的图像。然后我如何为每张卡片拍摄相关图像,调整它的大小以使其适合 canvas 上的 2.5 x 3.5 space 然后继续加载图像直到我在页面上有 9 .然后我想移动到一个新页面并再次执行此操作,直到我打印完我的套牌中的卡片(通常大约 50 张 - 所以大约 6 页)。
我一直在搜索,我不确定如何处理这些方面
- 阅读后调整 JPG 的大小
- 将它放在 canvas - 那里总共有 9 张图片
当前图像(大部分)为 390 x 546 像素。 (这是 2.5 x 3.5 英寸的正确比例)。
此外,为了尽量保护墨水和纸张,有没有一种方法可以在将 canvas 发送到打印机之前“预览”它(如果需要,可以进行打印预览),或者是在你做对之前,这只是一个巨大的反复试验。
虽然最好有具体的代码示例,但如果我能得到一个指向显示如何使用这些对象的网站的指针,我愿意做一些跑腿工作。
大约 15 年前,我把文本放到 TCanvas 上并打印它,但我不确定如何在从磁盘读取后使用 JPG 进行这项工作,然后调整它的大小以打印到我的比例想要这里
有谁能给我指点一下吗?
哦,如果重要的话,我正在使用 Delphi XE3 Enterprise / Windows 10.
谢谢。
有一些粗鲁的方法可以让它工作。
首先,我看到至少有两种制作方法:
- 将所有图像加载到数组或 ObjectList 中(我认为这更好),然后进行转换并在 canvas; 上绘制它们
- 一张一张地加载、转换和绘制图像;
他们中哪一个更好?我不知道。我更喜欢第二个,因为我想它会占用更少的内存。
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;
因此,您拥有制作页面的所有程序。只需制作Form,将TImage 和两个按钮放在其中。将TImage 的Stretched
和Proportional
属性设置为true
。将按钮的 captions
设置为 Load
和 Print
。不要忘记将带有过程的单元添加到 uses
或将它们作为 Form 的方法。将私有字段 _bmp:TBitmap
添加到您的 Form
;
对于 Load
按钮:
//Page preview.
procedure TForm1.Button1Click(Sender:TObject)
begin
if assigned(_bmp) then
FreeAndnIl(_bmp);
_bmp := LoadImages(2000,3000);
Image1.Picture.Assign(_bmp);
end;
对于 Print
按钮:
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;
我在 Delphi 10.1 上使用 PDF 打印机检查此代码后,我得到了我的 pdf 文件。
我已尽力使其尽可能简单,但代码很多。我可能会错过一些东西,但我随时准备提供帮助。所有常量都可以作为变量并作为函数的参数传递,由您决定。