/// <summary>
		/// Internal method for creating Image from Bitmap.
		/// </summary>
		/// <param name="bitmap">
		/// A <see cref="Drawing.Bitmap"/> to be converted into an <see cref="Image"/> instance.
		/// </param>
		/// <param name="criteria">
		/// A <see cref="MediaCodecCriteria"/> that specify image conversion criteria.
		/// </param>
		/// <returns>
		/// It returns a <see cref="Image"/> instance that's equivalent to <paramref name="bitmap"/>.
		/// </returns>
		/// <exception cref="ArgumentNullException">
		/// Exception thrown if <paramref name="bitmap"/> or <see cref="criteria"/> is null.
		/// </exception>
		internal static Image LoadFromBitmap(System.Drawing.Bitmap bitmap, MediaCodecCriteria criteria)
		{
			if (bitmap == null)
				throw new ArgumentNullException("bitmap");
			if (criteria == null)
				throw new ArgumentNullException("criteria");

			PixelLayout pType, pConvType;

			// Allocate image raster
			ConvertPixelFormat(bitmap, out pType);

			// Check for hardware/software support
			if (Pixel.IsSupportedInternalFormat(pType) == false) {
				if (criteria.IsDefined(ImageCodecCriteria.SoftwareSupport) && ((bool)criteria[ImageCodecCriteria.SoftwareSupport])) {
					// Pixel type not directly supported by hardware... try to guess suitable software conversion
					pConvType = Pixel.GuessBestSupportedConvertion(pType);
					if (pConvType == PixelLayout.None)
						throw new InvalidOperationException(String.Format("pixel type {0} is not supported by hardware neither software", pType));
				} else
					throw new InvalidOperationException(String.Format("pixel type {0} is not supported by hardware", pType));
			} else
				pConvType = pType;

			Image image = new Image(pType, (uint)bitmap.Width, (uint)bitmap.Height);

			switch (bitmap.PixelFormat) {
				case System.Drawing.Imaging.PixelFormat.Format1bppIndexed:
				case System.Drawing.Imaging.PixelFormat.Format4bppIndexed:
				case System.Drawing.Imaging.PixelFormat.Format8bppIndexed:
					if (Runtime.RunningMono) {
						// Bug 676362 - Bitmap Clone does not format return image to requested PixelFormat
						// https://bugzilla.novell.com/show_bug.cgi?id=676362
						//
						// ATM no mono version has resolved the bug; current workaround is performing image
						// sampling pixel by pixel, using internal conversion routines, even if it is very slow
						
						LoadBitmapByPixel(bitmap, image);
					} else
						LoadBitmapByClone(bitmap, image);
					break;
				default:
					LoadBitmapByLockBits(bitmap, image);
					break;
			}

			// ConvertItemType image to supported format, if necessary
			if ((pConvType != PixelLayout.None) && (pConvType != pType))
				image = image.Convert(pConvType);
			
			return (image);
		}
		/// <summary>
		/// Save media to stream.
		/// </summary>
		/// <param name="stream">
		/// A <see cref="IO.Stream"/> which stores the media data.
		/// </param>
		/// <param name="image">
		/// A <see cref="Image"/> holding the data to be stored.
		/// </param>
		/// <param name="format">
		/// A <see cref="String"/> that specify the media format to used for saving <paramref name="image"/>.
		/// </param>
		/// <param name="criteria">
		/// A <see cref="MediaCodecCriteria"/> that specify parameters for loading an image stream.
		/// </param>
		/// <exception cref="ArgumentNullException">
		/// Exception thrown if <paramref name="stream"/>, <paramref name="image"/> or <paramref name="criteria"/> is null.
		/// </exception>
		public void Save(Stream stream, Image image, string format, MediaCodecCriteria criteria)
		{
			Bitmap iBitmap;
			System.Drawing.Imaging.ImageFormat iBitmapFormat;
			System.Drawing.Imaging.PixelFormat iBitmapPixelFormat;
			int iBitmapFlags;

			ConvertImageFormat(format, out iBitmapFormat);
			ConvertPixelFormat(image.PixelLayout, out iBitmapPixelFormat, out iBitmapFlags);

			// Obtain source and destination data pointers
			using (iBitmap = new Bitmap((int)image.Width, (int)image.Height, iBitmapPixelFormat)) {
				BitmapData iBitmapData = null;
				IntPtr imageData = image.ImageBuffer;

				try {
					iBitmapData = iBitmap.LockBits(new System.Drawing.Rectangle(0, 0, iBitmap.Width, iBitmap.Height), ImageLockMode.ReadOnly, iBitmap.PixelFormat);

					// Copy Image data dst Bitmap
					unsafe {
						byte* hImageDataPtr = (byte*)imageData.ToPointer();
						byte* iBitmapDataPtr = (byte*)iBitmapData.Scan0.ToPointer();
						uint hImageDataStride = image.Stride;
						uint iBitmapDataStride = (uint)iBitmapData.Stride;
						
						// .NET Image Library stores bitmap scan line data in memory padded dst 4 bytes boundaries
						// .NET Image Library expect a bottom up image, so invert the scan line order

						iBitmapDataPtr = iBitmapDataPtr + ((image.Height-1) * iBitmapDataStride);

						for (uint line = 0; line < image.Height; line++, hImageDataPtr += hImageDataStride, iBitmapDataPtr -= iBitmapDataStride)
							Memory.MemoryCopy(iBitmapDataPtr, hImageDataPtr, hImageDataStride);
					}
				} finally {
					if (iBitmapData != null)
						iBitmap.UnlockBits(iBitmapData);
				}

				// Save image with the specified format
				ImageCodecInfo encoderInfo = Array.Find(ImageCodecInfo.GetImageEncoders(), delegate(ImageCodecInfo item) {
					return (item.FormatID == iBitmapFormat.Guid);
				});

				EncoderParameters encoderParams = null;

				try {
					EncoderParameters encoderInfoParamList = iBitmap.GetEncoderParameterList(encoderInfo.Clsid);
					EncoderParameter[] encoderInfoParams = encoderInfoParamList != null ? encoderInfoParamList.Param : null;
					bool supportQuality = false;
					int paramsCount = 0;

					if (encoderInfoParams != null) {
						Array.ForEach(encoderInfoParams, delegate(EncoderParameter item) {
							if (item.Encoder.Guid == Encoder.Quality.Guid) {
								supportQuality = true;
								paramsCount++;
							}
						});
					}

					encoderParams = new EncoderParameters(paramsCount);

					paramsCount = 0;
					if (supportQuality)
						encoderParams.Param[paramsCount++] = new EncoderParameter(Encoder.Quality, 100);
				} catch (Exception) {
					// Encoder does not support parameters
				}

				iBitmap.Save(stream, encoderInfo, encoderParams);
			}
		}
		/// <summary>
		/// Query media informations.
		/// </summary>
		/// <param name="stream">
		/// A <see cref="Stream"/> where the media data is stored.
		/// </param>
		/// <param name="criteria">
		/// A <see cref="MediaCodecCriteria"/> that specify parameters for loading an media stream.
		/// </param>
		/// <returns>
		/// A <see cref="ImageInfo"/> containing information about the specified media.
		/// </returns>
		/// <exception cref="ArgumentNullException">
		/// Exception thrown if <paramref name="stream"/> or <paramref name="criteria"/> is null.
		/// </exception>
		public ImageInfo QueryInfo(Stream stream, MediaCodecCriteria criteria)
		{
			if (stream == null)
				throw new ArgumentNullException("stream");
			if (criteria == null)
				throw new ArgumentNullException("criteria");

			ImageInfo info = new ImageInfo();
			
			using (System.Drawing.Bitmap iBitmap = new System.Drawing.Bitmap(stream)) {
				PixelLayout iBitmapPixelType;
				string containerFormat;

				ConvertImageFormat(iBitmap.RawFormat, out containerFormat);
				ConvertPixelFormat(iBitmap, out iBitmapPixelType);

				info.ContainerFormat = containerFormat;
				info.PixelType = iBitmapPixelType;
				info.Width = (uint)iBitmap.Width;
				info.Height = (uint)iBitmap.Height;
			}

			return (info);
		}