2005-01-31 Zoltan Varga <vargaz@freemail.hu>
[mono.git] / mcs / class / System.Drawing / System.Drawing / Image.cs
1 //
2 // System.Drawing.Image.cs
3 //
4 // Copyright (C) 2002 Ximian, Inc.  http://www.ximian.com
5 // Copyright (C) 2004 Novell, Inc.  http://www.novell.com
6 //
7 // Author:      Christian Meyer (Christian.Meyer@cs.tum.edu)
8 //              Alexandre Pigolkine (pigolkine@gmx.de)
9 //              Jordi Mas i Hernandez (jordi@ximian.com)
10 //              Sanjay Gupta (gsanjay@novell.com)
11 //              Ravindra (rkumar@novell.com)
12 //
13
14 //
15 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
16 //
17 // Permission is hereby granted, free of charge, to any person obtaining
18 // a copy of this software and associated documentation files (the
19 // "Software"), to deal in the Software without restriction, including
20 // without limitation the rights to use, copy, modify, merge, publish,
21 // distribute, sublicense, and/or sell copies of the Software, and to
22 // permit persons to whom the Software is furnished to do so, subject to
23 // the following conditions:
24 // 
25 // The above copyright notice and this permission notice shall be
26 // included in all copies or substantial portions of the Software.
27 // 
28 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
29 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
30 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
31 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
32 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
33 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
34 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
35 //
36
37 using System;
38 using System.Runtime.Remoting;
39 using System.Runtime.Serialization;
40 using System.Runtime.InteropServices;
41 using System.ComponentModel;
42 using System.Drawing.Imaging;
43 using System.IO;
44
45 namespace System.Drawing
46 {
47 [Serializable]
48 [ComVisible (true)]
49 [Editor ("System.Drawing.Design.ImageEditor, " + Consts.AssemblySystem_Drawing_Design, typeof (System.Drawing.Design.UITypeEditor))]
50 [TypeConverter (typeof(ImageConverter))]
51 [ImmutableObject (true)]
52 public abstract class Image : MarshalByRefObject, IDisposable , ICloneable, ISerializable 
53 {
54         public delegate bool GetThumbnailImageAbort();
55         
56         internal IntPtr nativeObject = IntPtr.Zero;     
57         ColorPalette colorPalette;
58         
59         
60         // constructor
61         internal  Image()
62         {               
63                 colorPalette = new ColorPalette();
64         }
65         
66         private Image (SerializationInfo info, StreamingContext context)
67         {
68                 foreach (SerializationEntry serEnum in info) {
69                         if (String.Compare(serEnum.Name, "Data", true) == 0) {
70                                 byte[] bytes = (byte[]) serEnum.Value;
71
72                                 if (bytes != null) {
73                                         InitFromStream(new MemoryStream(bytes));
74                                 }
75                         }
76                 }
77         }
78         
79         [MonoTODO]      
80         void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
81         {
82                 throw new NotImplementedException();
83         }
84     
85         // public methods
86         // static
87         public static Image FromFile(string filename)
88         {
89                 return new Bitmap (filename);
90         }
91         
92         public static Image FromFile(string filename, bool useEmbeddedColorManagement)
93         {
94                 return new Bitmap (filename, useEmbeddedColorManagement);
95         }
96
97         [MonoTODO]      
98         public static Bitmap FromHbitmap(IntPtr hbitmap)
99         {               
100                 throw new NotImplementedException ();
101         }
102
103         [MonoTODO]      
104         public static Bitmap FromHbitmap(IntPtr hbitmap, IntPtr hpalette)
105         {               
106                 throw new NotImplementedException ();
107         }
108
109         public static Image FromStream (Stream stream)
110         {
111                 return new Bitmap (stream);
112         }
113         
114         public static Image FromStream (Stream stream, bool useECM)
115         {
116                 return new Bitmap (stream, useECM);
117         }
118
119         public static int GetPixelFormatSize(PixelFormat pixfmt)
120         {
121                 int result = 0;
122                 switch (pixfmt) {
123                         case PixelFormat.Format16bppArgb1555:
124                         case PixelFormat.Format16bppGrayScale:
125                         case PixelFormat.Format16bppRgb555:
126                         case PixelFormat.Format16bppRgb565:
127                                 result = 16;
128                                 break;
129                         case PixelFormat.Format1bppIndexed:
130                                 result = 1;
131                                 break;
132                         case PixelFormat.Format24bppRgb:
133                                 result = 24;
134                                 break;
135                         case PixelFormat.Format32bppArgb:
136                         case PixelFormat.Format32bppPArgb:
137                         case PixelFormat.Format32bppRgb:
138                                 result = 32;
139                                 break;
140                         case PixelFormat.Format48bppRgb:
141                                 result = 48;
142                                 break;
143                         case PixelFormat.Format4bppIndexed:
144                                 result = 4;
145                                 break;
146                         case PixelFormat.Format64bppArgb:
147                         case PixelFormat.Format64bppPArgb:
148                                 result = 64;
149                                 break;
150                         case PixelFormat.Format8bppIndexed:
151                                 result = 8;
152                                 break;
153                 }
154                 return result;
155         }
156
157         public static bool IsAlphaPixelFormat(PixelFormat pixfmt)
158         {
159                 bool result = false;
160                 switch (pixfmt) {
161                         case PixelFormat.Format16bppArgb1555:
162                         case PixelFormat.Format32bppArgb:
163                         case PixelFormat.Format32bppPArgb:
164                         case PixelFormat.Format64bppArgb:
165                         case PixelFormat.Format64bppPArgb:
166                                 result = true;
167                                 break;
168                         case PixelFormat.Format16bppGrayScale:
169                         case PixelFormat.Format16bppRgb555:
170                         case PixelFormat.Format16bppRgb565:
171                         case PixelFormat.Format1bppIndexed:
172                         case PixelFormat.Format24bppRgb:
173                         case PixelFormat.Format32bppRgb:
174                         case PixelFormat.Format48bppRgb:
175                         case PixelFormat.Format4bppIndexed:
176                         case PixelFormat.Format8bppIndexed:
177                                 result = false;
178                                 break;
179                 }
180                 return result;
181         }
182         
183         public static bool IsCanonicalPixelFormat (PixelFormat pixfmt)
184         {
185                 return ((pixfmt & PixelFormat.Canonical) != 0);
186         }
187         
188         public static bool IsExtendedPixelFormat (PixelFormat pixfmt)
189         {
190                 return ((pixfmt & PixelFormat.Extended) != 0);
191         }
192
193         internal void InitFromStream (Stream stream)
194         {
195                 if (Environment.OSVersion.Platform == (PlatformID) 128) {
196                         // Unix, with libgdiplus
197                         // We use a custom API for this, because there's no easy way
198                         // to get the Stream down to libgdiplus.  So, we wrap the stream
199                         // with a set of delegates.
200                         GDIPlus.GdiPlusStreamHelper sh = new GDIPlus.GdiPlusStreamHelper (stream);
201                         IntPtr imagePtr;
202
203                         Status st = GDIPlus.GdipLoadImageFromDelegate_linux (sh.GetBytesDelegate, sh.PutBytesDelegate,
204                                                                         sh.SeekDelegate, sh.CloseDelegate, sh.SizeDelegate,
205                                                                                      out imagePtr);
206                         GDIPlus.CheckStatus (st);
207                         nativeObject = imagePtr;
208                 } else {
209                         // this is MS-land
210                         // FIXME
211                         // We can't call the native gdip functions here, because they expect
212                         // a COM IStream interface.  So, a hack is to create a tmp file, read
213                         // the stream, and then load from the tmp file.
214                         // This is an ugly hack.
215                         throw new NotImplementedException ("Bitmap.InitFromStream (win32)");
216                 }
217         }
218
219         // non-static   
220         public RectangleF GetBounds (ref GraphicsUnit pageUnit)
221         {       
222                 RectangleF source;                      
223                 
224                 Status status = GDIPlus.GdipGetImageBounds (nativeObject, out source, ref pageUnit);
225                 GDIPlus.CheckStatus (status);           
226                 
227                 return source;
228         }
229         
230         public EncoderParameters GetEncoderParameterList(Guid format)
231         {
232                 Status status;
233                 uint sz;
234
235                 status = GDIPlus.GdipGetEncoderParameterListSize (nativeObject, ref format, out sz);
236                 GDIPlus.CheckStatus (status);
237
238                 IntPtr rawEPList = Marshal.AllocHGlobal ((int) sz);
239                 EncoderParameters eps;
240
241                 try {
242                         status = GDIPlus.GdipGetEncoderParameterList (nativeObject, ref format, sz, rawEPList);
243                         eps = EncoderParameters.FromNativePtr (rawEPList);
244                         GDIPlus.CheckStatus (status);
245                 } catch {
246                         Marshal.FreeHGlobal (rawEPList);
247                         throw;
248                 }
249
250                 Marshal.FreeHGlobal (rawEPList);
251
252                 return eps;
253         }
254         
255         public int GetFrameCount(FrameDimension dimension)
256         {
257                 int count;
258                 Guid guid = dimension.Guid;
259                 Status status = GDIPlus.GdipImageGetFrameCount (nativeObject, ref guid, out  count); 
260
261                 GDIPlus.CheckStatus (status);           
262                 
263                 return count;
264                 
265         }
266         
267         public PropertyItem GetPropertyItem(int propid)
268         {
269                 int propSize;
270                 IntPtr property;
271                 PropertyItem item = new PropertyItem ();
272                 GdipPropertyItem gdipProperty = new GdipPropertyItem ();
273                 Status status;
274                         
275                 status = GDIPlus.GdipGetPropertyItemSize (nativeObject, propid, 
276                                                                         out propSize);
277                 GDIPlus.CheckStatus (status);
278
279                 /* Get PropertyItem */
280                 property = Marshal.AllocHGlobal (propSize);
281                 status = GDIPlus.GdipGetPropertyItem (nativeObject, propid, propSize,  
282                                                                                 property);
283                 GDIPlus.CheckStatus (status);
284                 gdipProperty = (GdipPropertyItem) Marshal.PtrToStructure ((IntPtr)property, 
285                                                                 typeof (GdipPropertyItem));                                             
286                 GdipPropertyItem.MarshalTo (gdipProperty, item);                                                                
287                 
288                 Marshal.FreeHGlobal (property);
289                 return item;
290         }
291         
292         public Image GetThumbnailImage(int thumbWidth, int thumbHeight, Image.GetThumbnailImageAbort callback, IntPtr callbackData)
293         {
294                 Status          status;
295                 Image           ThumbNail;
296                 Graphics        g;
297
298                 ThumbNail=new Bitmap(thumbWidth, thumbHeight);
299                 g=Graphics.FromImage(ThumbNail);
300                 
301                 status = GDIPlus.GdipDrawImageRectRectI(g.nativeObject, nativeObject,
302                                         0, 0, thumbWidth, thumbHeight,
303                                         0, 0, this.Width, this.Height,
304                                         GraphicsUnit.Pixel, IntPtr.Zero, null, IntPtr.Zero);
305                 GDIPlus.CheckStatus (status);
306                 g.Dispose();
307
308                 return(ThumbNail);
309         }
310         
311         
312         public void RemovePropertyItem (int propid)
313         {               
314                 Status status = GDIPlus.GdipRemovePropertyItem (nativeObject, propid);
315                 GDIPlus.CheckStatus (status);                                   
316         }       
317         
318         public void RotateFlip (RotateFlipType rotateFlipType)
319         {                       
320                 Status status = GDIPlus.GdipImageRotateFlip (nativeObject, rotateFlipType);
321                 GDIPlus.CheckStatus (status);                           
322         }
323
324         internal ImageCodecInfo findEncoderForFormat (ImageFormat format)
325         {
326                 ImageCodecInfo[] encoders = ImageCodecInfo.GetImageEncoders();                  
327                 ImageCodecInfo encoder = null;
328                 
329                 if (format.Guid.Equals (ImageFormat.MemoryBmp.Guid))
330                         format = ImageFormat.Bmp;
331         
332                 /* Look for the right encoder for our format*/
333                 for (int i = 0; i < encoders.Length; i++) {
334                         if (encoders[i].FormatID.Equals (format.Guid)) {
335                                 encoder = encoders[i];
336                                 break;
337                         }                       
338                 }
339
340                 return encoder;
341         }
342
343         public void Save (string filename)
344         {
345                 Save (filename, RawFormat);
346         }
347
348         public void Save(string filename, ImageFormat format) 
349         {
350                 ImageCodecInfo encoder = findEncoderForFormat (format);
351
352                 if (encoder == null)
353                         throw new ArgumentException ("No codec available for format:" + format.Guid);
354
355                 Save (filename, encoder, null);
356         }
357
358         public void Save(string filename, ImageCodecInfo encoder, EncoderParameters encoderParams)
359         {
360                 Status st;
361                 Guid guid = encoder.Clsid;
362
363                 if (encoderParams == null) {
364                         st = GDIPlus.GdipSaveImageToFile (nativeObject, filename, ref guid, IntPtr.Zero);
365                 } else {
366                         IntPtr nativeEncoderParams = encoderParams.ToNativePtr ();
367                         st = GDIPlus.GdipSaveImageToFile (nativeObject, filename, ref guid, nativeEncoderParams);
368                         Marshal.FreeHGlobal (nativeEncoderParams);
369                 }
370
371                 GDIPlus.CheckStatus (st);
372         }
373
374         public void Save (Stream stream, ImageFormat format)
375         {
376                 ImageCodecInfo encoder = findEncoderForFormat (format);
377
378                 if (encoder == null)
379                         throw new ArgumentException ("No codec available for format:" + format.Guid);
380
381                 Save (stream, encoder, null);
382         }
383
384         public void Save(Stream stream, ImageCodecInfo encoder, EncoderParameters encoderParams)
385         {
386                 Status st;
387                 Guid guid = encoder.Clsid;
388
389                 if (Environment.OSVersion.Platform == (PlatformID) 128) {
390                         GDIPlus.GdiPlusStreamHelper sh = new GDIPlus.GdiPlusStreamHelper (stream);
391                         if (encoderParams == null) {
392                                 st = GDIPlus.GdipSaveImageToDelegate_linux (nativeObject, sh.GetBytesDelegate, sh.PutBytesDelegate,
393                                                 sh.SeekDelegate, sh.CloseDelegate, sh.SizeDelegate, ref guid, IntPtr.Zero);
394                         } else {
395                                 IntPtr nativeEncoderParams = encoderParams.ToNativePtr ();
396                                 st = GDIPlus.GdipSaveImageToDelegate_linux (nativeObject, sh.GetBytesDelegate, sh.PutBytesDelegate,
397                                                 sh.SeekDelegate, sh.CloseDelegate, sh.SizeDelegate, ref guid, nativeEncoderParams);
398                                 Marshal.FreeHGlobal (nativeEncoderParams);
399                         }
400                 } else {
401                         throw new NotImplementedException ("Image.Save(Stream) (win32)");
402                 }
403                 GDIPlus.CheckStatus (st);
404         }
405         
406         public void SaveAdd (EncoderParameters encoderParams)
407         {
408                 Status st;
409                 
410                 IntPtr nativeEncoderParams = encoderParams.ToNativePtr ();
411                 st = GDIPlus.GdipSaveAdd (nativeObject, nativeEncoderParams);
412                 Marshal.FreeHGlobal (nativeEncoderParams);\r
413                 GDIPlus.CheckStatus (st);
414         }
415                 
416         public void SaveAdd (Image image, EncoderParameters encoderParams)
417         {
418                 Status st;
419                 
420                 IntPtr nativeEncoderParams = encoderParams.ToNativePtr ();
421                 st = GDIPlus.GdipSaveAddImage (nativeObject, image.NativeObject, nativeEncoderParams);
422                 Marshal.FreeHGlobal (nativeEncoderParams);\r
423                 GDIPlus.CheckStatus (st);
424         }
425                 
426         public int SelectActiveFrame(FrameDimension dimension, int frameIndex)
427         {
428                 Guid guid = dimension.Guid;             
429                 Status st = GDIPlus.GdipImageSelectActiveFrame (nativeObject, ref guid, frameIndex);
430                 
431                 GDIPlus.CheckStatus (st);                       
432                 
433                 return frameIndex;              
434         }
435         
436         public void SetPropertyItem(PropertyItem propitem)
437         {
438                 IntPtr property;
439                 int size = Marshal.SizeOf (typeof(GdipPropertyItem));
440                 property = Marshal.AllocHGlobal (size);
441
442                 Marshal.StructureToPtr (propitem, property, true);
443                 Status status = GDIPlus.GdipSetPropertyItem (nativeObject, property);
444                 GDIPlus.CheckStatus (status);
445         }
446
447         // properties   
448         [Browsable (false)]
449         public int Flags {
450                 get {
451                         int flags;
452                         
453                         Status status = GDIPlus.GdipGetImageFlags (nativeObject, out flags);                    
454                         GDIPlus.CheckStatus (status);                                           
455                         return flags;                   
456                 }
457         }
458         
459         [Browsable (false)]
460         public Guid[] FrameDimensionsList {
461                 get {
462                         uint found;
463                         Status status = GDIPlus.GdipImageGetFrameDimensionsCount (nativeObject, out found);
464                         GDIPlus.CheckStatus (status);
465                         Guid [] guid = new Guid [found];
466                         status = GDIPlus.GdipImageGetFrameDimensionsList (nativeObject, guid, found);
467                         GDIPlus.CheckStatus (status);  
468                         return guid;
469                 }
470         }
471
472         [DefaultValue (false)]
473         [Browsable (false)]
474         [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
475         public int Height {
476                 get {
477                         int height;                     
478                         Status status = GDIPlus.GdipGetImageHeight (nativeObject, out height);          
479                         GDIPlus.CheckStatus (status);                   
480                         
481                         return height;
482                 }
483         }
484         
485         public float HorizontalResolution {
486                 get {
487                         float resolution;
488                         
489                         Status status = GDIPlus.GdipGetImageHorizontalResolution (nativeObject, out resolution);                        
490                         GDIPlus.CheckStatus (status);                   
491                         
492                         return resolution;
493                 }
494         }
495         
496         [Browsable (false)]
497         public ColorPalette Palette {
498                 get {                                                   
499                         
500                         return colorPalette;
501                 }
502                 set {
503                         colorPalette = value;                                   
504                 }
505         }
506                 
507         public SizeF PhysicalDimension {
508                 get {
509                         float width,  height;
510                         Status status = GDIPlus.GdipGetImageDimension (nativeObject, out width, out height);            
511                         GDIPlus.CheckStatus (status);                   
512                         
513                         return new SizeF (width, height);
514                 }
515         }
516         
517         public PixelFormat PixelFormat {
518                 get {                   
519                         PixelFormat pixFormat;                          
520                         Status status = GDIPlus.GdipGetImagePixelFormat (nativeObject, out pixFormat);          
521                         GDIPlus.CheckStatus (status);                   
522                         
523                         return pixFormat;
524                 }               
525         }
526         
527         [Browsable (false)]
528         public int[] PropertyIdList {
529                 get {
530                         uint propNumbers;
531                         
532                         Status status = GDIPlus.GdipGetPropertyCount (nativeObject, 
533                                                                         out propNumbers);                       
534                         GDIPlus.CheckStatus (status);
535                         
536                         int [] idList = new int [propNumbers];
537                         status = GDIPlus.GdipGetPropertyIdList (nativeObject, 
538                                                                 propNumbers, idList);
539                         GDIPlus.CheckStatus (status);
540                         
541                         return idList;
542                 }
543         }
544         
545         [Browsable (false)]
546         public PropertyItem[] PropertyItems {
547                 get {
548                         int propNums, propsSize, propSize;
549                         IntPtr properties, propPtr;
550                         PropertyItem[] items;
551                         GdipPropertyItem gdipProperty = new GdipPropertyItem ();
552                         Status status;
553                         
554                         status = GDIPlus.GdipGetPropertySize (nativeObject, out propsSize, out propNums);
555                         GDIPlus.CheckStatus (status);
556
557                         items =  new PropertyItem [propNums];
558                         
559                         if (propNums == 0)
560                                 return items;                   
561                                         
562                         /* Get PropertyItem list*/
563                         properties = Marshal.AllocHGlobal (propsSize);
564                         status = GDIPlus.GdipGetAllPropertyItems (nativeObject, propsSize, 
565                                                                 propNums, properties);
566                         GDIPlus.CheckStatus (status);
567
568                         propSize = Marshal.SizeOf (gdipProperty);                       
569                         propPtr = properties;
570                         
571                         for (int i = 0; i < propNums; i++, propPtr = new IntPtr (propPtr.ToInt64 () + propSize))
572                         {
573                                 gdipProperty = (GdipPropertyItem) Marshal.PtrToStructure 
574                                                 (propPtr, typeof (GdipPropertyItem));                                           
575                                 items [i] = new PropertyItem ();
576                                 GdipPropertyItem.MarshalTo (gdipProperty, items [i]);                                                           
577                         }
578                         
579                         Marshal.FreeHGlobal (properties);
580                         return items;
581                 }
582         }
583
584         public ImageFormat RawFormat {
585                 get {
586                         Guid guid;
587                         Status st = GDIPlus.GdipGetImageRawFormat (nativeObject, out guid);
588                         
589                         GDIPlus.CheckStatus (st);
590                         return new ImageFormat (guid);                  
591                 }
592         }
593         
594         public Size Size {
595                 get {
596                         return new Size(Width, Height);
597                 }
598         }
599         
600         public float VerticalResolution {
601                 get {
602                         float resolution;
603                         
604                         Status status = GDIPlus.GdipGetImageVerticalResolution (nativeObject, out resolution);
605                         GDIPlus.CheckStatus (status);
606
607                         return resolution;
608                 }
609         }
610
611         [DefaultValue (false)]
612         [Browsable (false)]
613         [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
614         public int Width {
615                 get {
616                         int width;                      
617                         Status status = GDIPlus.GdipGetImageWidth (nativeObject, out width);            
618                         GDIPlus.CheckStatus (status);                   
619                         
620                         return width;
621                 }
622         }
623         
624         internal IntPtr NativeObject{
625                 get{
626                         return nativeObject;
627                 }
628                 set     {
629                         nativeObject = value;
630                 }
631         }
632         
633         public void Dispose ()
634         {
635                 Dispose (true);
636                 System.GC.SuppressFinalize (this);
637         }
638
639         ~Image ()
640         {
641                 Dispose (false);
642         }
643
644         private void DisposeResources ()
645         {
646                 lock (this)
647                 {
648                         Status status = GDIPlus.GdipDisposeImage (nativeObject);
649                         GDIPlus.CheckStatus (status);
650                 }
651         }
652         
653         protected virtual void Dispose (bool disposing)
654         {
655                 if (nativeObject != IntPtr.Zero){
656                         DisposeResources ();
657                         nativeObject = IntPtr.Zero;
658                 }
659         }
660         
661         public virtual object Clone()
662         {                               
663                 lock (this)
664                 {
665                         IntPtr newimage = IntPtr.Zero;
666                         
667                         if (!(this is Bitmap)) 
668                                 throw new NotImplementedException (); 
669                         
670                         Status status = GDIPlus.GdipCloneImage (NativeObject, out newimage);                    
671                         GDIPlus.CheckStatus (status);                   
672
673                         if (this is Bitmap){
674                                 Bitmap b = new Bitmap (newimage);
675
676                                 if (colorPalette != null)
677                                         b.colorPalette = colorPalette.Clone ();
678
679                                 return b;
680                         }
681                         
682                         throw new NotImplementedException (); 
683                 }
684         }
685
686 }
687
688 }