如何使用Delphi编写超过物理RAM的巨大JPEG?
问题就在这里。我有一大组512x512像素的JPEG图像块作为常规jpg文件 我已经写了一个软件,它可以做很多事情,并且需要在最后将所有这些文件拼接成一个巨大的JPEG 首先,我不想使用ImageMagick来做这件事,而是在我的软件中执行它 在Delphi中,无法将JPG文件复制到另一个JPG画布上,因此必须先创建TBitmap,然后将平铺复制到TBitmap画布上,然后将TBitmap转换为jpeg图片并保存到文件中 当生成的文件尺寸太大(如20000 x 20000像素)时,就会出现问题。当我调用TBitmap.SetSize时,自然会出现一个错误(内存不足或类似的情况) 我在同一台机器上使用Photoshop进行了一些测试,能够创建一个复杂的(非空白)30000x30000文件并将其保存到JPEG 所以问题是,我怎样才能做同样的事情?通过将结果直接写入磁盘或使用其他技巧来缝合所有这些JPEG 尽管20k x 20k像素看起来足够大,但这个值只适用于我的机器(4 GB ram),因此更小的ram将对软件造成更大的限制 谢谢 编辑:澄清: 我想要的是找到一种方法来缝合那些小JPG图像,并在不将大图像保存在RAM中的情况下编写大图像。显然,可以直接在磁盘上读取/写入位图流(不确定),但这会导致文件非常大。因此,如果JPG格式不允许这样做,任何其他压缩格式(如TIFF或PNG)都可以。我还想避免过多的重新压缩,以免丢失(已经压缩的)初始JPG质量如何使用Delphi编写超过物理RAM的巨大JPEG?,delphi,bitmap,jpeg,tiles,image-stitching,Delphi,Bitmap,Jpeg,Tiles,Image Stitching,问题就在这里。我有一大组512x512像素的JPEG图像块作为常规jpg文件 我已经写了一个软件,它可以做很多事情,并且需要在最后将所有这些文件拼接成一个巨大的JPEG 首先,我不想使用ImageMagick来做这件事,而是在我的软件中执行它 在Delphi中,无法将JPG文件复制到另一个JPG画布上,因此必须先创建TBitmap,然后将平铺复制到TBitmap画布上,然后将TBitmap转换为jpeg图片并保存到文件中 当生成的文件尺寸太大(如20000 x 20000像素)时,就会出现问题。
因此,完美的解决方案是直接读取小文件,然后以某种方式写入大文件。瓷砖的尺寸为256x256或512x512,以防它有助于JPEG压缩内容的对齐。Photoshop与许多其他面向媒体的程序一样,必须处理长时间使用大于主内存的文件的问题。对于大型照片,一种技术是仅平铺图像的一部分 实际上,这比简单的剪切和粘贴更复杂(双关语)
我不是Delphi程序员,但让我担心的是,当创建图像的内存不足时,当您尝试使用该图像时,会不会发生同样的情况?这是一个相当困难的领域,正如@Peter已经说过的,Photoshop的人一直在做这件事。您可能无法使用编程语言的内置JPG解码库,因为它们可能会在RAM中加载(并解压)整个图像
我建议寻找处理这个问题的外部库-我不知道是否有合适的免费库,但可能是这样。Delphi中图像的最大大小(至少在以前的版本中)更多地取决于windows图形驱动程序,而不是系统内存量 这方面的一些实验:
你的问题也让我想到了电子表格。当然,这里人口稀少。您可以尝试查看一些图像压缩库,这些库可能会给您一些想法 你也可以看看别人是怎么做的。我注意到,PixeLook开发组拥有用于创建图像和数据处理应用程序的Delphi6组件 他们声称,大型图像和数据矩阵易于处理,并且显示5200 x 5200图像(26 MB)的显示,他们还说,他们的测试也在图像大小高达220 MB的情况下进行 如果您真的需要在应用程序中直接进行大型图像处理,这个软件包可能需要50美元。如果它很接近但不完全正确(我不知道它是否会加入JPEG),那么你可以考虑购买源299美元,看看它做什么,并扩展它。
免责声明:我与本公司没有任何联系。您可能需要实现一个自定义类来处理此问题 在视频存储器中,图像(或屏幕缓冲区)是一个线性阵列。水平行按顺序存储,每个像素对应于(y*width+x)-1处的阵列偏移 因此,在320x200图像中,5,2处的像素将位于阵列索引5*320+2-1或1601处。在硬件加速之前的日子里,你需要一个屏幕大小的缓冲区,然后在数学上执行诸如绘制纹理、形状、灯光效果等操作,然后将缓冲区输出到视频RAM中 在您的例子中,您可以使用内置的位图和图像类处理适合内存的较小图像,然后将它们的像素数据复制到一个大数组或一系列数组中(我忘了虚拟内存是否允许您创建缓冲区>物理RAM的大小)。然后,使用直接在该阵列上工作的JPEG库(与机器上安装的RAM大小无关),您应该能够将该阵列馈送到库中,并让它将内容保存到磁盘。LZW压缩是非常简单的,我希望他们会有很多关于在web上手动实现JPEG压缩的资料 有一个警告:如果你使用的是32位操作系统,你的地址空间应该限制在4GB。我能想到的解决这个问题的唯一方法是创建更小的缓冲区(比如,一次一行),用待粘贴图像中该行对应的部分像素数据填充数据,保存数据,然后循环,直到覆盖整个图像区域 我希望这是清楚的。祝你好运 谢谢大家 事实上,答案和可能的解决方案是像Photoshop那样进行,即将位图流从瓷砖写入一个大的bmp-fi
procedure GetBitmapTile(BM: TBitmap; Y, X: Integer);
var JpegImage: TJpegImage;
begin
JpegImage := NIL; // Replace with tile lookup //
BM.PixelFormat := pf32bit;
BM.Width := JpegImage.Width;
BM.Height := JpegImage.Height;
BM.Canvas.Draw(0, 0, JpegImage);
end;
procedure WriteBitmapFile(TileCountY, TileCountX: Integer; BM_Stm: TStream);
var
BM: TBitmap;
TileY: Integer;
TileX: Integer;
PixelY: Integer;
begin
BM := TBitmap.Create;
for TileY := 0 to TileCountY-1 do
for TileX := 0 to TileCountX-1 do
begin
GetBitmapTile(BM, TileY, TileX);
for PixelY := 0 to 511 do
BM_Stm.Write(BM.ScanLine[PixelY]^, 512 * SizeOf(TRGBQuad));
end;
BM.Free;
end;