make fallbacks for GdiCharSet, GdiVerticalFont
[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 {\r
41                         ImageFlagsNone = 0,\r
42                         ImageFlagsScalable = 0x0001,\r
43                         ImageFlagsHasAlpha = 0x0002,\r
44                         ImageFlagsHasTranslucent = 0x0004,\r
45                         ImageFlagsPartiallyScalable = 0x0008,\r
46                         ImageFlagsColorSpaceRGB = 0x0010,\r
47                         ImageFlagsColorSpaceCMYK = 0x0020,\r
48                         ImageFlagsColorSpaceGRAY = 0x0040,\r
49                         ImageFlagsColorSpaceYCBCR = 0x0080,\r
50                         ImageFlagsColorSpaceYCCK = 0x0100,\r
51                         ImageFlagsHasRealDPI = 0x1000,\r
52                         ImageFlagsHasRealPixelSize = 0x2000,\r
53                         ImageFlagsReadOnly = 0x00010000,\r
54                         ImageFlagsCaching = 0x00020000\r
55                 }\r
56                 #endregion\r
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                 public static Image FromFile(string filename) {
107                         //FIXME: check if it's not a metafile, throw NotImplementedException
108                         return new Bitmap (filename);
109                 }
110         
111                 public static Image FromFile(string filename, bool useIcm) {
112                         //FIXME: check if it's not a metafile, throw NotImplementedException
113                         return new Bitmap (filename, useIcm);
114                 }
115                 #endregion
116
117                 #region GetThumbnailImageAbort
118                 [Serializable]
119                         public delegate bool GetThumbnailImageAbort();
120                 #endregion
121
122                 #region Clone
123                 public virtual object Clone() {
124                         throw new NotImplementedException ("Must be implemented in child class");
125                 }
126                 #endregion
127
128                 // static
129                 #region FromStream
130                 public static Image FromStream (Stream stream) {
131                         //FIXME: check if it's not a metafile, throw NotImplementedException
132                         return new Bitmap (stream);
133                 }
134         
135                 public static Image FromStream (Stream stream, bool useIcm) {
136                         //FIXME: check if it's not a metafile, throw NotImplementedException
137                         return new Bitmap (stream, useIcm);
138                 }
139                 #endregion
140
141                 #region GetPixelFormatSize
142                 public static int GetPixelFormatSize(PixelFormat pixfmt) {
143
144                         int result = 0;
145                         switch (pixfmt) {
146                                 case PixelFormat.Format16bppArgb1555:
147                                 case PixelFormat.Format16bppGrayScale:
148                                 case PixelFormat.Format16bppRgb555:
149                                 case PixelFormat.Format16bppRgb565:
150                                         result = 16;
151                                         break;
152                                 case PixelFormat.Format1bppIndexed:
153                                         result = 1;
154                                         break;
155                                 case PixelFormat.Format24bppRgb:
156                                         result = 24;
157                                         break;
158                                 case PixelFormat.Format32bppArgb:
159                                 case PixelFormat.Format32bppPArgb:
160                                 case PixelFormat.Format32bppRgb:
161                                         result = 32;
162                                         break;
163                                 case PixelFormat.Format48bppRgb:
164                                         result = 48;
165                                         break;
166                                 case PixelFormat.Format4bppIndexed:
167                                         result = 4;
168                                         break;
169                                 case PixelFormat.Format64bppArgb:
170                                 case PixelFormat.Format64bppPArgb:
171                                         result = 64;
172                                         break;
173                                 case PixelFormat.Format8bppIndexed:
174                                         result = 8;
175                                         break;
176                         }
177                         return result;
178                 }
179                 #endregion
180
181                 #region IsAlphaPixelFormat
182                 public static bool IsAlphaPixelFormat(PixelFormat pixfmt) {
183                         return (pixfmt & PixelFormat.Alpha) != PixelFormat.Undefined;
184                 }
185                 #endregion
186         
187                 #region IsCanonicalPixelFormat
188                 // TBD: implement this
189                 public static bool IsCanonicalPixelFormat (PixelFormat pixfmt) {
190                         return (pixfmt & PixelFormat.Canonical) != PixelFormat.Undefined;
191                 }
192                 #endregion
193         
194                 #region IsExtendedPixelFormat
195                 // TBD: implement this
196                 public static bool IsExtendedPixelFormat (PixelFormat pixfmt) {
197                         return (pixfmt & PixelFormat.Extended) != PixelFormat.Undefined;
198                 }
199                 #endregion
200
201                 // non-static
202                 #region GetBounds
203                 public RectangleF GetBounds (ref GraphicsUnit pageUnit) {       
204                         pageUnit = GraphicsUnit.Pixel; //java.awt.Image always returns pixels
205                         return new RectangleF((float)0,(float)0,(float)Width,(float)Height);
206                 }
207                 #endregion
208         
209                 #region GetEncoderParameterList
210                 // TBD: implement this
211                 public EncoderParameters GetEncoderParameterList(Guid encoder) {
212                         throw new NotImplementedException ();
213                 }
214                 #endregion
215         
216                 #region GetFrameCount
217                 public int GetFrameCount(FrameDimension dimension) {
218                         // FALLBACK: now, only one dimension assigned for all frames
219                         if (dimension.Guid != CurrentImage.Dimension.Guid) 
220                                 throw new ArgumentException ("dimension");
221
222                         return NativeObject.Count;
223                 }
224                 #endregion
225         
226                 #region GetPropertyItem
227                 // TBD: implement this
228                 public PropertyItem GetPropertyItem(int propid) {
229                         throw new NotImplementedException ();
230                 }
231                 #endregion
232
233                 #region RemovePropertyItem
234                 // TBD: implement this
235                 public void RemovePropertyItem (int propid) {           
236                         throw new NotImplementedException ();
237                 }
238                 #endregion
239         
240                 #region RotateFlip
241                 public void RotateFlip (RotateFlipType rotateFlipType) {
242                         awt.geom.AffineTransform tx;
243
244                         if ( !(CurrentImage.NativeImage is image.BufferedImage) )
245                                 // TBD: This implementation is for raster formats only
246                                 throw new NotImplementedException("Only raster formats are supported");
247
248                         switch (rotateFlipType) {
249                                 case RotateFlipType.RotateNoneFlipNone :
250                                         return;
251                                 
252                                 case RotateFlipType.Rotate90FlipNone :
253                                         tx = awt.geom.AffineTransform.getRotateInstance(Math.PI / 2);
254                                         tx.translate( 0, -Height );
255                                         break;
256
257                                 case RotateFlipType.Rotate180FlipNone :
258                                         tx = awt.geom.AffineTransform.getScaleInstance(-1, -1);
259                                         tx.translate( -Width, -Height );
260                                         break;
261
262                                 case RotateFlipType.Rotate270FlipNone :
263                                         tx = awt.geom.AffineTransform.getRotateInstance(-Math.PI / 2);
264                                         tx.translate( -Width, 0 );
265                                         break;
266
267                                 case RotateFlipType.RotateNoneFlipX :
268                                         tx = awt.geom.AffineTransform.getScaleInstance(-1, 1);
269                                         tx.translate( -Width, 0 );
270                                         break;
271
272                                 case RotateFlipType.Rotate90FlipX :
273                                         tx = awt.geom.AffineTransform.getRotateInstance(Math.PI / 2);
274                                         tx.scale(1, -1);
275                                         break;
276
277                                 case RotateFlipType.Rotate180FlipX :
278                                         tx = awt.geom.AffineTransform.getScaleInstance(1, -1);
279                                         tx.translate( 0, -Height );
280                                         break;
281
282                                 case RotateFlipType.Rotate270FlipX :
283                                         tx = awt.geom.AffineTransform.getRotateInstance(Math.PI / 2);
284                                         tx.scale(-1, 1);
285                                         tx.translate( -Width, -Height );
286                                         break;
287
288                                 default:
289                                         throw new ArgumentOutOfRangeException();
290                         }
291                         image.AffineTransformOp op = new image.AffineTransformOp(tx, image.AffineTransformOp.TYPE_NEAREST_NEIGHBOR);\r
292                         CurrentImage.NativeImage = op.filter((BufferedImage)CurrentImage.NativeImage, null);\r
293                 }
294                 #endregion
295
296                 #region Save
297                 protected abstract void InternalSave (ImageOutputStream output, Guid clsid);
298
299                 public void Save (Stream stream, ImageCodecInfo encoder, EncoderParameters encoderParams) {
300                         //TBD: implement encoderParams
301                         java.io.OutputStream jos = vmw.common.IOUtils.ToOutputStream (stream);
302                         MemoryCacheImageOutputStream output = new MemoryCacheImageOutputStream(jos);
303                 
304                         InternalSave (output, encoder.Clsid);
305                 }
306         
307                 public void Save(string filename, ImageCodecInfo encoder, EncoderParameters encoderParams) {
308                         //TBD: implement encoderParams
309                         java.io.File jf = vmw.common.IOUtils.getJavaFile (filename);
310                         FileImageOutputStream output = new FileImageOutputStream (jf);
311                         InternalSave (output, encoder.Clsid);
312                 }
313
314                 public void Save (string filename) {
315                         Save (filename, ImageFormat.Png);
316                 }
317
318                 public void Save (Stream stream, ImageFormat format) {
319                         Save (stream, ImageCodec.FindEncoder (
320                                 ImageCodec.ImageFormatToClsid (format)), null);
321                 }
322
323                 public void Save(string filename, ImageFormat format) {
324                         Save (filename, ImageCodec.FindEncoder (
325                                 ImageCodec.ImageFormatToClsid (format)), null);
326                 }
327                 #endregion
328
329                 #region SaveAdd
330                 // TBD: implement this
331                 public void SaveAdd(EncoderParameters encoderParams) {
332                         throw new NotImplementedException ();
333                 }
334         
335                 public void SaveAdd(Image image, EncoderParameters encoderParams) {
336                         throw new NotImplementedException ();
337                 }
338                 #endregion
339         
340                 #region SelectActiveFrame
341
342                 // TBD: .Net does not load all frames at the initialization. New frames loaded by request.
343                 public int SelectActiveFrame(FrameDimension dimension, int frameIndex) {
344                         // FALLBACK: now, only one dimension assigned for all frames
345                         if (dimension.Guid != CurrentImage.Dimension.Guid) 
346                                 throw new ArgumentException ("dimension");
347
348                         if (frameIndex < NativeObject.Count)
349                                 NativeObject.CurrentImageIndex = frameIndex;
350
351                         return frameIndex;
352                 }
353                 #endregion
354         
355                 #region SetPropertyItem
356                 // TBD: implement this
357                 public void SetPropertyItem(PropertyItem propitem) {
358                         throw new NotImplementedException ();
359                 }
360                 #endregion
361
362                 // properties
363                 #region Flags
364                 public int Flags {
365                         // TDB: ImageFlagsScalable, ImageFlagsHasTranslucent, ImageFlagsPartiallyScalable, ImageFlagsCaching
366                         get {
367                                 image.ColorModel colorModel = ((BufferedImage)CurrentImage.NativeImage).getColorModel();
368                                 int t = colorModel.getColorSpace().getType();
369                                 
370                                 if (t == awt.color.ColorSpace.TYPE_RGB)
371                                         _flags |= (int)ImageFlags.ImageFlagsColorSpaceRGB;
372                                 else if (t == awt.color.ColorSpace.TYPE_CMYK)
373                                         _flags |= (int)ImageFlags.ImageFlagsColorSpaceCMYK;
374                                 else if (t == awt.color.ColorSpace.TYPE_GRAY)
375                                         _flags |= (int)ImageFlags.ImageFlagsColorSpaceGRAY;
376                                 else if (t == awt.color.ColorSpace.TYPE_YCbCr)
377                                         _flags |= (int)ImageFlags.ImageFlagsColorSpaceYCBCR;
378
379                                 if (colorModel.hasAlpha())
380                                         _flags |= (int)ImageFlags.ImageFlagsHasAlpha;
381
382                                 if ((CurrentImage.HorizontalResolution > 0) || (CurrentImage.VerticalResolution > 0))
383                                         _flags |= (int)ImageFlags.ImageFlagsHasRealDPI;
384
385                                 return _flags;
386                         }
387                 }
388                 #endregion
389
390                 #region FrameDimensionsList
391                 public Guid[] FrameDimensionsList {
392                         // TBD: look over all frames and build array of dimensions
393                         // FALLBACK: now, only one dimension assigned for all frames
394                         get {
395                                 Guid [] dimList = new Guid[]{CurrentImage.Dimension.Guid};
396                                 return dimList;
397                         }
398                 }
399                 #endregion
400
401                 #region Height
402                 public int Height {
403                         get {
404                                 return CurrentImage.NativeImage.getHeight(null);
405                         }
406                 }
407                 #endregion
408         
409                 #region HorizontalResolution
410                 public float HorizontalResolution {
411                         get {
412                                 if (CurrentImage.HorizontalResolution == 0)
413                                         return Graphics.DefaultScreenResolution;
414
415                                 return CurrentImage.HorizontalResolution;
416                         }
417                 }
418                 #endregion
419         
420                 #region ColorPalette
421                 public ColorPalette Palette {
422                         get {
423                                 if (!(CurrentImage.NativeImage is BufferedImage))
424                                         // TBD: This implementation is for raster formats only
425                                         throw new NotImplementedException("Only raster formats are supported");
426
427                                 image.ColorModel colorModel = ((BufferedImage)CurrentImage.NativeImage).getColorModel();
428                                 if (colorModel is image.IndexColorModel) {
429
430                                         Color [] colors = new Color[ ((image.IndexColorModel)colorModel).getMapSize() ];
431                                         for (int i=0; i<colors.Length; i++) {
432                                                 colors[i] = Color.FromArgb( ((image.IndexColorModel)colorModel).getRGB(i) );
433                                         }
434                                         ColorPalette palette = new ColorPalette(0, colors);
435                                         return palette;
436                                 }
437                                 return new ColorPalette();
438                         }
439                         set {
440                                 // TBD: add set
441                                 throw new NotImplementedException ();
442                         }
443                 }
444                 #endregion
445                 
446                 #region PhysicalDimension
447                 public SizeF PhysicalDimension {
448                         get {
449                                 return new Size(Width, Height);
450                         }
451                 }
452                 #endregion
453         
454                 #region PixelFormat
455                 abstract protected PixelFormat InternalPixelFormat {get;}
456
457                 public PixelFormat PixelFormat {
458                         get {
459                                 return InternalPixelFormat;
460                         }
461                 }
462                 #endregion
463                 
464                 #region PropertiIdList
465                 // TBD: implement this
466                 public int[] PropertyIdList {
467                         get {
468                                 throw new NotImplementedException ();
469                         }
470                 }
471                 #endregion
472                 
473                 #region PropertItems
474                 // TBD: implement this
475                 public PropertyItem[] PropertyItems {
476                         get {
477                                 throw new NotImplementedException ();
478                         }
479                 }
480                 #endregion
481
482                 #region RawFormat
483                 public ImageFormat RawFormat {
484                         get {
485                                 return CurrentImage.ImageFormat;
486                         }
487                 }
488                 #endregion
489
490                 #region Size
491                 public Size Size {
492                         get {
493                                 return new Size(Width, Height);
494                         }
495                 }
496                 #endregion
497         
498                 #region VerticalResolution
499                 public float VerticalResolution {
500                         get {
501                                 if (CurrentImage.VerticalResolution == 0)
502                                         return Graphics.DefaultScreenResolution;
503
504                                 return CurrentImage.VerticalResolution;
505                         }
506                 }
507                 #endregion
508         
509                 #region Width
510                 public int Width {
511                         get {
512                                 return CurrentImage.NativeImage.getWidth(null);
513                         }
514                 }
515                 #endregion      
516
517                 public Image GetThumbnailImage(int thumbWidth, int thumbHeight, Image.GetThumbnailImageAbort callback, IntPtr callbackData) {
518                         awt.Image img;
519
520 #if THUMBNAIL_SUPPORTED
521                         if (CurrentImage.Thumbnails != null) {
522                                 for (int i=0; i < CurrentImage.Thumbnails.Length; i++)
523                                         if (CurrentImage.Thumbnails[i] != null) {
524                                                 img = CurrentImage.Thumbnails[i];
525                                                 if (img.getHeight(null) == thumbHeight && img.getWidth(null) == thumbWidth)
526                                                         return ImageFromNativeImage(img, RawFormat);
527                                         }
528                         }
529 #endif
530                         img = CurrentImage.NativeImage.getScaledInstance(thumbWidth, thumbHeight, awt.Image.SCALE_DEFAULT);
531
532                         return ImageFromNativeImage(img, RawFormat);
533                 }
534 #if INTPTR_SUPPORT
535         public static Bitmap FromHbitmap(IntPtr hbitmap)
536         {               
537                 throw new NotImplementedException ();
538         }       
539
540         public static Bitmap FromHbitmap(IntPtr hbitmap, IntPtr hpalette)
541         {               
542                 throw new NotImplementedException ();
543         }
544 #endif
545
546                 internal static Image ImageFromNativeImage(awt.Image nativeImage, ImageFormat format) {
547                         if (nativeImage is BufferedImage)
548                                 return new Bitmap(nativeImage, format);
549
550                         throw new ArgumentException("Invalid image type");
551                 }
552
553                 protected abstract awt.Image [] CloneNativeObjects(awt.Image [] src);
554         }
555
556 }