/// <summary> /// Initializes a new instance of the <see cref="GorgonChunkedFormat" /> class. /// </summary> /// <param name="stream">The stream to use to output the chunked data.</param> /// <param name="accessMode">Stream access mode for the chunk object.</param> /// <exception cref="System.ArgumentNullException">Thrown when the <paramref name="stream"/> parameter is NULL (Nothing in VB.Net).</exception> /// <exception cref="System.ArgumentException">Thrown when the <paramref name="accessMode"/> parameter is set to read, but the stream cannot be read. /// <para>-or-</para> /// <para>Thrown when the accessMode parameter is set to write, but the stream cannot be written.</para> /// <para>-or-</para> /// <para>Thrown if the stream can't perform seek operations.</para> /// </exception> protected GorgonChunkedFormat(Stream stream, ChunkAccessMode accessMode) { if (stream == null) { throw new ArgumentNullException("stream"); } ChunkAccessMode = accessMode; if (!stream.CanSeek) { throw new ArgumentException(Resources.GOR_STREAM_NOT_SEEKABLE, "stream"); } if (accessMode == ChunkAccessMode.Write) { if (!stream.CanWrite) { throw new ArgumentException(Resources.GOR_STREAM_IS_READONLY, "accessMode"); } Writer = new GorgonBinaryWriter(stream, true); } else { if (!stream.CanRead) { throw new ArgumentException(Resources.GOR_STREAM_IS_WRITEONLY, "accessMode"); } Reader = new GorgonBinaryReader(stream, true); } }
/// <summary> /// Function to write out the DDS header to the stream. /// </summary> /// <param name="settings">Meta data for the image header.</param> /// <param name="writer">Writer interface for the stream.</param> /// <param name="conversionFlags">Flags for image conversion.</param> private void WriteHeader(IImageSettings settings, GorgonBinaryWriter writer, out TGAConversionFlags conversionFlags) { TGAHeader header = default(TGAHeader); conversionFlags = TGAConversionFlags.None; if ((settings.Width > 0xFFFF) || (settings.Height > 0xFFFF)) { throw new IOException(string.Format(Resources.GORGFX_IMAGE_FILE_INCORRECT_ENCODER, Codec)); } header.Width = (ushort)(settings.Width); header.Height = (ushort)(settings.Height); switch (settings.Format) { case BufferFormat.R8G8B8A8_UIntNormal: case BufferFormat.R8G8B8A8_UIntNormal_sRGB: header.ImageType = TGAImageType.TrueColor; header.BPP = 32; header.Descriptor = TGADescriptor.InvertY | TGADescriptor.RGB888A8; conversionFlags |= TGAConversionFlags.Swizzle; break; case BufferFormat.B8G8R8A8_UIntNormal: case BufferFormat.B8G8R8A8_UIntNormal_sRGB: header.ImageType = TGAImageType.TrueColor; header.BPP = 32; header.Descriptor = TGADescriptor.InvertY | TGADescriptor.RGB888A8; break; case BufferFormat.B8G8R8X8_UIntNormal: case BufferFormat.B8G8R8X8_UIntNormal_sRGB: header.ImageType = TGAImageType.TrueColor; header.BPP = 24; header.Descriptor = TGADescriptor.InvertY; conversionFlags |= TGAConversionFlags.RGB888; break; case BufferFormat.R8_UIntNormal: case BufferFormat.A8_UIntNormal: header.ImageType = TGAImageType.BlackAndWhite; header.BPP = 8; header.Descriptor = TGADescriptor.InvertY; break; case BufferFormat.B5G5R5A1_UIntNormal: header.ImageType = TGAImageType.TrueColor; header.BPP = 16; header.Descriptor = TGADescriptor.InvertY | TGADescriptor.RGB555A1; break; default: throw new IOException(string.Format(Resources.GORGFX_FORMAT_NOT_SUPPORTED, settings.Format)); } // Persist to stream. writer.WriteValue(header); }
/// <summary> /// Initializes a new instance of the <see cref="GorgonChunkedFormat" /> class. /// </summary> /// <param name="stream">The stream to use to output the chunked data.</param> /// <param name="accessMode">Stream access mode for the chunk object.</param> /// <exception cref="ArgumentNullException">Thrown when the <paramref name="stream"/> parameter is NULL (Nothing in VB.Net).</exception> /// <exception cref="ArgumentException">Thrown when the <paramref name="accessMode"/> parameter is set to read, but the stream cannot be read. /// <para>-or-</para> /// <para>Thrown when the accessMode parameter is set to write, but the stream cannot be written.</para> /// <para>-or-</para> /// <para>Thrown if the stream can't perform seek operations.</para> /// </exception> protected GorgonChunkedFormat(Stream stream, ChunkAccessMode accessMode) { if (stream == null) { throw new ArgumentNullException(nameof(stream)); } ChunkAccessMode = accessMode; if (!stream.CanSeek) { throw new ArgumentException(Resources.GOR2DIO_ERR_STREAM_UNSEEKABLE, nameof(stream)); } if (accessMode == ChunkAccessMode.Write) { if (!stream.CanWrite) { throw new ArgumentException(Resources.GOR2DIO_ERR_STREAM_IS_READ_ONLY, nameof(accessMode)); } Writer = new GorgonBinaryWriter(stream, true); } else { if (!stream.CanRead) { throw new ArgumentException(Resources.GOR2DIO_ERR_STREAM_IS_WRITE_ONLY, nameof(accessMode)); } Reader = new GorgonBinaryReader(stream, true); } }
/// <summary> /// Function to persist image data to a stream. /// </summary> /// <param name="imageData"><see cref="GorgonLibrary.Graphics.GorgonImageData">Gorgon image data</see> to persist.</param> /// <param name="stream">Stream that will contain the data.</param> protected internal override void SaveToStream(GorgonImageData imageData, Stream stream) { // Use a binary writer. using (var writer = new GorgonBinaryWriter(stream, true)) { // Write the header for the file. TGAConversionFlags conversionFlags; WriteHeader(imageData.Settings, writer, out conversionFlags); GorgonFormatPitch pitch; if ((conversionFlags & TGAConversionFlags.RGB888) == TGAConversionFlags.RGB888) { pitch = new GorgonFormatPitch(imageData.Settings.Width * 3, imageData.Settings.Width * 3 * imageData.Settings.Height); } else { var formatInfo = GorgonBufferFormatInfo.GetInfo(imageData.Settings.Format); pitch = formatInfo.GetPitch(imageData.Settings.Width, imageData.Settings.Height, PitchFlags.None); } // Get the pointer to the first mip/array/depth level. var srcPointer = (byte *)imageData.Buffers[0].Data.UnsafePointer; var srcPitch = imageData.Buffers[0].PitchInformation; // If the two pitches are equal, then just write out the buffer. if ((pitch == srcPitch) && (conversionFlags == TGAConversionFlags.None)) { writer.Write(srcPointer, srcPitch.SlicePitch); return; } // If we have to do a conversion, create a worker buffer. using (var convertBuffer = new GorgonDataStream(pitch.SlicePitch)) { var destPtr = (byte *)convertBuffer.UnsafePointer; // Write out each scan line. for (int y = 0; y < imageData.Settings.Height; y++) { if ((conversionFlags & TGAConversionFlags.RGB888) == TGAConversionFlags.RGB888) { Compress24BPPScanLine(srcPointer, srcPitch.RowPitch, destPtr, pitch.RowPitch); } else if ((conversionFlags & TGAConversionFlags.Swizzle) == TGAConversionFlags.Swizzle) { SwizzleScanline(srcPointer, srcPitch.RowPitch, destPtr, pitch.RowPitch, imageData.Settings.Format, ImageBitFlags.None); } else { CopyScanline(srcPointer, srcPitch.RowPitch, destPtr, pitch.RowPitch, imageData.Settings.Format, ImageBitFlags.None); } destPtr += pitch.RowPitch; srcPointer += srcPitch.RowPitch; } // Persist to the stream. writer.Write(convertBuffer.UnsafePointer, pitch.SlicePitch); } } }