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 = FindDecoder(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 = FindEncoder(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 ImageCodecInfo codec = (ImageCodecInfo) Encoders[clsid];
182 // .net saves in png if cannot find requested encoder. atc id 316563
183 codec = (ImageCodecInfo) Encoders[ ImageCodec.PngClsid ];
188 internal static ImageCodecInfo FindDecoder (Guid clsid) {
189 ImageCodecInfo codec = (ImageCodecInfo) Decoders[clsid];
190 if (codec == null) {
\r
191 ImageFormat format = ClsidToImageFormat(clsid);
\r
192 string name = (format != null) ? format.ToString() : clsid.ToString();
\r
193 throw new NotSupportedException(String.Format("The '{0}' format decoder is not installed.", name));
\r
202 abstract class BaseSpiIterator {
203 protected abstract java.util.Iterator GetIterator (string mimeType);
204 protected abstract spi.ImageReaderWriterSpi GetNext (java.util.Iterator iter);
206 #region ProcessOneCodec
207 private ImageCodecInfo ProcessOneCodec (Guid clsid, Guid formatID, string mimeType) {
208 ImageCodecInfo ici = new ImageCodecInfo ();
210 ici.FormatID = formatID;
211 ici.MimeType = mimeType;
212 java.util.Iterator iter = null;
214 iter = GetIterator (mimeType);
219 while (iter.hasNext ()) {
220 spi.ImageReaderWriterSpi rw = GetNext (iter);
222 ici.CodecName = rw.getDescription (java.util.Locale.getDefault ());
223 //ici.DllName = null;
224 foreach (string suffix in rw.getFileSuffixes ()) {
225 if (ici.FilenameExtension != null)
226 ici.FilenameExtension += ";";
227 ici.FilenameExtension += "*."+suffix;
229 ici.Flags = ImageCodecFlags.Builtin|ImageCodecFlags.SupportBitmap;
230 if (rw is spi.ImageReaderSpi)
231 ici.Flags |= ImageCodecFlags.Decoder;
233 if (rw is spi.ImageWriterSpi)
234 ici.Flags |= ImageCodecFlags.Encoder;
236 ici.FormatDescription = string.Join(";",
237 rw.getFormatNames());
239 ici.Version = (int)Convert.ToDouble(rw.getVersion ());
250 internal Hashtable Iterate () {
251 // TBD: Insert Exception handling here
252 NameValueCollection nvc = (NameValueCollection) System.Configuration.ConfigurationSettings
\r
253 .GetConfig ("mainsoft.drawing/codecs");
254 Hashtable codecs = new Hashtable (10);
256 for (int i=0; i<nvc.Count; i++) {
257 Guid clsid = new Guid (nvc.GetKey (i));
258 ImageFormat format = ClsidToImageFormat (clsid);
259 ImageCodecInfo codec = ProcessOneCodec (clsid, format.Guid, nvc[i]);
260 if ((codec != null) && (codec.FilenameExtension != null))
261 codecs [clsid] = codec;
267 class ReaderSpiIterator: BaseSpiIterator {
268 protected override java.util.Iterator GetIterator(string mimeType) {
\r
269 return imageio.ImageIO.getImageReadersByMIMEType (mimeType);
\r
271 protected override javax.imageio.spi.ImageReaderWriterSpi GetNext(java.util.Iterator iter) {
\r
272 imageio.ImageReader r = (imageio.ImageReader) iter.next ();
\r
273 return r.getOriginatingProvider ();
\r
277 class WriterSpiIterator: BaseSpiIterator {
278 protected override java.util.Iterator GetIterator(string mimeType) {
\r
279 return imageio.ImageIO.getImageWritersByMIMEType (mimeType);
\r
281 protected override javax.imageio.spi.ImageReaderWriterSpi GetNext(java.util.Iterator iter) {
\r
282 imageio.ImageWriter w = (imageio.ImageWriter) iter.next ();
\r
283 return w.getOriginatingProvider ();
\r
288 #region Clsid and FormatID
289 static Guid BmpClsid = new Guid ("557cf400-1a04-11d3-9a73-0000f81ef32e");
290 static Guid JpegClsid = new Guid ("557cf401-1a04-11d3-9a73-0000f81ef32e");
291 static Guid GifClsid = new Guid ("557cf402-1a04-11d3-9a73-0000f81ef32e");
292 static Guid EmfClsid = new Guid ("557cf403-1a04-11d3-9a73-0000f81ef32e");
293 static Guid WmfClsid = new Guid ("557cf404-1a04-11d3-9a73-0000f81ef32e");
294 static Guid TiffClsid = new Guid ("557cf405-1a04-11d3-9a73-0000f81ef32e");
295 static Guid PngClsid = new Guid ("557cf406-1a04-11d3-9a73-0000f81ef32e");
296 static Guid IconClsid = new Guid ("557cf407-1a04-11d3-9a73-0000f81ef32e");
298 private static ImageFormat MimeTypesToImageFormat (string [] mimeTypes) {
299 foreach (ImageCodecInfo codec in Decoders.Values)
300 for (int i=0; i<mimeTypes.Length; i++)
\r
301 if (codec.MimeType == mimeTypes [i])
\r
302 return ClsidToImageFormat (codec.Clsid);
\r
306 internal static ImageFormat ClsidToImageFormat (Guid clsid) {
307 if (clsid.Equals (BmpClsid))
308 return ImageFormat.Bmp;
309 else if (clsid.Equals (JpegClsid))
310 return ImageFormat.Jpeg;
311 else if (clsid.Equals (GifClsid))
312 return ImageFormat.Gif;
313 else if (clsid.Equals (EmfClsid))
314 return ImageFormat.Emf;
315 else if (clsid.Equals (WmfClsid))
316 return ImageFormat.Wmf;
317 else if (clsid.Equals (TiffClsid))
318 return ImageFormat.Tiff;
319 else if (clsid.Equals (PngClsid))
320 return ImageFormat.Png;
321 else if (clsid.Equals (IconClsid))
322 return ImageFormat.Icon;
327 internal static Guid ImageFormatToClsid (ImageFormat format) {
331 if (format.Guid.Equals (ImageFormat.Bmp.Guid))
333 else if (format.Guid.Equals (ImageFormat.Jpeg.Guid))
335 else if (format.Guid.Equals (ImageFormat.Gif))
337 else if (format.Guid.Equals (ImageFormat.Emf.Guid))
339 else if (format.Guid.Equals (ImageFormat.Wmf.Guid))
341 else if (format.Guid.Equals (ImageFormat.Tiff.Guid))
343 else if (format.Guid.Equals (ImageFormat.Png.Guid))
345 else if (format.Guid.Equals (ImageFormat.Icon.Guid))
351 private FrameDimension FormatFrameDimesion {
353 if (ImageFormat == null)
354 return FrameDimension.Page;
356 if (ImageFormat.Guid.Equals (ImageFormat.Bmp.Guid))
357 return FrameDimension.Page;
358 else if (ImageFormat.Guid.Equals (ImageFormat.Jpeg.Guid))
359 return FrameDimension.Page;
360 else if (ImageFormat.Guid.Equals (ImageFormat.Gif))
361 return FrameDimension.Time;
362 else if (ImageFormat.Guid.Equals (ImageFormat.Emf.Guid))
363 return FrameDimension.Page;
364 else if (ImageFormat.Guid.Equals (ImageFormat.Wmf.Guid))
365 return FrameDimension.Page;
366 else if (ImageFormat.Guid.Equals (ImageFormat.Tiff.Guid))
367 return FrameDimension.Page;
368 else if (ImageFormat.Guid.Equals (ImageFormat.Png.Guid))
369 return FrameDimension.Page;
370 else if (ImageFormat.Guid.Equals (ImageFormat.Icon.Guid))
371 return FrameDimension.Resolution;
373 return FrameDimension.Page;
379 #region Image read/write methods
\r
381 internal PlainImage ReadPlainImage() {
\r
382 awt.Image img = ReadImage( _currentFrame );
\r
386 // its possible to fail to load thumbnails and metadata, but image is ok.
\r
387 awt.Image [] th = null;
\r
388 #if THUMBNAIL_SUPPORTED
\r
390 th = ReadThumbnails( _currentFrame );
\r
392 catch (Exception) {}
\r
395 XmlDocument md = null;
\r
396 imageio.metadata.IIOMetadata nativeMd = null;
\r
398 nativeMd = ReadImageMetadata( _currentFrame );
\r
399 md = ConvertImageMetadata( nativeMd );
\r
401 catch (Exception) {}
\r
403 float [] resolution = GetResolution( md );
\r
405 PlainImage pi = new PlainImage( img, th, ImageFormat, resolution[0], resolution[1], FormatFrameDimesion );
\r
406 pi.NativeMetadata = nativeMd;
\r
410 internal PlainImage ReadNextPlainImage() {
\r
412 return ReadPlainImage();
\r
415 private awt.Image ReadImage(int frame) {
\r
416 if (NativeStream == null)
\r
417 throw new Exception("Input stream not specified");
\r
420 return NativeReader.read (frame);
422 catch (java.lang.IndexOutOfBoundsException) {
425 catch (java.io.IOException ex) {
426 throw new System.IO.IOException(ex.Message, ex);
430 #if THUMBNAIL_SUPPORTED
\r
431 private awt.Image [] ReadThumbnails(int frameIndex) {
\r
432 awt.Image [] thArray = null;
435 if (NativeReader.readerSupportsThumbnails()) {
436 int tmbNumber = NativeReader.getNumThumbnails(frameIndex);
439 thArray = new awt.Image[ tmbNumber ];
441 for (int i = 0; i < tmbNumber; i++) {
442 thArray[i] = NativeReader.readThumbnail(frameIndex, i);
448 catch (java.io.IOException ex) {
449 throw new System.IO.IOException(ex.Message, ex);
453 internal void WritePlainImage(PlainImageCollection pic) {
\r
454 if ((pic == null) || (pic.Count == 0))
\r
457 if (pic.Count == 1) {
\r
458 WritePlainImage( pic[0] );
\r
463 if (NativeWriter.canWriteSequence ()) {
\r
464 NativeWriter.prepareWriteSequence (null);
\r
465 for (int i=0; i < pic.Count; i++) {
\r
466 imageio.IIOImage iio = GetIIOImageContainer( pic[i] );
\r
467 NativeWriter.writeToSequence (iio, null);
\r
469 NativeWriter.endWriteSequence ();
\r
472 WritePlainImage( pic[0] );
\r
474 catch (java.io.IOException ex) {
475 throw new System.IO.IOException(ex.Message, ex);
479 internal void WritePlainImage(PlainImage pi) {
\r
481 imageio.IIOImage iio = GetIIOImageContainer( pi );
\r
484 catch (java.io.IOException ex) {
485 throw new System.IO.IOException(ex.Message, ex);
489 private void WriteImage(imageio.IIOImage iio) {
\r
490 if (NativeStream == null)
\r
491 throw new Exception("Output stream not specified");
\r
493 NativeWriter.write( iio );
\r
496 private imageio.IIOImage GetIIOImageContainer(PlainImage pi) {
\r
497 java.util.ArrayList al = null;
\r
499 // prepare thumbnails list
\r
500 if (pi.Thumbnails != null) {
\r
501 al = new java.util.ArrayList( pi.Thumbnails.Length );
\r
502 for (int i=0; i < pi.Thumbnails.Length; i++)
\r
503 al.add(pi.Thumbnails[i]);
\r
506 // prepare IIOImage container
\r
507 if (pi.NativeImage is image.BufferedImage) {
\r
508 imageio.IIOImage iio = new javax.imageio.IIOImage(
\r
509 (image.BufferedImage)pi.NativeImage, al, null /*pi.NativeMetadata*/);
\r
513 // TBD: This codec is for raster formats only
\r
514 throw new NotSupportedException("Only raster formats are supported");
\r
518 private imageio.metadata.IIOMetadata ReadImageMetadata(int frameIndex) {
\r
519 if (NativeStream == null)
\r
520 throw new Exception("Input stream not specified");
\r
523 imageio.metadata.IIOMetadata md = NativeReader.getImageMetadata( frameIndex );
\r
526 catch (java.io.IOException ex) {
527 throw new System.IO.IOException(ex.Message, ex);
533 #region Extra properties
\r
535 public ImageFormat ImageFormat {
\r
536 get { return _imageFormat; }
\r
541 #region Metadata parse
\r
543 private float [] GetResolution(XmlDocument metaData) {
\r
544 if (metaData == null)
\r
545 return new float[]{0, 0};
\r
547 ResolutionConfigurationCollection rcc =
548 (ResolutionConfigurationCollection)
\r
549 ConfigurationSettings.GetConfig ("mainsoft.drawing/codecsmetadata");
552 throw new ConfigurationException("Configuration section codecsmetadata not found");
554 ResolutionConfiguration rc = rcc[ ImageFormat.ToString() ];
557 return new float[]{0, 0};
559 // Horizontal resolution
560 string xResPath = rc.XResPath;
563 if (xResPath == string.Empty)
564 xRes = rc.XResDefault;
566 xRes = GetValueFromMetadata(metaData, xResPath);
568 if ((xRes == null) || (xRes == string.Empty))
569 xRes = rc.XResDefault;
571 // Vertical resolution
572 string yResPath = rc.YResPath;
575 if (yResPath == string.Empty)
576 yRes = rc.YResDefault;
578 yRes = GetValueFromMetadata(metaData, yResPath);
580 if ((yRes == null) || (yRes == string.Empty))
581 yRes = rc.YResDefault;
584 string resUnitsPath = rc.UnitsTypePath;
587 if (resUnitsPath == string.Empty)
588 resUnitsType = rc.UnitsTypeDefault;
590 resUnitsType = GetValueFromMetadata(metaData, resUnitsPath);
592 if (resUnitsType == null)
593 resUnitsType = rc.UnitsTypeDefault;
596 string unitScale = rc.UnitsScale[resUnitsType].ToString();
598 // Adjust resolution to its units
599 float [] res = new float[2];
600 res[0] = ParseFloatValue(xRes) * ParseFloatValue(unitScale);
601 res[1] = ParseFloatValue(yRes) * ParseFloatValue(unitScale);
606 private string GetValueFromMetadata(XmlDocument metaData, string path) {
\r
607 XmlNode n = metaData.SelectSingleNode(path);
\r
611 return n.InnerText;
\r
614 private XmlDocument ConvertImageMetadata(imageio.metadata.IIOMetadata metaData) {
\r
615 string [] formatNames = metaData.getMetadataFormatNames();
616 dom.Element rootNode = (dom.Element) metaData.getAsTree(formatNames[0]);
618 XmlDocument _metadataDocument = new XmlDocument();
\r
619 XmlConvert(rootNode, _metadataDocument);
\r
621 return _metadataDocument;
\r
624 private void XmlConvert(dom.Node jNode, XmlNode nNode) {
\r
625 XmlDocument document = nNode.OwnerDocument;
\r
626 if (document == null)
\r
627 document = (XmlDocument)nNode;
\r
630 switch (jNode.getNodeType()) {
\r
632 n = document.CreateNode(XmlNodeType.Element, jNode.getNodeName(), jNode.getNamespaceURI());
\r
636 n = document.CreateNode(XmlNodeType.CDATA, jNode.getNodeName(), jNode.getNamespaceURI());
\r
643 n.InnerText = jNode.getNodeValue();
\r
644 nNode.AppendChild( n );
\r
647 org.w3c.dom.NamedNodeMap nm = jNode.getAttributes();
\r
648 for (int i=0; i<nm.getLength(); i++) {
\r
649 XmlAttribute a = document.CreateAttribute( nm.item(i).getNodeName() );
\r
650 a.Value = nm.item(i).getNodeValue();
\r
651 n.Attributes.Append( a );
\r
655 org.w3c.dom.NodeList nl = jNode.getChildNodes();
\r
656 for (int i=0; i<nl.getLength(); i++) {
\r
657 XmlConvert(nl.item(i), n);
\r
661 protected virtual float ParseFloatValue(string strValue) {
\r
663 if ((strValue != null) && (strValue != "")) {
664 int dividerPos = strValue.IndexOf("/");
666 if (dividerPos < 0) {
667 return float.Parse(strValue);
670 return float.Parse(strValue.Substring( 0, dividerPos )) /
671 float.Parse(strValue.Substring( dividerPos + 1 ));
676 catch (Exception) {
\r
683 #region IDisposable members
\r
685 public void Dispose() {
\r
686 if (NativeReader != null) {
\r
687 NativeReader.dispose();
\r
688 NativeReader = null;
\r
691 if (NativeWriter != null) {
\r
692 NativeWriter.dispose();
\r
693 NativeWriter = null;
\r