返回首页

{A}
{S0}目录 简介
前段时间,我是一个发展中的一个数字档案系统,为政府土地管理办公室的团队的一部分。基本上,系统将尝试做的是整理和数字化的管理提供了数字归档副本存档的​​物理文件。该系统有针对性地解决许多与文件流转速度,并发访问,和许多挂钩的问题。
发现这个系统的好处之一是进行全面细致的的访问该文件,系统的用户能够更好地查看文档比实际观看,而通过了一堆文件。由于这些文件的年龄到几十年,其中大部分是手写的,此功能是该系统的吸引力设施之一。 PictureBox控件。NET包中包含一个简单的形式显示在一个单一的形象完美,但我们需要一个更好的预览所显示的图像的实现还需要一个控制,可以处理多个图像增强的一个。
我经历了我的个人项目,并发现,我对我自己的开始,这个解决方案可能是一个起点。数字档案系统最后实施的版本功能更强大,复杂的,但依靠我转发的设计。
非常基本的需求时,观看一组图像进行彻底的访问,在小学原油条款,如下:泛变焦图像之间的导航旋转
我决定设计一个更精细的细节,可以执行这些任务很容易控制。这种控制的实施涉及未成年人基本上都是有限的坐标平移和缩放的计算。让我澄清的翻译和涉及的坐标系统。

坐标转换或到另一个。
{S2}
ImageViewer的组成部分,是大会的主要组成部分,因为这是所有的计算和命令实施。几乎每一个旋转,所有这些,我已减少到翻译中心的变焦值的显示和缩放功能,除了观看一个单独的图像时所需的命令。喜欢例如,抢夺和平移图像时,我们描述的中心和缩放功能的操作。
泛:缩放保持相同展示中心翻译在x坐标变化和y坐标的变化
下面是它是如何为所有的操作描述:

private void pic_MouseMove(object sender, MouseEventArgs e)

{

    //when a mouse is down and moving 

    //panning and region selection are posibilities

    switch (previewMode)

    {

        case PreviewMode.REGIONSELECTION:

            if (e.Button==MouseButtons.Left)

            {

                //display a rectangular region to the selected region 

                //to notify the user what he is selecting

                int w = Math.Abs(tempCenter.X - e.X), h = Math.Abs(tempCenter.Y - e.Y);

                if (w > 1 || h > 1)

                {

                    this.Refresh();

                    Graphics gr = pic.CreateGraphics();

                    gr.DrawString("(" + (tempCenter.X + e.X) / 2 + "," + 

                                 (tempCenter.Y + e.Y) / 2 + ")", this.Font, 

                                 Brushes.Khaki, new PointF((tempCenter.X + e.X) / 2, 

                                 (tempCenter.Y + e.Y) / 2));

                    gr.DrawRectangle(Pens.Red, new Rectangle((tempCenter.X + e.X - w) / 2, 

                                    (tempCenter.Y + e.Y - h) / 2, w, h));

                    gr.Dispose();

                }

            }

            break;

        case PreviewMode.PAN:

            if (e.Button==MouseButtons.Left&&(tempCenter.X != e.X || 

                                                      tempCenter.Y != e.Y))

            {

                displayCenter = new Point(displayCenter.X + 

                    (int)((tempCenter.X- e.X ) / mZoom),

                    displayCenter.Y + (int)((tempCenter.Y-e.Y) / mZoom));

                ZoomImage();

                tempCenter = e.Location;

            }

            break;

        default:

            break;

    }

}



private void pic_MouseUp(object sender, MouseEventArgs e)

{

    //when the mouse is up its when most of the previews are commited

    switch (previewMode)

    {

        case PreviewMode.REGIONSELECTION:

            displayCenter = new Point(displayCenter.X + 

                (int)(((double)(tempCenter.X + e.X - this.Width) / 2) / mZoom),

                displayCenter.Y + (int)(((double)(tempCenter.Y + 

                e.Y - this.Height) / 2) / mZoom));



    double z = mZoom * pic.Width / Math.Abs(tempCenter.X - e.X);

    if (mZoom * pic.Height / Math.Abs(tempCenter.Y - e.Y) < z)

        z = mZoom * pic.Height / Math.Abs(tempCenter.Y - e.Y);

    mZoom = z;

    ZoomImage();

    break;

        case PreviewMode.ZOOMIN:

            //when zoom in the zoom value is simply multiplied by two

            displayCenter=new Point(displayCenter.X+(int)((e.X-this.Width/2)/mZoom),

                displayCenter.Y+(int)((e.Y-this.Height/2)/mZoom));

            mZoom *= 2;

            //redraw the image with the new zoom value

            ZoomImage();

            break;

        case PreviewMode.ZOOMOUT:

            //when zoom out the zoom value is simply divided by two

            displayCenter = new Point(displayCenter.X + 

                (int)((e.X - this.Width / 2) / mZoom), 

                 displayCenter.Y + (int)((e.Y - this.Height / 2) / mZoom));

            mZoom /= 2;

            //redraw the image with the new zoom value

            ZoomImage();

            break;

        default:

            break;

    }

}

所示的代码,每个case语句的专用计算最重要的两个产生的图像,以显示所需的变量。一旦这些值计算,如果你调用的方法ZoomImage(),它有效地用新值重绘图像。类图部分看起来像:
{S3}实施托管图像查看器组件
此组件拥有所有所需的命令,并准备为消费者代码,但果汁,并提供一个非常有用的和有效的浏览器控制,您需要到主机这就像在一个用户控件,并提供事件来触发这些命令。随着这篇文章中,我已经包括一个灵活的主机控制,易于使用,如图片所示:
{S4}的
这种控制工具框如下图实施的所有基本工具。每个可用命令的按钮和下拉式清单中暴露。例如,组件的变焦能力是暴露的下拉列表中的事件处理程序的下降,在下面的代码示例:{C}
为了减少代码我应该写来提取的变焦模式枚举量,我使出解析字符串的枚举值,否则,它的一个简单的方法揭露的的图像查看器组件放大图像的方法。同样的故事与工具条按钮除,我已经使用每个按钮来存储各自的枚举值的标签,让我不会有切换??情况下,或者如果??其他所有案件和唐"没有处理所有按钮的Click事件。正如在下面的代码示例描述:
private void btn_Click(object sender, EventArgs e)

{

    img.ImagePreviewMode = (PreviewMode)Enum.Parse(typeof(PreviewMode), 

                           ((ToolStripButton)sender).Tag.ToString());

    btnPan.Checked = img.ImagePreviewMode == PreviewMode.PAN;

    btnRegionZoom.Checked = img.ImagePreviewMode == PreviewMode.REGIONSELECTION;

    btnZoomIn.Checked = img.ImagePreviewMode == PreviewMode.ZOOMIN;

    btnZoomOut.Checked = img.ImagePreviewMode == PreviewMode.ZOOMOUT;

    switch (img.ImagePreviewMode)

    {

        case PreviewMode.PAN:

            this.Cursor = Cursors.Hand;

            break;

        case PreviewMode.REGIONSELECTION:

            this.Cursor = Cursors.Cross;

            break;

        default:

            this.Cursor = Cursors.Default;

            break;



    }

}
{A11}图片来源
,并非所有的是,在大多数情况下,图像源是一个系统试图显示一个图像文件的文件系统。但在任何情况下,图像查看器组件接受任何形象只要源作为对象实现IZImage的接口,其定义是在下面的代码所示:
/// <summary>

/// a signiture interface that when implemented by any object

/// enables it to utilize the image viewer component

/// </summary>

public interface IZImage

{

    //gets the number of images that are available for display

    int ImageCount{ get;}

    //gets the current index of the image that is being displayed



    int CurrentIndex { get;}

    //retreives the next available image

    Image GetNextImage();

    //retrieves the previously displayed image

    Image GetPreviousImage();

}

在本文附带的示例代码中,有两个样本中实现sample.cs和PictureBoxEx.cs文件的IZImage接口。在样品的实施,我写了一个简单的代码,显示目录中的图像。我创建了一个类调用的代码> DirectoryImages,其定义如下所示???
public class DirectoryImages:IZImage

{

    //path of the directory

    string m_DirectoryName;

    //number of the image files that are found

    int m_ImageFilesCount;



    int m_CurrentIndex=-1;

    string[] ImageFiles;



    public DirectoryImages(string str)

    {

        m_DirectoryName = str;

        ImageFiles = Directory.GetFiles(str, "*.jpg");

        m_ImageFilesCount = ImageFiles.Length;

    }



    #region IZImage Members



    public int ImageCount

    {

        get { return m_ImageFilesCount; }

    }



    public int CurrentIndex

    {

        get { return m_CurrentIndex; }

    }



    public System.Drawing.Image GetNextImage()

    {

        m_CurrentIndex++;

        if (m_CurrentIndex >= m_ImageFilesCount)

            throw new Exception("No More Images");

        return System.Drawing.Image.FromFile(ImageFiles[m_CurrentIndex]);

    }



    public System.Drawing.Image GetPreviousImage()

    {

        m_CurrentIndex--;

        if (m_CurrentIndex <= 0)

            throw new Exception("No More Images");

        return System.Drawing.Image.FromFile(ImageFiles[m_CurrentIndex]);

    }



    #endregion

}

代码所示,该对象需要的目录路径,并显示该目录中的"JPG图像?延伸,一个接一个。要显示任何图像从任何来源获取一个对象,实施??代码> IZImage??接口,传递对象的存取控制。为了快速使用此图像浏览器,通读下一节。{A12}快速实施
计算机OOP的最伟大的成就之一是抽象的细节和事实,以使用一个类,你不需要知道它是如何做。因此,我提供了一个的存取控制,以便为它表现为一个图片框的默认实现;?这个定义可以发现在EM> PictureBoxEx.cs文件??
当你去通过的代码,你会发现,基本上有两种实现方式:存取控制(PictureBoxEx)和图像源类(ImageFile)。 示例应用程序
示例应用程序,我希望最好的编译说明使用这个增强的图像浏览器的电源。您可以使用"文件"菜单中打开一个单独的图像文件或浏览通过指定的文件夹在一个文件夹中的图像。
{五}{A13}结论
在我的结论,你可以建立复杂的主机控制此组件,甚至不担心组件中所涉及的计算,例如,采用鼠标中放大和缩小。我希望这个组件将有很大的帮助,给任何人,希望利用它。| samqty"

回答

评论会员:感谢很多 时间:2012/01/24
。xiaox2y2
评论会员:游客 时间:2012/01/24
当我使用的控制,我发现了一个异常codeprespanclass="code-keyword"case/spanZoomMode.FITPAGE:mZoom=(spanclass="code-keyword"double/span)spanclass="code-keyword"this/span.Height/originalImage.Height;spanclass="code-keyword"if/span((spanclass="code-keyword"double/span)spanclass="code-keyword"this/span.Width/originalImage.Width<mZoom)mZoom=spanclass="code-keyword"this/span.Width/originalImage.Width;/pre/code我觉得双是在最后一句错过
xiaox2y2
评论会员:游客 时间:2012/01/24
我学习GDI的现在和对我有用
ahlvienna
评论会员:游客 时间:2012/01/24
。。感谢它-我需要这样的事情-但也有一些失败-我并不需要您提供所以我用一个形状你们为我自己的实现的所有功能。这里有一些事情:在缩放可以有一个错误在Fitpage-occours上旋转不止一个timenbsp;{中六}-它可以被纠正,下面的代码:-;情况下ZoomMode.FITPAGE:-;mZoom=(双)this.Height/originalImage身高;-;双ZVAL=(双)this.Width/(双)originalImage.Width;-;(ZVAL放大器;LT;mZoom)BR}-;mZoom=ZVAL;-;displayCenter=新点(originalImage.Width/2originalImage.Height/2);-;突破;轮流在错误的方向旋转-说,真正为顺时针旋转方法-但事实证明逆时针。这次调整是很简单:-;公共无效RotateImage(BOOL顺时针)-;{-;(originalImage=NULL)-;{-;originalImage.RotateFlip(RotateFlipType.Rotate90FlipNone);)//而不是Rotate90FlipXY;{BR}-;ZoomImage(ZoomMode.FITPAGE)-;}-;}当然,这将是一个好主意来看待,而不是忽略它的BOOL-它不伤害,因为你只有一个旋转{中六}按钮有一些东西在无休止的放大,缩小无尽-我不搜索这个故障此外,尝试你的组件,我发现它非常有用做IZImage接口的基本实现,可用于消法:-;公共类SingleImage:IZImage-;{-;私人图片IMG=NULL;-;公共SingleImage(图片IMG)-;{-;this.img=IMG-;}-;//获取可用于显示图像的数量-;公众诠释ImageCount{{返回1;}}-;//获取图像的当前指数正在显示-;公众诠释CurrentIndex{{返回0;}}-;//retreives下一个可用的形象-;公众形象GetNextImage(){图;}-;//检索先前显示的图像-;公众形象GetPreviousImage(){图;}-;}我和覆盖setImage方法之一,直接与图像:-;公共无效SetImageSource(Image图像)-;{-;VARIM=新SingleImage(图片);-;-;img.SetImageSource(IM);-;}感谢你的灵感和工作-希望我的50ct。帮助关于
samqty
评论会员:游客 时间:2012/01/24
的意见表示感谢,这些漂亮的渔获您在代码中发现。的方式,我已经包含了一个文件,扩展一个图片框"PictureBoxEx.cs"的快速实施。我将肯定修补您的建议,以及我很高兴我树荫在你的项目中有一些启发
奈培:的的变化|的净最佳的形象在CodeProject上
控制
评论会员:基兰萨蒂什南比亚 时间:2012/01/24
嗨,

其一个很好的文章,好像在C#程序照顾,我试图解决矿山的一些问题的一些功能,虽然我的是在VC中的MFC。我试图解决的问题是做变焦/输出操作(而不是左上角,将滚动条的位置),在客户端窗口显示图像的中心。这里是我的{A14}]一起使用的代码,我,你认为如果你能揭示一些轻?

感谢

PKNT
评论会员:samqty 时间:2012/01/24
我已失去了我的VC的轨道,但与整体的概念,我可以帮你,如果我能,

让我看看,如果我理解你在说什么,你正在使用滚动条来放大和缩小?你控制它直接借鉴,或你在内存中绘制吗?在我的设计的基本思路是控制使用这两个属性1)变焦和2)中心的形象... ... posible操作大部分都是这两者的结合,我不使用的左上角,因为我将取决于主机控制的位置,它会cofuse我的地狱,

相反,我计算从中心左右上角(XO,哟)和承载控制和缩放值
尺寸
XO = Center_Of_Display.X - (Display_Width / 2)/ mZoom

希望这是一个LIL启发性
评论会员:游客 时间:2012/01/24
:感谢您的答复|基兰萨蒂什南比亚。其实,我不使用滚动条来放大/缩小。我使用滚动条位置来计算的新的左上角(像素坐标)我原来的形象。下面是其目前完成。比方说zoom_const1.0是100%。现在,当用户点击zoom_in按钮,我的zoom_const提高到1.2,然后调用更新视图功能,它更新的滚动条(这样,如果用户已经向下滚动到一定的位置,而在100%,更新滚动栏的大小,以反映新的zoom_constant和更新它们,而远离[垂直滚动条]和左[水平滚动条]不断滚动条)。多数民众赞成在这里完成-codeprem_cs.cx=ImgWidth()*zoom_const;m_cs.cy=ImgHeight()*zoom_const;SetScrollSizes(MM_TEXT,m_cs);InvalidateRect(NULL,spanclass="code-keyword"true/span);/pre/code然后,它调用绘制功能(InvalidateRect()),这个时候的滚动条反映了更新的图像大小,图像时仍然在100%和绘制函数不下面的codeprespanclass="code-keyword"if/span(zoom_const>spanclass="code-digit"1/span){dib->Draw(&dc,spanclass="code-keyword"true/span,spanclass="code-digit"0/span,spanclass="code-digit"0/span,myRect.Width(),myRect.Height(),sp.x/zoom_const,sp.y/zoom_const,myRect.Width()/zoom_const,myRect.Height()/zoom_const);}spanclass="code-keyword"else/spandib->Draw(&dc,spanclass="code-keyword"false/span,spanclass="code-digit"0/span,spanclass="code-digit"0/span,myRect.Width(),myRect.Height(),sp.x,sp.y,myRect.Width(),myRect.Height());/pre/codeDIB-GT;绘制函数的图像已被吸引到客户端窗口的尺寸(使用stretchblt)截面尺寸。正如你可以看到这一切都发生在滚动条的位置。现在我想给它,而就在客户端窗口显示的图像部分的中心。希望我很清楚......我试图理解你的代码,看看如何做。感谢PKNT
samqty
评论会员:游客 时间:2012/01/24
哦OK,我想我现在明白你说的,所以你可以使用滚动条水平和垂直平移图像权?OK,你可以修改你的设计,我试图早些时候建议,您将创建两个公共变量来保存1)中心坐标(X,Y)显示的图像(在实际图像坐标系),例如,如果图像的大小1000分之1000PXS,然后,如果要显示在客户端的大小为20/矩形20PX你持有的为中心的价值(500500)(10,10),如果要显示完全图像的中心,在中心窗口。2)变焦值像你现在正在做的(zoom_const)只有这些值然后发挥实现你在找什么,所有你所要做的的是写一个函数,这些值,并计算出要绘制的图像部分,那么你做,你可以添加许多功能您的浏览器。像泛水平(横向滚动)缩放值不会改变,但该中心的x坐标将是递增或decremeneted,然后调用函数来计算的节中,您希望显示。这更像是一个通用的解决方案,以您的情况,但在您的特定情况:codepredib->Draw(&dc,spanclass="code-keyword"true/span,spanclass="code-digit"0/span,spanclass="code-digit"0/span,myRect.Width(),myRect.Height(),sp.x/zoom_const,sp.y/zoom_const,myRect.Width()/zoom_const,myRect.Height()/zoom_const);/pre/codesp.x/zoom_const坐标不显示图片时放大中心(右上角){S8}你让我呢?你应该计算为X=(center.x-myRect.Width()/zoom_const)/2;Y=(center.y-myRect.Height()/zoom_cost)/2;我希望这个逻辑,在踢好运
奈培
评论会员:游客 时间:2012/01/24
你可以在你的控制滚动条是一个伟大的升级{S9}