[System.Net] Add support for .pac proxy config scripts on mac
[mono.git] / mcs / class / System.Drawing / System.Drawing / Image.jvm.cs
1 //
2 // System.Drawing.Image.cs
3 //
4 // (C) 2002 Ximian, Inc.  http://www.ximian.com
5 // Author:      Christian Meyer (Christian.Meyer@cs.tum.edu)
6 //              Alexandre Pigolkine (pigolkine@gmx.de)
7 //              Jordi Mas i Hernandez (jordi@ximian.com)
8 //
9 namespace System.Drawing {
10
11         using System;
12         using System.Runtime.Remoting;
13         using System.Runtime.Serialization;
14         using System.Runtime.InteropServices;
15         using System.ComponentModel;
16         using System.Drawing;
17         using System.Drawing.Imaging;
18         using System.IO;
19         using System.Xml;
20         using Mainsoft.Drawing.Imaging;
21
22         using BufferedImage = java.awt.image.BufferedImage;
23         using java.io;
24         using javax.imageio;
25         using javax.imageio.stream;
26         using vmw.common;
27         using awt = java.awt;
28         using image = java.awt.image;
29
30         public abstract class Image : MarshalByRefObject, IDisposable , ICloneable {    
31                 #region Vars    
32                 PlainImageCollection _nativeObject = new PlainImageCollection();
33                 protected int _flags = 0;
34
35                 //consider using Image[] to support many thumbnails per Image
36                 #endregion
37
38                 #region flags enum
39                 [Flags]
40                 protected enum ImageFlags {
41                         ImageFlagsNone = 0,
42                         ImageFlagsScalable = 0x0001,
43                         ImageFlagsHasAlpha = 0x0002,
44                         ImageFlagsHasTranslucent = 0x0004,
45                         ImageFlagsPartiallyScalable = 0x0008,
46                         ImageFlagsColorSpaceRGB = 0x0010,
47                         ImageFlagsColorSpaceCMYK = 0x0020,
48                         ImageFlagsColorSpaceGRAY = 0x0040,
49                         ImageFlagsColorSpaceYCBCR = 0x0080,
50                         ImageFlagsColorSpaceYCCK = 0x0100,
51                         ImageFlagsHasRealDPI = 0x1000,
52                         ImageFlagsHasRealPixelSize = 0x2000,
53                         ImageFlagsReadOnly = 0x00010000,
54                         ImageFlagsCaching = 0x00020000
55                 }
56                 #endregion
57
58                 #region Constructor
59                 public void Dispose () {
60                 }
61
62                 protected virtual void DisposeResources () {
63                 }
64         
65                 protected virtual void Dispose (bool disposing) {
66                 }
67
68                 // Derived classes must call Initialize () when they use this constructor
69                 protected Image () {
70                 }
71  
72                 protected Image (java.awt.Image nativeObject) : this(nativeObject, ImageFormat.MemoryBmp) {
73                 }
74
75                 protected Image (java.awt.Image nativeObject, ImageFormat format) {
76                         PlainImage pi = new PlainImage( nativeObject, null, format, 0, 0, FrameDimension.Page );
77                         Initialize( pi, false );
78                 }
79
80                 protected void Initialize (PlainImage pi, bool addToCollection) {
81                         if (!addToCollection)
82                                 NativeObject.Clear();
83                                 
84                         NativeObject.Add( pi );
85                 }
86
87                 #endregion
88         
89                 #region Internals
90
91                 internal PlainImageCollection NativeObject {
92                         get {
93                                 return _nativeObject;
94                         }
95                 }
96
97                 internal PlainImage CurrentImage {
98                         get {
99                                 return NativeObject.CurrentImage;
100                         }
101                 }
102                 
103                 #endregion
104     
105                 #region FromFile
106                 [MonoTODO]
107                 public static Image FromFile(string filename) {
108                         //FIXME: check if it's not a metafile, throw NotImplementedException
109                         return new Bitmap (filename);
110                 }
111         
112                 [MonoTODO]
113                 public static Image FromFile(string filename, bool useIcm) {
114                         //FIXME: check if it's not a metafile, throw NotImplementedException
115                         return new Bitmap (filename, useIcm);
116                 }
117                 #endregion
118
119                 #region GetThumbnailImageAbort
120                 [Serializable]
121                         public delegate bool GetThumbnailImageAbort();
122                 #endregion
123
124                 #region Clone
125                 public abstract object Clone();
126                 #endregion
127
128                 // static
129                 #region FromStream
130                 [MonoTODO]
131                 public static Image FromStream (Stream stream) {
132                         //FIXME: check if it's not a metafile, throw NotImplementedException
133                         return new Bitmap (stream);
134                 }
135         
136                 [MonoTODO]
137                 public static Image FromStream (Stream stream, bool useIcm) {
138                         //FIXME: check if it's not a metafile, throw NotImplementedException
139                         return new Bitmap (stream, useIcm);
140                 }
141                 #endregion
142
143                 #region GetPixelFormatSize
144                 public static int GetPixelFormatSize(PixelFormat pixfmt) {
145
146                         int result = 0;
147                         switch (pixfmt) {
148                                 case PixelFormat.Format16bppArgb1555:
149                                 case PixelFormat.Format16bppGrayScale:
150                                 case PixelFormat.Format16bppRgb555:
151                                 case PixelFormat.Format16bppRgb565:
152                                         result = 16;
153                                         break;
154                                 case PixelFormat.Format1bppIndexed:
155                                         result = 1;
156                                         break;
157                                 case PixelFormat.Format24bppRgb:
158                                         result = 24;
159                                         break;
160                                 case PixelFormat.Format32bppArgb:
161                                 case PixelFormat.Format32bppPArgb:
162                                 case PixelFormat.Format32bppRgb:
163                                         result = 32;
164                                         break;
165                                 case PixelFormat.Format48bppRgb:
166                                         result = 48;
167                                         break;
168                                 case PixelFormat.Format4bppIndexed:
169                                         result = 4;
170                                         break;
171                                 case PixelFormat.Format64bppArgb:
172                                 case PixelFormat.Format64bppPArgb:
173                                         result = 64;
174                                         break;
175                                 case PixelFormat.Format8bppIndexed:
176                                         result = 8;
177                                         break;
178                         }
179                         return result;
180                 }
181                 #endregion
182
183                 #region IsAlphaPixelFormat
184                 public static bool IsAlphaPixelFormat(PixelFormat pixfmt) {
185                         return (pixfmt & PixelFormat.Alpha) != PixelFormat.Undefined;
186                 }
187                 #endregion
188         
189                 #region IsCanonicalPixelFormat
190                 // TBD: implement this
191                 public static bool IsCanonicalPixelFormat (PixelFormat pixfmt) {
192                         return (pixfmt & PixelFormat.Canonical) != PixelFormat.Undefined;
193                 }
194                 #endregion
195         
196                 #region IsExtendedPixelFormat
197                 // TBD: implement this
198                 public static bool IsExtendedPixelFormat (PixelFormat pixfmt) {
199                         return (pixfmt & PixelFormat.Extended) != PixelFormat.Undefined;
200                 }
201                 #endregion
202
203                 // non-static
204                 #region GetBounds
205                 public RectangleF GetBounds (ref GraphicsUnit pageUnit) {       
206                         pageUnit = GraphicsUnit.Pixel; //java.awt.Image always returns pixels
207                         return new RectangleF((float)0,(float)0,(float)Width,(float)Height);
208                 }
209                 #endregion
210         
211                 #region GetEncoderParameterList
212                 [MonoTODO]
213                 public EncoderParameters GetEncoderParameterList(Guid encoder) {
214                         throw new NotImplementedException ();
215                 }
216                 #endregion
217         
218                 #region GetFrameCount
219                 public int GetFrameCount(FrameDimension dimension) {
220                         // FALLBACK: now, only one dimension assigned for all frames
221                         if (dimension.Guid != CurrentImage.Dimension.Guid) 
222                                 throw new ArgumentException ("dimension");
223
224                         return NativeObject.Count;
225                 }
226                 #endregion
227         
228                 #region GetPropertyItem
229                 [MonoTODO]
230                 public PropertyItem GetPropertyItem(int propid) {
231                         throw new NotImplementedException ();
232                 }
233                 #endregion
234
235                 #region RemovePropertyItem
236                 [MonoTODO]
237                 public void RemovePropertyItem (int propid) {           
238                         throw new NotImplementedException ();
239                 }
240                 #endregion
241         
242                 #region RotateFlip
243                 public void RotateFlip (RotateFlipType rotateFlipType) {
244                         awt.geom.AffineTransform tx;
245
246                         if ( !(CurrentImage.NativeImage is image.BufferedImage) )
247                                 // TBD: This implementation is for raster formats only
248                                 throw new NotImplementedException("Only raster formats are supported");
249
250                         switch (rotateFlipType) {
251                                 case RotateFlipType.RotateNoneFlipNone :
252                                         return;
253                                 
254                                 case RotateFlipType.Rotate90FlipNone :
255                                         tx = awt.geom.AffineTransform.getRotateInstance(Math.PI / 2);
256                                         tx.translate( 0, -Height );
257                                         break;
258
259                                 case RotateFlipType.Rotate180FlipNone :
260                                         tx = awt.geom.AffineTransform.getScaleInstance(-1, -1);
261                                         tx.translate( -Width, -Height );
262                                         break;
263
264                                 case RotateFlipType.Rotate270FlipNone :
265                                         tx = awt.geom.AffineTransform.getRotateInstance(-Math.PI / 2);
266                                         tx.translate( -Width, 0 );
267                                         break;
268
269                                 case RotateFlipType.RotateNoneFlipX :
270                                         tx = awt.geom.AffineTransform.getScaleInstance(-1, 1);
271                                         tx.translate( -Width, 0 );
272                                         break;
273
274                                 case RotateFlipType.Rotate90FlipX :
275                                         tx = awt.geom.AffineTransform.getRotateInstance(Math.PI / 2);
276                                         tx.scale(1, -1);
277                                         break;
278
279                                 case RotateFlipType.Rotate180FlipX :
280                                         tx = awt.geom.AffineTransform.getScaleInstance(1, -1);
281                                         tx.translate( 0, -Height );
282                                         break;
283
284                                 case RotateFlipType.Rotate270FlipX :
285                                         tx = awt.geom.AffineTransform.getRotateInstance(Math.PI / 2);
286                                         tx.scale(-1, 1);
287                                         tx.translate( -Width, -Height );
288                                         break;
289
290                                 default:
291                                         throw new ArgumentOutOfRangeException();
292                         }
293                         image.AffineTransformOp op = new image.AffineTransformOp(tx, image.AffineTransformOp.TYPE_NEAREST_NEIGHBOR);
294                         CurrentImage.NativeImage = op.filter((BufferedImage)CurrentImage.NativeImage, null);
295                 }
296                 #endregion
297
298                 #region Save
299                 protected abstract void InternalSave (ImageOutputStream output, Guid clsid);
300
301                 [MonoTODO]
302                 public void Save (Stream stream, ImageCodecInfo encoder, EncoderParameters encoderParams) {
303                         //TBD: implement encoderParams
304                         if (encoder == null)
305                                 throw new ArgumentNullException("Value cannot be null.");
306
307                         try {
308                                 java.io.OutputStream jos = vmw.common.IOUtils.ToOutputStream (stream);
309                                 MemoryCacheImageOutputStream output = new MemoryCacheImageOutputStream(jos);
310                                 InternalSave (output, encoder.Clsid);
311                                 output.flush();
312                         }
313                         catch (java.io.IOException ex) {
314                                 throw new System.IO.IOException(ex.Message, ex);
315                         }
316                 }
317         
318                 public void Save(string filename, ImageCodecInfo encoder, EncoderParameters encoderParams) {
319                         using (Stream outputStream = new FileStream(filename, FileMode.Create))
320                                 Save(outputStream, encoder, encoderParams);
321                 }
322
323                 public void Save (string filename) {
324                         Save (filename, ImageFormat.Png);
325                 }
326
327                 public void Save (Stream stream, ImageFormat format) {
328                         ImageCodecInfo encoder = ImageCodec.FindEncoder ( ImageCodec.ImageFormatToClsid (format) );
329                         Save (stream, encoder, null);
330                 }
331
332                 public void Save(string filename, ImageFormat format) {
333                         using (Stream outputStream = new FileStream(filename, FileMode.Create))
334                                 Save(outputStream, format);
335                 }
336                 #endregion
337
338                 #region SaveAdd
339                 [MonoTODO]
340                 public void SaveAdd(EncoderParameters encoderParams) {
341                         throw new NotImplementedException ();
342                 }
343         
344                 [MonoTODO]
345                 public void SaveAdd(Image image, EncoderParameters encoderParams) {
346                         throw new NotImplementedException ();
347                 }
348                 #endregion
349         
350                 #region SelectActiveFrame
351
352                 // TBD: .Net does not load all frames at the initialization. New frames loaded by request.
353                 [MonoTODO]
354                 public int SelectActiveFrame(FrameDimension dimension, int frameIndex) {
355                         // FALLBACK: now, only one dimension assigned for all frames
356                         if (dimension.Guid != CurrentImage.Dimension.Guid) 
357                                 throw new ArgumentException ("dimension");
358
359                         if (frameIndex < NativeObject.Count)
360                                 NativeObject.CurrentImageIndex = frameIndex;
361
362                         return frameIndex;
363                 }
364                 #endregion
365         
366                 #region SetPropertyItem
367                 [MonoTODO]
368                 public void SetPropertyItem(PropertyItem propitem) {
369                         throw new NotImplementedException ();
370                 }
371                 #endregion
372
373                 // properties
374                 #region Flags
375                 public int Flags {
376                         // TDB: ImageFlagsScalable, ImageFlagsHasTranslucent, ImageFlagsPartiallyScalable, ImageFlagsCaching
377                         [MonoTODO]
378                         get {
379                                 image.ColorModel colorModel = ((BufferedImage)CurrentImage.NativeImage).getColorModel();
380                                 int t = colorModel.getColorSpace().getType();
381                                 
382                                 if (t == awt.color.ColorSpace.TYPE_RGB)
383                                         _flags |= (int)ImageFlags.ImageFlagsColorSpaceRGB;
384                                 else if (t == awt.color.ColorSpace.TYPE_CMYK)
385                                         _flags |= (int)ImageFlags.ImageFlagsColorSpaceCMYK;
386                                 else if (t == awt.color.ColorSpace.TYPE_GRAY)
387                                         _flags |= (int)ImageFlags.ImageFlagsColorSpaceGRAY;
388                                 else if (t == awt.color.ColorSpace.TYPE_YCbCr)
389                                         _flags |= (int)ImageFlags.ImageFlagsColorSpaceYCBCR;
390
391                                 if (colorModel.hasAlpha())
392                                         _flags |= (int)ImageFlags.ImageFlagsHasAlpha;
393
394                                 if ((CurrentImage.HorizontalResolution > 0) || (CurrentImage.VerticalResolution > 0))
395                                         _flags |= (int)ImageFlags.ImageFlagsHasRealDPI;
396
397                                 return _flags;
398                         }
399                 }
400                 #endregion
401
402                 #region FrameDimensionsList
403                 [MonoTODO]
404                 public Guid[] FrameDimensionsList {
405                         // TBD: look over all frames and build array of dimensions
406                         // FALLBACK: now, only one dimension assigned for all frames
407                         get {
408                                 Guid [] dimList = new Guid[]{CurrentImage.Dimension.Guid};
409                                 return dimList;
410                         }
411                 }
412                 #endregion
413
414                 #region Height
415                 public int Height {
416                         get {
417                                 return CurrentImage.NativeImage.getHeight(null);
418                         }
419                 }
420                 #endregion
421         
422                 #region HorizontalResolution
423                 public float HorizontalResolution {
424                         get {
425                                 if (CurrentImage.HorizontalResolution <= 1)
426                                         return Graphics.DefaultScreenResolution;
427
428                                 return CurrentImage.HorizontalResolution;
429                         }
430                 }
431                 #endregion
432         
433                 #region ColorPalette
434                 [MonoTODO]
435                 public ColorPalette Palette {
436                         get {
437                                 if (!(CurrentImage.NativeImage is BufferedImage))
438                                         // TBD: This implementation is for raster formats only
439                                         throw new NotImplementedException("Only raster formats are supported");
440
441                                 image.ColorModel colorModel = ((BufferedImage)CurrentImage.NativeImage).getColorModel();
442                                 if (colorModel is image.IndexColorModel) {
443
444                                         Color [] colors = new Color[ ((image.IndexColorModel)colorModel).getMapSize() ];
445                                         for (int i=0; i<colors.Length; i++) {
446                                                 colors[i] = Color.FromArgb( ((image.IndexColorModel)colorModel).getRGB(i) );
447                                         }
448                                         ColorPalette palette = new ColorPalette(0, colors);
449                                         return palette;
450                                 }
451                                 return new ColorPalette();
452                         }
453                         set {
454                                 throw new NotImplementedException ();
455                         }
456                 }
457                 #endregion
458                 
459                 #region PhysicalDimension
460                 public SizeF PhysicalDimension {
461                         get {
462                                 return new Size(Width, Height);
463                         }
464                 }
465                 #endregion
466         
467                 #region PixelFormat
468                 abstract protected PixelFormat InternalPixelFormat {get;}
469
470                 public PixelFormat PixelFormat {
471                         get {
472                                 return InternalPixelFormat;
473                         }
474                 }
475                 #endregion
476                 
477                 #region PropertiIdList
478                 [MonoTODO]
479                 public int[] PropertyIdList {
480                         get {
481                                 throw new NotImplementedException ();
482                         }
483                 }
484                 #endregion
485                 
486                 #region PropertItems
487                 [MonoTODO]
488                 public PropertyItem[] PropertyItems {
489                         get {
490                                 throw new NotImplementedException ();
491                         }
492                 }
493                 #endregion
494
495                 #region RawFormat
496                 public ImageFormat RawFormat {
497                         get {
498                                 return CurrentImage.ImageFormat;
499                         }
500                 }
501                 #endregion
502
503                 #region Size
504                 public Size Size {
505                         get {
506                                 return new Size(Width, Height);
507                         }
508                 }
509                 #endregion
510         
511                 #region VerticalResolution
512                 public float VerticalResolution {
513                         get {
514                                 if (CurrentImage.VerticalResolution <= 1)
515                                         return Graphics.DefaultScreenResolution;
516
517                                 return CurrentImage.VerticalResolution;
518                         }
519                 }
520                 #endregion
521         
522                 #region Width
523                 public int Width {
524                         get {
525                                 return CurrentImage.NativeImage.getWidth(null);
526                         }
527                 }
528                 #endregion      
529
530                 public Image GetThumbnailImage(int thumbWidth, int thumbHeight, Image.GetThumbnailImageAbort callback, IntPtr callbackData) {
531                         awt.Image img;
532
533 #if THUMBNAIL_SUPPORTED
534                         if (CurrentImage.Thumbnails != null) {
535                                 for (int i=0; i < CurrentImage.Thumbnails.Length; i++)
536                                         if (CurrentImage.Thumbnails[i] != null) {
537                                                 img = CurrentImage.Thumbnails[i];
538                                                 if (img.getHeight(null) == thumbHeight && img.getWidth(null) == thumbWidth)
539                                                         return ImageFromNativeImage(img, RawFormat);
540                                         }
541                         }
542 #endif
543                         img = CurrentImage.NativeImage.getScaledInstance(thumbWidth, thumbHeight, awt.Image.SCALE_DEFAULT);
544
545                         return ImageFromNativeImage(img, RawFormat);
546                 }
547 #if INTPTR_SUPPORT
548                 [MonoTODO]
549         public static Bitmap FromHbitmap(IntPtr hbitmap)
550         {               
551                 throw new NotImplementedException ();
552         }       
553
554                 [MonoTODO]
555         public static Bitmap FromHbitmap(IntPtr hbitmap, IntPtr hpalette)
556         {               
557                 throw new NotImplementedException ();
558         }
559 #endif
560
561                 internal static Image ImageFromNativeImage(awt.Image nativeImage, ImageFormat format) {
562                         if (nativeImage is BufferedImage)
563                                 return new Bitmap(nativeImage, format);
564
565                         throw new ArgumentException("Invalid image type");
566                 }
567
568                 protected abstract awt.Image [] CloneNativeObjects(awt.Image [] src);
569         }
570
571 }