Ejemplo n.º 1
0
        public static unsafe void ToStream(Bitmap bmp, FileStream stream)
        {
            int w = bmp.Width, h = bmp.Height;

            TGAHeader header = new TGAHeader();
            TGAFooter footer = new TGAFooter(0, 0);

            PaletteEncoder pEnc = null;
            ColorParser    cEnc = null;
            ColorPalette   pal  = null;

            header.imageSpecification.width  = (ushort)w;
            header.imageSpecification.height = (ushort)h;
            header.imageType = TGAImageType.UncompressedTrueColor;
            switch (bmp.PixelFormat)
            {
            case PixelFormat.Format4bppIndexed:
            case PixelFormat.Format8bppIndexed:
            {
                pal = bmp.Palette;

                header.colorMapType = 1;
                header.imageType    = TGAImageType.UncompressedColorMapped;
                header.colorMapSpecification.length    = (ushort)pal.Entries.Length;
                header.colorMapSpecification.entrySize = 24;
                header.imageSpecification.pixelDepth   = 8;

                pEnc = (ref VoidPtr ptr, Color c) => { *(RGBPixel *)ptr = (RGBPixel)c; ptr += 3; };

                if (bmp.PixelFormat == PixelFormat.Format4bppIndexed)
                {
                    cEnc = delegate(VoidPtr sPtr, int sIndex, VoidPtr dPtr, int dIndex)
                    { ((byte *)dPtr)[dIndex] = ((sIndex & 1) == 0) ? (byte)(((byte *)sPtr)[sIndex >> 1] >> 4) : (byte)(((byte *)sPtr)[sIndex >> 1] & 0xF); }
                }
                ;
                else
                {
                    cEnc = delegate(VoidPtr sPtr, int sIndex, VoidPtr dPtr, int dIndex)
                    { ((byte *)dPtr)[dIndex] = ((byte *)sPtr)[sIndex]; }
                };

                break;
            }

            case PixelFormat.Format32bppRgb:
            case PixelFormat.Format32bppArgb:
            {
                header.imageSpecification.pixelDepth = 32;
                header.imageSpecification.AlphaBits  = (bmp.PixelFormat == PixelFormat.Format32bppArgb) ? (byte)8 : (byte)0;

                cEnc = delegate(VoidPtr sPtr, int sIndex, VoidPtr dPtr, int dIndex)
                { ((ARGBPixel *)dPtr)[dIndex] = ((ARGBPixel *)sPtr)[sIndex]; };
                break;
            }

            case PixelFormat.Format24bppRgb:
            {
                header.imageSpecification.pixelDepth = 24;

                cEnc = delegate(VoidPtr sPtr, int sIndex, VoidPtr dPtr, int dIndex)
                { ((RGBPixel *)dPtr)[dIndex] = ((RGBPixel *)sPtr)[sIndex]; };
                break;
            }

            case PixelFormat.Format16bppRgb555:
            {
                header.imageSpecification.pixelDepth = 15;
                cEnc = delegate(VoidPtr sPtr, int sIndex, VoidPtr dPtr, int dIndex)
                { ((RGB555Pixel *)dPtr)[dIndex] = ((RGB555Pixel *)sPtr)[sIndex]; };
                break;
            }

            case PixelFormat.Format16bppArgb1555:
            {
                header.imageSpecification.pixelDepth = 16;
                header.imageSpecification.AlphaBits  = 1;
                cEnc = delegate(VoidPtr sPtr, int sIndex, VoidPtr dPtr, int dIndex)
                { ((RGB555Pixel *)dPtr)[dIndex] = ((RGB555Pixel *)sPtr)[sIndex]; };
                break;
            }

            default:
                throw new FormatException("Input pixel format unsupported.");
            }

            int mapLen  = header.colorMapSpecification.DataLength;
            int dataLen = header.imageSpecification.DataLength;

            int totalLen = TGAHeader.Size + mapLen + dataLen + TGAFooter.Size;

            stream.SetLength(totalLen);

            BitmapData data = bmp.LockBits(new Rectangle(0, 0, w, h), ImageLockMode.ReadOnly, bmp.PixelFormat);

            //using (FileStream stream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None, 0x1000, FileOptions.RandomAccess))
            using (FileMap view = FileMap.FromStream(stream))// stream.MapView(0, (uint)totalLen, FileMapProtect.ReadWrite))
            {
                //Create header
                TGAHeader *pHeader = (TGAHeader *)view.Address;
                *          pHeader = header;

                //Write id

                //Write color map
                if (pal != null)
                {
                    VoidPtr pMap = pHeader->ColorMapData;
                    for (int i = 0; i < pal.Entries.Length; i++)
                    {
                        pEnc(ref pMap, pal.Entries[i]);
                    }
                }

                //Write color data
                int   dstStride = (pHeader->imageSpecification.pixelDepth * w).Align(8) / 8;
                int   origin    = (int)pHeader->imageSpecification.ImageOrigin;
                int   xStep     = ((origin & 1) == 0) ? 1 : -1;
                int   yStep     = ((origin & 2) != 0) ? 1 : -1;
                byte *imgDst    = pHeader->ImageData;
                for (int sY = (yStep == 1) ? 0 : h - 1, dY = 0; dY < h; sY += yStep, dY++)
                {
                    VoidPtr imgSrc = (VoidPtr)data.Scan0 + (data.Stride * sY);

                    //Do RLE encoding

                    for (int sX = (xStep == 1) ? 0 : w - 1, dX = 0; dX < w; sX += xStep, dX++)
                    {
                        cEnc(imgSrc, sX, imgDst, dX);
                    }

                    imgDst += dstStride;
                }

                //Write footer
                TGAFooter *pFooter = (TGAFooter *)(pHeader->ImageData + pHeader->imageSpecification.DataLength);
                *          pFooter = footer;
            }
            bmp.UnlockBits(data);
        }
Ejemplo n.º 2
0
        public static unsafe Bitmap FromFile(string path)
        {
            using (FileMap view = FileMap.FromFile(path, FileMapProtect.Read))// FileStream stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read))
            {
                TGAHeader *header = (TGAHeader *)view.Address;

                int w = header->imageSpecification.width, h = header->imageSpecification.height;
                int entryBpp  = header->imageSpecification.pixelDepth;
                int alphaBits = header->imageSpecification.AlphaBits;

                ColorPalette palette = null;
                PixelFormat  format;
                ColorParser  cParser;
                switch (header->imageType & (TGAImageType)0x3)
                {
                case TGAImageType.UncompressedColorMapped:
                {
                    int mapBpp = header->colorMapSpecification.entrySize;
                    if (entryBpp == 4)
                    {
                        format  = PixelFormat.Format4bppIndexed;
                        cParser = delegate(VoidPtr sPtr, int sIndex, VoidPtr dPtr, int dIndex)
                        {
                            byte val = ((byte *)sPtr)[sIndex >> 1], val2 = ((byte *)dPtr)[dIndex >> 1];
                            val = ((sIndex & 1) == 0) ? (byte)(val >> 4) : (byte)(val & 0xF);
                            ((byte *)dPtr)[dIndex >> 1] = ((dIndex & 1) == 0) ? (byte)((val2 & 0xF) | (val << 4)) : (byte)((val2 & 0xF0) | val);
                        };
                    }
                    else if (entryBpp == 8)
                    {
                        format  = PixelFormat.Format8bppIndexed;
                        cParser = delegate(VoidPtr sPtr, int sIndex, VoidPtr dPtr, int dIndex)
                        { ((byte *)dPtr)[dIndex] = ((byte *)sPtr)[sIndex]; };
                    }
                    else
                    {
                        throw new InvalidDataException("Invalid TGA color map format.");
                    }

                    int firstIndex = header->colorMapSpecification.firstEntryIndex;
                    int palSize    = firstIndex + header->colorMapSpecification.length;
                    palette = ColorPaletteExtension.CreatePalette(ColorPaletteFlags.None, palSize);

                    PaletteParser pParser;
                    if (mapBpp == 32)
                    {
                        pParser = (ref VoidPtr x) => { Color c = (Color)(*(ARGBPixel *)x); x += 4; return(c); }
                    }
                    ;
                    else if (mapBpp == 24)
                    {
                        pParser = (ref VoidPtr x) => { Color c = (Color)(*(RGBPixel *)x); x += 3; return(c); }
                    }
                    ;
                    else
                    {
                        throw new InvalidDataException("Invalid TGA color map format.");
                    }

                    VoidPtr palData = header->ColorMapData;
                    for (int i = firstIndex; i < palSize; i++)
                    {
                        palette.Entries[i] = pParser(ref palData);
                    }

                    break;
                }

                case TGAImageType.UncompressedTrueColor:
                {
                    if ((entryBpp == 15) || ((entryBpp == 16) && (alphaBits == 0)))
                    {
                        format  = PixelFormat.Format16bppRgb555;
                        cParser = delegate(VoidPtr sPtr, int sIndex, VoidPtr dPtr, int dIndex)
                        { ((RGB555Pixel *)dPtr)[dIndex] = ((RGB555Pixel *)sPtr)[sIndex]; };
                    }
                    else if (entryBpp == 16)
                    {
                        format  = PixelFormat.Format16bppArgb1555;
                        cParser = delegate(VoidPtr sPtr, int sIndex, VoidPtr dPtr, int dIndex)
                        { ((RGB555Pixel *)dPtr)[dIndex] = ((RGB555Pixel *)sPtr)[sIndex]; };
                    }
                    else if (entryBpp == 24)
                    {
                        format  = PixelFormat.Format24bppRgb;
                        cParser = delegate(VoidPtr sPtr, int sIndex, VoidPtr dPtr, int dIndex)
                        { ((RGBPixel *)dPtr)[dIndex] = ((RGBPixel *)sPtr)[sIndex]; };
                    }
                    else if (entryBpp == 32)
                    {
                        format  = (alphaBits == 8) ? PixelFormat.Format32bppArgb : PixelFormat.Format32bppRgb;
                        cParser = delegate(VoidPtr sPtr, int sIndex, VoidPtr dPtr, int dIndex)
                        { ((ARGBPixel *)dPtr)[dIndex] = ((ARGBPixel *)sPtr)[sIndex]; };
                    }
                    else
                    {
                        throw new InvalidDataException("Unknown TGA file format.");
                    }

                    break;
                }

                case TGAImageType.UncompressedGreyscale:
                {
                    if (entryBpp == 8)
                    {
                        format  = PixelFormat.Format24bppRgb;
                        cParser = delegate(VoidPtr sPtr, int sIndex, VoidPtr dPtr, int dIndex)
                        { ((RGBPixel *)dPtr)[dIndex] = RGBPixel.FromIntensity(((byte *)sPtr)[sIndex]); };
                    }
                    else
                    {
                        throw new InvalidDataException("Unknown TGA file format.");
                    }
                    break;
                }

                default: throw new InvalidDataException("Unknown TGA file format.");
                }

                Bitmap bmp = new Bitmap(w, h, format);
                if (palette != null)
                {
                    bmp.Palette = palette;
                }
                BitmapData data = bmp.LockBits(new Rectangle(0, 0, w, h), ImageLockMode.ReadWrite, format);

                bool rle          = ((int)header->imageType & 0x8) != 0;
                int  srcStride    = (entryBpp * w).Align(8) / 8;
                int  rleBufferLen = (rle) ? srcStride : 0;

                byte *buffer = stackalloc byte[rleBufferLen];

                int   origin = (int)header->imageSpecification.ImageOrigin;
                int   xStep  = ((origin & 1) == 0) ? 1 : -1;
                int   yStep  = ((origin & 2) != 0) ? 1 : -1;
                byte *imgSrc = header->ImageData;
                for (int dY = (yStep == 1) ? 0 : h - 1, sY = 0; sY < h; dY += yStep, sY++)
                {
                    VoidPtr imgDst = (VoidPtr)data.Scan0 + (data.Stride * dY);

                    if (rle)
                    {
                        imgSrc += DecodeRLE(imgSrc, buffer, srcStride, entryBpp);
                    }

                    for (int dX = (xStep == 1) ? 0 : w - 1, sX = 0; sX < w; dX += xStep, sX++)
                    {
                        cParser((rle) ? buffer : imgSrc, sX, imgDst, dX);
                    }

                    if (!rle)
                    {
                        imgSrc += srcStride;
                    }
                }

                bmp.UnlockBits(data);
                return(bmp);
            }
        }