Вот решение, использующее libvips .Это библиотека обработки потоковых изображений, поэтому вместо того, чтобы манипулировать огромными объектами в памяти, она строит конвейеры, а затем запускает их параллельно, передавая изображения в виде последовательности небольших областей.
В этом примере используется net-vips , привязка C # для libvips.
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: "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 «time»):
$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
Итак, на моем ПК с ОС Intel Core i5 8-го поколения он объединил 1000 изображений JPG в большое изображение JPG 60k x 60k в 36секунд.