コード例 #1
0
        /// <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);
        }
コード例 #2
0
        /// <summary>
        /// Function to write out the DDS header to the stream.
        /// </summary>
        /// <param name="settings">Meta data for the image header.</param>
        /// <param name="conversionFlags">Flags required for image conversion.</param>
        /// <returns>A TGA header value, populated with the correct settings.</returns>
        private TgaHeader GetHeader(IGorgonImageInfo settings, out TGAConversionFlags conversionFlags)
        {
            TgaHeader header = default;

            conversionFlags = TGAConversionFlags.None;

            if ((settings.Width > 0xFFFF) ||
                (settings.Height > 0xFFFF))
            {
                throw new IOException(string.Format(Resources.GORIMG_ERR_FILE_FORMAT_NOT_CORRECT, Codec));
            }

            header.Width  = (ushort)(settings.Width);
            header.Height = (ushort)(settings.Height);

            switch (settings.Format)
            {
            case BufferFormat.R8G8B8A8_UNorm:
            case BufferFormat.R8G8B8A8_UNorm_SRgb:
                header.ImageType  = TgaImageType.TrueColor;
                header.BPP        = 32;
                header.Descriptor = TgaDescriptor.InvertY | TgaDescriptor.RGB888A8;
                conversionFlags  |= TGAConversionFlags.Swizzle;
                break;

            case BufferFormat.B8G8R8A8_UNorm:
            case BufferFormat.B8G8R8A8_UNorm_SRgb:
                header.ImageType  = TgaImageType.TrueColor;
                header.BPP        = 32;
                header.Descriptor = TgaDescriptor.InvertY | TgaDescriptor.RGB888A8;
                break;

            case BufferFormat.B8G8R8X8_UNorm:
            case BufferFormat.B8G8R8X8_UNorm_SRgb:
                header.ImageType  = TgaImageType.TrueColor;
                header.BPP        = 24;
                header.Descriptor = TgaDescriptor.InvertY;
                conversionFlags  |= TGAConversionFlags.RGB888;
                break;

            case BufferFormat.R8_UNorm:
            case BufferFormat.A8_UNorm:
                header.ImageType  = TgaImageType.BlackAndWhite;
                header.BPP        = 8;
                header.Descriptor = TgaDescriptor.InvertY;
                break;

            case BufferFormat.B5G5R5A1_UNorm:
                header.ImageType  = TgaImageType.TrueColor;
                header.BPP        = 16;
                header.Descriptor = TgaDescriptor.InvertY | TgaDescriptor.RGB555A1;
                break;

            default:
                throw new IOException(string.Format(Resources.GORIMG_ERR_FORMAT_NOT_SUPPORTED, settings.Format));
            }

            // Persist to stream.
            return(header);
        }
コード例 #3
0
        /// <summary>
        /// Function to read uncompressed TGA scanline data.
        /// </summary>
        /// <param name="src">Pointer to the source data.</param>
        /// <param name="srcPitch">Pitch of the source scan line.</param>
        /// <param name="dest">Destination buffer pointner</param>
        /// <param name="format">Format of the destination buffer.</param>
        /// <param name="conversionFlags">Flags used for conversion.</param>
        private static bool ReadUncompressed(byte *src, int srcPitch, byte *dest, BufferFormat format, TGAConversionFlags conversionFlags)
        {
            bool setOpaque      = true;
            bool flipHorizontal = (conversionFlags & TGAConversionFlags.InvertX) == TGAConversionFlags.InvertX;

            switch (format)
            {
            case BufferFormat.R8_UIntNormal:
                for (int x = 0; x < srcPitch; x++)
                {
                    if (!flipHorizontal)
                    {
                        *(dest++) = *(src++);
                    }
                    else
                    {
                        *(dest--) = *(src++);
                    }
                }
                return(false);

            case BufferFormat.B5G5R5A1_UIntNormal:
            {
                var destPtr = (ushort *)dest;

                for (int x = 0; x < srcPitch; x += 2)
                {
                    var pixel = (ushort)(*(src++) | (*(src++) << 8));

                    if ((pixel & 0x8000) != 0)
                    {
                        setOpaque = false;
                    }

                    if (!flipHorizontal)
                    {
                        *(destPtr++) = pixel;
                    }
                    else
                    {
                        *(destPtr--) = pixel;
                    }
                }

                return(setOpaque);
            }

            case BufferFormat.R8G8B8A8_UIntNormal:
            {
                var destPtr = (uint *)dest;
                int x       = 0;

                while (x < srcPitch)
                {
                    uint pixel;

                    // We need to expand from 24 bit.
                    if ((conversionFlags & TGAConversionFlags.Expand) == TGAConversionFlags.Expand)
                    {
                        pixel     = ((uint)(*(src++) << 16) | (uint)(*(src++) << 8) | (*(src++)) | 0xFF000000);
                        setOpaque = false;
                        x        += 3;
                    }
                    else
                    {
                        uint alpha = 0;

                        pixel = ((uint)(*(src++) << 16) | (uint)(*(src++) << 8) | (*(src++)) | alpha);
                        alpha = (uint)(*(src++) << 24);

                        pixel |= alpha;

                        if (alpha != 0)
                        {
                            setOpaque = false;
                        }

                        x += 4;
                    }

                    if (!flipHorizontal)
                    {
                        *(destPtr++) = pixel;
                    }
                    else
                    {
                        *(destPtr--) = pixel;
                    }
                }

                return(setOpaque);
            }
            }

            return(false);
        }
コード例 #4
0
        /// <summary>
        /// Function to read uncompressed TGA scanline data.
        /// </summary>
        /// <param name="src">Pointer to the source data.</param>
        /// <param name="width">Image width.</param>
        /// <param name="dest">Destination buffer pointner</param>
        /// <param name="end">End of the scan line.</param>
        /// <param name="format">Format of the destination buffer.</param>
        /// <param name="conversionFlags">Flags used for conversion.</param>
        private bool ReadCompressed(ref byte *src, int width, byte *dest, byte *end, BufferFormat format, TGAConversionFlags conversionFlags)
        {
            bool setOpaque      = true;
            bool flipHorizontal = (conversionFlags & TGAConversionFlags.InvertX) == TGAConversionFlags.InvertX;

            switch (format)
            {
            case BufferFormat.R8_UIntNormal:
                for (int x = 0; x < width;)
                {
                    if (src >= end)
                    {
                        throw new IOException(string.Format(Resources.GORGFX_IMAGE_FILE_INCORRECT_DECODER, Codec));
                    }

                    int size = ((*src & 0x7F) + 1);

                    // Do a repeat run.
                    if ((*(src++) & 0x80) != 0)
                    {
                        if (src >= end)
                        {
                            throw new IOException(string.Format(Resources.GORGFX_IMAGE_FILE_INCORRECT_DECODER, Codec));
                        }

                        for (; size > 0; --size, ++x)
                        {
                            if (x >= width)
                            {
                                throw new IOException(string.Format(Resources.GORGFX_IMAGE_FILE_INCORRECT_DECODER, Codec));
                            }

                            if (!flipHorizontal)
                            {
                                *(dest++) = *src;
                            }
                            else
                            {
                                *(dest--) = *src;
                            }
                        }

                        ++src;
                    }
                    else
                    {
                        if (src + size > end)
                        {
                            throw new IOException(string.Format(Resources.GORGFX_IMAGE_FILE_INCORRECT_DECODER, Codec));
                        }

                        for (; size > 0; --size, ++x)
                        {
                            if (x >= width)
                            {
                                throw new IOException(string.Format(Resources.GORGFX_IMAGE_FILE_INCORRECT_DECODER, Codec));
                            }

                            if (!flipHorizontal)
                            {
                                *(dest++) = *(src++);
                            }
                            else
                            {
                                *(dest--) = *(src++);
                            }
                        }
                    }
                }
                return(false);

            case BufferFormat.B5G5R5A1_UIntNormal:
            {
                var destPtr = (ushort *)dest;

                for (int x = 0; x < width;)
                {
                    if (src >= end)
                    {
                        throw new IOException(string.Format(Resources.GORGFX_IMAGE_FILE_INCORRECT_DECODER, Codec));
                    }

                    int size = ((*src & 0x7F) + 1);

                    // Do a repeat run.
                    if ((*(src++) & 0x80) != 0)
                    {
                        if ((src + 1) >= end)
                        {
                            throw new IOException(string.Format(Resources.GORGFX_IMAGE_FILE_INCORRECT_DECODER, Codec));
                        }

                        var pixel = (ushort)(*(src++) | (*(src++) << 8));

                        if ((pixel & 0x8000) != 0)
                        {
                            setOpaque = false;
                        }

                        for (; size > 0; size--, ++x)
                        {
                            if (x >= width)
                            {
                                throw new IOException(string.Format(Resources.GORGFX_IMAGE_FILE_INCORRECT_DECODER, Codec));
                            }

                            if (!flipHorizontal)
                            {
                                *(destPtr++) = pixel;
                            }
                            else
                            {
                                *(destPtr--) = pixel;
                            }
                        }
                    }
                    else
                    {
                        if (src + (size * 2) > end)
                        {
                            throw new IOException(string.Format(Resources.GORGFX_IMAGE_FILE_INCORRECT_DECODER, Codec));
                        }

                        for (; size > 0; size--, ++x)
                        {
                            if (x >= width)
                            {
                                throw new IOException(string.Format(Resources.GORGFX_IMAGE_FILE_INCORRECT_DECODER, Codec));
                            }

                            var pixel = (ushort)(*(src++) | (*(src++) << 8));

                            if ((pixel & 0x8000) != 0)
                            {
                                setOpaque = false;
                            }

                            if (!flipHorizontal)
                            {
                                *(destPtr++) = pixel;
                            }
                            else
                            {
                                *(destPtr--) = pixel;
                            }
                        }
                    }
                }
                return(setOpaque);
            }

            case BufferFormat.R8G8B8A8_UIntNormal:
            {
                var destPtr = (uint *)dest;

                for (int x = 0; x < width;)
                {
                    if (src >= end)
                    {
                        throw new IOException(string.Format(Resources.GORGFX_IMAGE_FILE_INCORRECT_DECODER, Codec));
                    }

                    uint pixel;
                    int  size = (*src & 0x7F) + 1;

                    if ((*(src++) & 0x80) != 0)
                    {
                        // Do expansion.
                        if ((conversionFlags & TGAConversionFlags.Expand) == TGAConversionFlags.Expand)
                        {
                            if (src + 2 >= end)
                            {
                                throw new IOException(string.Format(Resources.GORGFX_IMAGE_FILE_INCORRECT_DECODER, Codec));
                            }

                            pixel     = ((uint)(*src << 16) | (uint)(*(src + 1) << 8) | (*(src + 2)) | 0xFF000000);
                            src      += 3;
                            setOpaque = false;
                        }
                        else
                        {
                            if (src + 3 >= end)
                            {
                                throw new IOException(string.Format(Resources.GORGFX_IMAGE_FILE_INCORRECT_DECODER, Codec));
                            }

                            pixel = ((uint)(*src << 16) | (uint)(*(src + 1) << 8) | (*(src + 2)) | (uint)(*(src + 3) << 24));

                            if (*(src + 3) > 0)
                            {
                                setOpaque = false;
                            }

                            src += 4;
                        }

                        for (; size > 0; --size, ++x)
                        {
                            if (x >= width)
                            {
                                throw new IOException(string.Format(Resources.GORGFX_IMAGE_FILE_INCORRECT_DECODER, Codec));
                            }

                            if (!flipHorizontal)
                            {
                                *(destPtr++) = pixel;
                            }
                            else
                            {
                                *(destPtr--) = pixel;
                            }
                        }
                    }
                    else
                    {
                        if ((conversionFlags & TGAConversionFlags.Expand) == TGAConversionFlags.Expand)
                        {
                            if (src + (size * 3) > end)
                            {
                                throw new IOException(string.Format(Resources.GORGFX_IMAGE_FILE_INCORRECT_DECODER, Codec));
                            }
                        }
                        else
                        {
                            if (src + (size * 4) > end)
                            {
                                throw new IOException(string.Format(Resources.GORGFX_IMAGE_FILE_INCORRECT_DECODER, Codec));
                            }
                        }

                        for (; size > 0; --size, ++x)
                        {
                            if (x >= width)
                            {
                                throw new IOException(string.Format(Resources.GORGFX_IMAGE_FILE_INCORRECT_DECODER, Codec));
                            }

                            if ((conversionFlags & TGAConversionFlags.Expand) == TGAConversionFlags.Expand)
                            {
                                if (src + 2 >= end)
                                {
                                    throw new IOException(string.Format(Resources.GORGFX_IMAGE_FILE_INCORRECT_DECODER, Codec));
                                }

                                pixel = ((uint)(*src << 16) | (uint)(*(src + 1) << 8) | (*(src + 2)) | 0xFF000000);
                                src  += 3;

                                setOpaque = false;
                            }
                            else
                            {
                                if (src + 3 >= end)
                                {
                                    throw new IOException(string.Format(Resources.GORGFX_IMAGE_FILE_INCORRECT_DECODER, Codec));
                                }

                                pixel = ((uint)(*src << 16) | (uint)(*(src + 1) << 8) | (*(src + 2)) | (uint)(*(src + 3) << 24));

                                if (*(src + 3) > 0)
                                {
                                    setOpaque = false;
                                }

                                src += 4;
                            }

                            if (!flipHorizontal)
                            {
                                *(destPtr++) = pixel;
                            }
                            else
                            {
                                *(destPtr--) = pixel;
                            }
                        }
                    }
                }

                return(setOpaque);
            }
            }

            return(false);
        }
コード例 #5
0
        /// <summary>
        /// Function to read in the DDS header from a stream.
        /// </summary>
        /// <param name="stream">Stream containing the data.</param>
        /// <param name="conversionFlags">Flags for conversion.</param>
        /// <returns>New image settings.</returns>
        private IImageSettings ReadHeader(GorgonDataStream stream, out TGAConversionFlags conversionFlags)
        {
            IImageSettings settings = new GorgonTexture2DSettings();

            conversionFlags = TGAConversionFlags.None;

            // Get the header for the file.
            var header = stream.Read <TGAHeader>();

            if ((header.ColorMapType != 0) || (header.ColorMapLength != 0) ||
                (header.Width <= 0) || (header.Height <= 0) ||
                ((header.Descriptor & TGADescriptor.Interleaved2Way) == TGADescriptor.Interleaved2Way) ||
                ((header.Descriptor & TGADescriptor.Interleaved4Way) == TGADescriptor.Interleaved4Way))
            {
                throw new IOException(string.Format(Resources.GORGFX_IMAGE_FILE_INCORRECT_DECODER, Codec));
            }

            settings.MipCount   = 1;
            settings.ArrayCount = 1;

            switch (header.ImageType)
            {
            case TGAImageType.TrueColor:
            case TGAImageType.TrueColorRLE:
                switch (header.BPP)
                {
                case 16:
                    settings.Format = BufferFormat.B5G5R5A1_UIntNormal;
                    break;

                case 24:
                case 32:
                    settings.Format = BufferFormat.R8G8B8A8_UIntNormal;
                    if (header.BPP == 24)
                    {
                        conversionFlags |= TGAConversionFlags.Expand;
                    }
                    break;
                }

                if (header.ImageType == TGAImageType.TrueColorRLE)
                {
                    conversionFlags |= TGAConversionFlags.RLE;
                }
                break;

            case TGAImageType.BlackAndWhite:
            case TGAImageType.BlackAndWhiteRLE:
                if (header.BPP == 8)
                {
                    settings.Format = BufferFormat.R8_UIntNormal;
                }
                else
                {
                    throw new IOException(string.Format(Resources.GORGFX_FORMAT_NOT_SUPPORTED, header.ImageType));
                }

                if (header.ImageType == TGAImageType.BlackAndWhiteRLE)
                {
                    conversionFlags |= TGAConversionFlags.RLE;
                }
                break;

            default:
                throw new IOException(string.Format(Resources.GORGFX_FORMAT_NOT_SUPPORTED, header.ImageType));
            }

            settings.Width  = header.Width;
            settings.Height = header.Height;

            if ((header.Descriptor & TGADescriptor.InvertX) == TGADescriptor.InvertX)
            {
                conversionFlags |= TGAConversionFlags.InvertX;
            }

            if ((header.Descriptor & TGADescriptor.InvertY) == TGADescriptor.InvertY)
            {
                conversionFlags |= TGAConversionFlags.InvertY;
            }

            if (header.IDLength <= 0)
            {
                return(settings);
            }

            // Skip these bytes.
            for (int i = 0; i < header.IDLength; i++)
            {
                stream.ReadByte();
            }

            return(settings);
        }
コード例 #6
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;
            }
        }
コード例 #7
0
        /// <summary>
        /// Function to perform the copying of image data into the buffer.
        /// </summary>
        /// <param name="reader">A reader used to read the data from the source stream.</param>
        /// <param name="image">Image data.</param>
        /// <param name="conversionFlags">Flags used to convert the image.</param>
        private void CopyImageData(GorgonBinaryReader reader, IGorgonImage image, TGAConversionFlags conversionFlags)
        {
            // TGA only supports 1 array level, and 1 mip level, so we only need to get the first buffer.
            IGorgonImageBuffer buffer = image.Buffers[0];

            // Determine how large a row is, in bytes.
            var formatInfo = new GorgonFormatInfo(image.Format);

            GorgonPitchLayout srcPitch = (conversionFlags & TGAConversionFlags.Expand) == TGAConversionFlags.Expand
                                             ? new GorgonPitchLayout(image.Width * 3, image.Width * 3 * image.Height)
                                             : formatInfo.GetPitchForFormat(image.Width, image.Height);

            unsafe
            {
                // Otherwise, allocate a buffer for conversion.
                byte *destPtr = (byte *)buffer.Data;

                // 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.Height - 1) * buffer.PitchInformation.RowPitch;
                }

                // Used to counter the number of lines to force as opaque.
                int opaqueLineCount = 0;
                // The buffer used to hold an uncompressed scanline.
                GorgonNativeBuffer <byte> lineBuffer = null;

                try
                {
                    for (int y = 0; y < image.Height; y++)
                    {
                        // Indicates that the scanline has an alpha of 0 for the entire run.
                        bool lineHasZeroAlpha;

                        if ((conversionFlags & TGAConversionFlags.RLE) == TGAConversionFlags.RLE)
                        {
                            lineHasZeroAlpha = ReadCompressed(reader, image.Width, destPtr, image.Format, conversionFlags);
                        }
                        else
                        {
                            // Read the current scanline into memory.
                            if (lineBuffer == null)
                            {
                                lineBuffer = new GorgonNativeBuffer <byte>(srcPitch.RowPitch);
                            }

                            reader.ReadRange(lineBuffer, count: srcPitch.RowPitch);

                            lineHasZeroAlpha = ReadUncompressed((byte *)lineBuffer, srcPitch.RowPitch, destPtr, image.Format, conversionFlags);
                        }

                        if ((lineHasZeroAlpha) && ((conversionFlags & TGAConversionFlags.SetOpaqueAlpha) == TGAConversionFlags.SetOpaqueAlpha))
                        {
                            opaqueLineCount++;
                        }

                        // The components of the pixel data in a TGA file need swizzling for 32 bit.
                        if (formatInfo.BitDepth == 32)
                        {
                            ImageUtilities.SwizzleScanline(destPtr,
                                                           buffer.PitchInformation.RowPitch,
                                                           destPtr,
                                                           buffer.PitchInformation.RowPitch,
                                                           image.Format,
                                                           ImageBitFlags.None);
                        }

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

                if (opaqueLineCount != image.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;
                for (int y = 0; y < image.Height; y++)
                {
                    ImageUtilities.CopyScanline(destPtr,
                                                buffer.PitchInformation.RowPitch,
                                                destPtr,
                                                buffer.PitchInformation.RowPitch,
                                                image.Format,
                                                ImageBitFlags.OpaqueAlpha);
                    destPtr += buffer.PitchInformation.RowPitch;
                }
            }
        }
コード例 #8
0
        /// <summary>
        /// Function to read uncompressed TGA scanline data.
        /// </summary>
        /// <param name="src">The pointer to the buffer containing the source data.</param>
        /// <param name="srcPitch">Pitch of the source scan line.</param>
        /// <param name="dest">Destination buffer pointner</param>
        /// <param name="format">Format of the destination buffer.</param>
        /// <param name="conversionFlags">Flags used for conversion.</param>
        private static unsafe bool ReadUncompressed(byte *src, int srcPitch, byte *dest, BufferFormat format, TGAConversionFlags conversionFlags)
        {
            bool flipHorizontal = (conversionFlags & TGAConversionFlags.InvertX) == TGAConversionFlags.InvertX;

            switch (format)
            {
            case BufferFormat.R8_UNorm:
            case BufferFormat.B5G5R5A1_UNorm:
                return(ImageUtilities.CopyScanline(src, srcPitch, dest, format, flipHorizontal));

            case BufferFormat.R8G8B8A8_UNorm:
                if ((conversionFlags & TGAConversionFlags.Expand) != TGAConversionFlags.Expand)
                {
                    return(ImageUtilities.CopyScanline(src, srcPitch, dest, format, flipHorizontal));
                }

                ImageUtilities.Expand24BPPScanLine(src, srcPitch, dest, flipHorizontal);

                // We're already opaque by virtue of being 24 bit.
                return(false);
            }

            return(false);
        }
コード例 #9
0
        /// <summary>
        /// Function to read uncompressed TGA scanline data.
        /// </summary>
        /// <param name="reader">The reader used to read in the data from the source stream.</param>
        /// <param name="width">Image width.</param>
        /// <param name="dest">Destination buffer pointner</param>
        /// <param name="format">Format of the destination buffer.</param>
        /// <param name="conversionFlags">Flags used for conversion.</param>
        private unsafe bool ReadCompressed(GorgonBinaryReader reader, int width, byte *dest, BufferFormat format, TGAConversionFlags conversionFlags)
        {
            bool setOpaque      = true;
            bool flipHorizontal = (conversionFlags & TGAConversionFlags.InvertX) == TGAConversionFlags.InvertX;
            bool expand         = (conversionFlags & TGAConversionFlags.Expand) == TGAConversionFlags.Expand;

            for (int x = 0; x < width;)
            {
                if (reader.BaseStream.Position >= reader.BaseStream.Length)
                {
                    throw new IOException(string.Format(Resources.GORIMG_ERR_FILE_FORMAT_NOT_CORRECT, Codec));
                }

                byte rleBlock = reader.ReadByte();
                int  size     = (rleBlock & 0x7F) + 1;
                if ((rleBlock & 0x80) != 0)
                {
                    if (!DecodeRleEncodedRun(reader, ref dest, ref x, size, width, expand, flipHorizontal, format))
                    {
                        setOpaque = false;
                    }
                    continue;
                }

                if (!DecodeUncompressedRun(reader, ref dest, ref x, size, width, expand, flipHorizontal, format))
                {
                    setOpaque = false;
                }
            }

            return(setOpaque);
        }
コード例 #10
0
        /// <summary>
        /// Function to read in the TGA header from a stream.
        /// </summary>
        /// <param name="reader">The reader used to read the stream containing the data.</param>
        /// <param name="conversionFlags">Flags for conversion.</param>
        /// <returns>New image settings.</returns>
        private static IGorgonImageInfo ReadHeader(GorgonBinaryReader reader, out TGAConversionFlags conversionFlags)
        {
            conversionFlags = TGAConversionFlags.None;

            // Get the header for the file.
            TgaHeader header = reader.ReadValue <TgaHeader>();

            if ((header.ColorMapType != 0) || (header.ColorMapLength != 0) ||
                (header.Width <= 0) || (header.Height <= 0) ||
                ((header.Descriptor & TgaDescriptor.Interleaved2Way) == TgaDescriptor.Interleaved2Way) ||
                ((header.Descriptor & TgaDescriptor.Interleaved4Way) == TgaDescriptor.Interleaved4Way))
            {
                throw new NotSupportedException(Resources.GORIMG_ERR_TGA_TYPE_NOT_SUPPORTED);
            }

            BufferFormat pixelFormat = BufferFormat.Unknown;

            switch (header.ImageType)
            {
            case TgaImageType.TrueColor:
            case TgaImageType.TrueColorRLE:
                switch (header.BPP)
                {
                case 16:
                    pixelFormat = BufferFormat.B5G5R5A1_UNorm;
                    break;

                case 24:
                case 32:
                    pixelFormat = BufferFormat.R8G8B8A8_UNorm;
                    if (header.BPP == 24)
                    {
                        conversionFlags |= TGAConversionFlags.Expand;
                    }
                    break;
                }

                if (header.ImageType == TgaImageType.TrueColorRLE)
                {
                    conversionFlags |= TGAConversionFlags.RLE;
                }
                break;

            case TgaImageType.BlackAndWhite:
            case TgaImageType.BlackAndWhiteRLE:
                if (header.BPP == 8)
                {
                    pixelFormat = BufferFormat.R8_UNorm;
                }
                else
                {
                    throw new IOException(string.Format(Resources.GORIMG_ERR_FORMAT_NOT_SUPPORTED, header.ImageType));
                }

                if (header.ImageType == TgaImageType.BlackAndWhiteRLE)
                {
                    conversionFlags |= TGAConversionFlags.RLE;
                }
                break;

            default:
                throw new IOException(string.Format(Resources.GORIMG_ERR_FORMAT_NOT_SUPPORTED, header.ImageType));
            }

            var settings = new GorgonImageInfo(ImageType.Image2D, pixelFormat)
            {
                MipCount   = 1,
                ArrayCount = 1,
                Width      = header.Width,
                Height     = header.Height
            };

            if ((header.Descriptor & TgaDescriptor.InvertX) == TgaDescriptor.InvertX)
            {
                conversionFlags |= TGAConversionFlags.InvertX;
            }

            if ((header.Descriptor & TgaDescriptor.InvertY) == TgaDescriptor.InvertY)
            {
                conversionFlags |= TGAConversionFlags.InvertY;
            }

            if (header.IDLength <= 0)
            {
                return(settings);
            }

            // Skip these bytes.
            for (int i = 0; i < header.IDLength; i++)
            {
                reader.ReadByte();
            }

            return(settings);
        }