我有一幅大的tiff图片(5.9 Mb,13k X 16k分辨率),用户将其加载到可滚动面板中,然后他可以放大/缩小,滚动和标记点,区域等.
对于可滚动的双缓冲面板,我使用的是鲍勃·鲍威尔(Bob Powell)令人敬畏的ZoomPicBox 的修改版.该面板仅显示当前查看的图片部分.
缩小时滚动图像时会发生结结巴巴(即使interpolationMode设置为low)
有什么可以做的(最好没有硬件加速)?
面板的绘画事件:
protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
{
if (_image == null)
{
base.OnPaintBackground(e);
return;
}
//scale
System.Drawing.Drawing2D.Matrix ScaleMat = new System.Drawing.Drawing2D.Matrix(_zoom, 0, 0, _zoom, 0, 0);
//move to position of scrollbas
ScaleMat.Translate(this.AutoScrollPosition.X / (_zoom), this.AutoScrollPosition.Y / (_zoom));
e.Graphics.Transform = ScaleMat;
e.Graphics.InterpolationMode = _interpolationMode;
e.Graphics.DrawImage(_image, new Rectangle(0, 0, _image.Width, _image.Height), 0, 0, _image.Width, _image.Height, GraphicsUnit.Pixel);
base.OnPaint(e);
}
构造函数:
public PicBoxPlus()
{
MouseMove += PicBoxPlus_MouseMove;
KeyDown += PicBoxPlus_KeyDown;
this.SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.ResizeRedraw | ControlStyles.OptimizedDoubleBuffer, true);
this.AutoScroll = true;
}
编辑:尝试缓存
我尝试实现Sinatr的代码,但出了点问题,因为我得到的只是一张黑色的图片(大小合适).任何人都知道有什么问题吗?
新的油漆事件:
protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
{
if (mCachedImage == null)
{
base.OnPaintBackground(e);
return;
}
//scale
System.Drawing.Drawing2D.Matrix ScaleMat = new System.Drawing.Drawing2D.Matrix(mZoom, 0, 0, mZoom, 0, 0);
//move to position of scrollbas
ScaleMat.Translate(this.AutoScrollPosition.X / (mZoom), this.AutoScrollPosition.Y / (mZoom));
try
{
if (mCachedImage == null)
{
mCachedImage = new Bitmap(this.ClientSize.Width, this.ClientSize.Height);
using (var cacheGraphics = Graphics.FromImage(mCachedImage))
{
cacheGraphics.Transform = ScaleMat;
cacheGraphics.InterpolationMode = _interpolationMode;
cacheGraphics.DrawImage(mCachedImage, new Rectangle(0, 0, mCachedImage.Width, mCachedImage.Height), 0, 0, mCachedImage.Width, mCachedImage.Height, GraphicsUnit.Pixel);
}
e.Graphics.DrawImage(mCachedImage, Point.Empty);
}
}
catch (Exception ex)
{
throw ex;
}
base.OnPaint(e);
}
图像和缩放属性:
public Bitmap Image
{
get { return mCachedImage; }
set
{
mCachedImage = value;
UpdateScaleFactor();
this.Invalidate();
}
}
public Single Zoom
{
get { return mZoom; }
set
{
if (value <= 0||value < 0.001)
{
value = 0.001f;
}
mZoom = value;
UpdateScaleFactor();
ResetCache(); // Sinatr's function
this.Invalidate();
}
}
从主窗体加载图像:
panelMap.Image = (Bitmap)Image.FromFile("pic.tiff");
Graphics
从位图创建),并在更改大小/缩放比例时销毁缓存.没有经过测试,但是应该给出一个想法.
Bitmap _cached = null;
override void OnPaint(PaintEventArgs e)
{
if(_cached == null)
{
_cached = new Bitmap(this.ClientSize.Width, this.ClientSize.Height);
using(var graphics = Graphics.FromImage(_cached)
{
// draw into this graphics once -> it will be cached in _cached bitmap
}
}
e.Graphics.DrawImage(_cached, Point.Empty);
}
// call this if _zoom or ClientSize is changed
void ResetCache()
{
_cache = null;
this.Invalidate(); // mandatory for _zoom change
}
另外,我不知道如何显示放大的图片,但是通常会有偏移,以便您可以移动(平移)图像.
base.OnPaint()
在绘画结束时打电话?I have a large tiff picture (5.9 Mb , 13k X 16k reolution) that the user loads into a scrollable panel that he then can zoom in/out of, scroll and mark points, regions etc on.
for the scrollable double buffered panel I am using a modification of Bob Powell's awesome ZoomPicBox The panel displays only the part of the picture currently in view.
The stutter occurs when scrolling the image when zoomed out (even if the interpolationMode is set to low)
Is there anything that can be done about it (preferably without hardware acceleration)?
The paint event of the panel :
protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
{
if (_image == null)
{
base.OnPaintBackground(e);
return;
}
//scale
System.Drawing.Drawing2D.Matrix ScaleMat = new System.Drawing.Drawing2D.Matrix(_zoom, 0, 0, _zoom, 0, 0);
//move to position of scrollbas
ScaleMat.Translate(this.AutoScrollPosition.X / (_zoom), this.AutoScrollPosition.Y / (_zoom));
e.Graphics.Transform = ScaleMat;
e.Graphics.InterpolationMode = _interpolationMode;
e.Graphics.DrawImage(_image, new Rectangle(0, 0, _image.Width, _image.Height), 0, 0, _image.Width, _image.Height, GraphicsUnit.Pixel);
base.OnPaint(e);
}
The constructor:
public PicBoxPlus()
{
MouseMove += PicBoxPlus_MouseMove;
KeyDown += PicBoxPlus_KeyDown;
this.SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.ResizeRedraw | ControlStyles.OptimizedDoubleBuffer, true);
this.AutoScroll = true;
}
EDIT : Attempting Caching
I tried implementing Sinatr's code but something is wrong, because all I get is a black image (of the right size). Anyone has an idea what could be wrong?
The new paint event:
protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
{
if (mCachedImage == null)
{
base.OnPaintBackground(e);
return;
}
//scale
System.Drawing.Drawing2D.Matrix ScaleMat = new System.Drawing.Drawing2D.Matrix(mZoom, 0, 0, mZoom, 0, 0);
//move to position of scrollbas
ScaleMat.Translate(this.AutoScrollPosition.X / (mZoom), this.AutoScrollPosition.Y / (mZoom));
try
{
if (mCachedImage == null)
{
mCachedImage = new Bitmap(this.ClientSize.Width, this.ClientSize.Height);
using (var cacheGraphics = Graphics.FromImage(mCachedImage))
{
cacheGraphics.Transform = ScaleMat;
cacheGraphics.InterpolationMode = _interpolationMode;
cacheGraphics.DrawImage(mCachedImage, new Rectangle(0, 0, mCachedImage.Width, mCachedImage.Height), 0, 0, mCachedImage.Width, mCachedImage.Height, GraphicsUnit.Pixel);
}
e.Graphics.DrawImage(mCachedImage, Point.Empty);
}
}
catch (Exception ex)
{
throw ex;
}
base.OnPaint(e);
}
The Image and zoom properties:
public Bitmap Image
{
get { return mCachedImage; }
set
{
mCachedImage = value;
UpdateScaleFactor();
this.Invalidate();
}
}
public Single Zoom
{
get { return mZoom; }
set
{
if (value <= 0||value < 0.001)
{
value = 0.001f;
}
mZoom = value;
UpdateScaleFactor();
ResetCache(); // Sinatr's function
this.Invalidate();
}
}
Loading the image from the main form:
panelMap.Image = (Bitmap)Image.FromFile("pic.tiff");
Graphics
from bitmap) and destroy cache if size/zoom is changed.Is not tested, but should give an idea.
Bitmap _cached = null;
override void OnPaint(PaintEventArgs e)
{
if(_cached == null)
{
_cached = new Bitmap(this.ClientSize.Width, this.ClientSize.Height);
using(var graphics = Graphics.FromImage(_cached)
{
// draw into this graphics once -> it will be cached in _cached bitmap
}
}
e.Graphics.DrawImage(_cached, Point.Empty);
}
// call this if _zoom or ClientSize is changed
void ResetCache()
{
_cache = null;
this.Invalidate(); // mandatory for _zoom change
}
Also, I don't know how to do you present your zoomed-in picture, but usually there is an offset so that you can move (pan) image.
base.OnPaint()
at the end of painting?本人是.net程序员,因为英语不行,使用工具翻译,希望对有需要的人有所帮助
如果本文质量不好,还请谅解,毕竟这些操作还是比较费时的,英语较好的可以看原文