题记:最近一直想做一个基于swt的图像处理桌面工具条。在网上收集了一些资料,偶然的发现这篇e文,感觉这张帖子文显义深,并且内容比较丰富。网上的东西总是凌乱的,于是很想把他翻译整理一下,算是对自己约束也是学习吧。

原文链接:http://www.eclipse.org/articles/Article-Image-Viewer/Image_viewer.html#Introduction

demo:  http://www.eclipse.org/articles/Article-Image-Viewer/imageviewer.zip

译者注:安装方法的翻译被我省去就是一般插件的安装方法

Translated by Aivin  ,Written by Chengdong Li

摘要:

     这篇文章讲述了如何通过java2d的转换来扩展swt画布来完成一个迷你的图像查看器插件。它的功能可用于旋转和放大图片,并且也可以衍生到其他变换中 。该软件完全基于swt且不含awt内容。该插件已经在Windows, Linux GTK, 和Mac OS X Carbon平台用Eclipse2.1或以上版本测试过。

目录

·          介绍

·          类图描述

·          画布实现

o   导入图片

o   扩展 org.eclipse.swt.widgets.Canvas

o   绘制图片

o   变换

o   滚动条同步

·          旋转

·          插件实现

o   建立插件视图

o   添加延伸视图

·          归纳

·          鸣谢

·          参考

约定&术语

在该文档中下列印刷的约定:

斜体:用于对文章的链接

courier new字体:用于代码和变量

下面的是在文档中的约定:

略(因为下面已经译出)

 

介绍

如果是是SWT的初学者请先读完这篇 Taking a look at SWT Images. 图一是工具的效果图:

Figure 1 - Image viewer

该软件并不同于从Eclipse example中得到的Image Analyzer软件。该软件用于滚动和变焦图像的转换。

该软件的有点:

1.   它提供了无限尺寸的变焦

2.   它对于大的图片效果很好

在下一个环节中,我们将首先总体看一下包的结构和类之间的关系,然后我们将讨论图像画布是怎样工作和怎样实现能够滚屏的和变焦的图像画布——SWTImageCanvas。

类图描述

下面的图2显示在源代码中所有的类结构。 SWTImageCanvas是org.eclipse.swt..widgets.Canvas的子类;它实现了图像的加载,绘制,滚动和变焦。ImageView类是org.eclipse.ui.part.ViewPart的子类;它有一个SWTImageCanvas实例。辅助类SWT2Dutil实现了有用的功能。PushActionDelegate继承org.eclipse.ui.plugin.AbstractUIPlugin(这个类是PDE-generated)。

Figure 2 - Class diagram

plugin.xml文件定义了运行时的需求和对Eclipse的影响(视图和视图操作的扩充)。Eclipse将生成工具条能工作的工具条按钮。

画布实现

SWTImageCanvas类控制了图片的加载,绘制,滚动和变焦。它在内存中保存了原始图片的镜像,然后用java.awt.geom.AffineTransform翻译并且按标度图像。绘制和转换仅仅被用于图像在屏幕上能被看见(视觉效果最佳)的部分。AffineTransform类用于实现滚动条。

l          加载图片

首先让我们看看如何把一张图片加载到内存中。下面提供了几种方法。

1.   从本地的文件系统中加载图片

2.   从工作区间加载图片

3.   从网页上加载图片

在这个简单的软件中,我们仅仅从本地的文件系统加载图片。为改进一下,你将引入org.eclipse.ui.popupMenus包。这样无论一个图片文件是否被选中,菜单项依然可用。用户可以选择从工作区间加载图片(你需要添加图片名字并且你可能还需要使用空间的程序接口(API)。为了搞清楚如何从URL上加载图片,请参考SWT 自带的例子Image Analyzer。

图像的加载过程如图3所示:

Figure 3 - Image-loading diagram

SWT提供了ImageLoader来加载图片到内存。你可以通过构造器Image(Display,String)来完成图片的加载。为了使图片的加载我们靠SWT ImageLoader支持 提供对话框来定位所有的图片。

public void onFileOpen(){
        FileDialog fileChooser = new FileDialog(getShell(), SWT.OPEN);
        fileChooser.setText("Open image file");
         fileChooser.setFilterPath(currentDir);
        fileChooser.setFilterExtensions(
            new String[] { "*.gif; *.jpg; *.png; *.ico; *.bmp" });
        fileChooser.setFilterNames{
            new String[] { "SWT image" + " (gif, jpeg, png, ico, bmp)" });
        String filename = fileChooser.open();
        if (filename != null)
      loadImage(filename);
         currentDir = fileChooser.getFilterPath();
        }
}
public Image loadImage(String filename) { 
        if(sourceImage!=null && !sourceImage.isDisposed()){
            sourceImage.dispose();
            sourceImage=null;
        }
      sourceImage= new Image(getDisplay(),filename);
    showOriginal();
        return sourceImage;
}

在1到3中我们用currentDir来寄存文件打开对话框的目录,这样用户稍后能在相同的目录下选择其他的文件。

2中的loadImage方法处理旧图像创建新的图片,然后它调用showOriginal()方法来通知画布来绘制(paint)新的图像。如果加载失败,画布将清除绘画区域和禁用滚动条。注意我们在上面的代码中不能直接看到ImageLoader,然而,当我们在第4步中调用Image(Display,String)方法时,Eclipse将调用ImageLoader.load()来加载图片到内存。第5步通常用于显示原始尺寸的图片;稍后我们将更详细头论这些。

事实上,上面的两个子程序可以合成一个方法。 我们之所不那样做是因为我们可以在不同的函数中单独的调用他们。比如, 我们可以从数据库中得到函数的名字, 然后我们可以通过调用loadImage()重新加载他们

 扩展 org.eclipse.swt.widgets.Canvas

现在,让我们来看看如何创建一个画布来绘制图片并且作出一些变换org.eclipse.swt.widgets.Canvas适合于被扩展来绘制图片。SWTImageCanvas扩充了它并且添加了滚动条。通过在Canvas的函数体中设置SWT.V_SCROLLSWT.H_SCROLL格式可以做到。

 
public SWTImageCanvas(final Composite parent, int style) {
  super(parent,style|SWT.BORDER|SWT.V_SCROLL|SWT.H_SCROLL
                      |SWT.NO_BACKGROUND);
  addControlListener(new ControlAdapter() { /* resize listener */
        public void controlResized(ControlEvent event) {
            syncScrollBars();
        }
    });
  addPaintListener(new PaintListener() { /* paint listener */
        public void paintControl(PaintEvent event) {
            paint(event.gc);
        }
    });
  initScrollBars();
}
private void initScrollBars() {
    ScrollBar horizontal = getHorizontalBar();
    horizontal.setEnabled(false);
    horizontal.addSelectionListener(new SelectionAdapter() {
        public void widgetSelected(SelectionEvent event) {
            scrollHorizontally((ScrollBar) event.widget);
        }
    });
    ScrollBar vertical = getVerticalBar();
    vertical.setEnabled(false);
    vertical.addSelectionListener(new SelectionAdapter() {
        public void widgetSelected(SelectionEvent event) {
            scrollVertically((ScrollBar) event.widget);
        }
    });
}

为了加快绘制的进程减少颤动, 我们在 设置格式SWT.NO_BACKGROUND (稍后我们将用双缓冲来绘制) 以便背景(绘制区域)不会被清除。 新的图片覆盖背景。 当新的图片没有完全覆盖背景时我们需要填充背景和图片之间的空隙。

注册了一个调整尺寸的监听器来锁定尺寸 并且滚动条拨弄(注:作者大概是说是用鼠标轮滚动)图片聚焦尺寸和平移; 添加了绘制监听(这个它做 paint(GC gc))只要PaintEvent被触发就将绘制图片; 为每个滚动条添加了 SelectionListener, SelectionListener 将 通知 SWTImageCanvas to 滚动和聚焦当前滚动条下的图片;SelectionListener 另一个功能是是基于图像尺寸和变比尺寸的滚动条失效和有效。

 绘制图片

每当swt paintevent被激发后,绘画监听器(paint(GC,gc))将被调用来绘画受损区域。因为我们支持回滚和变焦,我们需要指明原始区域的哪一部分被当作绘画区域那部分。绘画的过程如下:

1.  在源图中找到一块矩形区域;在矩形区域的图片将被当作要被绘制的部分;

2. 映射imageRect到绘制区域得到destRect

3. imageRect中绘画得到destRect(如果尺寸不同则按比例调整);

4. 如果必要填充空隙(在下面的图中显示用红蓝块来填充)。

1)和 2) 基于AffineTransform完成,我们将在下面讨论。3) 用Gc的drawImage绘制了源图像的一部分到 目的区域;

drawImage (Image image, int srcX, int srcY, int srcWidth, int srcHeight, int destX, int destY, int destWidth, int destHeight)——它能自动按比例调整矩形区域。

    如果我们直接在屏幕上绘制举行区域,我们需要在4)中计算空隙并且填充他们,这里我们充分利用了双缓冲并且填充他们。

  我们用下面的方法来绘制图像: 我们仅保存源图像。 当画布需要更新可视区域, 它在画布上从源图像到目的图像复制对应的区域。这种方法能提供非常大的变焦尺寸并且保存到内存。因为它不需要保存正张放大图片。绘画的过程也被加速。如果画布的面积非常大,我们能把画布切割为几个小格子,并且用我们的方法绘制每个小格子;这样这个方法将能做一些可伸缩的扩展。

下面来让我们具体地看一下代码:

private void paint(GC gc) {
1   Rectangle clientRect = getClientArea(); /* canvas' painting area */
2   if (sourceImage != null) {
/**
* Line 3 to line 10 are used to find a rectangle (imageRect) in the 
* sourceimage 
**/
 
3       Rectangle imageRect=SWT2Dutil.inverseTransformRect(transform, clientRect);
4       
5       int gap = 2; /* find a better start point to render. */
6       imageRect.x -= gap; imageRect.y -= gap;
7       imageRect.width += 2 * gap; imageRect.height += 2 * gap;
8
9       Rectangle imageBound=sourceImage.getBounds();
//The imageRect of line 10 is the exact rectangle we need
10      imageRect = imageRect.intersection(imageBound);
//we transform imageRect back to the canvas domain in line 11
11      Rectangle destRect = SWT2Dutil.transformRect(transform, imageRect);
12      
13      if (screenImage != null){screenImage.dispose();}
14      screenImage = new Image( getDisplay(),clientRect.width, clientRect.height);
15      GC newGC = new GC(screenImage);
16      newGC.setClipping(clientRect);
17      newGC.drawImage( sourceImage,
18            imageRect.x,
19            imageRect.y,
20            imageRect.width,
21            imageRect.height,
22            destRect.x,
23            destRect.y,
24            destRect.width,
25            destRect.height);
26      newGC.dispose();
27
28      gc.drawImage(screenImage, 0, 0);
29  } else {
/**Line 30 to line 32 are used to clear the canvas and reset the scrollbar * whenever the source image is set to null
 **/
30      gc.setClipping(clientRect);
31      gc.fillRectangle(clientRect);
32      initScrollBars();
33  }
}

Line 5 to line 7用于发现更好的坐标绘制矩形图像, 因为转换会压缩或放大没一象素的尺寸。 为了使回滚和聚焦平缓,我们一直从一个象素的开头就绘制图像. 这也保证了如果它比画布大图像将填充画布。

流程图见 (Figure 5):

Figure 5 - Rendering flowchart

《未完待续》

A Basic Image Viewer相关推荐

  1. Basic Theory of Physically-Based Rendering

    By Jeff Russell Physically-based rendering (PBR) is an exciting, if loosely defined, trend in real t ...

  2. QML学习【一】Basic Types

      QML入门教程(1) QML是什么? QML是一种描述性的脚本语言,文件格式以.qml结尾.语法格式非常像CSS(参考后文具体例子),但又支持javacript形式的编程控制.它结合了QtDesi ...

  3. C# Word控件 dsoframer、office viewer、pageoffice、setparent

    Word Visual Basic for Applications (VBA) 参考 | Microsoft Docs [word界面交互] 1.dsoframer ActiveX控件dsoFram ...

  4. RadiAnt DICOM Viewer Crack by Xacker

    不管你以前安装过什么版都可以使用,一次购买永久用,绿色版,复制到电脑或者U盘即可使用 New features:Ω578867473 Send studies to PACS (add-on pack ...

  5. html访问MDB数据库,使用MDB Viewer打开和查看访问数据库 | MOS86

    您有需要打开,编辑或修改Microsoft Access数据库文件(MDB),但您的计算机上没有Microsoft Access? Microsoft没有安装原始软件的程序来查看Word文档,Exce ...

  6. RadiAnt DICOM Viewer 2021.1 Crack

    RadiAnt DICOM Viewer灵活.简单.快速Ω578867473 RadiAnt 是一个医学图像的PACS DICOM浏览器 设计是为了给您独特体验 它界面直观,性能无与伦比 您一定会流连 ...

  7. remote: HTTP Basic: Access denied

    github 提交项目 提示 remote: HTTP Basic: Access denied 这个一般就是自己更改github账号的密码引起的 处理方法1 进入控制面板-->用户账号--&g ...

  8. PAT (Basic Level) Practise (中文)-1025. 反转链表 (25)

    PAT (Basic Level) Practise (中文)-1025. 反转链表 (25)   http://www.patest.cn/contests/pat-b-practise/1025 ...

  9. linux利用* vim提权,linux 通过suid vim.basic文件提权

    在kali上复现 先给需要的vim.basic文件设置suid权限 chmod u+s /usr/bin/vim.basic 先adduser test1一个普通权限用户 现在就是一个合适的提权环境 ...

最新文章

  1. 用户体验已成过去时 AI要从公民乃至社会的角度去思考问题
  2. JAVA springboot ssm b2b2c多用户商城系统源码-SSO单点登录之OAuth2.0登录流程(2)
  3. Lambda表达式很鸡肋?它到底有何用呢?
  4. CDN应用进阶 | 正确使用CDN 让你更好规避安全风险
  5. python解析xml文件选用模块_Python标准库系列之xml模块
  6. verilog学习记(快速入门)
  7. /usr/include/features.h:356:25: 致命错误: sys/cdefs.h:没有那个文件或目录
  8. python从键盘获取数学表达式字符串_python – 数学表达式中String类型的字符串操作...
  9. java的继承实例_Java 继承方法实例详解
  10. win7安装android驱动,Windows7:安卓智能手机刷机驱动安装教程(图文详解)
  11. python画正切函数_在matplotlib中绘制tan
  12. 新计算机安装系统后鼠标键盘都无反应处理
  13. graphite快速搭建手册
  14. sigil 查找替换_使用Sigil提高ePub电子书的质量
  15. 路由器WIFI密码怎么设置?快速设置,只需1分钟
  16. 窗口管理工具:HazeOver for Mac
  17. 黑客 骚扰欺诈 呼死你之外还假冒给好友打电话
  18. Win10 系统一天蓝屏好多次,怎么解决?
  19. laravel+容联.云通讯 实现手机短信验证用户注册
  20. QUECTEL上海移远4G通讯CAT4模组EC20CEFAG模块串口调试指南之04【EC20模组SIM卡和驻网模组指令说明】

热门文章

  1. echarts图表中增加一条警戒线【平均值】
  2. 【JavaScript 教程】事件——键盘事件
  3. 将excel数据导入到SQL server数据库,SQL server引入导入excel报表,如何解决“未在本地计算机上注册“Microsoft.ACE.OLEDB.12.0”提供程序”问题
  4. 本杰明•富兰克林效应
  5. 瑞萨16 位R8C/TINY 系列单片机
  6. 打造高质量的App——《App研发录》
  7. MTK Android 11.0:充电低电指示灯会被未读消息信号灯灭掉,无优先级控制。
  8. Docker技术攻陷笔记
  9. 【2019西安ICPC邀请赛热身赛A hdu2036】求多(四)边形面积(四边形面积公式/向量叉积)
  10. 微博和qq说说定时发送畅想