如何在图片框

时间:2016-03-02 19:11:51

标签: c# .net image winforms resize

概述
我正在使用WinForms。在我的代码中我有这个方法。我正在尝试使用此代码按比例重新调整tif图像的大小。我的目标是从流(源)获取图像并重新调整大小。我想要重新调整大小的图像是具有多个页面的tif个文档。如何按比例重新调整图像大小?

代码功能&计划
下面的代码是在另一个线程中缓存tif个图像。问题是我使用了非常大的tif图像。当我用多个页面打开这些非常大的tif图像时,我的应用程序崩溃并滞后。我的目标或想法是在图像加载之前我应该​​重新调整大小,以便应用程序不会崩溃并且性能变得更快。

示例Tif文档:

我创建了一个用于测试的大型tif文档,您可以从以下链接下载它:http://www.filedropper.com/tiftestingdoc

class PageBuffer : IDisposable
{
public const int DefaultCacheSize = 5;

public static PageBuffer Open(string path, int cacheSize = DefaultCacheSize)
{
    return new PageBuffer(File.OpenRead(path), cacheSize);
}

private PageBuffer(Stream stream, int cacheSize)
{
    this.stream = stream;
    source = Image.FromStream(stream);
    pageCount = source.GetFrameCount(FrameDimension.Page);
    if (pageCount < 2) return;
    pageCache = new Image[Math.Min(pageCount, Math.Max(cacheSize, 3))];
    var worker = new Thread(LoadPages) { IsBackground = true };
    worker.Start();
}

private void LoadPages()
{
    while (true)
    {
        lock (syncLock)
        {
            if (disposed) return;
            int index = Array.FindIndex(pageCache, 0, pageCacheSize, p => p == null);
            if (index < 0)
                Monitor.Wait(syncLock);
            else
                pageCache[index] = LoadPage(pageCacheStart + index);
        }
    }
}

private Image LoadPage(int index)
{
    source.SelectActiveFrame(FrameDimension.Page, index);
    return new Bitmap(source);
}

private Stream stream;
private Image source;
private int pageCount;
private Image[] pageCache;
private int pageCacheStart, pageCacheSize;
private object syncLock = new object();
private bool disposed;

public Image Source { get { return source; } }
public int PageCount { get { return pageCount; } }
public Image GetPage(int index)
{
    if (disposed) throw new ObjectDisposedException(GetType().Name);
    if (PageCount < 2) return Source;
    lock (syncLock)
    {
        AdjustPageCache(index);
        int cacheIndex = index - pageCacheStart;
        var image = pageCache[cacheIndex];
        if (image == null)
            image = pageCache[cacheIndex] = LoadPage(index);
        return image;
    }
}

private void AdjustPageCache(int pageIndex)
{
    int start, end;
    if ((start = pageIndex - pageCache.Length / 2) <= 0)
        end = (start = 0) + pageCache.Length;
    else if ((end = start + pageCache.Length) >= PageCount)
        start = (end = PageCount) - pageCache.Length;
    if (start < pageCacheStart)
    {
        int shift = pageCacheStart - start;
        if (shift >= pageCacheSize)
            ClearPageCache(0, pageCacheSize);
        else
        {
            ClearPageCache(pageCacheSize - shift, pageCacheSize);
            for (int j = pageCacheSize - 1, i = j - shift; i >= 0; j--, i--)
                Exchange(ref pageCache[i], ref pageCache[j]);
        }
    }
    else if (start > pageCacheStart)
    {
        int shift = start - pageCacheStart;
        if (shift >= pageCacheSize)
            ClearPageCache(0, pageCacheSize);
        else
        {
            ClearPageCache(0, shift);
            for (int j = 0, i = shift; i < pageCacheSize; j++, i++)
                Exchange(ref pageCache[i], ref pageCache[j]);
        }
    }
    if (pageCacheStart != start || pageCacheStart + pageCacheSize != end)
    {
        pageCacheStart = start;
        pageCacheSize = end - start;
        Monitor.Pulse(syncLock);
    }
}

void ClearPageCache(int start, int end)
{
    for (int i = start; i < end; i++)
        Dispose(ref pageCache[i]);
}

static void Dispose<T>(ref T target) where T : class, IDisposable
{
    var value = target;
    if (value != null) value.Dispose();
    target = null;
}

static void Exchange<T>(ref T a, ref T b) { var c = a; a = b; b = c; }

public void Dispose()
{
    if (disposed) return;
    lock (syncLock)
    {
        disposed = true;
        if (pageCache != null)
        {
            ClearPageCache(0, pageCacheSize);
            pageCache = null;
        }
        Dispose(ref source);
        Dispose(ref stream);
        if (pageCount > 2)
            Monitor.Pulse(syncLock);
    }
  }
}

2 个答案:

答案 0 :(得分:1)

一种尝试是限制缓存位图的大小。

为此,请介绍一个新成员

private Size pageSize;

并按如下方式使用

private Image LoadPage(int index)
{
    source.SelectActiveFrame(FrameDimension.Page, index);
    return new Bitmap(source, pageSize);
}

最后一行根据Bitmap Constructor (Image, Size)文档进行实际调整大小:

  

从指定的现有图像初始化位图类的新实例,并缩放到指定的大小。

我们需要引入额外的参数:

public static PageBuffer Open(string path, Size maxSize, int cacheSize = DefaultCacheSize)
{
    return new PageBuffer(File.OpenRead(path), maxSize, cacheSize);
}

private PageBuffer(Stream stream, Size maxSize, int cacheSize)
{
    // ...
} 

因此您可以传递最大所需的尺寸。在该限制下的实际页面大小,保持原始图像大小的比例计算如下:

var sourceSize = source.Size;
float scale = Math.Min((float)maxSize.Width / sourceSize.Width, (float)maxSize.Height / sourceSize.Height);
var targetSize = new Size((int)(sourceSize.Width * scale), (int)(sourceSize.Height * scale));

以下是完整代码:

class PageBuffer : IDisposable
{
    public const int DefaultCacheSize = 5;

    public static PageBuffer Open(string path, Size maxSize, int cacheSize = DefaultCacheSize)
    {
        return new PageBuffer(File.OpenRead(path), maxSize, cacheSize);
    }

    private PageBuffer(Stream stream, Size maxSize, int cacheSize)
    {
        this.stream = stream;
        source = Image.FromStream(stream);
        pageCount = source.GetFrameCount(FrameDimension.Page);
        if (pageCount < 2) return;
        pageCache = new Image[Math.Min(pageCount, Math.Max(cacheSize, 3))];
        pageSize = source.Size;
        if (!maxSize.IsEmpty)
        {
            float scale = Math.Min((float)maxSize.Width / pageSize.Width, (float)maxSize.Height / pageSize.Height);
            pageSize = new Size((int)(pageSize.Width * scale), (int)(pageSize.Height * scale));
        }
        var worker = new Thread(LoadPages) { IsBackground = true };
        worker.Start();
    }

    private void LoadPages()
    {
        while (true)
        {
            lock (syncLock)
            {
                if (disposed) return;
                int index = Array.FindIndex(pageCache, 0, pageCacheSize, p => p == null);
                if (index < 0)
                    Monitor.Wait(syncLock);
                else
                    pageCache[index] = LoadPage(pageCacheStart + index);
            }
        }
    }

    private Image LoadPage(int index)
    {
        source.SelectActiveFrame(FrameDimension.Page, index);
        return new Bitmap(source, pageSize);
    }

    private Stream stream;
    private Image source;
    private int pageCount;
    private Image[] pageCache;
    private int pageCacheStart, pageCacheSize;
    private object syncLock = new object();
    private bool disposed;
    private Size pageSize;

    public Image Source { get { return source; } }
    public int PageCount { get { return pageCount; } }
    public Image GetPage(int index)
    {
        if (disposed) throw new ObjectDisposedException(GetType().Name);
        if (PageCount < 2) return Source;
        lock (syncLock)
        {
            AdjustPageCache(index);
            int cacheIndex = index - pageCacheStart;
            var image = pageCache[cacheIndex];
            if (image == null)
                image = pageCache[cacheIndex] = LoadPage(index);
            return image;
        }
    }

    private void AdjustPageCache(int pageIndex)
    {
        int start, end;
        if ((start = pageIndex - pageCache.Length / 2) <= 0)
            end = (start = 0) + pageCache.Length;
        else if ((end = start + pageCache.Length) >= PageCount)
            start = (end = PageCount) - pageCache.Length;
        if (start < pageCacheStart)
        {
            int shift = pageCacheStart - start;
            if (shift >= pageCacheSize)
                ClearPageCache(0, pageCacheSize);
            else
            {
                ClearPageCache(pageCacheSize - shift, pageCacheSize);
                for (int j = pageCacheSize - 1, i = j - shift; i >= 0; j--, i--)
                    Exchange(ref pageCache[i], ref pageCache[j]);
            }
        }
        else if (start > pageCacheStart)
        {
            int shift = start - pageCacheStart;
            if (shift >= pageCacheSize)
                ClearPageCache(0, pageCacheSize);
            else
            {
                ClearPageCache(0, shift);
                for (int j = 0, i = shift; i < pageCacheSize; j++, i++)
                    Exchange(ref pageCache[i], ref pageCache[j]);
            }
        }
        if (pageCacheStart != start || pageCacheStart + pageCacheSize != end)
        {
            pageCacheStart = start;
            pageCacheSize = end - start;
            Monitor.Pulse(syncLock);
        }
    }

    void ClearPageCache(int start, int end)
    {
        for (int i = start; i < end; i++)
            Dispose(ref pageCache[i]);
    }

    static void Dispose<T>(ref T target) where T : class, IDisposable
    {
        var value = target;
        if (value != null) value.Dispose();
        target = null;
    }

    static void Exchange<T>(ref T a, ref T b) { var c = a; a = b; b = c; }

    public void Dispose()
    {
        if (disposed) return;
        lock (syncLock)
        {
            disposed = true;
            if (pageCache != null)
            {
                ClearPageCache(0, pageCacheSize);
                pageCache = null;
            }
            Dispose(ref source);
            Dispose(ref stream);
            if (pageCount > 2)
                Monitor.Pulse(syncLock);
        }
    }
}

样本用法:

var data = PageBuffer.Open(path, new Size(850, 1100));

答案 1 :(得分:0)

        Bitmap bmp = new Bitmap(newWidth, newHeight);
        Graphics g = Graphics.FromImage(bmp);
    for (int idx = 0; idx < count; idx++)
        {
            bmp.SelectActiveFrame(FrameDimension.Page, idx);
        g.DrawImage(source, new Rectangle(0,0,source.Width,source.Height), 
         new Rectangle(0,0,bmp.Width,bmp.Height));
            ImageCodecInfo myImageCodecInfo;
            System.Drawing.Imaging.Encoder myEncoder;
            EncoderParameter myEncoderParameter;
            EncoderParameters myEncoderParameters;
            myImageCodecInfo = GetEncoderInfo("image/tiff");
            myEncoder = System.Drawing.Imaging.Encoder.Compression;
            myEncoderParameters = new EncoderParameters(1);
            myEncoderParameter = new EncoderParameter(
                myEncoder,
                (long)EncoderValue.CompressionLZW);
            myEncoderParameters.Param[0] = myEncoderParameter;    
            bmp.SaveAdd(byteStream, ImageFormat.Tiff);
        }


 private static ImageCodecInfo GetEncoderInfo(String mimeType)
        {
            int j;
            ImageCodecInfo[] encoders;
            encoders = ImageCodecInfo.GetImageEncoders();
            for (j = 0; j < encoders.Length; ++j)
            {
                if (encoders[j].MimeType == mimeType)
                    return encoders[j];
            }
            return null;
        }