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); }
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); }