How can I optimize this code for creating TIFF files and/or what alternate libraries should I consider to improve performance?

StackOverflow https://stackoverflow.com/questions/20668744

سؤال

I am creating a process to extract a TIFF, perform an operation on one of the images, and then rebuild the TIFF. The operation in the middle doesn't matter, however, extraction and rebuild are proving to be very costly in terms of processing.

const string tifPath = "14 page.TIFF";
MemoryStream[] imageStreams;
var stream = new MemoryStream();

//extract tiff
using (var imageFile = Image.FromFile(tifPath))
{
    var imagePageCount = imageFile.GetFrameCount(FrameDimension.Page);
    imageStreams = new MemoryStream[imagePageCount];
    var frameDimension = new FrameDimension(imageFile.FrameDimensionsList[0]);

    for (var i = 0; i < imagePageCount; i++)
    {
        imageFile.SelectActiveFrame(frameDimension, i);
        var bmp = new Bitmap(imageFile);

        bmp.Save(stream, ImageFormat.Bmp);
        imageStreams[i] = stream;
    }
}

//build tiff
var encoder = Encoder.SaveFlag;
var encoderInfo = ImageCodecInfo.GetImageEncoders().First(i => i.MimeType == "image/tiff");
var encoderParameters = new EncoderParameters(1);
encoderParameters.Param[0] = new EncoderParameter(encoder, (long)EncoderValue.MultiFrame);

stream = new MemoryStream();
var firstImage = new Bitmap(Image.FromStream(imageStreams[0]));
firstImage.Save(stream, encoderInfo, encoderParameters);
encoderParameters.Param[0] = new EncoderParameter(encoder, (long)EncoderValue.FrameDimensionPage);

for (var i = 1; i < imageStreams.Length; i++)
{
    var img = Image.FromStream(imageStreams[i]);
    firstImage.SaveAdd(img, encoderParameters);
}

encoderParameters.Param[0] = new EncoderParameter(encoder, (long)EncoderValue.Flush);
firstImage.SaveAdd(encoderParameters);

I found that clearing my stream helped in some places. With Microsoft's and other libraries (LeadTools and LibTiff) it averages around 5 seconds. I am not set on using a C# solution, but trying to find a way to squeeze it down as much as possible.

هل كانت مفيدة؟

المحلول

I couldn't find a good way to parallelize the creation process. Attempting to build an Image from a MemoryStream that was built outside of the Parallel.ForEach only threw a general GDI+ error.

const string tifPath = "14 Page.TIFF";

//extract tiff
var imageFile = Image.FromFile(tifPath);
var imagePageCount = imageFile.GetFrameCount(FrameDimension.Page);
var imageStreams = new Bitmap[imagePageCount];
var rangePartioner = Partitioner.Create(0, imagePageCount);
var frameDimension = new FrameDimension(imageFile.FrameDimensionsList[0]);
imageFile.Dispose();

Parallel.ForEach(rangePartioner, (range, loopState) =>
{
    for (var i = range.Item1; i < range.Item2; i++)
    {
        using (var imageFile2 = Image.FromFile(tifPath))
        {
            imageFile2.SelectActiveFrame(frameDimension, i);
            imageStreams[i] = new Bitmap(imageFile2);
        }
    }
});

//build tiff
var encoder = Encoder.SaveFlag;
var encoderInfo = ImageCodecInfo.GetImageEncoders().First(i => i.MimeType == "image/tiff");
var encoderParameters = new EncoderParameters(1);
encoderParameters.Param[0] = new EncoderParameter(encoder, (long) EncoderValue.MultiFrame);

var stream2 = new MemoryStream();

using(var firstImage = imageStreams[0])
{
    firstImage.Save(stream2, encoderInfo, encoderParameters);

    encoderParameters.Param[0] = new EncoderParameter(encoder, (long) EncoderValue.FrameDimensionPage);

    for (var i = 1; i < imageStreams.Length; i++)
    {
        firstImage.SaveAdd(imageStreams[i], encoderParameters);
    }

    encoderParameters.Param[0] = new EncoderParameter(encoder, (long) EncoderValue.Flush);
    firstImage.SaveAdd(encoderParameters);
}           

This shaved off about 2 seconds. Still hunting for a good way to handle the second half.

EDIT: Added suggested changes of only converting the image and not saving it to a stream. EDIT: Added remainder of fixes.

نصائح أخرى

Start profiling your code and see which parts take time. It's hard to assume things. You can parallelize extracting TIFF, same with building. That would get you 4x speedup.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top