/// <summary> /// 從串流<see cref="System.IO.Stream"/>建立貼圖資源(非DDS) /// </summary> /// <param name="stream">串流</param> /// <param name="device">D3D Device</param> /// <param name="d3dContext">If a Direct3D 11 device context is provided and the current device supports it for the given pixel format, it will auto-generate mipmaps.</param> public static void CreateWICTextureFromStream(Device device, Stream stream, out Resource texture, out ShaderResourceView textureView, DeviceContext d3dContext = null) { texture = null; textureView = null; Guid containerFormatGuid; if (stream.CanRead) { if (stream.Length < 104857600 && stream.Length >= 8) { var temp = new byte[8]; stream.Read(temp, 0, 8); stream.Seek(0, SeekOrigin.Begin); // https://en.wikipedia.org/wiki/List_of_file_signatures if (temp[0] == 0xFF && temp[1] == 0xD8 && temp[2] == 0xFF) { containerFormatGuid = ContainerFormatGuids.Jpeg; } else if (temp[0] == 0x89 && temp[1] == 0x50 && temp[2] == 0x4E && temp[3] == 0x47 && temp[4] == 0x0D && temp[5] == 0x0A && temp[6] == 0x1A && temp[7] == 0x0A) { containerFormatGuid = ContainerFormatGuids.Png; } else if (temp[0] == 0x42 && temp[1] == 0x4D) { containerFormatGuid = ContainerFormatGuids.Bmp; } else if (temp[0] == 0x47 && temp[1] == 0x49 && temp[2] == 0x46 && temp[3] == 0x38 && (temp[4] == 0x37 || temp[4] == 0x39) && temp[5] == 0x61) { containerFormatGuid = ContainerFormatGuids.Gif; } else { return; } } using (var decoder = new BitmapDecoder(ImagingFactory, containerFormatGuid)) using (var wicstream = new WICStream(ImagingFactory, stream)) { try { decoder.Initialize(wicstream, DecodeOptions.CacheOnDemand); using (var frame = decoder.GetFrame(0)) { CreateWICTexture(device, d3dContext, frame, 0, ResourceUsage.Default, BindFlags.ShaderResource, CpuAccessFlags.None, ResourceOptionFlags.None, LoadFlags.Default, out texture, out textureView); } } catch (SharpDXException e) { System.Diagnostics.Debug.WriteLine(e.ToString()); } } } }
/// <summary> /// Function to determine if this codec can read the file or not. /// </summary> /// <param name="stream">Stream used to read the file information.</param> /// <returns> /// TRUE if the codec can read the file, FALSE if not. /// </returns> /// <exception cref="System.ArgumentNullException">Thrown when the <paramref name="stream"/> parameter is NULL (Nothing in VB.Net).</exception> /// <exception cref="System.IO.IOException">Thrown when the stream is write-only. /// <para>-or-</para> /// <para>Thrown when the stream cannot perform seek operations.</para> /// </exception> public override bool IsReadable(Stream stream) { if (stream == null) { throw new ArgumentNullException("stream"); } if (!stream.CanRead) { throw new IOException(Resources.GORGFX_STREAM_READ_ONLY); } if (!stream.CanSeek) { throw new IOException(Resources.GORGFX_STREAM_EOF); } long position = stream.Position; try { // Get our WIC interface. // Wrap the stream so WIC doesn't mess up the position. var wrapperStream = new GorgonStreamWrapper(stream); using (var wic = new GorgonWICImage()) { using (var decoder = new BitmapDecoder(wic.Factory, SupportedFormat)) { using (var wicStream = new WICStream(wic.Factory, wrapperStream)) { try { decoder.Initialize(wicStream, DecodeOptions.CacheOnDemand); } catch (SharpDXException) { return(false); } // Only load supported WIC formats. if (SupportedFormat != decoder.ContainerFormat) { return(false); } using (var frame = decoder.GetFrame(0)) { Guid bestFormat; var settings = ReadMetaData(wic, decoder, frame, out bestFormat); return(settings.Format != BufferFormat.Unknown); } } } } } finally { stream.Position = position; } }
/// <summary> /// Function to read file meta data. /// </summary> /// <param name="stream">Stream used to read the metadata.</param> /// <returns> /// The image meta data as a <see cref="GorgonLibrary.Graphics.IImageSettings">IImageSettings</see> value. /// </returns> /// <exception cref="System.ArgumentNullException">Thrown when the <paramref name="stream"/> parameter is NULL (Nothing in VB.Net).</exception> /// <exception cref="System.IO.IOException">Thrown when the stream is write-only. /// <para>-or-</para> /// <para>Thrown when the stream cannot perform seek operations.</para> /// </exception> /// <exception cref="System.IO.EndOfStreamException">Thrown when an attempt to read beyond the end of the stream is made.</exception> public override IImageSettings GetMetaData(Stream stream) { if (stream == null) { throw new ArgumentNullException("stream"); } if (!stream.CanRead) { throw new IOException(Resources.GORGFX_STREAM_WRITE_ONLY); } if (!stream.CanSeek) { throw new IOException(Resources.GORGFX_STREAM_NO_SEEK); } long position = stream.Position; try { // Wrap the stream so WIC doesn't mess up the position. var wrapperStream = new GorgonStreamWrapper(stream); // Get our WIC interface. using (var wic = new GorgonWICImage()) { using (var decoder = new BitmapDecoder(wic.Factory, SupportedFormat)) { using (var wicStream = new WICStream(wic.Factory, wrapperStream)) { try { decoder.Initialize(wicStream, DecodeOptions.CacheOnDemand); } catch (SharpDXException) { throw new IOException(string.Format(Resources.GORGFX_IMAGE_FILE_INCORRECT_ENCODER, Codec)); } using (var frame = decoder.GetFrame(0)) { Guid bestFormat; var settings = ReadMetaData(wic, decoder, frame, out bestFormat); if (settings.Format == BufferFormat.Unknown) { throw new IOException(string.Format(Resources.GORGFX_FORMAT_NOT_SUPPORTED, settings.Format)); } return(settings); } } } } } finally { stream.Position = position; } }
/// <summary> /// Function to load an image from a stream. /// </summary> /// <param name="stream">Stream containing the data to load.</param> /// <param name="size">Size of the data to read, in bytes.</param> /// <returns> /// The image data that was in the stream. /// </returns> protected internal override GorgonImageData LoadFromStream(GorgonDataStream stream, int size) { GorgonImageData result = null; // Get our WIC interface. var wrapperStream = new GorgonStreamWrapper(stream); using (var wic = new GorgonWICImage()) { using (var decoder = new BitmapDecoder(wic.Factory, SupportedFormat)) { using (var wicStream = new WICStream(wic.Factory, wrapperStream)) { try { decoder.Initialize(wicStream, DecodeOptions.CacheOnDemand); } catch (SharpDXException) { // Repackage this exception to keep in line with our API. throw new IOException(string.Format(Resources.GORGFX_IMAGE_FILE_INCORRECT_DECODER, Codec)); } using (var frame = decoder.GetFrame(0)) { Guid bestFormat; var settings = ReadMetaData(wic, decoder, frame, out bestFormat); if (settings.Format == BufferFormat.Unknown) { throw new IOException(string.Format(Resources.GORGFX_FORMAT_NOT_SUPPORTED, settings.Format)); } // Create our image data. try { _actualArrayCount = settings.ArrayCount; if (ArrayCount > 0) { settings.ArrayCount = ArrayCount; } result = new GorgonImageData(settings); if ((settings.ArrayCount > 1) && (_actualArrayCount > 1)) { ReadFrames(wic, result, decoder); } else { ReadFrame(wic, result, frame.PixelFormat, bestFormat, frame); } // If we've not read the full length of the data (WIC seems to ignore the CRC on the IEND chunk for PNG files for example), // then we need to move the pointer up by however many bytes we've missed. if (wrapperStream.Position < size) { wrapperStream.Position = size; } } catch { // If we run into a problem, dump the memory buffer. if (result != null) { result.Dispose(); } throw; } } } } } return(result); }
/// <summary> /// Function to retrieve a list of frame delays for each frame in an animated GIF. /// </summary> /// <param name="stream">Stream containing the animated GIF.</param> /// <returns> /// An array of frame delays (1/100th of a second), or an empty array if the image is not an animated GIF. /// </returns> /// <exception cref="System.ArgumentNullException">Thrown when the <paramref name="stream"/> parameter is NULL (Nothing in VB.Net).</exception> /// <exception cref="System.IO.IOException">Thrown when the stream parameter is write-only. /// <para>-or-</para> /// <para>The data in the stream could not be decoded as GIF file.</para> /// <para>-or-</para> /// <para>The stream cannot perform seek operations.</para> /// </exception> /// <exception cref="System.IO.EndOfStreamException">Thrown when an attempt to read beyond the end of the stream is made.</exception> public ushort[] GetFrameDelays(Stream stream) { var result = new ushort[0]; if (stream == null) { throw new ArgumentNullException("stream"); } if (!stream.CanRead) { throw new IOException(Resources.GORGFX_STREAM_WRITE_ONLY); } if (!stream.CanSeek) { throw new IOException(Resources.GORGFX_STREAM_NO_SEEK); } if (!UseAllFrames) { return(result); } long position = stream.Position; try { var wrapperStream = new GorgonStreamWrapper(stream); // Get our WIC interface. using (var wic = new GorgonWICImage()) { using (var decoder = new BitmapDecoder(wic.Factory, SupportedFormat)) { using (var wicStream = new WICStream(wic.Factory, wrapperStream)) { try { decoder.Initialize(wicStream, DecodeOptions.CacheOnDemand); } catch (DX.SharpDXException) { // Repackage the exception to keep in line with our API defintion. throw new IOException(string.Format(Resources.GORGFX_IMAGE_FILE_INCORRECT_DECODER, Codec)); } if (decoder.FrameCount < 2) { return(result); } result = new ushort[decoder.FrameCount]; for (int frame = 0; frame < result.Length; frame++) { using (var frameImage = decoder.GetFrame(frame)) { // Check to see if we can actually read this thing. if (frame == 0) { Guid temp; IImageSettings settings = ReadMetaData(wic, decoder, frameImage, out temp); if (settings.Format == BufferFormat.Unknown) { throw new IOException(string.Format(Resources.GORGFX_FORMAT_NOT_SUPPORTED, settings.Format)); } } using (var reader = frameImage.MetadataQueryReader) { var metaData = reader.GetMetadataByName("/grctlext/Delay"); if (metaData != null) { result[frame] = (ushort)metaData; } else { result[frame] = 0; } } } } } } } } finally { stream.Position = position; } return(result); }