public static ImageSource Decode(TgaHeader tgaHeader, byte[] imageBuffer, int size)
        {
            const double DPI_X       = 96d;
            const double DPI_Y       = 96d;
            var          stride      = GetStride(tgaHeader);
            var          pixelFormat = GetPixelFormat(tgaHeader);

            var bitmap = BitmapSource.Create(
                tgaHeader.Width,
                tgaHeader.Height,
                DPI_X,
                DPI_Y,
                pixelFormat,
                null,
                imageBuffer,
                stride);


            var transformedBmp = new TransformedBitmap();

            transformedBmp.BeginInit();
            transformedBmp.Source    = bitmap;
            transformedBmp.Transform = CreateShrinkTransform(tgaHeader, size);
            transformedBmp.EndInit();

            return(transformedBmp);
        }
        public static int GetImageDataOffset(TgaHeader tgaHeader)
        {
            int offset = tgaHeader.IdLength;

            offset += tgaHeader.ColorMapType == 0 ? 0 : GetColorMapLength(tgaHeader);
            return(offset);
        }
Пример #3
0
        public static bool WriteTga(this RayImage img, Stream output)
        {
            try
            {
                var sizeHeader = Marshal.SizeOf <TgaHeader>();
                //const int sizeHeader = 18;
                var sizePixels = img.Width * img.Height * 3;

                var buffer = new byte[sizeHeader + sizePixels];
                var span   = new Span <byte>(buffer);

                // write header.
                // IMPORTENT TO USE REF HERE.
                ref TgaHeader header = ref MemoryMarshal.Cast <byte, TgaHeader>(span)[0];
                //var header = MemoryMarshal.Cast<byte, TgaHeader>(span)[0];
                //var header = MemoryMarshal.AsRef<TgaHeader>(span.Slice(0, sizeHeader));
                header.DataTypeCode = 2;
                header.Width        = (short)img.Width;
                header.Height       = (short)img.Height;
                header.BitsPerPixel = 24;


                // convert rgb3f to bgr8
                var slicePixels = span.Slice(sizeHeader, sizePixels);
                FormatUtils.ConvertBGR8(img, ref slicePixels);

                output.Write(span);

                output.Flush();

                return(true);
            }
Пример #4
0
        // For now, we only export in uncompressed ARGB32 format. If someone requests this functionality,
        // we can always add more through an export dialog.
        public void Export(Document document, string fileName)
        {
            ImageSurface surf   = document.GetFlattenedImage();            // Assumes the surface is in ARGB32 format
            BinaryWriter writer = new BinaryWriter(new FileStream(fileName, FileMode.Create, FileAccess.Write));

            try {
                TgaHeader header = new TgaHeader();

                header.idLength      = 0;
                header.cmapType      = 0;
                header.imageType     = 2;             // uncompressed RGB
                header.cmapIndex     = 0;
                header.cmapLength    = 0;
                header.cmapEntrySize = 0;
                header.xOrigin       = 0;
                header.yOrigin       = 0;
                header.imageWidth    = (ushort)surf.Width;
                header.imageHeight   = (ushort)surf.Height;
                header.pixelDepth    = 32;
                header.imageDesc     = 8;             // 32-bit, lower-left origin, which is weird but hey...
                header.WriteTo(writer);

                byte[] data = surf.Data;

                // It just so happens that the Cairo ARGB32 internal representation matches
                // the TGA format, except vertically-flipped. In little-endian, of course.
                for (int y = surf.Height - 1; y >= 0; y--)
                {
                    writer.Write(data, surf.Stride * y, surf.Stride);
                }
            } finally {
                (surf as IDisposable).Dispose();
                writer.Close();
            }
        }
Пример #5
0
        public static TgaHeader TakeTga(Stream stream)
        {
            using (var br = new BinaryReader(stream)) {
                var header = new TgaHeader();

                /* char	 */ header.idlength        = br.ReadByte();
                /* char	 */ header.colourmaptype   = br.ReadByte();
                /* char	 */ header.datatypecode    = br.ReadByte();
                /* short */ header.colourmaporigin = br.ReadInt16();
                /* short */ header.colourmaplength = br.ReadInt16();
                /* char	 */ header.colourmapdepth  = br.ReadByte();
                /* short */ header.x_origin        = br.ReadInt16();
                /* short */ header.y_origin        = br.ReadInt16();
                /* short */ header.width           = br.ReadInt16();
                /* short */ header.height          = br.ReadInt16();
                /* char	 */ header.bitsperpixel    = br.ReadByte();
                /* char	 */ header.imagedescriptor = br.ReadByte();

                if (header.datatypecode != 2)
                {
                    throw new Exception(string.Format("Only uncompressed RGB and RGBA images are supported. Got {0} data type code", header.datatypecode));
                }

                if (header.bitsperpixel != 24 && header.bitsperpixel != 32)
                {
                    throw new Exception(string.Format("Only 24- and 32-bit images are supported. Got {0} bits per pixel", header.bitsperpixel));
                }

                return(header);
            }
        }
Пример #6
0
        // For now, we only export in uncompressed ARGB32 format. If someone requests this functionality,
        // we can always add more through an export dialog.
        public void Export(Document document, string fileName)
        {
            ImageSurface surf = document.GetFlattenedImage (); // Assumes the surface is in ARGB32 format
            BinaryWriter writer = new BinaryWriter (new FileStream (fileName, FileMode.Create, FileAccess.Write));

            try {
                TgaHeader header = new TgaHeader();

                header.idLength = (byte) (ImageIdField.Length + 1);
                header.cmapType = 0;
                header.imageType = 2; // uncompressed RGB
                header.cmapIndex = 0;
                header.cmapLength = 0;
                header.cmapEntrySize = 0;
                header.xOrigin = 0;
                header.yOrigin = 0;
                header.imageWidth = (ushort) surf.Width;
                header.imageHeight = (ushort) surf.Height;
                header.pixelDepth = 32;
                header.imageDesc = 8; // 32-bit, lower-left origin, which is weird but hey...
                header.WriteTo (writer);

                writer.Write(ImageIdField);

                byte[] data = surf.Data;

                // It just so happens that the Cairo ARGB32 internal representation matches
                // the TGA format, except vertically-flipped. In little-endian, of course.
                for (int y = surf.Height - 1; y >= 0; y--)
                    writer.Write (data, surf.Stride * y, surf.Stride);
            } finally {
                (surf as IDisposable).Dispose ();
                writer.Close ();
            }
        }
        public static int GetStride(TgaHeader tgaHeader)
        {
            var bytesPerPixel = GetBytesPerPixel(tgaHeader);
            var stride        = bytesPerPixel * tgaHeader.Width;

            return(stride);
        }
        private static double GetScale(TgaHeader tgaHeader, int size, Func <TgaHeader, bool> isFlipped)
        {
            var divisor = Math.Max(tgaHeader.Width, tgaHeader.Height);
            var scaleY  = (isFlipped(tgaHeader) ? -1 : 1) * ((double)size / divisor);

            return(scaleY);
        }
Пример #9
0
 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 string ReadIdString(BinaryReader reader, TgaHeader header)
        {
            byte[] idString = reader.ReadBytes(header.idLength);

            ASCIIEncoding encoding = new ASCIIEncoding();

            return(encoding.GetString(idString, 0, idString.Length));
        }
        private static ScaleTransform CreateShrinkTransform(TgaHeader tgaHeader, int size)
        {
            var scaleX = GetScaleX(tgaHeader, size);
            var scaleY = GetScaleY(tgaHeader, size);
            var transformedBmpTransform = new ScaleTransform(scaleX, scaleY);

            return(transformedBmpTransform);
        }
Пример #12
0
        private byte ExpandCompressedLine(MemoryBlock dst, int dstIndex, ref TgaHeader header, Stream input, int width, int y, byte rleLeftOver, ColorBgra[] palette)
        {
            byte num;
            long position = 0L;

            for (int i = 0; i < width; i += num)
            {
                if (rleLeftOver != 0xff)
                {
                    num         = rleLeftOver;
                    rleLeftOver = 0xff;
                }
                else
                {
                    int num4 = input.ReadByte();
                    if (num4 == -1)
                    {
                        throw new EndOfStreamException();
                    }
                    num = (byte)num4;
                }
                if ((num & 0x80) != 0)
                {
                    num = (byte)(num - 0x7f);
                    if ((i + num) > width)
                    {
                        rleLeftOver = (byte)(0x80 + ((num - (width - i)) - 1));
                        position    = input.Position;
                        num         = (byte)(width - i);
                    }
                    ColorBgra bgra = this.ReadColor(input, header.pixelDepth, palette);
                    for (int j = 0; j < num; j++)
                    {
                        int num6 = dstIndex + (j * 4);
                        dst[(long)num6]       = bgra[0];
                        dst[(long)(1 + num6)] = bgra[1];
                        dst[(long)(2 + num6)] = bgra[2];
                        dst[(long)(3 + num6)] = bgra[3];
                    }
                    if (rleLeftOver != 0xff)
                    {
                        input.Position = position;
                    }
                }
                else
                {
                    num = (byte)(num + 1);
                    if ((i + num) > width)
                    {
                        rleLeftOver = (byte)((num - (width - i)) - 1);
                        num         = (byte)(width - i);
                    }
                    this.ExpandUncompressedLine(dst, dstIndex, ref header, input, num, y, i, palette);
                }
                dstIndex += num * 4;
            }
            return(rleLeftOver);
        }
Пример #13
0
        public static ImageSource Decode(byte[] data, TgaHeader tgaHeader, int size)
        {
            var imageDataOffset = RgbBufferDecoder.GetImageDataOffset(tgaHeader);

            var numberOfPixels = RgbBufferDecoder.GetStride(tgaHeader) * tgaHeader.Height;
            var imageBuffer    = data.Skip(imageDataOffset).Take(numberOfPixels).ToArray();

            return(RgbBufferDecoder.Decode(tgaHeader, imageBuffer, size));
        }
Пример #14
0
        private static void SaveTgaRowRle(Stream output, Surface input, ref TgaHeader header, int y)
        {
            TgaPacketStateMachine machine = new TgaPacketStateMachine(output, header.pixelDepth);

            for (int i = 0; i < input.Width; i++)
            {
                machine.Push(input[i, y]);
            }
            machine.Flush();
        }
Пример #15
0
        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)));
                }
            }
        }
Пример #16
0
 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 bgra = this.ReadColor(input, header.pixelDepth, palette);
         dst[(long)dstIndex]       = bgra[0];
         dst[(long)(1 + dstIndex)] = bgra[1];
         dst[(long)(2 + dstIndex)] = bgra[2];
         dst[(long)(3 + dstIndex)] = bgra[3];
         dstIndex += 4;
     }
 }
        private static PixelFormat GetPixelFormat(TgaHeader tgaHeader)
        {
            switch (tgaHeader.BitsPerPixel)
            {
            case 24:
                return(PixelFormats.Bgr24);

            case 32:
                return(PixelFormats.Bgra32);
            }
            throw new UnsupportedPixelFormatException();
        }
Пример #18
0
 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 byte[] ReadColorMap(BinaryReader reader, TgaHeader header)
        {
            if ((ImageDataType)header.dataType != ImageDataType.UncompressedMappedColor)
            {
                return(null);
            }

            int bytesPerEntry = header.colorMapDepth / 8;

            byte[] colorMap = reader.ReadBytes(bytesPerEntry * header.colorMapLength);

            return(colorMap);
        }
Пример #20
0
        private static TgaHeader LoadTgaHeader(BinaryReader r)
        {
            TgaHeader th = new TgaHeader();

            r.BaseStream.Seek(0, SeekOrigin.Current);
            //  fread(&th, sizeof(gvImgTGAHeader), 1, fp);
            // due to byte alignment read the components one at a time
            th.identSize      = r.ReadByte();
            th.colorMapType   = r.ReadByte();
            th.imageType      = r.ReadByte();
            th.colorMapStart  = r.ReadUInt16();
            th.colorMapLength = r.ReadUInt16();
            th.colorMapBits   = r.ReadByte();
            th.xStart         = r.ReadUInt16();
            th.ySstart        = r.ReadUInt16();
            th.width          = r.ReadUInt16();
            th.height         = r.ReadUInt16();
            th.bits           = r.ReadByte();
            th.descriptor     = r.ReadByte();
            Debug.LogFormat("TGA descriptor = {0}", th.descriptor);
            // check if the image contains no data
            if (th.imageType == 0)
            {
                new Exception("TGA image contains no data.");                    // GV_IMG_ERROR_NO_DATA;
            }
            // check for other types (compressed images)
            if (th.imageType > 10)
            {
                new Exception("compressed TGA not supported.");                    //GV_IMG_ERROR_COMPRESSED_FILE;
            }
            // check if the image is color indexed
            if (th.imageType == 1 || th.imageType == 9)
            {
                new Exception("color indexed TGA not supported.");                                         //GV_IMG_ERROR_INDEXED_COLOR;
            }
            // for now we only consider 24bit rgb or rle images
            if (th.bits != 24 && th.bits != 32)
            {
                throw new Exception("only 24/32 bits TGA supported.");                                 //GV_IMG_ERROR_BITS;
            }
            // width and height must be valid ones
            if (th.width <= 0 || th.height <= 0)
            {
                throw new Exception("TGA texture has invalid size.");                                 // GV_IMG_ERROR_SIZE;
            }
            // skips id header
            r.BaseStream.Seek(th.identSize, SeekOrigin.Current);

            return(th);
        }
Пример #21
0
        private void SaveTga(Surface input, Stream output, InternalFileType.SavableBitDepths bitDepth, bool rleCompress, ProgressEventHandler progressCallback)
        {
            TgaHeader header = new TgaHeader {
                idLength      = 0,
                cmapType      = 0,
                imageType     = rleCompress ? TgaType.RleRgb : TgaType.Rgb,
                cmapIndex     = 0,
                cmapLength    = 0,
                cmapEntrySize = 0,
                xOrigin       = 0,
                yOrigin       = 0,
                imageWidth    = (ushort)input.Width,
                imageHeight   = (ushort)input.Height,
                imageDesc     = 0
            };

            if (bitDepth != InternalFileType.SavableBitDepths.Rgba32)
            {
                if (bitDepth != InternalFileType.SavableBitDepths.Rgb24)
                {
                    throw ExceptionUtil.InvalidEnumArgumentException <InternalFileType.SavableBitDepths>(bitDepth, "bitDepth");
                }
            }
            else
            {
                header.pixelDepth = 0x20;
                header.imageDesc  = (byte)(header.imageDesc | 8);
                goto Label_00AC;
            }
            header.pixelDepth = 0x18;
Label_00AC:
            header.Write(output);
            for (int i = input.Height - 1; i >= 0; i--)
            {
                if (rleCompress)
                {
                    SaveTgaRowRle(output, input, ref header, i);
                }
                else
                {
                    SaveTgaRowRaw(output, input, ref header, i);
                }
                if (progressCallback != null)
                {
                    progressCallback(this, new ProgressEventArgs(100.0 * (((double)(input.Height - i)) / ((double)input.Height))));
                }
            }
        }
        private int CalculateOpenGlPixelFormat(TgaHeader header)
        {
            int bpp = GetPixelDepth(header);

            switch (bpp)
            {
            case 24:
                return(Gl.GL_BGR);

            case 32:
                return(Gl.GL_BGRA);

            default:
                throw new InvalidOperationException("Unknown pixel depth.");
            }
        }
        private byte[] ReadPixels(BinaryReader reader, TgaHeader header, byte[] colorMap)
        {
            if (header.bitsPerPixel == 16)
            {
                throw new NotImplementedException("16bpp RGB unpacking is not supported yet.");
            }

            int bytesPerPixel       = header.bitsPerPixel / 8;
            int pixelCount          = header.imageHeight * header.imageWidth;
            int expectedPayloadSize = pixelCount * bytesPerPixel;

            byte[] pixelPayload;

            if ((ImageDataType)header.dataType == ImageDataType.RleCompressedUnmappedColor)
            {
                int payloadSize = (int)(reader.BaseStream.Length - reader.BaseStream.Position);
                pixelPayload = reader.ReadBytes(payloadSize);
                pixelPayload = DecompressRle(pixelPayload, header);
            }
            else
            {
                // ignore footer
                pixelPayload = reader.ReadBytes(expectedPayloadSize);
            }

            if (pixelPayload.Length != expectedPayloadSize)
            {
                throw new InvalidDataException("Targa payload size (" +
                                               pixelPayload.Length +
                                               ") does not match expected size (" +
                                               expectedPayloadSize + ")");
            }

            if ((ColorMapType)header.colorMapType == ColorMapType.ColorMapPresent)
            {
                pixelPayload = ExpandPayloadToUnmappedPixels(header, pixelPayload, colorMap);
            }

            if (YOriginIsAtBottomOfImage(header.imageDescriptor))
            {
                InvertImageAroundY(pixelPayload, header);
            }

            return(pixelPayload);
        }
        private byte[] ExpandPayloadToUnmappedPixels(TgaHeader header, byte[] pixelPayload, byte[] colorMap)
        {
            int mappedPixelSize = header.bitsPerPixel / 8;

            if (mappedPixelSize != 1)
            {
                throw new NotSupportedException("Mapped pixel elements greater than 8bpp are not supported yet.");
            }

            int unmappedPixelSize = header.colorMapDepth / 8;

            if (unmappedPixelSize != 3 && unmappedPixelSize != 4)
            {
                throw new NotSupportedException("Unmapped pixel elements other than 24bpp and 32bpp are not supported yet.");
            }

            int pixelCount = header.imageHeight * header.imageWidth;

            byte[] unmappedPixels = new byte[unmappedPixelSize * pixelCount];

            MemoryStream unmappedPixelStream = new MemoryStream(unmappedPixels);

            for (int i = 0; i < pixelCount; ++i)
            {
                int index    = pixelPayload[i];
                int mapEntry = index * unmappedPixelSize;

                if (unmappedPixelSize == 3)
                {
                    unmappedPixelStream.WriteByte(colorMap[mapEntry]);
                    unmappedPixelStream.WriteByte(colorMap[mapEntry + 1]);
                    unmappedPixelStream.WriteByte(colorMap[mapEntry + 2]);
                }
                else
                {
                    unmappedPixelStream.WriteByte(colorMap[mapEntry]);
                    unmappedPixelStream.WriteByte(colorMap[mapEntry + 1]);
                    unmappedPixelStream.WriteByte(colorMap[mapEntry + 2]);
                    unmappedPixelStream.WriteByte(colorMap[mapEntry + 3]);
                }
            }

            return(unmappedPixels);
        }
        private TgaHeader ReadHeader(BinaryReader reader)
        {
            TgaHeader header = new TgaHeader();

            header.idLength        = reader.ReadByte();
            header.colorMapType    = reader.ReadByte();
            header.dataType        = reader.ReadByte();
            header.colorMapStart   = reader.ReadInt16();
            header.colorMapLength  = reader.ReadInt16();
            header.colorMapDepth   = reader.ReadByte();
            header.xOrigin         = reader.ReadInt16();
            header.yOrigin         = reader.ReadInt16();
            header.imageWidth      = reader.ReadInt16();
            header.imageHeight     = reader.ReadInt16();
            header.bitsPerPixel    = reader.ReadByte();
            header.imageDescriptor = reader.ReadByte();

            return(header);
        }
Пример #26
0
        private void SaveTga(Surface input, Stream output, SaveConfigToken token, ProgressEventHandler progressCallback)
        {
            TgaSaveConfigToken tgaToken = (TgaSaveConfigToken)token;

            TgaHeader header = new TgaHeader();

            header.idLength      = 0;
            header.cmapType      = 0;
            header.imageType     = tgaToken.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.pixelDepth    = (byte)tgaToken.BitDepth;
            header.imageDesc     = 0;

            header.Write(output);

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

            for (int y = input.Height - 1; y >= 0; --y)
            {
                // non-rle output
                if (tgaToken.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 void InvertImageAroundY(byte[] pixels, TgaHeader header)
        {
            int bytesPerPixel = GetPixelDepth(header) / 8;
            int bytesPerRow   = header.imageWidth * bytesPerPixel;

            byte[] row = new byte[bytesPerRow];

            int topOffset          = 0;
            int bottomOffset       = bytesPerRow * (header.imageHeight - 1);
            int totalRowsToReflect = header.imageHeight / 2;

            for (int i = 0; i < totalRowsToReflect; ++i)
            {
                Buffer.BlockCopy(pixels, topOffset, row, 0, bytesPerRow);
                Buffer.BlockCopy(pixels, bottomOffset, pixels, topOffset, bytesPerRow);
                Buffer.BlockCopy(row, 0, pixels, bottomOffset, bytesPerRow);

                topOffset    += bytesPerRow;
                bottomOffset -= bytesPerRow;
            }
        }
Пример #28
0
        private static byte[] GetImageBuffer(byte[] data, TgaHeader tgaHeader)
        {
            var imageDataOffset = RgbBufferDecoder.GetImageDataOffset(tgaHeader);
            var bytesPerPixel   = RgbBufferDecoder.GetBytesPerPixel(tgaHeader);
            var pixelsToDecode  = tgaHeader.Width * tgaHeader.Height;

            var outBuffer = new byte[pixelsToDecode * bytesPerPixel];


            for (int i = 0, inOffset = imageDataOffset, outOffset = 0; i < pixelsToDecode;)
            {
                var header     = data[inOffset++];
                var pixelCount = GetPixelCount(header);

                if (IsRle(header))
                {
                    for (int count = 0; count < pixelCount; count++)
                    {
                        Array.Copy(data, inOffset, outBuffer, outOffset, bytesPerPixel);
                        outOffset += bytesPerPixel;
                    }

                    inOffset += bytesPerPixel;
                }
                else
                {
                    var pixelsBytesLength = pixelCount * bytesPerPixel;
                    Array.Copy(data, inOffset, outBuffer, outOffset, pixelsBytesLength);

                    inOffset  += pixelsBytesLength;
                    outOffset += pixelsBytesLength;
                }
                i += pixelCount;
            }

            return(outBuffer);
        }
        private byte[] DecompressRle(byte[] rleCompressedPixels, TgaHeader header)
        {
            int bytesPerPixel         = GetPixelDepth(header) / 8;
            int decompressedByteCount = header.imageWidth * header.imageHeight * bytesPerPixel;

            byte[] decompressedPixels = new byte[decompressedByteCount];

            using (BinaryReader reader = new BinaryReader(new MemoryStream(rleCompressedPixels)))
                using (BinaryWriter writer = new BinaryWriter(new MemoryStream(decompressedPixels)))
                {
                    while (writer.BaseStream.Position != writer.BaseStream.Length)
                    {
                        byte packetHeader = reader.ReadByte();

                        int pixelCountThisPayload = (packetHeader & 0x7F) + 1;
                        if (PacketPreceedsRlePayload(packetHeader))
                        {
                            byte[] runColor = reader.ReadBytes(bytesPerPixel);
                            while (pixelCountThisPayload > 0)
                            {
                                writer.Write(runColor);
                                --pixelCountThisPayload;
                            }
                        }
                        else
                        {
                            // copy straight through
                            int    payloadSizeInBytes = pixelCountThisPayload * bytesPerPixel;
                            byte[] payload            = reader.ReadBytes(payloadSizeInBytes);
                            writer.Write(payload);
                        }
                    }
                }

            return(decompressedPixels);
        }
Пример #30
0
 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;
     }
 }
Пример #31
0
        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;
            }
        }
Пример #32
0
        private void SaveTga(Surface input, Stream output, SaveConfigToken token, ProgressEventHandler progressCallback)
        {
            TgaSaveConfigToken tgaToken = (TgaSaveConfigToken)token;

            TgaHeader header = new TgaHeader();

            header.idLength = 0;
            header.cmapType = 0;
            header.imageType = tgaToken.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.pixelDepth = (byte)tgaToken.BitDepth;
            header.imageDesc = 0;

            header.Write(output);

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

            for (int y = input.Height - 1; y >= 0; --y)
            {
                // non-rle output
                if (tgaToken.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)));
                }
            }
        }
Пример #33
0
        private TgaHeader ReadHeader(BinaryReader reader)
        {
            TgaHeader header = new TgaHeader();
            header.idLength = reader.ReadByte();
            header.colorMapType = reader.ReadByte();
            header.dataType = reader.ReadByte();
            header.colorMapStart = reader.ReadInt16();
            header.colorMapLength = reader.ReadInt16();
            header.colorMapDepth = reader.ReadByte();
            header.xOrigin = reader.ReadInt16();
            header.yOrigin = reader.ReadInt16();
            header.imageWidth = reader.ReadInt16();
            header.imageHeight = reader.ReadInt16();
            header.bitsPerPixel = reader.ReadByte();
            header.imageDescriptor = reader.ReadByte();

            return header;
        }
Пример #34
0
        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;
        }
Пример #35
0
 private int CalculateOpenGlPixelFormat(TgaHeader header)
 {
     int bpp = GetPixelDepth(header);
     switch (bpp)
     {
         case 24:
             return Gl.GL_BGR;
             
         case 32:
             return Gl.GL_BGRA;
             
         default:
             throw new InvalidOperationException("Unknown pixel depth.");
     }
 }
Пример #36
0
 private int GetPixelDepth(TgaHeader header)
 {
     ColorMapType colorMapType = (ColorMapType)header.colorMapType;
     return (colorMapType == ColorMapType.ColorMapPresent) ? header.colorMapDepth : header.bitsPerPixel;
 }
Пример #37
0
        private byte[] ExpandPayloadToUnmappedPixels(TgaHeader header, byte[] pixelPayload, byte[] colorMap)
        {
            int mappedPixelSize = header.bitsPerPixel/8;
            if (mappedPixelSize != 1)
                throw new NotSupportedException("Mapped pixel elements greater than 8bpp are not supported yet.");

            int unmappedPixelSize = header.colorMapDepth/8;
            if (unmappedPixelSize != 3 && unmappedPixelSize != 4)
                throw new NotSupportedException("Unmapped pixel elements other than 24bpp and 32bpp are not supported yet.");
            
            int pixelCount = header.imageHeight*header.imageWidth;
            
            byte[] unmappedPixels = new byte[unmappedPixelSize*pixelCount];
            
            MemoryStream unmappedPixelStream = new MemoryStream(unmappedPixels);

            for (int i = 0; i < pixelCount; ++i)
            {
                int index = pixelPayload[i];
                int mapEntry = index*unmappedPixelSize;
                
                if (unmappedPixelSize == 3)
                {
                    unmappedPixelStream.WriteByte(colorMap[mapEntry]);
                    unmappedPixelStream.WriteByte(colorMap[mapEntry + 1]);
                    unmappedPixelStream.WriteByte(colorMap[mapEntry + 2]);
                }
                else
                {
                    unmappedPixelStream.WriteByte(colorMap[mapEntry]);
                    unmappedPixelStream.WriteByte(colorMap[mapEntry + 1]);
                    unmappedPixelStream.WriteByte(colorMap[mapEntry + 2]);
                    unmappedPixelStream.WriteByte(colorMap[mapEntry + 3]);
                }
            }

            return unmappedPixels;
        }
Пример #38
0
        private void InvertImageAroundY(byte[] pixels, TgaHeader header)
        {
            int bytesPerPixel = GetPixelDepth(header) / 8;
            int bytesPerRow = header.imageWidth * bytesPerPixel;

            byte[] row = new byte[bytesPerRow];

            int topOffset = 0;
            int bottomOffset = bytesPerRow * (header.imageHeight - 1);
            int totalRowsToReflect = header.imageHeight / 2;
            for (int i = 0; i < totalRowsToReflect; ++i)
            {
                Buffer.BlockCopy(pixels, topOffset, row, 0, bytesPerRow);
                Buffer.BlockCopy(pixels, bottomOffset, pixels, topOffset, bytesPerRow);
                Buffer.BlockCopy(row, 0, pixels, bottomOffset, bytesPerRow);

                topOffset += bytesPerRow;
                bottomOffset -= bytesPerRow;
            }
        }
Пример #39
0
        private byte[] DecompressRle(byte[] rleCompressedPixels, TgaHeader header)
        {
            int bytesPerPixel = GetPixelDepth(header) / 8;
            int decompressedByteCount = header.imageWidth * header.imageHeight * bytesPerPixel;
            byte[] decompressedPixels = new byte[decompressedByteCount];

            using (BinaryReader reader = new BinaryReader(new MemoryStream(rleCompressedPixels)))
            using (BinaryWriter writer = new BinaryWriter(new MemoryStream(decompressedPixels)))
            {
                while (writer.BaseStream.Position != writer.BaseStream.Length)
                {
                    byte packetHeader = reader.ReadByte();

                    int pixelCountThisPayload = (packetHeader & 0x7F) + 1;
                    if (PacketPreceedsRlePayload(packetHeader))
                    {
                        byte[] runColor = reader.ReadBytes(bytesPerPixel);
                        while (pixelCountThisPayload > 0)
                        {
                            writer.Write(runColor);
                            --pixelCountThisPayload;
                        }
                    }
                    else
                    {
                        // copy straight through
                        int payloadSizeInBytes = pixelCountThisPayload * bytesPerPixel;
                        byte[] payload = reader.ReadBytes(payloadSizeInBytes);
                        writer.Write(payload);
                    }
                }
            }

            return decompressedPixels;
        }
Пример #40
0
        private byte[] ReadPixels(BinaryReader reader, TgaHeader header, byte[] colorMap)
        {
            if (header.bitsPerPixel == 16)
                throw new NotImplementedException("16bpp RGB unpacking is not supported yet.");

            int bytesPerPixel = header.bitsPerPixel / 8;
            int pixelCount = header.imageHeight * header.imageWidth;
            int expectedPayloadSize = pixelCount * bytesPerPixel;

            byte[] pixelPayload;

            if ((ImageDataType)header.dataType == ImageDataType.RleCompressedUnmappedColor)
            {
                int payloadSize = (int)(reader.BaseStream.Length - reader.BaseStream.Position);
                pixelPayload = reader.ReadBytes(payloadSize);
                pixelPayload = DecompressRle(pixelPayload, header);
            }
            else
            {
                // ignore footer
                pixelPayload = reader.ReadBytes(expectedPayloadSize);
            }

            if (pixelPayload.Length != expectedPayloadSize)
            {
                throw new InvalidDataException("Targa payload size (" +
                                               pixelPayload.Length +
                                               ") does not match expected size (" +
                                               expectedPayloadSize + ")");
            }

            if ((ColorMapType)header.colorMapType == ColorMapType.ColorMapPresent)
                pixelPayload = ExpandPayloadToUnmappedPixels(header, pixelPayload, colorMap);

            if (YOriginIsAtBottomOfImage(header.imageDescriptor))
                InvertImageAroundY(pixelPayload, header);

            return pixelPayload;
        }
Пример #41
0
        private byte[] ReadColorMap(BinaryReader reader, TgaHeader header)
        {
            if ((ImageDataType)header.dataType != ImageDataType.UncompressedMappedColor)
                return null;

            int bytesPerEntry = header.colorMapDepth/8;
            byte[] colorMap = reader.ReadBytes(bytesPerEntry*header.colorMapLength);

            return colorMap;
        }
Пример #42
0
        private string ReadIdString(BinaryReader reader, TgaHeader header)
        {
            byte[] idString = reader.ReadBytes(header.idLength);

            ASCIIEncoding encoding = new ASCIIEncoding();
            return encoding.GetString(idString, 0, idString.Length);
        }
Пример #43
0
        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);
        }
Пример #44
0
        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)));
                }
            }
        }
Пример #45
0
        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 int GetPixelDepth(TgaHeader header)
        {
            ColorMapType colorMapType = (ColorMapType)header.colorMapType;

            return((colorMapType == ColorMapType.ColorMapPresent) ? header.colorMapDepth : header.bitsPerPixel);
        }
Пример #47
0
 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);
     }
 }
Пример #48
0
        public static Image LoadTga( string path )
        {
            var fs = File.OpenRead( path );
            var br = new BinaryReader( fs );

            var header	=	new TgaHeader();

            /* char	 */	header.idlength			=	br.ReadByte();
            /* char	 */	header.colourmaptype	=	br.ReadByte();
            /* char	 */	header.datatypecode		=	br.ReadByte();
            /* short */	header.colourmaporigin	=	br.ReadInt16();
            /* short */	header.colourmaplength	=	br.ReadInt16();
            /* char	 */	header.colourmapdepth	=	br.ReadByte();
            /* short */	header.x_origin			=	br.ReadInt16();
            /* short */	header.y_origin			=	br.ReadInt16();
            /* short */	header.width			=	br.ReadInt16();
            /* short */	header.height			=	br.ReadInt16();
            /* char	 */	header.bitsperpixel		=	br.ReadByte();
            /* char	 */	header.imagedescriptor	=	br.ReadByte();

            if ( header.datatypecode != 2 ) {
                throw new Exception(string.Format("Only uncompressed RGB and RGBA images are supported. Got {0} data type code", header.datatypecode));
            }

            if ( header.bitsperpixel != 24 && header.bitsperpixel != 32 ) {
                throw new Exception(string.Format("Only 24- and 32-bit images are supported. Got {0} bits per pixel", header.bitsperpixel));
            }

            int w = header.width;
            int h = header.height;
            int bytePerPixel = header.bitsperpixel / 8;

            Image	image	= new Image( w, h );
            byte[]	data	= new byte[ w * h * bytePerPixel ];

            br.Read( data, 0, w * h * bytePerPixel );

            br.Dispose();
            fs.Dispose();

            bool flip	=	!MathUtil.IsBitSet(header.imagedescriptor, 5);

            unsafe {
                if ( bytePerPixel==3 ) {
                    for ( int x=0; x<w; ++x ) {
                        for ( int y=0; y<h; ++y ) {
                            int p =  flip ? ((h-y-1) * w + x) : (y * w + x);

                            image.RawImageData[ y * w + x ].Red		=	data[p*3+2]	/ 255.0f;
                            image.RawImageData[ y * w + x ].Green	=	data[p*3+1]	/ 255.0f;
                            image.RawImageData[ y * w + x ].Blue	=	data[p*3+0]	/ 255.0f;
                            image.RawImageData[ y * w + x ].Alpha	=	255			/ 255.0f;
                        }
                    }
                } else {
                    for ( int x=0; x<w; ++x ) {
                        for ( int y=0; y<h; ++y ) {
                            int p =  flip ? ((h-y-1) * w + x) : (y * w + x);

                            image.RawImageData[ y * w + x ].Red		=	data[p*4+2] / 255.0f;
                            image.RawImageData[ y * w + x ].Green	=	data[p*4+1] / 255.0f;
                            image.RawImageData[ y * w + x ].Blue	=	data[p*4+0] / 255.0f;
                            image.RawImageData[ y * w + x ].Alpha	=	data[p*4+3] / 255.0f;
                        }
                    }
                }
            }

            image.Name	=	path;

            return image;
        }
Пример #49
0
 public static TgaHeader FromStream(Stream stream)
 {
     var h = new TgaHeader();
     h.IDLength = (byte)stream.ReadByte();
     h.ColorMapType = (byte)stream.ReadByte();
     h.ImageType = (byte)stream.ReadByte();
     h.CMapStart = ReadShort(stream);
     h.CMapLength = ReadShort(stream);
     h.CMapDepth = (byte)stream.ReadByte();
     h.XOffset = ReadShort(stream);
     h.YOffset = ReadShort(stream);
     h.Width = ReadShort(stream);
     h.Height = ReadShort(stream);
     h.PixelDepth = (byte)stream.ReadByte();
     h.ImageDescriptor = (byte)stream.ReadByte();
     return h;
 }