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 : IDisposable {
\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
52 _imageFormat = MimeTypesToImageFormat( value.getOriginatingProvider().getMIMETypes() );
\r
55 internal imageio.ImageWriter NativeWriter {
\r
56 get { return _nativeWriter; }
\r
58 _nativeWriter = value;
\r
61 _imageFormat = MimeTypesToImageFormat( value.getOriginatingProvider().getMIMETypes() );
\r
65 internal stream.ImageInputStream NativeStream {
\r
66 get { return _nativeStream; }
\r
68 _nativeStream = value;
\r
72 if (NativeReader != null)
\r
73 NativeReader.setInput( value );
\r
75 if (NativeWriter != null)
\r
76 NativeWriter.setOutput( value );
\r
82 #region ImageCodec factory methods
\r
84 public static ImageCodec CreateReader(stream.ImageInputStream inputStream) {
\r
85 java.util.Iterator iter = imageio.ImageIO.getImageReaders( inputStream );
\r
86 return CreateReader(iter);
\r
89 public static ImageCodec CreateReader(ImageFormat imageFormat) {
\r
90 return CreateReader( ImageFormatToClsid( imageFormat ) );
\r
93 public static ImageCodec CreateReader(Guid clsid) {
\r
94 ImageCodec codec = null;
\r
96 ImageCodecInfo codecInfo = (ImageCodecInfo) Decoders[clsid];
\r
97 java.util.Iterator iter = imageio.ImageIO.getImageReadersByMIMEType( codecInfo.MimeType );
\r
98 codec = CreateReader(iter);
\r
102 if (codec == null) {
\r
103 ImageFormat format = ClsidToImageFormat(clsid);
\r
104 string name = (format != null) ? format.ToString() : clsid.ToString();
\r
105 throw new NotSupportedException(String.Format("The '{0}' format decoder is not installed.", name));
\r
111 private static ImageCodec CreateReader(java.util.Iterator iter) {
\r
112 if ( !iter.hasNext() )
115 ImageCodec imageCodec = new ImageCodec();
\r
116 imageCodec.NativeReader = (imageio.ImageReader) iter.next();
\r
120 public static ImageCodec CreateWriter(ImageFormat imageFormat) {
\r
121 return CreateWriter( ImageFormatToClsid( imageFormat ) );
\r
124 public static ImageCodec CreateWriter(Guid clsid) {
\r
125 ImageCodec codec = null;
\r
127 ImageCodecInfo codecInfo = (ImageCodecInfo) Encoders[clsid];
\r
128 java.util.Iterator iter = imageio.ImageIO.getImageWritersByMIMEType( codecInfo.MimeType );
\r
129 codec = CreateWriter(iter);
\r
133 if (codec == null) {
\r
134 ImageFormat format = ClsidToImageFormat(clsid);
\r
135 string name = (format != null) ? format.ToString() : clsid.ToString();
\r
136 throw new NotSupportedException(String.Format("The '{0}' format encoder is not installed.", name));
\r
142 private static ImageCodec CreateWriter(java.util.Iterator iter) {
\r
143 if ( !iter.hasNext() )
146 ImageCodec imageCodec = new ImageCodec();
\r
147 imageCodec.NativeWriter = (imageio.ImageWriter) iter.next();
\r
153 #region Codec enumerations
\r
155 internal static Hashtable Decoders {
157 const string MYNAME = "System.Drawing.Imaging.ImageCodecInfo.decoders";
158 Hashtable o = (Hashtable) AppDomain.CurrentDomain.GetData (MYNAME);
161 o = new ReaderSpiIterator().Iterate();
162 AppDomain.CurrentDomain.SetData(MYNAME, o);
167 internal static Hashtable Encoders {
169 const string MYNAME = "System.Drawing.Imaging.ImageCodecInfo.encoders";
170 Hashtable o = (Hashtable) AppDomain.CurrentDomain.GetData (MYNAME);
173 o = new WriterSpiIterator().Iterate();
174 AppDomain.CurrentDomain.SetData(MYNAME, o);
179 internal static ImageCodecInfo FindEncoder (Guid clsid) {
180 return (ImageCodecInfo) Encoders[clsid];
183 internal static ImageCodecInfo FindDecoder (Guid clsid) {
184 return (ImageCodecInfo) Decoders[clsid];
191 abstract class BaseSpiIterator {
192 protected abstract java.util.Iterator GetIterator (string mimeType);
193 protected abstract spi.ImageReaderWriterSpi GetNext (java.util.Iterator iter);
195 #region ProcessOneCodec
196 private ImageCodecInfo ProcessOneCodec (Guid clsid, Guid formatID, string mimeType) {
197 ImageCodecInfo ici = new ImageCodecInfo ();
199 ici.FormatID = formatID;
200 ici.MimeType = mimeType;
201 java.util.Iterator iter = GetIterator (mimeType);
202 while (iter.hasNext ()) {
203 spi.ImageReaderWriterSpi rw = GetNext (iter);
205 ici.CodecName = rw.getDescription (java.util.Locale.getDefault ());
207 foreach (string suffix in rw.getFileSuffixes ()) {
208 if (ici.FilenameExtension != null)
209 ici.FilenameExtension += ";";
210 ici.FilenameExtension += "*."+suffix;
212 ici.Flags = ImageCodecFlags.Builtin|ImageCodecFlags.SupportBitmap;
213 if (rw is spi.ImageReaderSpi) {
214 ici.Flags |= ImageCodecFlags.Decoder;
215 if ((rw as spi.ImageReaderSpi).getImageWriterSpiNames().Length != 0)
216 ici.Flags |= ImageCodecFlags.Encoder;
218 if (rw is spi.ImageWriterSpi) {
219 ici.Flags |= ImageCodecFlags.Encoder;
220 if ((rw as spi.ImageWriterSpi).getImageReaderSpiNames().Length != 0)
221 ici.Flags |= ImageCodecFlags.Decoder;
223 ici.FormatDescription = string.Join(";",
224 rw.getFormatNames());
225 ici.Version = (int)Convert.ToDouble(rw.getVersion ());
235 internal Hashtable Iterate () {
236 // TBD: Insert Exception handling here
237 NameValueCollection nvc = (NameValueCollection) System.Configuration.ConfigurationSettings
238 .GetConfig ("system.drawing/codecs");
239 Hashtable codecs = new Hashtable (10);
241 for (int i=0; i<nvc.Count; i++) {
242 Guid clsid = new Guid (nvc.GetKey (i));
243 ImageFormat format = ClsidToImageFormat (clsid);
244 ImageCodecInfo codec = ProcessOneCodec (clsid, format.Guid, nvc[i]);
245 if (codec.FilenameExtension != null)
246 codecs [clsid] = codec;
252 class ReaderSpiIterator: BaseSpiIterator {
253 protected override java.util.Iterator GetIterator(string mimeType) {
\r
254 return imageio.ImageIO.getImageReadersByMIMEType (mimeType);
\r
256 protected override javax.imageio.spi.ImageReaderWriterSpi GetNext(java.util.Iterator iter) {
\r
257 imageio.ImageReader r = (imageio.ImageReader) iter.next ();
\r
258 return r.getOriginatingProvider ();
\r
262 class WriterSpiIterator: BaseSpiIterator {
263 protected override java.util.Iterator GetIterator(string mimeType) {
\r
264 return imageio.ImageIO.getImageWritersByMIMEType (mimeType);
\r
266 protected override javax.imageio.spi.ImageReaderWriterSpi GetNext(java.util.Iterator iter) {
\r
267 imageio.ImageWriter w = (imageio.ImageWriter) iter.next ();
\r
268 return w.getOriginatingProvider ();
\r
273 #region Clsid and FormatID
274 static Guid BmpClsid = new Guid ("557cf400-1a04-11d3-9a73-0000f81ef32e");
275 static Guid JpegClsid = new Guid ("557cf401-1a04-11d3-9a73-0000f81ef32e");
276 static Guid GifClsid = new Guid ("557cf402-1a04-11d3-9a73-0000f81ef32e");
277 static Guid EmfClsid = new Guid ("557cf403-1a04-11d3-9a73-0000f81ef32e");
278 static Guid WmfClsid = new Guid ("557cf404-1a04-11d3-9a73-0000f81ef32e");
279 static Guid TiffClsid = new Guid ("557cf405-1a04-11d3-9a73-0000f81ef32e");
280 static Guid PngClsid = new Guid ("557cf406-1a04-11d3-9a73-0000f81ef32e");
281 static Guid IconClsid = new Guid ("557cf407-1a04-11d3-9a73-0000f81ef32e");
283 private static ImageFormat MimeTypesToImageFormat (string [] mimeTypes) {
284 foreach (ImageCodecInfo codec in Decoders.Values)
285 for (int i=0; i<mimeTypes.Length; i++)
286 if (codec.MimeType == mimeTypes [i])
287 return new ImageFormat (codec.FormatID);
291 internal static ImageFormat ClsidToImageFormat (Guid clsid) {
292 if (clsid.Equals (BmpClsid))
293 return ImageFormat.Bmp;
294 else if (clsid.Equals (JpegClsid))
295 return ImageFormat.Jpeg;
296 else if (clsid.Equals (GifClsid))
297 return ImageFormat.Gif;
298 else if (clsid.Equals (EmfClsid))
299 return ImageFormat.Emf;
300 else if (clsid.Equals (WmfClsid))
301 return ImageFormat.Wmf;
302 else if (clsid.Equals (TiffClsid))
303 return ImageFormat.Tiff;
304 else if (clsid.Equals (PngClsid))
305 return ImageFormat.Png;
306 else if (clsid.Equals (IconClsid))
307 return ImageFormat.Icon;
312 internal static Guid ImageFormatToClsid (ImageFormat format) {
316 if (format.Guid.Equals (ImageFormat.Bmp.Guid))
318 else if (format.Guid.Equals (ImageFormat.Jpeg.Guid))
320 else if (format.Guid.Equals (ImageFormat.Gif))
322 else if (format.Guid.Equals (ImageFormat.Emf.Guid))
324 else if (format.Guid.Equals (ImageFormat.Wmf.Guid))
326 else if (format.Guid.Equals (ImageFormat.Tiff.Guid))
328 else if (format.Guid.Equals (ImageFormat.Png.Guid))
330 else if (format.Guid.Equals (ImageFormat.Icon.Guid))
336 private FrameDimension FormatFrameDimesion {
338 if (ImageFormat == null)
339 return FrameDimension.Page;
341 if (ImageFormat.Guid.Equals (ImageFormat.Bmp.Guid))
342 return FrameDimension.Page;
343 else if (ImageFormat.Guid.Equals (ImageFormat.Jpeg.Guid))
344 return FrameDimension.Page;
345 else if (ImageFormat.Guid.Equals (ImageFormat.Gif))
346 return FrameDimension.Time;
347 else if (ImageFormat.Guid.Equals (ImageFormat.Emf.Guid))
348 return FrameDimension.Page;
349 else if (ImageFormat.Guid.Equals (ImageFormat.Wmf.Guid))
350 return FrameDimension.Page;
351 else if (ImageFormat.Guid.Equals (ImageFormat.Tiff.Guid))
352 return FrameDimension.Page;
353 else if (ImageFormat.Guid.Equals (ImageFormat.Png.Guid))
354 return FrameDimension.Page;
355 else if (ImageFormat.Guid.Equals (ImageFormat.Icon.Guid))
356 return FrameDimension.Resolution;
358 return FrameDimension.Page;
364 #region Image read/write methods
\r
366 public PlainImage ReadPlainImage() {
\r
367 awt.Image img = ReadImage( _currentFrame );
\r
371 // its possible to fail to load thumbnails and metadata, but image is ok.
\r
372 awt.Image [] th = null;
\r
373 #if THUMBNAIL_SUPPORTED
\r
375 th = ReadThumbnails( _currentFrame );
\r
377 catch (Exception) {}
\r
380 XmlDocument md = null;
\r
381 imageio.metadata.IIOMetadata nativeMd = null;
\r
383 nativeMd = ReadImageMetadata( _currentFrame );
\r
384 md = ConvertImageMetadata( nativeMd );
\r
386 catch (Exception) {}
\r
388 float [] resolution = GetResolution( md );
\r
390 PlainImage pi = new PlainImage( img, th, ImageFormat, resolution[0], resolution[1], FormatFrameDimesion );
\r
391 pi.NativeMetadata = nativeMd;
\r
395 public PlainImage ReadNextPlainImage() {
\r
397 return ReadPlainImage();
\r
400 private awt.Image ReadImage(int frame) {
\r
401 if (NativeStream == null)
\r
402 throw new Exception("Input stream not specified");
\r
405 return NativeReader.read (frame);
407 catch (java.lang.IndexOutOfBoundsException) {
410 catch (java.io.IOException ex) {
411 throw new System.IO.IOException(ex.Message, ex);
415 #if THUMBNAIL_SUPPORTED
\r
416 private awt.Image [] ReadThumbnails(int frameIndex) {
\r
417 awt.Image [] thArray = null;
420 if (NativeReader.readerSupportsThumbnails()) {
421 int tmbNumber = NativeReader.getNumThumbnails(frameIndex);
424 thArray = new awt.Image[ tmbNumber ];
426 for (int i = 0; i < tmbNumber; i++) {
427 thArray[i] = NativeReader.readThumbnail(frameIndex, i);
433 catch (java.io.IOException ex) {
434 throw new System.IO.IOException(ex.Message, ex);
438 public void WritePlainImage(PlainImageCollection pic) {
\r
439 if ((pic == null) || (pic.Count == 0))
\r
442 if (pic.Count == 1) {
\r
443 WritePlainImage( pic[0] );
\r
448 if (NativeWriter.canWriteSequence ()) {
\r
449 NativeWriter.prepareWriteSequence (null);
\r
450 for (int i=0; i < pic.Count; i++) {
\r
451 imageio.IIOImage iio = GetIIOImageContainer( pic[i] );
\r
452 NativeWriter.writeToSequence (iio, null);
\r
454 NativeWriter.endWriteSequence ();
\r
457 WritePlainImage( pic[0] );
\r
459 catch (java.io.IOException ex) {
460 throw new System.IO.IOException(ex.Message, ex);
464 public void WritePlainImage(PlainImage pi) {
\r
466 imageio.IIOImage iio = GetIIOImageContainer( pi );
\r
469 catch (java.io.IOException ex) {
470 throw new System.IO.IOException(ex.Message, ex);
474 private void WriteImage(imageio.IIOImage iio) {
\r
475 if (NativeStream == null)
\r
476 throw new Exception("Output stream not specified");
\r
478 NativeWriter.write( iio );
\r
479 NativeStream.flush();
\r
482 private imageio.IIOImage GetIIOImageContainer(PlainImage pi) {
\r
483 java.util.ArrayList al = null;
\r
485 // prepare thumbnails list
\r
486 if (pi.Thumbnails != null) {
\r
487 al = new java.util.ArrayList( pi.Thumbnails.Length );
\r
488 for (int i=0; i < pi.Thumbnails.Length; i++)
\r
489 al.add(pi.Thumbnails[i]);
\r
492 // prepare IIOImage container
\r
493 if (pi.NativeImage is image.BufferedImage) {
\r
494 imageio.IIOImage iio = new javax.imageio.IIOImage(
\r
495 (image.BufferedImage)pi.NativeImage, al, null /*pi.NativeMetadata*/);
\r
499 // TBD: This codec is for raster formats only
\r
500 throw new NotSupportedException("Only raster formats are supported");
\r
504 private imageio.metadata.IIOMetadata ReadImageMetadata(int frameIndex) {
\r
505 if (NativeStream == null)
\r
506 throw new Exception("Input stream not specified");
\r
509 imageio.metadata.IIOMetadata md = NativeReader.getImageMetadata( frameIndex );
\r
512 catch (java.io.IOException ex) {
513 throw new System.IO.IOException(ex.Message, ex);
519 #region Extra properties
\r
521 public ImageFormat ImageFormat {
\r
522 get { return _imageFormat; }
\r
527 #region Metadata parse
\r
529 private float [] GetResolution(XmlDocument metaData) {
\r
530 if (metaData == null)
\r
531 return new float[]{0, 0};
\r
533 ResolutionConfigurationCollection rcc =
534 (ResolutionConfigurationCollection)
535 ConfigurationSettings.GetConfig("system.drawing/codecsmetadata");
538 throw new ConfigurationException("Configuration section codecsmetadata not found");
540 ResolutionConfiguration rc = rcc[ ImageFormat.ToString() ];
543 return new float[]{0, 0};
545 // Horizontal resolution
546 string xResPath = rc.XResPath;
549 if (xResPath == string.Empty)
550 xRes = rc.XResDefault;
552 xRes = GetValueFromMetadata(metaData, xResPath);
554 if ((xRes == null) || (xRes == string.Empty))
555 xRes = rc.XResDefault;
557 // Vertical resolution
558 string yResPath = rc.YResPath;
561 if (yResPath == string.Empty)
562 yRes = rc.YResDefault;
564 yRes = GetValueFromMetadata(metaData, yResPath);
566 if ((yRes == null) || (yRes == string.Empty))
567 yRes = rc.YResDefault;
570 string resUnitsPath = rc.UnitsTypePath;
573 if (resUnitsPath == string.Empty)
574 resUnitsType = rc.UnitsTypeDefault;
576 resUnitsType = GetValueFromMetadata(metaData, resUnitsPath);
578 if (resUnitsType == null)
579 resUnitsType = rc.UnitsTypeDefault;
582 string unitScale = rc.UnitsScale[resUnitsType].ToString();
584 // Adjust resolution to its units
585 float [] res = new float[2];
586 res[0] = ParseFloatValue(xRes) * ParseFloatValue(unitScale);
587 res[1] = ParseFloatValue(yRes) * ParseFloatValue(unitScale);
592 private string GetValueFromMetadata(XmlDocument metaData, string path) {
\r
593 XmlNode n = metaData.SelectSingleNode(path);
\r
597 return n.InnerText;
\r
600 private XmlDocument ConvertImageMetadata(imageio.metadata.IIOMetadata metaData) {
\r
601 string [] formatNames = metaData.getMetadataFormatNames();
602 dom.Element rootNode = (dom.Element) metaData.getAsTree(formatNames[0]);
604 XmlDocument _metadataDocument = new XmlDocument();
\r
605 XmlConvert(rootNode, _metadataDocument);
\r
607 return _metadataDocument;
\r
610 private void XmlConvert(dom.Node jNode, XmlNode nNode) {
\r
611 XmlDocument document = nNode.OwnerDocument;
\r
612 if (document == null)
\r
613 document = (XmlDocument)nNode;
\r
616 switch (jNode.getNodeType()) {
\r
618 n = document.CreateNode(XmlNodeType.Element, jNode.getNodeName(), jNode.getNamespaceURI());
\r
622 n = document.CreateNode(XmlNodeType.CDATA, jNode.getNodeName(), jNode.getNamespaceURI());
\r
629 n.InnerText = jNode.getNodeValue();
\r
630 nNode.AppendChild( n );
\r
633 org.w3c.dom.NamedNodeMap nm = jNode.getAttributes();
\r
634 for (int i=0; i<nm.getLength(); i++) {
\r
635 XmlAttribute a = document.CreateAttribute( nm.item(i).getNodeName() );
\r
636 a.Value = nm.item(i).getNodeValue();
\r
637 n.Attributes.Append( a );
\r
641 org.w3c.dom.NodeList nl = jNode.getChildNodes();
\r
642 for (int i=0; i<nl.getLength(); i++) {
\r
643 XmlConvert(nl.item(i), n);
\r
647 protected virtual float ParseFloatValue(string strValue) {
\r
649 if ((strValue != null) && (strValue != "")) {
650 int dividerPos = strValue.IndexOf("/");
652 if (dividerPos < 0) {
653 return float.Parse(strValue);
656 return float.Parse(strValue.Substring( 0, dividerPos )) /
657 float.Parse(strValue.Substring( dividerPos + 1 ));
662 catch (Exception) {
\r
669 #region IDisposable members
\r
671 public void Dispose() {
\r
672 if (NativeReader != null) {
\r
673 NativeReader.dispose();
\r
674 NativeReader = null;
\r
677 if (NativeWriter != null) {
\r
678 NativeWriter.dispose();
\r
679 NativeWriter = null;
\r