11

这是问题所在。我有一大组 512x512 像素的 JPEG 图块作为常规 jpg 文件。

我已经编写了一个软件,它可以做很多事情,并且需要在最后将所有这些文件拼接成一个巨大的 JPEG。

首先,我不希望使用 ImageMagick 来执行此操作,而是在我的软件中执行它!

在 Delphi 中,无法将 JPG 文件复制到另一个 JPG 画布上,因此必须先创建 TBitmap,然后将图块复制到 TBitmap 画布上,然后将 TBitmap 转换为 jpeg 图片并保存到文件中。

当生成的文件尺寸太大(如 20 000 x 20 000 像素)时,就会出现问题。当我调用 TBitmap.SetSize 我自然会得到一个错误(内存不足或类似的东西)。

我在同一台机器上使用 Photoshop 进行了一些测试,能够创建一个复杂的(非空白)30 000 x 30 000 文件并将其保存为 JPEG。

所以问题是,我怎么能做同样的事情?通过将结果直接写入磁盘或使用其他技巧来寻找某种方法来拼接所有这些 JPEGS?...

尽管 20k x 20k 像素看起来足够大,但这个值只适用于我的机器(4 GB 内存),因此更少量的内存对软件的限制更大!

谢谢

编辑:澄清:

我想要的是找到一种拼接那些小的JPG图像并写入大的而不将大图像保存在RAM中的方法。显然,可以直接在磁盘上读取/写入位图流(不确定),但这会导致文件非常大。因此,如果 JPG 格式不允许这样做,任何其他压缩格式(如 TIFF 或 PNG)都可以。我还想避免过多的重新压缩,以免失去(已经压缩的)初始 JPG 质量。

因此,完美的解决方案是一种直接读取小文件并以某种方式写入大文件的方法。瓷砖的尺寸为 256x256 或 512x512,以防它有助于在 JPEG 压缩内容上进行一些对齐。

4

8 回答 8

8

谢谢大家 !

实际上,答案和可能的解决方案是像 Photoshop 一样进行操作,即将位图流从图块写入磁盘上的大 bmp 文件(例如,20 000 x 30 000 文件将是 2.4 Gb),然后使用NativeJpg 库通过逐条提供位图数据将这个大位图转换为 jpg,每个位图数据高 8 像素。

也可以缝合一行瓦片(512 像素高),然后将其 8 x 8 馈送到 NativeJpg 库,然后继续下一行瓦片!

Erik Turner 的一些示例代码:

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;

NativeJpg 库:http ://www.simdesign.nl/nativejpg.html

于 2010-06-27T17:42:28.987 回答
1

与许多其他面向媒体的程序一样,Photoshop 不得不长时间处理大于主内存的文件的问题。对于大照片,一种技术是平铺仅适用于图像的一部分。

在实践中,这比简单的剪切和粘贴更复杂(双关语)。

我不是 Delphi 程序员,但让我担心的是,当您用完创建图像的内存时,当您尝试使用该图像时会不会发生同样的情况?

于 2010-06-27T10:45:07.660 回答
1

这是一个相当艰难的领域,正如@Peter 已经说过的那样,Photoshop 的人从 1990 年就开始从事这项工作。您可能无法使用您的编程语言的内置 JPG 解码库,因为它们可能会在 RAM 中加载(并解压缩)整个图像。

我建议寻找处理这个问题的外部库——我不知道是否有免费的像样的库,但很可能是这样。

于 2010-06-27T10:50:37.133 回答
1

Delphi 中图像的最大尺寸(至少在以前的版本中)更多地取决于 Windows 图形驱动程序而不是系统内存量

这方面的一些实验: EFG 的计算机实验室

于 2010-06-27T11:29:34.763 回答
1

您可能需要实现一个自定义类来处理这个问题。

在视频内存中,图像(或屏幕缓冲区)是一个线性阵列。水平行顺序存储,每个像素对应于(y*width+x)-1处的数组偏移量。

因此,在 320x200 图像中,5,2 处的像素将位于数组索引 5*320+2-1 或 1601 处。早在硬件加速之前的日子里,您会 malloc() 一个屏幕大小的缓冲区并以数学方式执行绘制纹理、形状、照明效果等操作,然后将缓冲区 BLT 输出到视频 RAM。

在您的情况下,您可以使用内置的位图和图像类来处理适合内存的较小图像,然后将它们的像素数据复制到一个大数组或一系列数组中(我忘记了虚拟内存是否允许您创建缓冲区 > 物理 RAM 的大小)。然后,使用直接在该阵列上工作的 JPEG 库(与机器上安装的 RAM 大小无关),您应该能够将阵列馈送到库中并将内容保存到磁盘。LZW 压缩非常简单,我希望它们会成为在 Web 上手动实现 JPEG 压缩的大量材料。

对此有一个警告:如果您使用的是 32 位操作系统,则地址空间应限制为 4GB。我能想到的解决这个问题的唯一方法是创建更小的缓冲区(例如,一次一行),用该行对应的部分像素数据填充数据你要拼接的图像,保存它,然后循环,直到你覆盖了整个图像区域。

我希望这很清楚。祝你好运!

于 2010-06-27T15:56:17.973 回答
1

对于像这样的繁重工作,我求助于http://www.graphicsmagick.org/

这里还有一组帕斯卡单位http://graphics32.org/但它们非常数学和复杂(因此我还没有让它们工作),但也是为辛勤工作而构建的。

于 2010-06-28T09:05:55.980 回答
0

你的问题也让我想到了电子表格。当然只有人烟稀少。您可以尝试查看一些可能会给您一些想法的图像压缩库。

你也可以做的是看看别人是怎么做的。我注意到 PixeLook Development Group 有他们的 PixeLook 库,它是 Delphi 6 的组件,用于创建图像和数据处理应用程序。

他们声称大图像和数据矩阵很容易处理,并且在他们的屏幕截图页面上,他们显示了 5200 x 5200 图像(26 MB)的显示,他们说他们的测试也是在图像大小高达 220 MB 的情况下进行的。

如果你真的需要在你的应用程序中直接处理大图像,这个包可能对你有用,只需 50 美元。如果它很接近但不太正确(我不知道它是否会加入 jpegs),那么您可能会考虑以 299 美元的价格购买源代码,看看它的作用,然后扩展它。

免责声明:我与这家公司没有任何关系。

于 2010-06-27T15:45:03.393 回答
0

部分外部软件/内部调用解决方案呢?IJG(独立 JPEG 组)有一个出色的命令行工具 jpegtran,我在查看器中使用它来进行无损旋转。在您自己的代码中使用 CreateProcess、WaitForsingleObject 以使其看起来像您自己的代码是没有问题的。您甚至可以将可执行文件打包到资源中并临时提取

所以他们也有 jpegjoin 实用程序(在http://jpegclub.org/jpegtran/找到它)可以以同样的方式使用。更新:此实用程序用于无损连接,因此需要更小的内存/磁盘占用空间

于 2010-07-08T09:13:08.697 回答