Exemple #1
0
        /// <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);
                }
            }
        }
Exemple #2
0
        /// <summary>
        /// Function to perform the copying of image data into the buffer.
        /// </summary>
        /// <param name="stream">Stream containing the image data.</param>
        /// <param name="image">Image data.</param>
        /// <param name="conversionFlags">Flags used to convert the image.</param>
        private void CopyImageData(GorgonDataStream stream, GorgonImageData image, TGAConversionFlags conversionFlags)
        {
            var buffer     = image.Buffers[0];                  // Get the first buffer only.
            var formatInfo = GorgonBufferFormatInfo.GetInfo(image.Settings.Format);

            GorgonFormatPitch srcPitch = (conversionFlags & TGAConversionFlags.Expand) == TGAConversionFlags.Expand
                                                             ? new GorgonFormatPitch(image.Settings.Width * 3, image.Settings.Width * 3 * image.Settings.Height)
                                                             : formatInfo.GetPitch(image.Settings.Width, image.Settings.Height, PitchFlags.None);

            // Otherwise, allocate a buffer for conversion.
            var srcPtr  = (byte *)stream.PositionPointerUnsafe;
            var destPtr = (byte *)buffer.Data.UnsafePointer;

            // Adjust destination for inverted axes.
            if ((conversionFlags & TGAConversionFlags.InvertX) == TGAConversionFlags.InvertX)
            {
                destPtr += buffer.PitchInformation.RowPitch - formatInfo.SizeInBytes;
            }

            if ((conversionFlags & TGAConversionFlags.InvertY) != TGAConversionFlags.InvertY)
            {
                destPtr += (image.Settings.Height - 1) * buffer.PitchInformation.RowPitch;
            }

            // Get bounds of image memory.
            var   scanSize = (int)(stream.Length - stream.Position);
            byte *endScan  = (byte *)stream.PositionPointerUnsafe + scanSize;

            int opaqueLineCount = 0;

            for (int y = 0; y < image.Settings.Height; y++)
            {
                bool setOpaque;

                if ((conversionFlags & TGAConversionFlags.RLE) == TGAConversionFlags.RLE)
                {
                    setOpaque = ReadCompressed(ref srcPtr, image.Settings.Width, destPtr, endScan, image.Settings.Format, conversionFlags);
                }
                else
                {
                    setOpaque = ReadUncompressed(srcPtr, srcPitch.RowPitch, destPtr, image.Settings.Format, conversionFlags);
                    srcPtr   += srcPitch.RowPitch;
                }

                if ((setOpaque) && (SetOpaqueIfZeroAlpha))
                {
                    opaqueLineCount++;
                }

                if ((conversionFlags & TGAConversionFlags.InvertY) != TGAConversionFlags.InvertY)
                {
                    destPtr -= buffer.PitchInformation.RowPitch;
                }
                else
                {
                    destPtr += buffer.PitchInformation.RowPitch;
                }
            }

            if (opaqueLineCount != image.Settings.Height)
            {
                return;
            }

            // Set the alpha to opaque if we don't have any alpha values (i.e. alpha = 0 for all pixels).
            destPtr = (byte *)buffer.Data.UnsafePointer;
            for (int y = 0; y < image.Settings.Height; y++)
            {
                CopyScanline(destPtr, buffer.PitchInformation.RowPitch, destPtr, buffer.PitchInformation.RowPitch, image.Settings.Format, ImageBitFlags.OpaqueAlpha);
                destPtr += buffer.PitchInformation.RowPitch;
            }
        }