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 ima
What's very costy is the resizing of the image because it's a big image (you also have an extra clone before resize that seems useless and costs like ~10%).
I'm not sure you can find a faster loader / resizer, maybe irfan view wrote one specifically (TIF like the one in your sample is a simple 1 bpp B&W image. Once the image loaded, you could resize in a multithreaded mode, spawning say 2,4,8 or 16 worker threads, each one on a rectangle portion of the image, and divide overall by the number of threads).
W/o any 3rd party, here is pure .NET a sample that works in your environment, with a specific multi-threaded SizedTifImage utility class that caches all frames already resized in memory. When you run it, you will only see the initial ~1s load time and then browsing through images shouldn't be noticeable:
public partial class Form1 : Form
{
SizedTifImage _tif;
private void btn_Open_Click(object sender, EventArgs e)
{
...
_tif = new SizedTifImage(@"Large_Tif_Image_15pages.tif", pictureBox1.Width, pictureBox1.Height);
pictureBox1.Image = _tif.GetFrame(0);
btn_Next_Click(null, null);
}
private void btn_Next_Click(object sender, EventArgs e)
{
counter++;
if (counter >= _tif.FrameCount)
{
counter = _tif.FrameCount - 1;
btn_Next.Enabled = false;
}
btn_Next.Enabled = false;
LoadPage();
btn_Next.Enabled = true;
}
private void LoadPage()
{
StartWatch();
pictureBox1.Image = _tif.GetFrame(counter);
Stopwatch();
}
}
public class SizedTifImage : IDisposable
{
private Image _image;
private ConcurrentDictionary _frames = new ConcurrentDictionary();
public SizedTifImage(string filename, int width, int height)
{
Width = width;
Height = height;
_image = Image.FromFile(filename);
FrameCount = _image.GetFrameCount(FrameDimension.Page);
ThreadPool.QueueUserWorkItem(ResizeFrame);
}
public int FrameCount { get; private set; }
public int Width { get; private set; }
public int Height { get; private set; }
private void ResizeFrame(object state)
{
for (int i = 0; i < FrameCount; i++)
{
if (_image == null)
return;
_image.SelectActiveFrame(FrameDimension.Page, i);
var bmp = new Bitmap(Width, Height);
using (var g = Graphics.FromImage(bmp))
{
if (_image == null)
return;
g.DrawImage(_image, 0, 0, bmp.Width, bmp.Height);
}
_frames.AddOrUpdate(i, bmp, (k, oldValue) => { bmp.Dispose(); return oldValue; });
}
}
public Image GetFrame(int i)
{
if (i >= FrameCount)
throw new IndexOutOfRangeException();
if (_image == null)
throw new ObjectDisposedException("Image");
Image img;
do
{
if (_frames.TryGetValue(i, out img))
return img;
Thread.Sleep(10);
}
while (true);
}
public void Dispose()
{
var images = _frames.Values.ToArray();
_frames.Clear();
foreach (var img in images)
{
img.Dispose();
}
if (_image != null)
{
_image.Dispose();
_image = null;
}
}