/// <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); }
/// <summary> /// Save media to a <see cref="IO.Stream"/>. /// </summary> /// <param name="path"> /// A <see cref="String"/> that specify the file path where media data is stored. /// </param> /// <param name="media"> /// A <typeparamref name="TMedia"/> that holds the data to be stored. /// </param> /// <param name="format"> /// A <see cref="String"/> that specify the media format to used for saving <paramref name="media"/>. /// </param> /// <param name="criteria"> /// A <see cref="MediaCodecCriteria"/> that specify parameters for loading an image stream. /// </param> /// <exception cref="ArgumentNullException"> /// This exception is thrown if at least one of the parameters <paramref name="path"/> or <paramref name="media"/> /// is null. /// </exception> /// <exception cref="InvalidOperationException"> /// This exception is thrown if no plugin cannot save the image <paramref name="media"/> on <paramref name="path"/>. /// </exception> public void Save(string path, TMedia media, string format, MediaCodecCriteria criteria) { if (path == null) { throw new ArgumentNullException("path"); } if (media == null) { throw new ArgumentNullException("media"); } string tempMediaPath = Path.GetTempFileName(); bool alreadyExisting = File.Exists(path); try { // Save media (on temporary file) using (FileStream fs = new FileStream(tempMediaPath, FileMode.Create, FileAccess.Write)) { Save(fs, media, format, criteria); } // Place saved media if (alreadyExisting) { File.Copy(tempMediaPath, path, true); // Copy existing file (overwriting) } else { File.Move(tempMediaPath, path); // Move temporary file } } catch { File.Delete(tempMediaPath); throw; } }
/// <summary> /// Load media from stream. /// </summary> /// <param name="stream"> /// A <see cref="Stream"/> where the media data is stored. /// </param> /// <param name="format"> /// The <see cref="String"/> which defines the format of the stream data. /// </param> /// <param name="criteria"> /// A <see cref="MediaCodecCriteria"/> that specify parameters for loading an media stream. /// </param> /// <returns> /// An <typeparamref name="TMedia"/> holding the media data. /// </returns> /// <exception cref="ArgumentNullException"> /// Exception thrown if <paramref name="stream"/> or <paramref name="criteria"/> is null. /// </exception> /// <exception cref="ArgumentException"> /// Exception thrown if <paramref name="stream"/> is not readable or seekable. /// </exception> /// <exception cref="InvalidOperationException"> /// Exception thrown if no plugin is available for <paramref name="format"/> (filtered by /// <paramref name="criteria"/>) or all plugins are not able to load media from /// <paramref name="stream"/>. /// </exception> /// <exception cref="NotSupportedException"> /// Exception thrown if <paramref name="format"/> is not supported by any loaded plugin. /// </exception> public override Image Load(Stream stream, string format, MediaCodecCriteria criteria) { // Base implementation Image image = base.Load(stream, format, criteria); // Fix container format in MediaInformation image.MediaInformation.ContainerFormat = format; return(image); }
/// <summary> /// Load media from a local file. /// </summary> /// <param name="uri"> /// A <see cref="String"/> that specify the resource path where the media data is stored. /// </param> /// <param name="format"> /// The <see cref="String"/> which defines the format of the stream data. /// </param> /// <param name="criteria"> /// A <see cref="MediaCodecCriteria"/> that specify parameters for loading an media stream. /// </param> /// <returns> /// An <typeparamref name="TMedia"/> holding the media data. /// </returns> public TMedia Load(string uri, string format, MediaCodecCriteria criteria) { if (uri == null) { throw new ArgumentNullException("uri"); } using (MediaStream ms = new MediaStream(uri, FileMode.Open, FileAccess.Read)) { return(Load(ms, format, criteria)); } }
/// <summary> /// Query media informations. /// </summary> /// <param name="path"> /// A <see cref="String"/> that specify the file path where media data is stored. /// </param> /// <param name="criteria"> /// A <see cref="MediaCodecCriteria"/> that specify parameters for loading an media stream. /// </param> /// <returns> /// A <typeparamref name="TMediaInfo"/> containing information about the specified media. /// </returns> public TMediaInfo QueryInfo(string path, MediaCodecCriteria criteria) { if (path == null) { throw new ArgumentNullException("path"); } if (criteria == null) { throw new ArgumentNullException("criteria"); } using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read)) { return(QueryInfo(fs, criteria)); } }
/// <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 <typeparamref name="TMediaInfo"/> containing information about the specified media. /// </returns> public TMediaInfo QueryInfo(Stream stream, MediaCodecCriteria criteria) { if (stream == null) { throw new ArgumentNullException("stream"); } if (stream.CanRead == false) { throw new ArgumentException(String.Format("unable to read from stream")); } if (stream.CanSeek == false) { throw new ArgumentException(String.Format("stream is not seekable")); } if (criteria == null) { throw new ArgumentNullException("criteria"); } List <TPlugin> supportedPlugins = Plugins; // Class filtering if (supportedPlugins != null) { supportedPlugins = FilterReadPlugins(supportedPlugins, criteria); } if (supportedPlugins == null) { throw new InvalidOperationException("no plugin available"); } foreach (TPlugin plugin in supportedPlugins) { try { // Rewind stream if (stream.CanSeek) { stream.Seek(0, SeekOrigin.Begin); } // Try to get information return(plugin.QueryInfo(stream, criteria)); } catch { } } // Don't returns not assigned information throw new InvalidOperationException(String.Format("no plugin can query information on media")); }
/// <summary> /// Load media from a local file. /// </summary> /// <param name="uri"> /// A <see cref="String"/> that specify the resource path where the media data is stored. /// </param> /// <param name="criteria"> /// A <see cref="MediaCodecCriteria"/> that specify parameters for loading an media stream. /// </param> /// <returns> /// An <typeparamref name="TMedia"/> holding the media data. /// </returns> /// <exception cref="InvalidOperationException"> /// Eception thrown if no media plugin can open <paramref name="uri"/>. /// </exception> public TMedia Load(string uri, MediaCodecCriteria criteria) { if (uri == null) { throw new ArgumentNullException("uri"); } foreach (string format in GetFormatsFromUrl(uri)) { using (MediaStream ms = new MediaStream(uri, FileMode.Open, FileAccess.Read)) { return(Load(ms, format, criteria)); } } throw new InvalidOperationException(String.Format("no format recognized from URI \"{0}\"", uri)); }
/// <summary> /// Query media informations. /// </summary> /// <param name="uri"> /// A <see cref="Uri"/> that specify the resource location where media data is stored. /// </param> /// <param name="criteria"> /// A <see cref="MediaCodecCriteria"/> that specify parameters for loading an media stream. /// </param> /// <returns> /// A <typeparamref name="TMediaInfo"/> containing information about the specified media. /// </returns> public TMediaInfo QueryInfo(Uri uri, MediaCodecCriteria criteria) { if (uri == null) { throw new ArgumentNullException("uri"); } if (criteria == null) { throw new ArgumentNullException("criteria"); } string localPath = GetLocalUriPath(uri); using (FileStream fs = new FileStream(localPath, FileMode.Open, FileAccess.Read)) { return(QueryInfo(fs, criteria)); } }
/// <summary> /// Filters the plugins (used for reading) by criteria. /// </summary> /// <returns> /// The read plugins. /// </returns> /// <param name='plugins'> /// The actual plugin list. /// </param> /// <param name='criteria'> /// Criteria. /// </param> /// <exception cref='ArgumentNullException'> /// Is thrown when an argument passed to a method is invalid because it is <see langword="null" /> . /// </exception> protected virtual List <TPlugin> FilterWritePlugins(List <TPlugin> plugins, MediaCodecCriteria criteria) { if (plugins == null) { throw new ArgumentNullException("plugins"); } if (criteria == null) { throw new ArgumentNullException("criteria"); } // Criteria: PluginName if (criteria.IsDefined(PluginName)) { plugins = plugins.FindAll(delegate(TPlugin obj) { return(obj.Name == (string)criteria[PluginName]); }); } return(plugins); }
/// <summary> /// Load media from stream. /// </summary> /// <param name="stream"> /// A <see cref="Stream"/> where the media data is stored. /// </param> /// <param name="format"> /// The <see cref="String"/> which defines the format of the stream data. /// </param> /// <param name="criteria"> /// A <see cref="MediaCodecCriteria"/> that specify parameters for loading an media stream. /// </param> /// <returns> /// An <typeparamref name="TMedia"/> holding the media data. /// </returns> /// <exception cref="ArgumentNullException"> /// Exception thrown if <paramref name="stream"/> or <paramref name="criteria"/> is null. /// </exception> /// <exception cref="ArgumentException"> /// Exception thrown if <paramref name="stream"/> is not readable or seekable. /// </exception> /// <exception cref="InvalidOperationException"> /// Exception thrown if no plugin is available for <paramref name="format"/> (filtered by /// <paramref name="criteria"/>) or all plugins are not able to load media from /// <paramref name="stream"/>. /// </exception> /// <exception cref="NotSupportedException"> /// Exception thrown if <paramref name="format"/> is not supported by any loaded plugin. /// </exception> public virtual TMedia Load(Stream stream, string format, MediaCodecCriteria criteria) { if (stream == null) { throw new ArgumentNullException("stream"); } if (criteria == null) { throw new ArgumentNullException("criteria"); } if (stream.CanRead == false) { throw new ArgumentException("unable to read from stream"); } List <TPlugin> supportedPlugins = Plugins; // Format filtering if (supportedPlugins != null) { supportedPlugins = FilterReadPlugins(supportedPlugins, format); } if ((supportedPlugins == null) || (supportedPlugins.Count == 0)) { throw new NotSupportedException(String.Format("format {0} is not supported", format)); } // Class filtering supportedPlugins = FilterReadPlugins(supportedPlugins, criteria); if ((supportedPlugins == null) || (supportedPlugins.Count == 0)) { throw new InvalidOperationException("no plugin available"); } StringBuilder exceptionMessage = new StringBuilder(); foreach (TPlugin plugin in supportedPlugins) { try { // Rewind stream if (stream.CanSeek) { stream.Seek(0, SeekOrigin.Begin); } // Try to get information return(plugin.Load(stream, criteria)); } catch (Exception exception) { if (supportedPlugins.Count > 1) { exceptionMessage.AppendLine(String.Format("- '{0}' exception: {1};", plugin.Name, exception.Message)); continue; } throw new InvalidOperationException(String.Format("no plugin can load media: {0}", exception.Message)); } } // Remove trailing carriage return. exceptionMessage = exceptionMessage.Remove(exceptionMessage.Length - 1, 1); // Don't returns not assigned information throw new InvalidOperationException(String.Format("no plugin can load media; the reasons are:\n{0}", exceptionMessage)); }
/// <summary> /// Save media to a <see cref="IO.Stream"/>. /// </summary> /// <param name="stream"> /// A <see cref="IO.Stream"/> that stores the media data. /// </param> /// <param name="media"> /// A <typeparamref name="TMedia"/> that holds the data to be stored. /// </param> /// <param name="format"> /// A <see cref="String"/> that specify the media format to used for saving <paramref name="media"/>. /// </param> /// <param name="criteria"> /// A <see cref="MediaCodecCriteria"/> that specify parameters for loading an image stream. /// </param> /// <exception cref="ArgumentNullException"> /// This exception is thrown if at least one of the parameters <paramref name="stream"/> or <paramref name="media"/> /// is null. /// </exception> /// <exception cref="ArgumentException"> /// This exception is thrown if <paramref name="stream"/> cannot be seek or cannot be written. /// </exception> /// <exception cref="InvalidOperationException"> /// This exception is thrown if no plugin cannot save the media <paramref name="media"/> on the stream <paramref name="stream"/>. /// </exception> public void Save(Stream stream, TMedia media, string format, MediaCodecCriteria criteria) { if (stream == null) { throw new ArgumentNullException("stream"); } if (media == null) { throw new ArgumentNullException("media"); } if (stream.CanWrite == false) { throw new ArgumentException(String.Format("unable to write to stream")); } if (stream.CanSeek == false) { throw new ArgumentException(String.Format("unable to seek on stream")); } List <TPlugin> supportedPlugins = Plugins; // Format filtering if (supportedPlugins != null) { supportedPlugins = FilterWritePlugins(supportedPlugins, format); } if (supportedPlugins == null) { throw new NotSupportedException(String.Format("format {0} is not supported", format)); } // Class filtering if (criteria != null) { supportedPlugins = FilterWritePlugins(supportedPlugins, criteria); } if (supportedPlugins == null) { throw new InvalidOperationException("no plugin available"); } StringBuilder pluginLog = new StringBuilder(); // Write image pixel data foreach (TPlugin plugin in supportedPlugins) { try { // Position file cursor at beginning if (stream.CanSeek) { stream.Seek(0, SeekOrigin.Begin); } // Save image pixel data plugin.Save(stream, media, format, criteria); return; } catch (Exception exception) { pluginLog.AppendLine(String.Format("- Exception of plugin '{0}': {1}", plugin.Name, exception.Message)); } } throw new InvalidOperationException(String.Format("no plugin can save media. Detailed information:\n{0}", pluginLog)); }
/// <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> /// 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); }