Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

View large multi page Tif images within 100 milliseconds

I'm using WinForms. Inside my form I have a pictureBox (set to normal mode), next and previous button. I want to resize and load Multipage TIF images quickly. When I go to the next page in the Multipage TIF image I experience a delay every time the image is drawn to the pictureBox. The average speed of the image takes about 800 milliseconds. I want the pages to load within 100 Milliseconds.

I want the performance of processing large TIF images as fast as IrfanView. IrfanView is a small image viewing application. If you Download IrfanView you can see how fast the performance is. Currently I have another solution where I use multi-threading background worker to load the TIF pages into an array then I scale it down. This method requires some time initially, but the goal here is not having to wait.

Is there a way to improve Graphics.DrawImage performance for large images in .NET?

g.DrawImage(img, 0, 0, width, height); //This line causes the delay " 800 milliseconds depending on your computer"

  • The size of TIF images i work with: Width=16800, Height=10800
  • Only Black and White Tif images
  • Bit depth = 1
  • Resolution Unit = 2

enter image description here

 using System;
 using System.Collections.Generic;
 using System.ComponentModel;
 using System.Data;
 using System.Diagnostics;
 using System.Drawing;
 using System.Linq;
 using System.Text;
 using System.Threading.Tasks;
 using System.Windows.Forms;

namespace Tif_Preformance_Question
{
public partial class Form1 : Form
{

    int counter = -1;
    int frameCount = 0;
    Stopwatch s = new Stopwatch();
    Image img;
    Image[] images;

    public Form1()
    {
        InitializeComponent();
    }

    private void btn_Open_Click(object sender, EventArgs e)
    {
        var s = new Stopwatch();
        s.Start();
        s.Stop();
        this.Text = "Elapsed Time Milliseconds" + s.ElapsedMilliseconds;


        img = Image.FromFile(@"C:\image\Large_Tif_Image_15pages.tif");
        frameCount = img.GetFrameCount(System.Drawing.Imaging.FrameDimension.Page);
        images = new Image[frameCount];

        for (int i = 0; i < frameCount; i++)
        {
            img.SelectActiveFrame(System.Drawing.Imaging.FrameDimension.Page, i);
            images[i] = (Image)img.Clone();
        }
        img.SelectActiveFrame(System.Drawing.Imaging.FrameDimension.Page, 0);
        pictureBox1.Image = (Image)img.Clone();

    }

    private void btn_Next_Click(object sender, EventArgs e)
    {
        counter++;
        if (counter >= frameCount)
        {
            counter = frameCount - 1;
            btn_Next.Enabled = false;
        }
        btn_Next.Enabled = false;
        LoadPage();
        btn_Next.Enabled = true;
    }

    private void LoadPage()
    {

        StartWatch();
        img.SelectActiveFrame(System.Drawing.Imaging.FrameDimension.Page, counter);
        pictureBox1.Image = ResizeImage((Image)img.Clone(), pictureBox1.Width, pictureBox1.Height);
        pictureBox1.Refresh();
        Stopwatch();
    }

    public Image ResizeImage(Image img, int width, int height)
    {
        Bitmap b = new Bitmap(width, height);
        using (Graphics g = Graphics.FromImage((Image)b))
        {
            g.DrawImage(img, 0, 0, width, height);
        }
        return (Image)b;
    }

    private void StartWatch()
    {
        s.Start();
    }
    private void Stopwatch()
    {

        s.Stop();
        this.Text = "Elapsed Time Milliseconds: " + s.ElapsedMilliseconds;
        s.Reset();
    }
  }
}

References

IrfanView:

http://www.irfanview.com/

Test: Large TIF image Below

http://www.filedropper.com/largetifimage15pages_2

Visual Studio Solution

http://www.filedropper.com/tifpreformancequestion_1

like image 376
taji01 Avatar asked Jun 28 '16 19:06

taji01


People also ask

Can TIFF files have multiple pages?

Yes, a TIFF file can have multiple pages. A multipage TIFF file saves multiple pages as individual image frames. However, mostly the TIFF images are saved one page per file.


2 Answers

I suspect that there are several issues here. First I suspect that IrfanView isn't written in C#. C# is a wonderful language but some of it's strengths do not always promote maximum performance. For example C# has more overhead when dealing with memory (it clears it on allocation, it tracks usage and garbage collects, etc).

The areas I would look at are I/O and threading. On my machine it takes ~30 ms to read the file (that is almost 1/3 of your 100 ms budget. I suspect the problem with DrawImage is that it isn't threaded (my guess). To do the resize it has to run thru 22 MB of data on non-byte boundary's; 10x10 1 bit pixels in the old image have to be processed to produce 1 pixel in the new (scaled) image. You could confirm this by watching the task manager CPU graph (logical processors view) during your execution and then during an execution of IrfanView.

Fixing either problem may be non-trivial. You can speed up your I/O using Memory Mapped I/O. I suspect the real win would be threading the resize; 800 ms / 8 cores ~= 100 ms (since resizing is very parallelizable). You could write your own threaded resizer or there may be a 3rd party library available to do what you need. Or you may be able to modify an open source library to be threaded/faster.

You can also look at MS's source for the DrawImage call here It appears to be wrapping a gidplus.dll GdipDrawImageRectI call.

You might also take a look at Parallelizing GDI+ Image Resizing .net for ideas

like image 83
Dweeberly Avatar answered Sep 22 '22 09:09

Dweeberly


You might have an advantage in creating your own PictureBox that inherits from the original. You can override the OnPaint and tweak the following parameters of the passed Graphics object:

private override OnPaint(object sender, PaintEventArgs e)
{
    e.Graphics.CompositingQuality = CompositingQuality.HighSpeed;
    e.Graphics.InterpolationMode = InterpolationMode.NearestNeighbor;
    e.Graphics.SmoothingMode = SmoothingMode.None;
    e.Graphics.PixelOffsetMode = PixelOffsetMode.Half;
    e.Graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAliasGridFit;
    e.Graphics.CompositingMode = CompositingMode.SourceCopy;
    base OnPaint(sender, e)
}

Some of these parameters have a huge impact on the rendering speed (and to the quality of the result).

The parameters used in the code example are already quite fast but maybe you find better combinations for your requirements.

like image 20
Thomas Voß Avatar answered Sep 18 '22 09:09

Thomas Voß