// Ravindra (rkumar@novell.com)
//
+//
+// Copyright (C) 2004 Novell, Inc (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
using System;
using System.Runtime.Remoting;
using System.Runtime.Serialization;
using System.ComponentModel;
using System.Drawing.Imaging;
using System.IO;
+using System.Reflection;
namespace System.Drawing
{
public abstract class Image : MarshalByRefObject, IDisposable , ICloneable, ISerializable
{
public delegate bool GetThumbnailImageAbort();
+ private object tag;
internal IntPtr nativeObject = IntPtr.Zero;
- protected ColorPalette colorPalette;
// constructor
internal Image()
- {
- colorPalette = new ColorPalette();
+ {
+
}
private Image (SerializationInfo info, StreamingContext context)
}
}
}
+
+ private static bool IsIndexedPixelFormat(PixelFormat pixfmt)
+ {
+ return ((pixfmt & PixelFormat.Indexed) != 0);
+ }
+
- [MonoTODO]
void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
{
- throw new NotImplementedException();
+ MemoryStream ms = new MemoryStream ();
+ this.Save (ms, RawFormat);
+ info.AddValue ("Data", ms.ToArray ());
}
// public methods
// static
public static Image FromFile(string filename)
{
- return new Bitmap (filename);
+ return FromFile (filename, false);
}
public static Image FromFile(string filename, bool useEmbeddedColorManagement)
{
- return new Bitmap (filename, useEmbeddedColorManagement);
+ IntPtr imagePtr;
+ Status st;
+
+ if (!File.Exists (filename))
+ throw new FileNotFoundException (filename);
+
+ if (useEmbeddedColorManagement)
+ st = GDIPlus.GdipLoadImageFromFileICM (filename, out imagePtr);
+ else
+ st = GDIPlus.GdipLoadImageFromFile (filename, out imagePtr);
+
+ GDIPlus.CheckStatus (st);
+ return new Bitmap (imagePtr);
}
- [MonoTODO]
public static Bitmap FromHbitmap(IntPtr hbitmap)
- {
- throw new NotImplementedException ();
+ {
+ return FromHbitmap (hbitmap, IntPtr.Zero);
}
- [MonoTODO]
public static Bitmap FromHbitmap(IntPtr hbitmap, IntPtr hpalette)
{
- throw new NotImplementedException ();
+ IntPtr imagePtr;
+ Status st;
+
+ st = GDIPlus.GdipCreateBitmapFromHBITMAP (hbitmap, hpalette, out imagePtr);
+
+ GDIPlus.CheckStatus (st);
+ return new Bitmap (imagePtr);
}
public static Image FromStream (Stream stream)
return new Bitmap (stream, useECM);
}
+ // See http://support.microsoft.com/default.aspx?scid=kb;en-us;831419 for performance discussion
+ public static Image FromStream (Stream stream, bool useECM, bool validateImageData)
+ {
+ return new Bitmap (stream, useECM);
+ }
+
public static int GetPixelFormatSize(PixelFormat pixfmt)
{
int result = 0;
return ((pixfmt & PixelFormat.Extended) != 0);
}
- internal protected void InitFromStream (Stream stream)
+ internal void InitFromStream (Stream stream)
{
- if (Environment.OSVersion.Platform == (PlatformID) 128) {
+ IntPtr imagePtr;
+ Status st;
+
+ // Seeking required
+ if (!stream.CanSeek) {
+ byte[] buffer = new byte[256];
+ int index = 0;
+ int count;
+
+ do {
+ if (buffer.Length < index + 256) {
+ byte[] newBuffer = new byte[buffer.Length * 2];
+ Array.Copy(buffer, newBuffer, buffer.Length);
+ buffer = newBuffer;
+ }
+ count = stream.Read(buffer, index, 256);
+ index += count;
+ }
+ while (count != 0);
+
+ stream = new MemoryStream(buffer, 0, index);
+ }
+
+ // check for Unix platforms - see FAQ for more details
+ // http://www.mono-project.com/FAQ:_Technical#How_to_detect_the_execution_platform_.3F
+ int platform = (int) Environment.OSVersion.Platform;
+ if ((platform == 4) || (platform == 128)) {
// Unix, with libgdiplus
// We use a custom API for this, because there's no easy way
// to get the Stream down to libgdiplus. So, we wrap the stream
// with a set of delegates.
GDIPlus.GdiPlusStreamHelper sh = new GDIPlus.GdiPlusStreamHelper (stream);
- IntPtr imagePtr;
- Status st = GDIPlus.GdipLoadImageFromDelegate_linux (sh.GetBytesDelegate,
- sh.SeekDelegate,
- out imagePtr);
- GDIPlus.CheckStatus (st);
- nativeObject = imagePtr;
+ st = GDIPlus.GdipLoadImageFromDelegate_linux (sh.GetHeaderDelegate, sh.GetBytesDelegate,
+ sh.PutBytesDelegate, sh.SeekDelegate, sh.CloseDelegate, sh.SizeDelegate, out imagePtr);
} else {
// this is MS-land
- // FIXME
- // We can't call the native gdip functions here, because they expect
- // a COM IStream interface. So, a hack is to create a tmp file, read
- // the stream, and then load from the tmp file.
- // This is an ugly hack.
- throw new NotImplementedException ("Bitmap.InitFromStream (win32)");
+ st = GDIPlus.GdipLoadImageFromStream(new ComIStreamWrapper(stream), out imagePtr);
}
+
+ GDIPlus.CheckStatus (st);
+ nativeObject = imagePtr;
}
// non-static
return source;
}
- [MonoTODO]
- public EncoderParameters GetEncoderParameterList(Guid encoder)
+ public EncoderParameters GetEncoderParameterList(Guid format)
{
- throw new NotImplementedException ();
+ Status status;
+ uint sz;
+
+ status = GDIPlus.GdipGetEncoderParameterListSize (nativeObject, ref format, out sz);
+ GDIPlus.CheckStatus (status);
+
+ IntPtr rawEPList = Marshal.AllocHGlobal ((int) sz);
+ EncoderParameters eps;
+
+ try {
+ status = GDIPlus.GdipGetEncoderParameterList (nativeObject, ref format, sz, rawEPList);
+ eps = EncoderParameters.FromNativePtr (rawEPList);
+ GDIPlus.CheckStatus (status);
+ }
+ finally {
+ Marshal.FreeHGlobal (rawEPList);
+ }
+
+ return eps;
}
public int GetFrameCount(FrameDimension dimension)
}
- [MonoTODO]
public PropertyItem GetPropertyItem(int propid)
{
- throw new NotImplementedException ();
+ int propSize;
+ IntPtr property;
+ PropertyItem item = new PropertyItem ();
+ GdipPropertyItem gdipProperty = new GdipPropertyItem ();
+ Status status;
+
+ status = GDIPlus.GdipGetPropertyItemSize (nativeObject, propid,
+ out propSize);
+ GDIPlus.CheckStatus (status);
+
+ /* Get PropertyItem */
+ property = Marshal.AllocHGlobal (propSize);
+ try {
+ status = GDIPlus.GdipGetPropertyItem (nativeObject, propid, propSize, property);
+ GDIPlus.CheckStatus (status);
+ gdipProperty = (GdipPropertyItem) Marshal.PtrToStructure (property,
+ typeof (GdipPropertyItem));
+ GdipPropertyItem.MarshalTo (gdipProperty, item);
+ }
+ finally {
+ Marshal.FreeHGlobal (property);
+ }
+ return item;
}
- [MonoTODO]
- public Image GetThumbnailImage(int thumbWidth, int thumbHeight, Image.GetThumbnailImageAbort callback, IntPtr callbackData)
+ public Image GetThumbnailImage (int thumbWidth, int thumbHeight, Image.GetThumbnailImageAbort callback, IntPtr callbackData)
{
- throw new NotImplementedException ();
+ if ((thumbWidth <= 0) || (thumbHeight <= 0))
+ throw new OutOfMemoryException ("Invalid thumbnail size");
+
+ Image ThumbNail = new Bitmap (thumbWidth, thumbHeight);
+
+ using (Graphics g = Graphics.FromImage (ThumbNail)) {
+ Status status = GDIPlus.GdipDrawImageRectRectI (g.nativeObject, nativeObject,
+ 0, 0, thumbWidth, thumbHeight,
+ 0, 0, this.Width, this.Height,
+ GraphicsUnit.Pixel, IntPtr.Zero, null, IntPtr.Zero);
+
+ GDIPlus.CheckStatus (status);
+ }
+
+ return ThumbNail;
}
GDIPlus.CheckStatus (status);
}
- public void Save (string filename)
- {
- Save (filename, RawFormat);
- }
-
- public void Save (Stream stream, ImageFormat format)
+ internal ImageCodecInfo findEncoderForFormat (ImageFormat format)
{
- Status st;
- if (Environment.OSVersion.Platform == (PlatformID) 128) {
- byte[] g = format.Guid.ToByteArray();
- GDIPlus.GdiPlusStreamHelper sh = new GDIPlus.GdiPlusStreamHelper (stream);
- st = GDIPlus.GdipSaveImageToDelegate_linux (nativeObject, sh.PutBytesDelegate, g, IntPtr.Zero);
-
- } else {
- throw new NotImplementedException ("Image.Save(Stream) (win32)");
- }
- GDIPlus.CheckStatus (st);
- }
-
- public void Save(string filename, ImageFormat format)
- {
- Status st;
- ImageCodecInfo[] encoders = ImageCodecInfo.GetImageEncoders();
+ ImageCodecInfo[] encoders = ImageCodecInfo.GetImageEncoders();
ImageCodecInfo encoder = null;
- Guid guid;
if (format.Guid.Equals (ImageFormat.MemoryBmp.Guid))
- format = ImageFormat.Bmp;
+ format = ImageFormat.Png;
/* Look for the right encoder for our format*/
for (int i = 0; i < encoders.Length; i++) {
break;
}
}
-
+
+ return encoder;
+ }
+
+ public void Save (string filename)
+ {
+ Save (filename, RawFormat);
+ }
+
+ public void Save(string filename, ImageFormat format)
+ {
+ ImageCodecInfo encoder = findEncoderForFormat (format);
+
if (encoder == null)
- throw new ArgumentException ("No coded available for format:" + format.Guid);
-
- guid = encoder.Clsid;
- st = GDIPlus.GdipSaveImageToFile (nativeObject, filename, ref guid, IntPtr.Zero);
- GDIPlus.CheckStatus (st);
+ throw new ArgumentException ("No codec available for format:" + format.Guid);
+
+ Save (filename, encoder, null);
}
-
- internal void setGDIPalette()
+
+ public void Save(string filename, ImageCodecInfo encoder, EncoderParameters encoderParams)
{
- IntPtr gdipalette;
+ Status st;
+ Guid guid = encoder.Clsid;
- gdipalette = colorPalette.getGDIPalette ();
- Status st = GDIPlus.GdipSetImagePalette (NativeObject, gdipalette);
- Marshal.FreeHGlobal (gdipalette);
+ if (encoderParams == null) {
+ st = GDIPlus.GdipSaveImageToFile (nativeObject, filename, ref guid, IntPtr.Zero);
+ } else {
+ IntPtr nativeEncoderParams = encoderParams.ToNativePtr ();
+ st = GDIPlus.GdipSaveImageToFile (nativeObject, filename, ref guid, nativeEncoderParams);
+ Marshal.FreeHGlobal (nativeEncoderParams);
+ }
GDIPlus.CheckStatus (st);
}
- [MonoTODO ("Ignoring EncoderParameters")]
- public void Save(Stream stream, ImageCodecInfo encoder, EncoderParameters encoderParams)
+ public void Save (Stream stream, ImageFormat format)
{
- Save (stream, new ImageFormat (encoder.FormatID));
+ ImageCodecInfo encoder = findEncoderForFormat (format);
+
+ if (encoder == null)
+ throw new ArgumentException ("No codec available for format:" + format.Guid);
+
+ Save (stream, encoder, null);
}
-
- [MonoTODO ("Ignoring EncoderParameters")]
- public void Save(string filename, ImageCodecInfo encoder, EncoderParameters encoderParams)
+
+ public void Save(Stream stream, ImageCodecInfo encoder, EncoderParameters encoderParams)
{
- Save (filename, new ImageFormat (encoder.FormatID));
+ Status st;
+ IntPtr nativeEncoderParams;
+ Guid guid = encoder.Clsid;
+
+ if (encoderParams == null)
+ nativeEncoderParams = IntPtr.Zero;
+ else
+ nativeEncoderParams = encoderParams.ToNativePtr ();
+
+ try {
+ // check for Unix platforms - see FAQ for more details
+ // http://www.mono-project.com/FAQ:_Technical#How_to_detect_the_execution_platform_.3F
+ int platform = (int) Environment.OSVersion.Platform;
+ if ((platform == 4) || (platform == 128)) {
+ GDIPlus.GdiPlusStreamHelper sh = new GDIPlus.GdiPlusStreamHelper (stream);
+ st = GDIPlus.GdipSaveImageToDelegate_linux (nativeObject, sh.GetBytesDelegate, sh.PutBytesDelegate,
+ sh.SeekDelegate, sh.CloseDelegate, sh.SizeDelegate, ref guid, nativeEncoderParams);
+ }
+ else
+ st = GDIPlus.GdipSaveImageToStream(new HandleRef(this, nativeObject), new ComIStreamWrapper(stream), ref guid, new HandleRef(encoderParams, nativeEncoderParams));
+ }
+ finally {
+ if (nativeEncoderParams != IntPtr.Zero)
+ Marshal.FreeHGlobal (nativeEncoderParams);
+ }
+
+ GDIPlus.CheckStatus (st);
}
- [MonoTODO]
- public void SaveAdd(EncoderParameters encoderParams)
+ public void SaveAdd (EncoderParameters encoderParams)
{
- throw new NotImplementedException ();
+ Status st;
+
+ IntPtr nativeEncoderParams = encoderParams.ToNativePtr ();
+ st = GDIPlus.GdipSaveAdd (nativeObject, nativeEncoderParams);
+ Marshal.FreeHGlobal (nativeEncoderParams);
+ GDIPlus.CheckStatus (st);
}
-
- [MonoTODO]
- public void SaveAdd(Image image, EncoderParameters encoderParams)
+
+ public void SaveAdd (Image image, EncoderParameters encoderParams)
{
- throw new NotImplementedException ();
+ Status st;
+
+ IntPtr nativeEncoderParams = encoderParams.ToNativePtr ();
+ st = GDIPlus.GdipSaveAddImage (nativeObject, image.NativeObject, nativeEncoderParams);
+ Marshal.FreeHGlobal (nativeEncoderParams);
+ GDIPlus.CheckStatus (st);
}
-
-
+
public int SelectActiveFrame(FrameDimension dimension, int frameIndex)
{
Guid guid = dimension.Guid;
return frameIndex;
}
- [MonoTODO]
public void SetPropertyItem(PropertyItem propitem)
{
- throw new NotImplementedException ();
+ IntPtr property;
+ int size = Marshal.SizeOf (typeof(GdipPropertyItem));
+ property = Marshal.AllocHGlobal (size);
+
+ Marshal.StructureToPtr (propitem, property, true);
+ Status status = GDIPlus.GdipSetPropertyItem (nativeObject, property);
+ GDIPlus.CheckStatus (status);
+ // FIXME: GdipSetPropertyItem isn't implemented in libgdiplus (but returns Ok)
+ // so who's freeing "property" ? GDI+ ?
}
// properties
uint found;
Status status = GDIPlus.GdipImageGetFrameDimensionsCount (nativeObject, out found);
GDIPlus.CheckStatus (status);
- Guid [] guid = new Guid [found ];
+ Guid [] guid = new Guid [found];
status = GDIPlus.GdipImageGetFrameDimensionsList (nativeObject, guid, found);
GDIPlus.CheckStatus (status);
return guid;
[Browsable (false)]
public ColorPalette Palette {
get {
-
- return colorPalette;
+ return retrieveGDIPalette();
}
set {
- colorPalette = value;
+ storeGDIPalette(value);
}
}
-
-
+
+ internal ColorPalette retrieveGDIPalette()
+ {
+ ColorPalette ret = new ColorPalette();
+ if (!IsIndexedPixelFormat (PixelFormat)) {
+ return ret;
+ }
+ Status st;
+ int bytes;
+
+ st = GDIPlus.GdipGetImagePaletteSize (nativeObject, out bytes);
+ GDIPlus.CheckStatus (st);
+ IntPtr palette_data = Marshal.AllocHGlobal (bytes);
+ try {
+ st = GDIPlus.GdipGetImagePalette (nativeObject, palette_data, bytes);
+ GDIPlus.CheckStatus (st);
+ ret.setFromGDIPalette (palette_data);
+ return ret;
+ }
+
+ finally {
+ Marshal.FreeHGlobal (palette_data);
+ }
+ }
+
+ internal void storeGDIPalette(ColorPalette palette)
+ {
+ if (palette == null) {
+ throw new ArgumentNullException("palette");
+ }
+ IntPtr palette_data = palette.getGDIPalette();
+ if (palette_data == IntPtr.Zero) {
+ return;
+ }
+
+ try {
+ Status st = GDIPlus.GdipSetImagePalette (nativeObject, palette_data);
+ GDIPlus.CheckStatus (st);
+ }
+
+ finally {
+ Marshal.FreeHGlobal(palette_data);
+ }
+ }
+
+
public SizeF PhysicalDimension {
get {
float width, height;
}
}
-
- [MonoTODO]
[Browsable (false)]
public int[] PropertyIdList {
get {
- throw new NotImplementedException ();
+ uint propNumbers;
+
+ Status status = GDIPlus.GdipGetPropertyCount (nativeObject,
+ out propNumbers);
+ GDIPlus.CheckStatus (status);
+
+ int [] idList = new int [propNumbers];
+ status = GDIPlus.GdipGetPropertyIdList (nativeObject,
+ propNumbers, idList);
+ GDIPlus.CheckStatus (status);
+
+ return idList;
}
}
- [MonoTODO]
[Browsable (false)]
public PropertyItem[] PropertyItems {
get {
- throw new NotImplementedException ();
+ int propNums, propsSize, propSize;
+ IntPtr properties, propPtr;
+ PropertyItem[] items;
+ GdipPropertyItem gdipProperty = new GdipPropertyItem ();
+ Status status;
+
+ status = GDIPlus.GdipGetPropertySize (nativeObject, out propsSize, out propNums);
+ GDIPlus.CheckStatus (status);
+
+ items = new PropertyItem [propNums];
+
+ if (propNums == 0)
+ return items;
+
+ /* Get PropertyItem list*/
+ properties = Marshal.AllocHGlobal (propsSize * propNums);
+ try {
+ status = GDIPlus.GdipGetAllPropertyItems (nativeObject, propsSize,
+ propNums, properties);
+ GDIPlus.CheckStatus (status);
+
+ propSize = Marshal.SizeOf (gdipProperty);
+ propPtr = properties;
+
+ for (int i = 0; i < propNums; i++, propPtr = new IntPtr (propPtr.ToInt64 () + propSize)) {
+ gdipProperty = (GdipPropertyItem) Marshal.PtrToStructure
+ (propPtr, typeof (GdipPropertyItem));
+ items [i] = new PropertyItem ();
+ GdipPropertyItem.MarshalTo (gdipProperty, items [i]);
+ }
+ }
+ finally {
+ Marshal.FreeHGlobal (properties);
+ }
+ return items;
}
}
return new Size(Width, Height);
}
}
-
+
+#if NET_2_0
+ [DefaultValue (null)]
+ [LocalizableAttribute(false)]
+ [BindableAttribute(true)]
+ [TypeConverter (typeof (StringConverter))]
+ public object Tag {
+ get { return tag; }
+ set { tag = value; }
+ }
+#endif
public float VerticalResolution {
get {
float resolution;
public void Dispose ()
{
Dispose (true);
+ System.GC.SuppressFinalize (this);
}
~Image ()
Dispose (false);
}
- protected virtual void DisposeResources ()
- {
- Status status = GDIPlus.GdipDisposeImage (nativeObject);
- GDIPlus.CheckStatus (status);
- }
-
protected virtual void Dispose (bool disposing)
{
- if (nativeObject != (IntPtr) 0){
- DisposeResources ();
- nativeObject=IntPtr.Zero;
+ if (nativeObject != IntPtr.Zero){
+ Status status = GDIPlus.GdipDisposeImage (nativeObject);
+ // set nativeObject to null before throwing an exception
+ nativeObject = IntPtr.Zero;
+ GDIPlus.CheckStatus (status);
}
}
-
- public virtual object Clone()
- {
+ public object Clone ()
+ {
+ Bitmap b = (this as Bitmap);
+ if (b == null)
+ throw new NotImplementedException ("This Image instance isn't a Bitmap instance.");
+
IntPtr newimage = IntPtr.Zero;
-
- if (!(this is Bitmap))
- throw new NotImplementedException ();
-
Status status = GDIPlus.GdipCloneImage (NativeObject, out newimage);
-
GDIPlus.CheckStatus (status);
-
- if (this is Bitmap)
- return new Bitmap (newimage);
-
- throw new NotImplementedException ();
- }
+ return new Bitmap (newimage);
+ }
}
}