View large multi page Tif images within 100 milliseconds

后端 未结 4 1714
悲&欢浪女
悲&欢浪女 2021-01-02 03:42

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

4条回答
  •  时光说笑
    2021-01-02 04:12

    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;
            }
        }
    

提交回复
热议问题