2 using System.Configuration;
\r
3 using System.Collections;
\r
4 using System.Collections.Specialized;
\r
5 using System.Drawing.Imaging;
\r
7 using Mainsoft.Drawing.Configuration;
\r
9 using imageio = javax.imageio;
\r
10 using stream = javax.imageio.stream;
\r
11 using awt = java.awt;
\r
12 using image = java.awt.image;
\r
13 using spi = javax.imageio.spi;
\r
14 using dom = org.w3c.dom;
\r
16 namespace Mainsoft.Drawing.Imaging {
\r
18 /// Summary description for ImageCodec.
\r
20 public class ImageCodec {
\r
24 imageio.ImageReader _nativeReader = null;
\r
25 imageio.ImageWriter _nativeWriter = null;
\r
26 stream.ImageInputStream _nativeStream = null;
\r
28 ImageFormat _imageFormat = null;
\r
30 int _currentFrame = 0;
\r
34 #region Constructros
\r
36 protected ImageCodec() {
\r
39 static ImageCodec() {
\r
44 #region Internal properties
\r
46 internal imageio.ImageReader NativeReader {
\r
47 get { return _nativeReader; }
\r
49 _nativeReader = value;
\r
50 _imageFormat = MimeTypesToImageFormat( value.getOriginatingProvider().getMIMETypes() );
\r
53 internal imageio.ImageWriter NativeWriter {
\r
54 get { return _nativeWriter; }
\r
56 _nativeWriter = value;
\r
57 _imageFormat = MimeTypesToImageFormat( value.getOriginatingProvider().getMIMETypes() );
\r
61 internal stream.ImageInputStream NativeStream {
\r
62 get { return _nativeStream; }
\r
65 throw new ArgumentNullException("stream");
\r
67 _nativeStream = value;
\r
69 if (NativeReader != null)
\r
70 NativeReader.setInput( value );
\r
72 if (NativeWriter != null)
\r
73 NativeWriter.setOutput( value );
\r
79 #region ImageCodec factory methods
\r
81 public static ImageCodec CreateReader(stream.ImageInputStream inputStream) {
\r
82 java.util.Iterator iter = imageio.ImageIO.getImageReaders( inputStream );
\r
83 return CreateReader(iter);
\r
86 public static ImageCodec CreateReader(ImageFormat imageFormat) {
\r
87 return CreateReader( ImageFormatToClsid( imageFormat ) );
\r
90 public static ImageCodec CreateReader(Guid clsid) {
\r
91 ImageCodecInfo codecInfo = (ImageCodecInfo) Decoders[clsid];
\r
92 java.util.Iterator iter = imageio.ImageIO.getImageReadersByMIMEType( codecInfo.MimeType );
\r
93 return CreateReader(iter);
\r
96 private static ImageCodec CreateReader(java.util.Iterator iter) {
\r
97 if ( !iter.hasNext() )
98 throw new OutOfMemoryException ("Out of memory");
100 ImageCodec imageCodec = new ImageCodec();
\r
101 imageCodec.NativeReader = (imageio.ImageReader) iter.next();
\r
105 public static ImageCodec CreateWriter(ImageFormat imageFormat) {
\r
106 return CreateWriter( ImageFormatToClsid( imageFormat ) );
\r
109 public static ImageCodec CreateWriter(Guid clsid) {
\r
110 ImageCodecInfo codecInfo = (ImageCodecInfo) Encoders[clsid];
\r
111 java.util.Iterator iter = imageio.ImageIO.getImageWritersByMIMEType( codecInfo.MimeType );
\r
112 return CreateWriter(iter);
\r
115 public static ImageCodec CreateWriter(java.util.Iterator iter) {
\r
116 if ( !iter.hasNext() )
117 throw new OutOfMemoryException ("Out of memory");
119 ImageCodec imageCodec = new ImageCodec();
\r
120 imageCodec.NativeWriter = (imageio.ImageWriter) iter.next();
\r
126 #region Codec enumerations
\r
128 internal static Hashtable Decoders {
130 const string MYNAME = "System.Drawing.Imaging.ImageCodecInfo.decoders";
131 Hashtable o = (Hashtable) AppDomain.CurrentDomain.GetData (MYNAME);
134 o = new ReaderSpiIterator().Iterate();
135 AppDomain.CurrentDomain.SetData(MYNAME, o);
140 internal static Hashtable Encoders {
142 const string MYNAME = "System.Drawing.Imaging.ImageCodecInfo.encoders";
143 Hashtable o = (Hashtable) AppDomain.CurrentDomain.GetData (MYNAME);
146 o = new WriterSpiIterator().Iterate();
147 AppDomain.CurrentDomain.SetData(MYNAME, o);
152 internal static ImageCodecInfo FindEncoder (Guid clsid) {
153 return (ImageCodecInfo) Encoders[clsid];
156 internal static ImageCodecInfo FindDecoder (Guid clsid) {
157 return (ImageCodecInfo) Decoders[clsid];
164 abstract class BaseSpiIterator {
165 protected abstract java.util.Iterator GetIterator (string mimeType);
166 protected abstract spi.ImageReaderWriterSpi GetNext (java.util.Iterator iter);
168 #region ProcessOneCodec
169 private ImageCodecInfo ProcessOneCodec (Guid clsid, Guid formatID, string mimeType) {
170 ImageCodecInfo ici = new ImageCodecInfo ();
172 ici.FormatID = formatID;
173 ici.MimeType = mimeType;
174 java.util.Iterator iter = GetIterator (mimeType);
175 while (iter.hasNext ()) {
176 spi.ImageReaderWriterSpi rw = GetNext (iter);
178 ici.CodecName = rw.getDescription (java.util.Locale.getDefault ());
180 foreach (string suffix in rw.getFileSuffixes ()) {
181 if (ici.FilenameExtension != null)
182 ici.FilenameExtension += ";";
183 ici.FilenameExtension += "*."+suffix;
185 ici.Flags = ImageCodecFlags.Builtin|ImageCodecFlags.SupportBitmap;
186 if (rw is spi.ImageReaderSpi) {
187 ici.Flags |= ImageCodecFlags.Decoder;
188 if ((rw as spi.ImageReaderSpi).getImageWriterSpiNames().Length != 0)
189 ici.Flags |= ImageCodecFlags.Encoder;
191 if (rw is spi.ImageWriterSpi) {
192 ici.Flags |= ImageCodecFlags.Encoder;
193 if ((rw as spi.ImageWriterSpi).getImageReaderSpiNames().Length != 0)
194 ici.Flags |= ImageCodecFlags.Decoder;
196 ici.FormatDescription = string.Join(";",
197 rw.getFormatNames());
198 ici.Version = (int)Convert.ToDouble(rw.getVersion ());
208 internal Hashtable Iterate () {
209 // TBD: Insert Exception handling here
210 NameValueCollection nvc = (NameValueCollection) System.Configuration.ConfigurationSettings
211 .GetConfig ("system.drawing/codecs");
212 Hashtable codecs = new Hashtable (10);
214 for (int i=0; i<nvc.Count; i++) {
215 Guid clsid = new Guid (nvc.GetKey (i));
216 ImageFormat format = ClsidToImageFormat (clsid);
217 ImageCodecInfo codec = ProcessOneCodec (clsid, format.Guid, nvc[i]);
218 if (codec.FilenameExtension != null)
219 codecs [clsid] = codec;
225 class ReaderSpiIterator: BaseSpiIterator {
226 protected override java.util.Iterator GetIterator(string mimeType) {
\r
227 return imageio.ImageIO.getImageReadersByMIMEType (mimeType);
\r
229 protected override javax.imageio.spi.ImageReaderWriterSpi GetNext(java.util.Iterator iter) {
\r
230 imageio.ImageReader r = (imageio.ImageReader) iter.next ();
\r
231 return r.getOriginatingProvider ();
\r
235 class WriterSpiIterator: BaseSpiIterator {
236 protected override java.util.Iterator GetIterator(string mimeType) {
\r
237 return imageio.ImageIO.getImageWritersByMIMEType (mimeType);
\r
239 protected override javax.imageio.spi.ImageReaderWriterSpi GetNext(java.util.Iterator iter) {
\r
240 imageio.ImageWriter w = (imageio.ImageWriter) iter.next ();
\r
241 return w.getOriginatingProvider ();
\r
246 #region Clsid and FormatID
247 static Guid BmpClsid = new Guid ("557cf400-1a04-11d3-9a73-0000f81ef32e");
248 static Guid JpegClsid = new Guid ("557cf401-1a04-11d3-9a73-0000f81ef32e");
249 static Guid GifClsid = new Guid ("557cf402-1a04-11d3-9a73-0000f81ef32e");
250 static Guid EmfClsid = new Guid ("557cf403-1a04-11d3-9a73-0000f81ef32e");
251 static Guid WmfClsid = new Guid ("557cf404-1a04-11d3-9a73-0000f81ef32e");
252 static Guid TiffClsid = new Guid ("557cf405-1a04-11d3-9a73-0000f81ef32e");
253 static Guid PngClsid = new Guid ("557cf406-1a04-11d3-9a73-0000f81ef32e");
254 static Guid IconClsid = new Guid ("557cf407-1a04-11d3-9a73-0000f81ef32e");
256 private static ImageFormat MimeTypesToImageFormat (string [] mimeTypes) {
257 foreach (ImageCodecInfo codec in Decoders.Values)
258 for (int i=0; i<mimeTypes.Length; i++)
259 if (codec.MimeType == mimeTypes [i])
260 return new ImageFormat (codec.FormatID);
264 internal static ImageFormat ClsidToImageFormat (Guid clsid) {
265 if (clsid.Equals (BmpClsid))
266 return ImageFormat.Bmp;
267 else if (clsid.Equals (JpegClsid))
268 return ImageFormat.Jpeg;
269 else if (clsid.Equals (GifClsid))
270 return ImageFormat.Gif;
271 else if (clsid.Equals (EmfClsid))
272 return ImageFormat.Emf;
273 else if (clsid.Equals (WmfClsid))
274 return ImageFormat.Wmf;
275 else if (clsid.Equals (TiffClsid))
276 return ImageFormat.Tiff;
277 else if (clsid.Equals (PngClsid))
278 return ImageFormat.Png;
279 else if (clsid.Equals (IconClsid))
280 return ImageFormat.Icon;
285 internal static Guid ImageFormatToClsid (ImageFormat format) {
289 if (format.Guid.Equals (ImageFormat.Bmp.Guid))
291 else if (format.Guid.Equals (ImageFormat.Jpeg.Guid))
293 else if (format.Guid.Equals (ImageFormat.Gif))
295 else if (format.Guid.Equals (ImageFormat.Emf.Guid))
297 else if (format.Guid.Equals (ImageFormat.Wmf.Guid))
299 else if (format.Guid.Equals (ImageFormat.Tiff.Guid))
301 else if (format.Guid.Equals (ImageFormat.Png.Guid))
303 else if (format.Guid.Equals (ImageFormat.Icon.Guid))
309 private FrameDimension FormatFrameDimesion {
311 if (ImageFormat == null)
312 return FrameDimension.Page;
314 if (ImageFormat.Guid.Equals (ImageFormat.Bmp.Guid))
315 return FrameDimension.Page;
316 else if (ImageFormat.Guid.Equals (ImageFormat.Jpeg.Guid))
317 return FrameDimension.Page;
318 else if (ImageFormat.Guid.Equals (ImageFormat.Gif))
319 return FrameDimension.Time;
320 else if (ImageFormat.Guid.Equals (ImageFormat.Emf.Guid))
321 return FrameDimension.Page;
322 else if (ImageFormat.Guid.Equals (ImageFormat.Wmf.Guid))
323 return FrameDimension.Page;
324 else if (ImageFormat.Guid.Equals (ImageFormat.Tiff.Guid))
325 return FrameDimension.Page;
326 else if (ImageFormat.Guid.Equals (ImageFormat.Png.Guid))
327 return FrameDimension.Page;
328 else if (ImageFormat.Guid.Equals (ImageFormat.Icon.Guid))
329 return FrameDimension.Resolution;
331 return FrameDimension.Page;
337 #region Image read/write methods
\r
339 public PlainImage ReadPlainImage() {
\r
340 awt.Image img = ReadImage( _currentFrame );
\r
344 // its possible to fail to load thumbnails and metadata, but image is ok.
\r
345 awt.Image [] th = null;
\r
346 #if THUMBNAIL_SUPPORTED
\r
348 th = ReadThumbnails( _currentFrame );
\r
350 catch (Exception) {}
\r
353 XmlDocument md = null;
\r
354 imageio.metadata.IIOMetadata nativeMd = null;
\r
356 nativeMd = ReadImageMetadata( _currentFrame );
\r
357 md = ConvertImageMetadata( nativeMd );
\r
359 catch (Exception) {}
\r
361 float [] resolution = GetResolution( md );
\r
363 PlainImage pi = new PlainImage( img, th, ImageFormat, resolution[0], resolution[1], FormatFrameDimesion );
\r
364 pi.NativeMetadata = nativeMd;
\r
368 public PlainImage ReadNextPlainImage() {
\r
370 return ReadPlainImage();
\r
373 private awt.Image ReadImage(int frame) {
\r
374 if (NativeStream == null)
\r
375 throw new Exception("Input stream not specified");
\r
378 return NativeReader.read (frame);
380 catch (java.lang.IndexOutOfBoundsException) {
383 catch (java.io.IOException ex) {
384 throw new System.IO.IOException(ex.Message, ex);
388 #if THUMBNAIL_SUPPORTED
\r
389 private awt.Image [] ReadThumbnails(int frameIndex) {
\r
390 awt.Image [] thArray = null;
393 if (NativeReader.readerSupportsThumbnails()) {
394 int tmbNumber = NativeReader.getNumThumbnails(frameIndex);
397 thArray = new awt.Image[ tmbNumber ];
399 for (int i = 0; i < tmbNumber; i++) {
400 thArray[i] = NativeReader.readThumbnail(frameIndex, i);
406 catch (java.io.IOException ex) {
407 throw new System.IO.IOException(ex.Message, ex);
411 public void WritePlainImage(PlainImageCollection pic) {
\r
412 if ((pic == null) || (pic.Count == 0))
\r
415 if (pic.Count == 1) {
\r
416 WritePlainImage( pic[0] );
\r
421 if (NativeWriter.canWriteSequence ()) {
\r
422 NativeWriter.prepareWriteSequence (null);
\r
423 for (int i=0; i < pic.Count; i++) {
\r
424 imageio.IIOImage iio = GetIIOImageContainer( pic[i] );
\r
425 NativeWriter.writeToSequence (iio, null);
\r
427 NativeWriter.endWriteSequence ();
\r
430 WritePlainImage( pic[0] );
\r
432 catch (java.io.IOException ex) {
433 throw new System.IO.IOException(ex.Message, ex);
437 public void WritePlainImage(PlainImage pi) {
\r
439 imageio.IIOImage iio = GetIIOImageContainer( pi );
\r
442 catch (java.io.IOException ex) {
443 throw new System.IO.IOException(ex.Message, ex);
447 private void WriteImage(imageio.IIOImage iio) {
\r
448 if (NativeStream == null)
\r
449 throw new Exception("Output stream not specified");
\r
451 NativeWriter.write( iio );
\r
454 private imageio.IIOImage GetIIOImageContainer(PlainImage pi) {
\r
455 java.util.ArrayList al = null;
\r
457 // prepare thumbnails list
\r
458 if (pi.Thumbnails != null) {
\r
459 al = new java.util.ArrayList( pi.Thumbnails.Length );
\r
460 for (int i=0; i < pi.Thumbnails.Length; i++)
\r
461 al.add(pi.Thumbnails[i]);
\r
464 // prepare IIOImage container
\r
465 if (pi.NativeImage is image.BufferedImage) {
\r
466 imageio.IIOImage iio = new javax.imageio.IIOImage(
\r
467 (image.BufferedImage)pi.NativeImage, al, pi.NativeMetadata);
\r
471 // TBD: This codec is for raster formats only
\r
472 throw new NotSupportedException("Only raster formats are supported");
\r
476 private imageio.metadata.IIOMetadata ReadImageMetadata(int frameIndex) {
\r
477 if (NativeStream == null)
\r
478 throw new Exception("Input stream not specified");
\r
481 imageio.metadata.IIOMetadata md = NativeReader.getImageMetadata( frameIndex );
\r
484 catch (java.io.IOException ex) {
485 throw new System.IO.IOException(ex.Message, ex);
491 #region Extra properties
\r
493 public ImageFormat ImageFormat {
\r
494 get { return _imageFormat; }
\r
499 #region Metadata parse
\r
501 private float [] GetResolution(XmlDocument metaData) {
\r
502 if (metaData == null)
\r
503 return new float[]{0, 0};
\r
505 ResolutionConfigurationCollection rcc =
506 (ResolutionConfigurationCollection)
507 ConfigurationSettings.GetConfig("system.drawing/codecsmetadata");
510 throw new ConfigurationException("Configuration section codecsmetadata not found");
512 ResolutionConfiguration rc = rcc[ ImageFormat.ToString() ];
515 return new float[]{0, 0};
517 // Horizontal resolution
518 string xResPath = rc.XResPath;
521 if (xResPath == string.Empty)
522 xRes = rc.XResDefault;
524 xRes = GetValueFromMetadata(metaData, xResPath);
526 if ((xRes == null) || (xRes == string.Empty))
527 xRes = rc.XResDefault;
529 // Vertical resolution
530 string yResPath = rc.YResPath;
533 if (yResPath == string.Empty)
534 yRes = rc.YResDefault;
536 yRes = GetValueFromMetadata(metaData, yResPath);
538 if ((yRes == null) || (yRes == string.Empty))
539 yRes = rc.YResDefault;
542 string resUnitsPath = rc.UnitsTypePath;
545 if (resUnitsPath == string.Empty)
546 resUnitsType = rc.UnitsTypeDefault;
548 resUnitsType = GetValueFromMetadata(metaData, resUnitsPath);
550 if (resUnitsType == null)
551 resUnitsType = rc.UnitsTypeDefault;
554 string unitScale = rc.UnitsScale[resUnitsType].ToString();
556 // Adjust resolution to its units
557 float [] res = new float[2];
558 res[0] = ParseFloatValue(xRes) * ParseFloatValue(unitScale);
559 res[1] = ParseFloatValue(yRes) * ParseFloatValue(unitScale);
564 private string GetValueFromMetadata(XmlDocument metaData, string path) {
\r
565 XmlNode n = metaData.SelectSingleNode(path);
\r
569 return n.InnerText;
\r
572 private XmlDocument ConvertImageMetadata(imageio.metadata.IIOMetadata metaData) {
\r
573 string [] formatNames = metaData.getMetadataFormatNames();
574 dom.Element rootNode = (dom.Element) metaData.getAsTree(formatNames[0]);
576 XmlDocument _metadataDocument = new XmlDocument();
\r
577 XmlConvert(rootNode, _metadataDocument);
\r
579 return _metadataDocument;
\r
582 private void XmlConvert(dom.Node jNode, XmlNode nNode) {
\r
583 XmlDocument document = nNode.OwnerDocument;
\r
584 if (document == null)
\r
585 document = (XmlDocument)nNode;
\r
588 switch (jNode.getNodeType()) {
\r
590 n = document.CreateNode(XmlNodeType.Element, jNode.getNodeName(), jNode.getNamespaceURI());
\r
594 n = document.CreateNode(XmlNodeType.CDATA, jNode.getNodeName(), jNode.getNamespaceURI());
\r
601 n.InnerText = jNode.getNodeValue();
\r
602 nNode.AppendChild( n );
\r
605 org.w3c.dom.NamedNodeMap nm = jNode.getAttributes();
\r
606 for (int i=0; i<nm.getLength(); i++) {
\r
607 XmlAttribute a = document.CreateAttribute( nm.item(i).getNodeName() );
\r
608 a.Value = nm.item(i).getNodeValue();
\r
609 n.Attributes.Append( a );
\r
613 org.w3c.dom.NodeList nl = jNode.getChildNodes();
\r
614 for (int i=0; i<nl.getLength(); i++) {
\r
615 XmlConvert(nl.item(i), n);
\r
619 protected virtual float ParseFloatValue(string strValue) {
\r
621 if ((strValue != null) && (strValue != "")) {
622 int dividerPos = strValue.IndexOf("/");
624 if (dividerPos < 0) {
625 return float.Parse(strValue);
628 return float.Parse(strValue.Substring( 0, dividerPos )) /
629 float.Parse(strValue.Substring( dividerPos + 1 ));
634 catch (Exception) {
\r