2005年05月22日

上篇文章里我非常简单地介绍了FreeImage,有兴趣的可以看看;最近在学习DotNET,忽然想起了著名的开源项目:FreeImage,隐约记得它提供了DotNET的封装类,于是下载了最新的版本一看,果然如此,很是开心,这个宝贝也许很适合配合我的iText.NET使用呢。

下载,解压缩,用#Develop打开例子,编译,错误多的吓人(63个),经分析,主要是以下两种情况:

1.封装类里把静态函数FreeImage_前缀都去掉了,但demo中仍加上了;

2.UInt32和Integer之间没有做转换;

经过如下修改:

1.把FreeImage_都去掉;

2.把这行代码

Int image = FreeImage.Load(FIF.FIF_PPM, @"C:\FreeImage.ppm", 0);

中的Int改为UInt32

编译成功;

运行测试时又发现问题了,碰到了两个不存在的函数:

GetDotsPerMeterX

和FreeImage_ColorQuantize

一检查,原来是封装中把GetDotsPerMeterX写成了GetDotsPerMeter,而FreeImage_ColorQuantize被写成了

ColorQuantize(封装FreeImage.dll的函数时有FreeImage_是前缀的,封装后的没有)

再次把封装类也修改掉,重新编译FreeImage.NET.dll,编译Demo,运行成功。

还忘记了一个问题,如果你生成的是debug版本,你还会碰到一个问题,就是报freeimaged.dl不存在,这时你需要把freeimage.dll改名为freeimaged.dll(不知道为什么debug版本和relase版本使用不同的FreeImage静态链接库的名字)

至此,FreeImage.NET中所发现的错误已经修正完毕,感觉比较纳闷的是这么一个著名的开源项目中的demo和封装类怎么会有那么多的错误,似乎非常有损FreeImage的形象。

对了,由于本人不怎么熟悉C#,就用#Develop把Demo转为VB.NET版本的来看看,转后又发现一个问题:

  byte[] rawBytes = new byte[] {0,1,0,1,1,1,0};
  Console.WriteLine("ConvertFromRawBits");
  FreeImage.ConvertFromRawBits(rawBytes, 16, 16, 1, 1, 1, 1, 1, false);
  
  Console.WriteLine("ConvertToRawBits");
  IntPtr lpBits = IntPtr.Zero;
  FreeImage.ConvertToRawBits(lpBits, image, 1, 1, 1, 1, 1, false);

这段代码对于VB.NET的代码要改为:

  Dim rawBytes As Byte() = New Byte() {0, 1, 0, 1, 1, 1, 0}
  Console.WriteLine("ConvertFromRawBits")
  Dim i As UInt32=System.Convert.ToUInt32(1)
  
  FreeImage.ConvertFromRawBits(rawBytes, 16, 16, 1, i, i, i, i, False)
  Console.WriteLine("ConvertToRawBits")
  Dim lpBits As IntPtr = IntPtr.Zero
  FreeImage.ConvertToRawBits(lpBits, image, 1, i, i, i, i, False)

才能编译通过,想必各位已经看出红色字体部分的不同了吧?在C#下ConvertFromRawBits和ConvertToRawBits函数的5-8(后者为4-7)位参数使用整型就可以,但在VB.NET下必须是UInt32才可以(函数声明的是UInt32),还没有查找是什么原因呢。

P.S.修改后的源代码和VB.NET Demo

FreeImage是非常有名的开源的图片处理软件,支持跨平台,安全的多线程支持,支持多种编程语言(如C, C++, VB, C#, Delphi, Java和脚本语言:Perl, Python, PHP, TCL or Ruby),可以说非常的强大,下面把FreeImage的特点简单介绍下:

1.易用,这个各位自己试下吧,也没有什么好说的了;

FreeImage支持多种图片格式,如:

  • BMP files [reading, writing]
  • DDS files [reading]
  • Dr. Halo files [reading] *
  • GIF files [reading, writing]
  • HDR files [reading, writing]
  • ICO files [reading, writing]
  • IFF files [reading]
  • JBIG [reading, writing] **
  • JNG files [reading]
  • JPEG/JIF files [reading, writing]
  • KOALA files [reading]
  • LBM files [reading]
  • Kodak PhotoCD files [reading]
  • MNG files [reading]
  • PCX files [reading]
  • PBM files [reading, writing]
  • PGM files [reading, writing]
  • PNG files [reading, writing]
  • PPM files [reading, writing]
  • PhotoShop files [reading]
  • Sun RAS files [reading]
  • TARGA files [reading, writing]
  • TIFF files [reading, writing]
  • WBMP files [reading, writing]
  • XBM files [reading]
  • XPM files [reading, writing]


* 仅灰度格式
** 只能通过外部插件实现,有些是商业的

3.在本地PC上没有使用限制:独特的FreeImageIO 结构可以方便地通过多种途径获得和处理图片:独立的图片文件,内存,压缩文件中,网络;

4.插件驱动:方便编写和使用自己编写的插件

5.支持多种颜色效果转换

6.支持HDR图像

7.直接读取bitmaps bits 和palette

8.支持Metadata

9.开源

10两种信用证可选择:可方便用于开源项目或者商业项目

11.可以方便地与DirectX 、OpenGL集成.

但下篇讲讲下FreeImage.NET中的多处错误(FreeImage的DotNET封装和相关例子都有多处错误)

2005年05月20日

        在www.somee.com申请了一个支持asp.net免费空间,用于测试我的iText.NET of IKVM,现在只放了两个简单的asp.net程序,一个类似helloworld,一个是测试中文PDF的显示。

        根据我的时间安排,我会慢慢把iText的教程翻译了上传到网上演示。

2005年05月16日

monoforge.com为对linux下测试.net(mono)感兴趣的人员提供了10M的免费空间和MySql数据库支持,

只需要简单的注册就可以获得帐号。

2005年05月13日

      iText是java下著名的PDF生成和处理包,很多报表工具都使用了该java包;之前我也用gnu的gcj把一些使用的java程序编译成win32程序,只是由于gnu对CJK的支持一直有问题,也许是我没有弄明白怎么做,也就放在了一边;几天前无意间在网上看到了IKVM,并在一篇介绍里讲了如何编译FOP(我试了下最新版本的,有太多的warning,也就扔到一边去了),便想如果用ikvmc编译iText如何。

      iText的.Net版本现在能见到的有iTextdotNETiTextSharp

    iTextSharp是iText的C#版本,很久没有更新了,似乎已经停止开发了;功能不完整,版本也比较低,对CJK的支持和编码文件的处理都不行。

     iTextdotNET是在.NET框架下用J#实现的iText 。这个库可以让你轻松地生成PDF, (X)HTML, XML, RTF 文件。功能比较完整,但如果使用这个类的话,你还要额外安装Microsoft Visual J# .NET 1.1 版可再发行组件包。

     经过一番努力和测试,IKVM版本的iText.NET诞生了,这个版本的特点,你不仅可以使用C#,VB.NET,ASP.NET,而且可以使用java来编写类,然后用ikvmc直接编译成.Net可执行程序或者动态链接库文件,是你又多了一种编程语言。

     IKVM版本的iText.NET目前还没有确定的名称,是从完整版本的itext-paulo-154.jarPORT过来,支持iText的全部功能,当然也象iText的java包一样能够很好的支持CJK。

     通过对IKVM的研究,感觉GCJ只要做些适当的设置应该能很好的支持CJK了,只是我使用的thisiscool版本的GCC似乎有些问题,有些不是很稳定,同样的工作在有些机器上不成功,在有些机器上成功,等有兴趣再去研究吧。

    这里只是做个简单记录,以庆祝自己的喜悦心情,接下来还有很多的工作要做。

     HSQLDB是一个纯Java的数据库,小巧方便,在做应用程序的demo时会带来很大的方便。我们可以从http://hsqldb.sourceforge.net/下载hsqldb,里面包括源代码,文档以及demo等等。

    IKVM如何获得与安装,我这里就不废话了;framework是1.1版本 ,HSQLDB是最新版本的,IDE是sharpDevelop v1.1.0 build1913。

    我下面要做的工作,就是想测试下是否可以成功把HSQLDB编译成.Net版本的链接库以及生成相关的程序(因为在网上看到了相关的询问,当然网上也有一个C#版本SharpHSQL,有兴趣的可以自己去看看),比如server.exe,webserver.exe等。

    1.进行最简单的测试工作:

   1)ikvmc -target:winexe hsqldb.jar

   成功生成hsqldb.exe(实际上是org.hsqldb.util.SqlTool),在命令行下进行简单测试,没有问题。

    2)ikvmc -target:library hsqldb.jar

   成功生成hsqldb.dll,在#develop中建一工程,引用hsqldb.dll,程序中调用org.hsqldb.util.SqlTool.main(args)和org.hsqldb.util.WebServer.main(args),结果报均报AWT方面的错误,WebServer并没有使用AWT方面的引用;

     3)gnu java 对AWT的支持非常有限,看来要做些简单的修改。忽然想到hsqldb中集成了datamanager,看了看hsql.jar,索性把整个util文件夹删除,重新进行2)的测试工作,成功!

看来只要简单修改就可以把hsqldb port 为hsqldb.net,至于性能如何,我还没有测试过。

In a nutshell, IKVM can be described as a Java Virtual Machine for the .NET CLR. But that brief statement hides a whole new world — IKVM is the first serious option for in-process Java-to-.NET interoperability. Developed primarily by Jeroen Frijters and a small team of contributors, IKVM is an amazing new technology that conclusively breaks down the barriers between Java and .NET. So if you are creating a .NET application, but want to use that cool new Java library that doesn’t yet have a .NET counterpart, here’s a solution for you. Conversely, if you are a Java developer who wants to call a .NET library from Java, IKVM is what you need.

Installation

IKVM requires a .NET runtime to be available on your system. If you are on a Windows operating system, you should have the Microsoft .NET Framework installed. If you are on Linux (or Solaris or OS X), you should have Mono (preferably version 1.0) installed.

Since the IKVM binary distribution consists primarily of .NET assemblies, installing is simple. Just download the binary .zip from the web site, and unzip its content into a directory. Linux users also have the option of downloading a packaged version of IKVM bundled with the Mono 1.0 distribution.

To develop applications with IKVM, you should also have a Java compiler installed. You can use any compiler that produces standard bytecodes, such as Jikes or or the Sun JDK (javac). In Windows, you may wish to install the IKVM .dlls into the Global Assembly Cache to make development easier.

IKVM Components

IKVM essentially consists of a compiler that can transform Java bytecodes into .NET IL representation, either statically or dynamically. It includes the Java standard libraries, in the form of a version of GNU Classpath, pre-compiled into .NET. It also includes JNI providers for Mono and Windows, to enable Java code to access native (C/C++) libraries.

All of the above boils down to three major modes of operation. First is the application ikvm, which can be used as a drop-in replacement for any other JVM. When run in this mode, the Java bytecodes are compiled to .NET IL at runtime, and hence, is known as the dynamic mode of operation.

Second is the ikvmc command, which can be used to convert Java bytecodes into .NET IL. Thus, you can convert a set of Java class files into a .NET assembly.

Since this manner of use statically compiles the Java bytecodes, it’s known as the static mode. Note that while the dynamic mode fully supports the Java classloader semantics, in the static mode, there are necessarily some limitations. Among the issues to watch out for is the fact that all classes are loaded by the bootstrap classloader. See the threads for the gory details. In brief, many Java programs assume this.class.getClassLoader() will return non-null. That, however, is not a valid assumption for classes loaded by the bootstrap loader.

Also, while classloader functionality (such as Class.forName(..)) is available to use, and indeed can be used to load either statically compiled classes or Java bytecode, remember that loading classes out of .NET assemblies that are not referenced directly or indirectly from your application may not work without manual intervention. See the documentation for more detail on this and other hairy issues that arise when two different worlds collide!

The third and final component of IKVM is the ikvmstub compiler, which can be used to generate stubs in Java that wrap .NET classes. With this, you can write Java code that calls into .NET libraries. Note however, that the compiled Java code has to be run on the IKVM JVM. This feature, when coupled with the ikvmc command, makes Java a first-class language to develop applications targeting the .NET CLR

Usage

Let us illustrate all of this with a real-life example. XSL:FO is a W3C recommendation that describes the formatting and flow semantics for paginated presentation in an XML syntax. It is widely used for creating structured source documents for eventual transformation into printed materials. Read "What is XSL-FO?" by G. Ken Holman for an accessible introduction to this technology.

Apache FOP is an open source Java library that can convert xsl:fo files into .pdf format. It was one of the first xsl:fo processors available, and thus over the years has grown into a feature-rich and stable application. As a .NET developer, however, you would have bemoaned the lack of a quality open source FO processor that you could use. This is exactly where IKVM comes in.

To get FOP, you can either build from CVS (get the fop-0_20_2-maintain branch) or download the binary distribution and unzip the package into any directory. For our example, we will use the the normal.fo sample that is included in FOP. To create a .pdf from the xsl:fo file, we would normally use a command such as:

java -cp build/fop.jar:lib/xml-apis.jar:
    lib/xercesImpl-2.2.1.jar:
    lib/avalon-framework-cvs-20020806.jar:
    lib/batik.jar
    org.apache.fop.apps.Fop -fo normal.fo
         -pdf normal.pdf

Note: All of the commands displayed in this article have been broken up to fit a narrow web page, but need to be typed together on one line. All code and commands in this article were written and run on a Linux OS using Mono. To use in Windows, simply change the path and file-separation characters. Also note that you do not need to provide references to assemblies installed in the GAC; the framework will automatically search and resolve such references.

In exactly the same way, we can use IKVM to run FOP via dynamically compiling Java bytecodes to .NET IL:

ikvm -cp build/fop.jar:lib/xml-apis.jar:
    lib/xercesImpl-2.2.1.jar:
    lib/avalon-framework-cvs-20020806.jar:
    lib/batik.jar
    org.apache.fop.apps.Fop -fo normal.fo
         -pdf normal.pdf

And that’s it! You have successfully run a Java program — a reasonably complex program, for which no .NET equivalent exists — within the .NET Framework. However, this is not all. You can now make calls to FOP methods from within a C# program!

First you need to compile the FOP .jar and its dependencies into .NET assemblies. Note that you do not necessarily need to compile all dependencies; IKVM will happily mix .NET and Java by loading some classes from Java bytecodes at runtime.

ikvmc -target:library
     -reference:/usr/lib/IKVM.GNU.Classpath.dll
     lib/xml-apis.jar

ikvmc -target:library
     -reference:/usr/lib/IKVM.GNU.Classpath.dll
     -reference:xml-apis.dll
     lib/xercesImpl-2.2.1.jar

ikvmc -target:library
    -reference:/usr/lib/IKVM.GNU.Classpath.dll
    -reference:xml-apis.dll
    lib/avalon-framework-cvs-20020806.jar

ikvmc -target:library
    -reference:/usr/lib/IKVM.GNU.Classpath.dll
    -reference:xml-apis.dll
    lib/batik.jar

ikvmc -target:library
   -reference:/usr/lib/IKVM.GNU.Classpath.dll
   -reference:xml-apis.dll -reference:batik.dll
   build/fop.jar

This will give you the following .NET assemblies in your current directory:

avalon-framework-cvs-20020806.dll  batik.dll
fop.dll  xercesImpl-2.2.1.dll  xml-apis.dll

Now load up your favorite IDE (for example, VisualStudio in Windows or MonoDevelop on Linux), and add references to these .dlls in your project. And voilà! Your favorite Java project is ready to be used from within .NET programs. For example, the following simple code in C# is used to call FOP’s Driver class to transform an xsl:fo file into a .pdf file:

// Main.cs
using System;
using org.apache.fop.apps;
using ikvm.lang;

class MainClass
{
   public static void Main(string[] args)
   {
    //Load assemblies that are not directly
    //referenced since no CLASSPATH is defined
     AppDomain.CurrentDomain.Load("xercesImpl-2.2.1");
     AppDomain.CurrentDomain.Load("batik");
     java.lang.System.setProperty(
       "javax.xml.parsers.SAXParserFactory",
       "org.apache.xerces.jaxp.SAXParserFactoryImpl");

     java.io.FileOutputStream fs = new
          java.io.FileOutputStream("normal.pdf");
     org.xml.sax.InputSource isrc = new
          org.xml.sax.InputSource("normal.fo");
     Driver driver = new Driver(isrc, fs);
     driver.setRenderer(Driver.RENDER_PDF);
     driver.run();
   }
}

If you have downloaded a binary of FOP 0.20.5, you will need a patched version of fop.jar to successfully run the above code. This is fixed in later CVS versions. The patch is for the bootstrap classloader problem mentioned earlier.

This gives a flavor of what can be done with IKVM. There is, of course, a lot of technology that goes under to covers to achieve this, but that is a topic large enough for another article.

Status

The JVM implementation of IKVM is reasonably complete. It has, for example, full support for reflection, as well as JNI. However, it is well known that to ship a JVM, the most effort has to go into the implementation of the standard libraries. In this regard, IKVM leverages the GNU Classpath project, and therefore has as much support for the standard libraries as GNU Classpath. Thus, IKVM today can run many complex server-side Java libraries. The weak point is the GUI capabilities, not only for the immature (though rapidly improving) implementation of AWT and Swing in GNU Classpath, but also the fact that the AWT peers need to be natively implemented in IKVM. This is where the project is most in need of contributions.

Conclusion

IKVM breaks down the barriers between Java and .NET, probably two of the most significant language platforms of the day. In the sometimes adversarial atmosphere between the two communities, this can be viewed with concern by many Java developers, since the barrier of interoperability against a large installed library base is not longer sufficient to protect your skills. However, one can also see it as an opportunity, increasing the range of target platforms on which the Java programmer may utilize his skills. I think IKVM eventually makes language bigotry the loser, and the winner is that old cliché — "the right tool for the job."

Avik Sengupta is the CTO at Itellix Software Solutions and a contributor to the