【问题标题】:How to merge many JPG images in one large (huge) image using C#如何使用 C# 将多个 JPG 图像合并到一张大(巨大)图像中
【发布时间】:2019-06-14 12:15:27
【问题描述】:

我有一百张 JPG 图片,想将它们合并成一个大的 JPG。 为了实现这一点,我使用以下代码:

using (var combinedBitmap = new Bitmap(combinedWidth, combinedHeights)) {
    combinedBitmap.SetResolution(96, 96);
    using (var g = Graphics.FromImage(combinedBitmap))
    {
        g.Clear(Color.White);

        foreach (var imagePiece in imagePieces)
        {
            var imagePath = Path.Combine(slideFolderPath, imagePiece.FileName);

            using (var image = Image.FromFile(imagePath)) 
            {
                var x = columnXs[imagePiece.Column];
                var y = rowYs[imagePiece.Row];

                g.DrawImage(image, new Point(x, y));
             }
        }
    }

    combinedBitmap.Save(combinedImagePath, ImageFormat.Jpeg);
}

一切都很好,直到尺寸(combinedWidthcombinedHeights)超过此处所说的窗帘阈值https://stackoverflow.com/a/29175905/623190

合并后的 JPG 文件大小为 23170 x 23170 像素,大小约为 50MB — 不会太大而不会占用内存。

但是不能创建更大尺寸的位图——只是由于错误的参数异常而中断。

有没有其他方法可以使用 C# 将 JPG 图像片段合并到一个尺寸大于 23170 x 23170 的大型 JPG 中?

【问题讨论】:

  • The merged JPG file with dimensions of 23170 x 23170 pixels is about 50MB — not too big to kiil the memory. 磁盘大小和内存大小不一定相同。
  • mjwills — 当然 BitMap 它的内存比磁盘上压缩的 JPG 大。我想知道是否有办法直接使用 JPG? :)
  • 我的意思是我的电脑有 16Gb 的 RAM,可以处理 50Mb 的文件,我猜。
  • 不,我没有。是否有任何使用 WIC 的 C# 示例?
  • @Castorix 您能否分享一个 C# sn-p 如何使用 IShellImageDataFactory API 将 40,000x30000 像素大小的 jpg 加载到 .Net 的 GDI 内存中并用它做一些有意义的事情?对于仅用于未压缩图像数据的标准 24 位 RGB 图像,大约 3.4GB 的 RAM。 .NET/GDI 中断了我在 8GB Ram PC 上的测试。谢谢你。作为参考...这里是.Net Image Memory Limit stackoverflow.com/questions/29175585/…

标签: c# bitmap gdi+


【解决方案1】:

这是使用libvips 的解决方案。这是一个流式图像处理库,因此它不是在内存中操作巨大的对象,而是构建管道,然后并行运行它们,在一系列小区域中流式传输图像。

此示例使用 net-vips,这是 libvips 的 C# 绑定。

using System;
using System.Linq;
using NetVips;

class Merge
{
    static void Main(string[] args)
    {
        if (args.Length < 2)
        {
            Console.WriteLine("Usage: [output] [images]");
            return;
        }

        var image = Image.Black(60000, 60000);
        var random = new Random();

        foreach (var filename in args.Skip(1))
        {
            var tile = Image.NewFromFile(filename, access: Enums.Access.Sequential);

            var x = random.Next(0, image.Width - tile.Width);
            var y = random.Next(0, image.Height - tile.Height);

            image = image.Insert(tile, x, y);
        }

        image.WriteToFile(args[0]);
    }
}

我制作了一组 1000 张 jpg 图像,每张 1450 x 2048 RGB 使用:

for ($i = 0; $i -lt 1000; $i++)
{
    # https://commons.wikimedia.org/wiki/File:Taiaroa_Head_-_Otago.jpg
    Copy-Item "$PSScriptRoot\..\Taiaroa_Head_-_Otago.jpg" -Destination "$PSScriptRoot\$i.jpg"
}

为了测量执行上述代码所需的时间,我使用了 PowerShell 内置的“Measure-Command”(类似于 Bash 的“时间”命令):

$fileNames = (Get-ChildItem -Path $PSScriptRoot -Recurse -Include *.jpg).Name
$results = Measure-Command { dotnet Merge.dll x.jpg $fileNames }
$results | Format-List *

使用准备好的图像和上面的脚本,我看到了:

C:\merge>.\merge.ps1
Ticks             : 368520029
Days              : 0
Hours             : 0
Milliseconds      : 852
Minutes           : 0
Seconds           : 36
TotalDays         : 0.000426527811342593
TotalHours        : 0.0102366674722222
TotalMilliseconds : 36852.0029
TotalMinutes      : 0.614200048333333
TotalSeconds      : 36.8520029

所以在我的第 8 代 Intel Core i5 Windows PC 上,它已在 36 秒内将 1000 张 jpg 图像合并成一张 60k x 60k jpg 的大图像。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-07-01
    • 2014-07-18
    • 2012-04-13
    • 1970-01-01
    • 2013-07-18
    • 2019-02-18
    • 2013-09-25
    • 1970-01-01
    相关资源
    最近更新 更多