TgaFileType.cs :  » GUI » Paint.net » PaintDotNet » Data » C# / CSharp Open Source

Home
C# / CSharp Open Source
1.2.6.4 mono .net core
2.2.6.4 mono core
3.Aspect Oriented Frameworks
4.Bloggers
5.Build Systems
6.Business Application
7.Charting Reporting Tools
8.Chat Servers
9.Code Coverage Tools
10.Content Management Systems CMS
11.CRM ERP
12.Database
13.Development
14.Email
15.Forum
16.Game
17.GIS
18.GUI
19.IDEs
20.Installers Generators
21.Inversion of Control Dependency Injection
22.Issue Tracking
23.Logging Tools
24.Message
25.Mobile
26.Network Clients
27.Network Servers
28.Office
29.PDF
30.Persistence Frameworks
31.Portals
32.Profilers
33.Project Management
34.RSS RDF
35.Rule Engines
36.Script
37.Search Engines
38.Sound Audio
39.Source Control
40.SQL Clients
41.Template Engines
42.Testing
43.UML
44.Web Frameworks
45.Web Service
46.Web Testing
47.Wiki Engines
48.Windows Presentation Foundation
49.Workflows
50.XML Parsers
C# / C Sharp
C# / C Sharp by API
C# / CSharp Tutorial
C# / CSharp Open Source » GUI » Paint.net 
Paint.net » PaintDotNet » Data » TgaFileType.cs
/////////////////////////////////////////////////////////////////////////////////
// Paint.NET                                                                   //
// Copyright (C) dotPDN LLC, Rick Brewster, Tom Jackson, and contributors.     //
// Portions Copyright (C) Microsoft Corporation. All Rights Reserved.          //
// See src/Resources/Files/License.txt for full licensing and attribution      //
// details.                                                                    //
// .                                                                           //
/////////////////////////////////////////////////////////////////////////////////

/////////////////////////////////////////////////////////////////////////////////
// Some of this code is adapted from code in the CxImage library by Davide Pizzolato. 
// The following text is the original license.txt from that library:
// 
// COPYRIGHT NOTICE, DISCLAIMER, and LICENSE:
// 
// CxImage version 5.99c 17/Oct/2004
// 
// CxImage : Copyright (C) 2001 - 2004, Davide Pizzolato
// 
// Original CImage and CImageIterator implementation are:
// Copyright (C) 1995, Alejandro Aguilar Sierra (asierra(at)servidor(dot)unam(dot)mx)
// 
// Covered code is provided under this license on an "as is" basis, without warranty
// of any kind, either expressed or implied, including, without limitation, warranties
// that the covered code is free of defects, merchantable, fit for a particular purpose
// or non-infringing. The entire risk as to the quality and performance of the covered
// code is with you. Should any covered code prove defective in any respect, you (not
// the initial developer or any other contributor) assume the cost of any necessary
// servicing, repair or correction. This disclaimer of warranty constitutes an essential
// part of this license. No use of any covered code is authorized hereunder except under
// this disclaimer.
// 
// Permission is hereby granted to use, copy, modify, and distribute this
// source code, or portions hereof, for any purpose, including commercial applications,
// freely and without fee, subject to the following restrictions: 
// 
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
// 
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
// 
// 3. This notice may not be removed or altered from any source distribution.
// 
/////////////////////////////////////////////////////////////////////////////////

using PaintDotNet;
using PaintDotNet.IndirectUI;
using PaintDotNet.PropertySystem;
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Runtime.InteropServices;

namespace PaintDotNet.Data{
    public sealed class TgaFileType
        : InternalFileType
    {
        public enum PropertyNames
        {
            BitDepth = 0,
            RleCompress = 1
        }

        public enum TgaBitDepthUIChoices
        {
            AutoDetect = 0,
            Bpp32 = 1,
            Bpp24 = 2
        }

        protected override bool IsReflexive(PropertyBasedSaveConfigToken token)
        {
            if ((TgaBitDepthUIChoices)token.GetProperty<StaticListChoiceProperty>(PropertyNames.BitDepth).Value == TgaBitDepthUIChoices.Bpp32)
            {
                return true;
            }
            else
            {
                return base.IsReflexive(token);
            }
        }

        private enum TgaType 
            : byte
        {
            Null = 0,
            Map = 1,
            Rgb = 2,
            Mono = 3,
            RleMap = 9,
            RleRgb = 10,
            RleMono = 11,
            CompMap = 32,
            CompMap4 = 33
        }

        [StructLayout(LayoutKind.Sequential)]
        private struct TgaHeader
        {
            public byte idLength;            // Image ID Field Length
            public byte cmapType;            // Color Map Type
            public TgaType imageType;        // Image Type

            public ushort cmapIndex;         // First Entry Index
            public ushort cmapLength;        // Color Map Length
            public byte cmapEntrySize;       // Color Map Entry Size

            public ushort xOrigin;           // X-origin of Image
            public ushort yOrigin;           // Y-origin of Image
            public ushort imageWidth;        // Image Width
            public ushort imageHeight;       // Image Height
            public byte pixelDepth;          // Pixel Depth
            public byte imageDesc;           // Image Descriptor

            public void Write(Stream output)
            {
                output.WriteByte(this.idLength);
                output.WriteByte(this.cmapType);
                output.WriteByte((byte)this.imageType);

                Utility.WriteUInt16(output, this.cmapIndex);
                Utility.WriteUInt16(output, this.cmapLength);
                output.WriteByte(this.cmapEntrySize);

                Utility.WriteUInt16(output, this.xOrigin);
                Utility.WriteUInt16(output, this.yOrigin);
                Utility.WriteUInt16(output, this.imageWidth);
                Utility.WriteUInt16(output, this.imageHeight);
                output.WriteByte(this.pixelDepth);
                output.WriteByte(this.imageDesc);
            }

            public TgaHeader(Stream input)
            {
                int byteRead = input.ReadByte();
                if (byteRead == -1)
                {
                    throw new EndOfStreamException();
                }
                else
                {
                    this.idLength = (byte)byteRead;
                }

                byteRead = input.ReadByte();
                if (byteRead == -1)
                {
                    throw new EndOfStreamException();
                }
                else
                {
                    this.cmapType = (byte)byteRead;
                }

                byteRead = input.ReadByte();
                if (byteRead == -1)
                {
                    throw new EndOfStreamException();
                }
                else
                {
                    this.imageType = (TgaType)byteRead;
                }

                int shortRead = Utility.ReadUInt16(input);
                if (shortRead == -1)
                {
                    throw new EndOfStreamException();
                }
                else
                {
                    this.cmapIndex = (ushort)shortRead;
                }

                shortRead = Utility.ReadUInt16(input);
                if (shortRead == -1)
                {
                    throw new EndOfStreamException();
                }
                else
                {
                    this.cmapLength = (ushort)shortRead;
                }

                byteRead = input.ReadByte();
                if (byteRead == -1)
                {
                    throw new EndOfStreamException();
                }
                else
                {
                    this.cmapEntrySize = (byte)byteRead;
                }

                shortRead = Utility.ReadUInt16(input);
                if (shortRead == -1)
                {
                    throw new EndOfStreamException();
                }
                else
                {
                    this.xOrigin = (ushort)shortRead;
                }

                shortRead = Utility.ReadUInt16(input);
                if (shortRead == -1)
                {
                    throw new EndOfStreamException();
                }
                else
                {
                    this.yOrigin = (ushort)shortRead;
                }

                shortRead = Utility.ReadUInt16(input);
                if (shortRead == -1)
                {
                    throw new EndOfStreamException();
                }
                else
                {
                    this.imageWidth = (ushort)shortRead;
                }

                shortRead = Utility.ReadUInt16(input);
                if (shortRead == -1)
                {
                    throw new EndOfStreamException();
                }
                else
                {
                    this.imageHeight = (ushort)shortRead;
                }

                byteRead = input.ReadByte();
                if (byteRead == -1)
                {
                    throw new EndOfStreamException();
                }
                else
                {
                    this.pixelDepth = (byte)byteRead;
                }

                byteRead = input.ReadByte();
                if (byteRead == -1)
                {
                    throw new EndOfStreamException();
                }
                else
                {
                    this.imageDesc = (byte)byteRead;
                }                
            }
        }

        internal override Set<SavableBitDepths> CreateAllowedBitDepthListFromToken(PropertyBasedSaveConfigToken token)
        {
            TgaBitDepthUIChoices bitDepth = (TgaBitDepthUIChoices)token.GetProperty<StaticListChoiceProperty>(PropertyNames.BitDepth).Value;

            Set<SavableBitDepths> bitDepths = new Set<SavableBitDepths>();

            switch (bitDepth)
            {
                case TgaBitDepthUIChoices.AutoDetect:
                    bitDepths.Add(SavableBitDepths.Rgb24);
                    bitDepths.Add(SavableBitDepths.Rgba32);
                    break;

                case TgaBitDepthUIChoices.Bpp24:
                    bitDepths.Add(SavableBitDepths.Rgb24);
                    break;

                case TgaBitDepthUIChoices.Bpp32:
                    bitDepths.Add(SavableBitDepths.Rgba32);
                    break;

                default:
                    throw new InvalidEnumArgumentException("bitDepth", (int)bitDepth, typeof(TgaBitDepthUIChoices));
            }

            return bitDepths;
        }

        internal override int GetDitherLevelFromToken(PropertyBasedSaveConfigToken token)
        {
            return 0;
        }

        internal override int GetThresholdFromToken(PropertyBasedSaveConfigToken token)
        {
            return 0;
        }

        public override PropertyCollection OnCreateSavePropertyCollection()
        {
            List<Property> props = new List<Property>();

            props.Add(StaticListChoiceProperty.CreateForEnum<TgaBitDepthUIChoices>(PropertyNames.BitDepth, TgaBitDepthUIChoices.AutoDetect, false));
            props.Add(new BooleanProperty(PropertyNames.RleCompress, true));

            return new PropertyCollection(props);
        }

        public override ControlInfo OnCreateSaveConfigUI(PropertyCollection props)
        {
            ControlInfo configUI = CreateDefaultSaveConfigUI(props);

            configUI.SetPropertyControlValue(
                PropertyNames.BitDepth,
                ControlInfoPropertyNames.DisplayName,
                PdnResources.GetString("TgaFileType.ConfigUI.BitDepth.DisplayName"));

            configUI.SetPropertyControlType(PropertyNames.BitDepth, PropertyControlType.RadioButton);

            PropertyControlInfo bitDepthPCI = configUI.FindControlForPropertyName(PropertyNames.BitDepth);
            bitDepthPCI.SetValueDisplayName(TgaBitDepthUIChoices.AutoDetect, PdnResources.GetString("TgaFileType.ConfigUI.BitDepth.AutoDetect.DisplayName"));
            bitDepthPCI.SetValueDisplayName(TgaBitDepthUIChoices.Bpp24, PdnResources.GetString("TgaFileType.ConfigUI.BitDepth.Bpp24.DisplayName"));
            bitDepthPCI.SetValueDisplayName(TgaBitDepthUIChoices.Bpp32, PdnResources.GetString("TgaFileType.ConfigUI.BitDepth.Bpp32.DisplayName"));

            configUI.SetPropertyControlValue(
                PropertyNames.RleCompress,
                ControlInfoPropertyNames.DisplayName,
                string.Empty);

            configUI.SetPropertyControlValue(
                PropertyNames.RleCompress,
                ControlInfoPropertyNames.Description,
                PdnResources.GetString("TgaFileType.ConfigUI.RleCompress.Description"));

            return configUI;
        }

        protected override Document OnLoad(System.IO.Stream input)
        {
            TgaHeader header = new TgaHeader(input);
            bool compressed;

            switch (header.imageType)
            {
                case TgaType.Map:
                case TgaType.Rgb:
                case TgaType.Mono:
                    compressed = false;
                    break;
                    
                case TgaType.RleMap:
                case TgaType.RleRgb:
                case TgaType.RleMono:
                    compressed = true;
                    break;

                default:
                    throw new FormatException("unknown TGA image type");
            }

            if (header.imageWidth == 0 || 
                header.imageHeight == 0 || 
                header.pixelDepth == 0 || 
                header.cmapLength > 256)
            {
                throw new FormatException("bad TGA header");
            }

            if (header.pixelDepth != 8 && 
                header.pixelDepth != 15 && 
                header.pixelDepth != 16 && 
                header.pixelDepth != 24 && 
                header.pixelDepth != 32)
            {
                throw new FormatException("bad TGA header: pixelDepth not one of {8, 15, 16, 24, 32}");
            }

            if (header.idLength > 0)
            {
                input.Position += header.idLength; // skip descriptor
            }

            BitmapLayer layer = Layer.CreateBackgroundLayer(header.imageWidth, header.imageHeight);

            try
            {
                Surface surface = layer.Surface;
                surface.Clear((ColorBgra)0xffffffff);

                ColorBgra[] palette = null;
                if (header.cmapType != 0)
                {
                    palette = LoadPalette(input, header.cmapLength);
                }

                if (header.imageType == TgaType.Mono ||
                    header.imageType == TgaType.RleMono)
                {
                    palette = CreateGrayPalette();
                }

                // Bits 0 - 3 of the image descriptor byte describe number of bits used for alpha channel
                // For loading, we won't worry about this. Not all TGA implementations are correct (such
                // as older Paint.NET TGA implementations!) and we don't want to lose all their alpha bits.
                //int alphaBits = header.imageDesc & 0xf;

                // Bits 4 & 5 of the image descriptor byte control the ordering of the pixels
                bool xReversed = ((header.imageDesc & 16) == 16);
                bool yReversed = ((header.imageDesc & 32) == 32);            

                byte rleLeftOver = 255; // for images with illegal packet boundary

                for (int y = 0; y < header.imageHeight; ++y)
                {
                    MemoryBlock dstRow;

                    if (yReversed)
                    {
                        dstRow = surface.GetRow(y);
                    }
                    else
                    {
                        dstRow = surface.GetRow(header.imageHeight - y - 1);
                    }

                    if (compressed)
                    {
                        rleLeftOver = ExpandCompressedLine(dstRow, 0, ref header, input, header.imageWidth, y, rleLeftOver, palette);
                    }
                    else
                    {
                        ExpandUncompressedLine(dstRow, 0, ref header, input, header.imageWidth, y, 0, palette);
                    }
                }

                if (xReversed)
                {
                    MirrorX(surface);
                }

                Document document = new Document(surface.Width, surface.Height);
                document.Layers.Add(layer);
                return document;
            }

            catch
            {
                if (layer != null)
                {
                    layer.Dispose();
                    layer = null;
                }

                throw;
            }
        }

        private void MirrorX(Surface surface)
        {
            for (int y = 0; y < surface.Height; ++y)
            {
                for (int x = 0; x < surface.Width / 2; ++x)
                {
                    ColorBgra rightSide = surface[surface.Width - x - 1, y];
                    surface[surface.Width - x - 1, y] = surface[x, y];
                    surface[x, y] = rightSide;
                }
            }
        }

        private ColorBgra[] CreateGrayPalette()
        {
            ColorBgra[] palette = new ColorBgra[256];

            for (int i = 0; i < palette.Length; ++i)
            {
                palette[i] = ColorBgra.FromBgra((byte)i, (byte)i, (byte)i, 255);
            }

            return palette;
        }

        private ColorBgra[] LoadPalette(Stream input, int count)
        {
            ColorBgra[] palette = new ColorBgra[count];

            for (int i = 0; i < palette.Length; ++i)
            {
                int blue = input.ReadByte();
                if (blue == -1)
                {
                    throw new EndOfStreamException();
                }

                int green = input.ReadByte();
                if (green == -1)
                {
                    throw new EndOfStreamException();
                }

                int red = input.ReadByte();
                if (red == -1)
                {
                    throw new EndOfStreamException();
                }

                palette[i] = ColorBgra.FromBgra((byte)blue, (byte)green, (byte)red, 255);
            }

            return palette;
        }

        private byte ExpandCompressedLine(MemoryBlock dst, int dstIndex, ref TgaHeader header, Stream input, int width, int y, byte rleLeftOver, ColorBgra[] palette)
        {
            byte rle;
            long filePos = 0;

            int x = 0;
            while (x < width)
            {
                if (rleLeftOver != 255)
                {
                    rle = rleLeftOver;
                    rleLeftOver = 255;
                }
                else
                {
                    int byte1 = input.ReadByte();

                    if (byte1 == -1)
                    {
                        throw new EndOfStreamException();
                    }
                    else
                    {
                        rle = (byte)byte1;
                    }
                }

                if ((rle & 128) != 0)
                {
                    // RLE Encoded packet
                    rle -= 127; // calculate real repeat count

                    if ((x + rle) > width)
                    {
                        rleLeftOver = (byte)(128 + (rle - (width - x) - 1));
                        filePos = input.Position;
                        rle = (byte)(width - x);
                    }
                
                    ColorBgra color = ReadColor(input, header.pixelDepth, palette);

                    for (int ix = 0; ix < rle; ++ix)
                    {
                        int index = dstIndex + (ix * ColorBgra.SizeOf);

                        dst[index] = color[0];
                        dst[1 + index] = color[1];
                        dst[2 + index] = color[2];
                        dst[3 + index] = color[3];
                    }

                    if (rleLeftOver != 255)
                    {
                        input.Position = filePos;
                    }
                }
                else
                {
                    // Raw packet
                    rle += 1; // calculate real repeat count

                    if ((x + rle) > width)
                    {
                        rleLeftOver = (byte)(rle - (width - x) - 1);
                        rle = (byte)(width - x);
                    }

                    ExpandUncompressedLine(dst, dstIndex, ref header, input, rle, y, x, palette);
                }

                dstIndex += rle * ColorBgra.SizeOf;
                x += rle;
            }

            return rleLeftOver;
        }

        private void ExpandUncompressedLine(MemoryBlock dst, int dstIndex, ref TgaHeader header, Stream input, int width, int y, int xoffset, ColorBgra[] palette)
        {
            for (int i = 0; i < width; ++i)
            {
                ColorBgra color = ReadColor(input, header.pixelDepth, palette);
                dst[dstIndex] = color[0];
                dst[1 + dstIndex] = color[1];
                dst[2 + dstIndex] = color[2];
                dst[3 + dstIndex] = color[3];
                dstIndex += 4;
            }
        }

        private ColorBgra ReadColor(Stream input, int pixelDepth, ColorBgra[] palette)
        {
            ColorBgra color;

            switch (pixelDepth)
            {
                case 32:
                {
                    long colorInt = Utility.ReadUInt32(input);

                    if (colorInt == -1)
                    {
                        throw new EndOfStreamException();
                    }

                    color = ColorBgra.FromUInt32((uint)colorInt);
                    break;
                }

                case 24:
                {
                    int colorInt = Utility.ReadUInt24(input);

                    if (colorInt == -1)
                    {
                        throw new EndOfStreamException();
                    }

                    color = ColorBgra.FromUInt32((uint)colorInt);
                    color.A = 255;
                    break;
                }

                case 15:
                case 16:
                {
                    int colorWord = Utility.ReadUInt16(input);

                    if (colorWord == -1)
                    {
                        throw new EndOfStreamException();
                    }

                    color = ColorBgra.FromBgra(
                        (byte)((colorWord >> 7) & 0xf8),
                        (byte)((colorWord >> 2) & 0xf8),
                        (byte)((colorWord & 0x1f) * 8),
                        255);

                    break;
                }

                case 8:
                {
                    int colorByte = input.ReadByte();

                    if (colorByte == -1)
                    {
                        throw new EndOfStreamException();
                    }

                    if (colorByte >= palette.Length)
                    {
                        throw new FormatException("color index was outside the bounds of the palette");
                    }

                    color = palette[colorByte];                            
                    break;
                }

                default:
                    throw new FormatException("colorDepth was not one of {8, 15, 16, 24, 32}");
            }

            return color;
        }

        internal override void FinalSave(
            Document input, 
            Stream output, 
            Surface scratchSurface, 
            int ditherLevel, 
            SavableBitDepths bitDepth, 
            PropertyBasedSaveConfigToken token, 
            ProgressEventHandler progressCallback)
        {
            bool rleCompress = token.GetProperty<BooleanProperty>(PropertyNames.RleCompress).Value;
            SaveTga(scratchSurface, output, bitDepth, rleCompress, progressCallback);
        }

        private void SaveTga(Surface input, Stream output, SavableBitDepths bitDepth, bool rleCompress, ProgressEventHandler progressCallback)
        {
            TgaHeader header = new TgaHeader();

            header.idLength = 0;
            header.cmapType = 0;
            header.imageType = rleCompress ? TgaType.RleRgb : TgaType.Rgb;
            header.cmapIndex = 0;
            header.cmapLength = 0;
            header.cmapEntrySize = 0; // if bpp=8, set this to 24
            header.xOrigin = 0;
            header.yOrigin = 0;
            header.imageWidth = (ushort)input.Width;
            header.imageHeight = (ushort)input.Height;

            header.imageDesc = 0;

            switch (bitDepth)
            {
                case SavableBitDepths.Rgba32:
                    header.pixelDepth = 32;
                    header.imageDesc |= 8;
                    break;

                case SavableBitDepths.Rgb24:
                    header.pixelDepth = 24;
                    break;

                default:
                    throw new InvalidEnumArgumentException("bitDepth", (int)bitDepth, typeof(SavableBitDepths));
            }

            header.Write(output);

            // write palette if doing 8-bit
            // ... todo?

            for (int y = input.Height - 1; y >= 0; --y)
            {
                // non-rle output
                if (rleCompress)
                {
                    SaveTgaRowRle(output, input, ref header, y);
                }
                else
                {
                    SaveTgaRowRaw(output, input, ref header, y);
                }

                if (progressCallback != null)
                {
                    progressCallback(this, new ProgressEventArgs(100.0 * ((double)(input.Height - y) / (double)input.Height)));
                }
            }
        }

        private class TgaPacketStateMachine
        {
            private bool rlePacket = false;
            private ColorBgra[] packetColors = new ColorBgra[128];
            private int packetLength;
            private Stream output;
            private int bitDepth;

            public void Flush()
            {
                byte header = (byte)((rlePacket ? 128 : 0) + (byte)(packetLength - 1));
                output.WriteByte(header);

                int length = (rlePacket ? 1 : packetLength);
                for (int i = 0; i < length; ++i)
                {
                    WriteColor(this.output, packetColors[i], this.bitDepth);
                }

                packetLength = 0;
            }

            public void Push(ColorBgra color)
            {
                if (packetLength == 0)
                {
                    // Starting a fresh packet.
                    rlePacket = false;
                    packetColors[0] = color;
                    packetLength = 1;
                }
                else if (packetLength == 1)
                {
                    // 2nd byte of this packet... decide RLE or non-RLE.
                    rlePacket = (color == packetColors[0]);
                    packetColors[1] = color;
                    packetLength = 2;
                }
                else if (packetLength == packetColors.Length)
                {
                    // Packet is full. Start a new one.
                    Flush();
                    Push(color);
                }
                else if (packetLength >= 2 && rlePacket && color != packetColors[packetLength - 1])
                {
                    // We were filling in an RLE packet, and we got a non-repeated color.
                    // Emit the current packet and start a new one.
                    Flush();
                    Push(color);
                }
                else if (packetLength >= 2 && rlePacket && color == packetColors[packetLength - 1])
                {
                    // We are filling in an RLE packet, and we got another repeated color.
                    // Add the new color to the current packet.
                    ++packetLength;
                    packetColors[packetLength - 1] = color;
                }
                else if (packetLength >= 2 && !rlePacket && color != packetColors[packetLength - 1])
                {
                    // We are filling in a raw packet, and we got another random color.
                    // Add the new color to the current packet.
                    ++packetLength;
                    packetColors[packetLength - 1] = color;
                }
                else if (packetLength >= 2 && !rlePacket && color == packetColors[packetLength - 1])
                {
                    // We were filling in a raw packet, but we got a repeated color.
                    // Emit the current packet without its last color, and start a
                    // new RLE packet that starts with a length of 2.
                    --packetLength;
                    Flush();
                    Push(color);
                    Push(color);
                }
            }

            public TgaPacketStateMachine(Stream output, int bitDepth)
            {
                this.output = output;
                this.bitDepth = bitDepth;
            }
        }

        private static void SaveTgaRowRle(Stream output, Surface input, ref TgaHeader header, int y)
        {
            TgaPacketStateMachine machine = new TgaPacketStateMachine(output, header.pixelDepth);

            for (int x = 0; x < input.Width; ++x)
            {
                machine.Push(input[x, y]);
            }

            machine.Flush();
        }

        private static void SaveTgaRowRaw(Stream output, Surface input, ref TgaHeader header, int y)
        {
            for (int x = 0; x < input.Width; ++x)
            {
                ColorBgra color = input[x, y];
                WriteColor(output, color, header.pixelDepth);
            }
        }

        private static void WriteColor(Stream output, ColorBgra color, int bitDepth)
        {
            switch (bitDepth)
            {
                case 24:
                {
                    int red = ((color.R * color.A) + (255 * (255 - color.A))) / 255;
                    int green = ((color.G * color.A) + (255 * (255 - color.A))) / 255;
                    int blue = ((color.B * color.A) + (255 * (255 - color.A))) / 255;
                    int colorInt = blue + (green << 8) + (red << 16);

                    Utility.WriteUInt24(output, colorInt);
                    break;
                }

                case 32:
                    Utility.WriteUInt32(output, color.Bgra);
                    break;
            }
        }

        public TgaFileType()
            : base("TGA",
                   FileTypeFlags.SavesWithProgress |
                       FileTypeFlags.SupportsLoading |
                       FileTypeFlags.SupportsSaving,
                   new string[] { ".tga" })
        {
        }
    }
}
www.java2v.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.