示例#1
0
    public static void ReadPixels(ref BITMAP_READ_DETAILS info, BitmapCorePixelFormat imgDestFmt, byte *sourceBufferStart, byte *destBufferStart, uint bcrFlags)
    {
        bool forcebgra32        = (bcrFlags & BC_READ_FORCE_BGRA32) > 0;
        bool preserveFormat     = (bcrFlags & BC_READ_STRICT_PRESERVE_FORMAT) > 0;
        bool preserveAlpha      = (bcrFlags & BC_READ_PRESERVE_INVALID_ALPHA) > 0;
        bool ignoreColorProfile = (bcrFlags & BC_READ_IGNORE_COLOR_PROFILE) > 0;

        if (preserveFormat && (info.imgSourceFmt != imgDestFmt))
        {
            throw new NotSupportedException("StrictPreserveFormat was set while the source and/or target format is not supported.");
        }

        if (forcebgra32 && imgDestFmt != BitmapCorePixelFormat.Bgra32)
        {
            throw new InvalidOperationException("ForceBGRA32 was set but this is not supported with the source pixel format.");
        }

        if (imgDestFmt == null)
        {
            throw new ArgumentNullException(nameof(imgDestFmt));
        }

        var compr = info.compression;

        if (compr == BitmapCompressionMode.BI_JPEG || compr == BitmapCompressionMode.BI_PNG)
        {
            throw new NotSupportedException("BI_JPEG and BI_PNG passthrough compression is not supported.");
        }
        else if (compr == BitmapCompressionMode.BI_RLE4 || compr == BitmapCompressionMode.BI_RLE8 || compr == BitmapCompressionMode.OS2_RLE24)
        {
            if (imgDestFmt != BitmapCorePixelFormat.Bgra32)
            {
                throw new NotSupportedException("RLE only supports being translated to Bgra32");
            }
            BitmapCorePixelReader.ReadRLE_32(ref info, sourceBufferStart, destBufferStart);
        }
        else if (compr == BitmapCompressionMode.OS2_HUFFMAN1D)
        {
            BitmapCorePixelReader.ReadHuffmanG31D(ref info, sourceBufferStart, destBufferStart);
        }
        else if (info.imgSourceFmt == imgDestFmt && info.cTrueAlpha == imgDestFmt.HasAlpha)
        {
            // if the source is a known/supported/standard format, we can basically just copy the buffer straight over with no further processing
            if (info.imgTopDown)
            {
                var size = info.imgStride * info.imgHeight;
                Buffer.MemoryCopy(sourceBufferStart, destBufferStart, size, size);
            }
            else
            {
                uint stride = info.imgStride;
                int  y, height = info.imgHeight, h = height;
                while (--h >= 0)
                {
                    y = height - h - 1;
                    byte *sourceln = sourceBufferStart + (y * stride);
                    byte *destln   = destBufferStart + (h * stride);
                    Buffer.MemoryCopy(sourceln, destln, stride, stride);
                }
            }
        }
        else if (info.bbp <= 8)
        {
            if (imgDestFmt != BitmapCorePixelFormat.Bgra32)
            {
                throw new NotSupportedException("RLE only supports being translated to Bgra32");
            }

            BitmapCorePixelReader.ReadIndexedTo32(ref info, sourceBufferStart, destBufferStart);
        }
        else if (info.bbp > 8)
        {
            BitmapCorePixelReader.ConvertChannelBGRA(ref info, imgDestFmt, sourceBufferStart, destBufferStart, preserveAlpha);
        }
        else
        {
            throw new NotSupportedException("Pixel format / compression not supported");
        }

        // translate pixels to sRGB via embedded color profile
        if (!ignoreColorProfile && info.colorProfile != null && !info.colorProfile.IsInvalid && !imgDestFmt.IsIndexed && imgDestFmt.MscmsFormat.HasValue)
        {
            try
            {
                uint stride = StructUtil.CalcStride(imgDestFmt.BitsPerPixel, info.imgWidth);
                mscms.TransformPixelsTo_sRGB(info.colorProfile, imgDestFmt.MscmsFormat.Value, destBufferStart, info.imgWidth, info.imgHeight, stride, info.colorProfileIntent);
            }
            catch
            {
                // ignore color transformation errors
            }
        }
    }
示例#2
0
 public static byte[] WriteToBMP(ref BITMAP_WRITE_REQUEST info, byte *sourceBufferStart, BitmapCorePixelFormat fmt, uint bcwFlags)
 {
     return(WriteToBMP(ref info, sourceBufferStart, fmt.Masks, fmt.BitsPerPixel, bcwFlags));
 }
示例#3
0
    public static void ConvertChannelBGRA(ref BITMAP_READ_DETAILS info, BitmapCorePixelFormat convertToFmt, byte *sourceBufferStart, byte *destBufferStart, bool preserveFakeAlpha)
    {
        var nbits           = info.bbp;
        var width           = info.imgWidth;
        var height          = info.imgHeight;
        var upside_down     = info.imgTopDown;
        var hasAlphaChannel = info.cTrueAlpha;

        var maskR = info.cMasks.maskRed;
        var maskG = info.cMasks.maskGreen;
        var maskB = info.cMasks.maskBlue;
        var maskA = info.cMasks.maskAlpha;

        int  shiftR = 0, shiftG = 0, shiftB = 0, shiftA = 0;
        uint maxR = 0, maxG = 0, maxB = 0, maxA = 0;
        uint multR = 0, multG = 0, multB = 0, multA = 0;

        if (maskR != 0)
        {
            shiftR = StructUtil.CalcShift(maskR);
            maxR   = maskR >> shiftR;
            multR  = (uint)(Math.Ceiling(255d / maxR * 65536 * 256)); // bitshift << 24
        }

        if (maskG != 0)
        {
            shiftG = StructUtil.CalcShift(maskG);
            maxG   = maskG >> shiftG;
            multG  = (uint)(Math.Ceiling(255d / maxG * 65536 * 256));
        }

        if (maskB != 0)
        {
            shiftB = StructUtil.CalcShift(maskB);
            maxB   = maskB >> shiftB;
            multB  = (uint)(Math.Ceiling(255d / maxB * 65536 * 256));
        }

        if (maskA != 0)
        {
            shiftA = StructUtil.CalcShift(maskA);
            maxA   = maskA >> shiftA;
            multA  = (uint)(Math.Ceiling(255d / maxA * 65536 * 256)); // bitshift << 24
        }

        var  write         = convertToFmt.Write;
        uint source_stride = StructUtil.CalcStride(nbits, width);
        uint dest_stride   = StructUtil.CalcStride(convertToFmt.BitsPerPixel, width);

restartLoop:

        byte b, r, g, a;
        uint  i32;
        byte *source, dest;
        int   y, w, h = height, nbytes = (nbits / 8);

        if (hasAlphaChannel)
        {
            while (--h >= 0)
            {
                y      = height - h - 1;
                dest   = destBufferStart + ((upside_down ? y : h) * dest_stride);
                source = sourceBufferStart + (y * source_stride);
                w      = width;
                while (--w >= 0)
                {
                    i32 = *(uint *)source;

                    b = (byte)((((i32 & maskB) >> shiftB) * multB) >> 24);
                    g = (byte)((((i32 & maskG) >> shiftG) * multG) >> 24);
                    r = (byte)((((i32 & maskR) >> shiftR) * multR) >> 24);
                    a = (byte)((((i32 & maskA) >> shiftA) * multA) >> 24);

                    dest    = write(dest, b, g, r, a);
                    source += nbytes;
                }
            }
        }
        else if (maskA != 0 && preserveFakeAlpha) // hasAlpha = false, and maskA != 0 - we might have _fake_ alpha.. need to check for it
        {
            while (--h >= 0)
            {
                y      = height - h - 1;
                dest   = destBufferStart + ((upside_down ? y : h) * dest_stride);
                source = sourceBufferStart + (y * source_stride);
                w      = width;
                while (--w >= 0)
                {
                    i32 = *(uint *)source;

                    b = (byte)((((i32 & maskB) >> shiftB) * multB) >> 24);
                    g = (byte)((((i32 & maskG) >> shiftG) * multG) >> 24);
                    r = (byte)((((i32 & maskR) >> shiftR) * multR) >> 24);
                    a = (byte)((((i32 & maskA) >> shiftA) * multA) >> 24);

                    if (a != 0)
                    {
                        // this BMP should not have an alpha channel, but windows likes doing this and we need to detect it
                        hasAlphaChannel = true;
                        goto restartLoop;
                    }

                    dest    = write(dest, b, g, r, 0xFF);
                    source += nbytes;
                }
            }
        }
        else  // simple bmp, no transparency
        {
            while (--h >= 0)
            {
                y      = height - h - 1;
                dest   = destBufferStart + ((upside_down ? y : h) * dest_stride);
                source = sourceBufferStart + (y * source_stride);
                w      = width;
                while (--w >= 0)
                {
                    i32 = *(uint *)source;
                    b   = (byte)((((i32 & maskB) >> shiftB) * multB) >> 24);
                    g   = (byte)((((i32 & maskG) >> shiftG) * multG) >> 24);
                    r   = (byte)((((i32 & maskR) >> shiftR) * multR) >> 24);

                    dest    = write(dest, b, g, r, 0xFF);
                    source += nbytes;
                }
            }
        }
    }
示例#4
0
 public PxMap(PixelFormat wpf, BitmapCorePixelFormat core)
 {
     wpfFmt  = wpf;
     coreFmt = core;
 }
示例#5
0
    public unsafe static BitmapSource Read(ref BITMAP_READ_DETAILS info, byte *pixels, uint bcrFlags)
    {
        // we do this parsing here since BitmapCore has no references to PresentationCore
        if (info.compression == BitmapCompressionMode.BI_PNG)
        {
            var stream = new PointerStream(pixels, info.imgDataSize);
            var png    = new PngBitmapDecoder(stream, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
            return(png.Frames[0]);
        }
        else if (info.compression == BitmapCompressionMode.BI_JPEG)
        {
            var stream = new PointerStream(pixels, info.imgDataSize);
            var jpg    = new JpegBitmapDecoder(stream, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
            return(jpg.Frames[0]);
        }

        PixelFormat           wpfFmt  = PixelFormats.Bgra32;
        BitmapCorePixelFormat coreFmt = BitmapCorePixelFormat.Bgra32;

        bool forceBgra32 = (bcrFlags & BitmapCore.BC_READ_FORCE_BGRA32) > 0;

        if (!forceBgra32 && info.imgSourceFmt != null)
        {
            var origFmt = info.imgSourceFmt;
            var pxarr   = Formats.Where(m => m.coreFmt == origFmt).ToArray();
            if (pxarr.Length > 0)
            {
                var px = pxarr.First();
                wpfFmt  = px.wpfFmt;
                coreFmt = px.coreFmt;
            }
        }

        BitmapPalette palette = null;

        if (info.imgColorTable.Length > 0)
        {
            var clrs = info.imgColorTable.Select(c => Color.FromRgb(c.rgbRed, c.rgbGreen, c.rgbBlue));
            if (info.imgColorTable.Length > 256) // wpf throws on oversized palettes
            {
                clrs = clrs.Take(256);
            }
            palette = new BitmapPalette(clrs.ToList());
        }

        var bitmap = new WriteableBitmap(
            info.imgWidth,
            info.imgHeight,
            info.dpiX,
            info.dpiY,
            wpfFmt,
            palette);

        var buf = (byte *)bitmap.BackBuffer;

        bitmap.Lock();

        BitmapCore.ReadPixels(ref info, coreFmt, pixels, buf, bcrFlags);

        bitmap.AddDirtyRect(new System.Windows.Int32Rect(0, 0, info.imgWidth, info.imgHeight));
        bitmap.Unlock();
        bitmap.Freeze(); // dispose back buffer

        return(bitmap);
    }
示例#6
0
    /// <inheritdoc/>
    public override unsafe Bitmap Read(byte *data, int dataLength, BitmapReaderFlags rFlags)
    {
        uint bcrFlags = (uint)rFlags;

        BITMAP_READ_DETAILS info;

        BitmapCore.ReadHeader(data, dataLength, out info, bcrFlags);

        byte *pixels = data + info.imgDataOffset;

        // we do this parsing here since BitmapCore has no references to System.Drawing
        if (info.compression == BitmapCompressionMode.BI_PNG || info.compression == BitmapCompressionMode.BI_JPEG)
        {
            return(new Bitmap(new PointerStream(pixels, info.imgDataSize)));
        }

        // defaults
        PixelFormat           gdiFmt  = PixelFormat.Format32bppArgb;
        BitmapCorePixelFormat coreFmt = BitmapCorePixelFormat.Bgra32;

        var formatbgra32 = (rFlags & BitmapReaderFlags.ForceFormatBGRA32) > 0;

        if (!formatbgra32 && info.imgSourceFmt != null)
        {
            var origFmt = info.imgSourceFmt;
            if (origFmt == BitmapCorePixelFormat.Rgb24)
            {
                // we need BitmapCore to reverse the pixel order for GDI
                coreFmt = BitmapCorePixelFormat.Bgr24;
                gdiFmt  = PixelFormat.Format24bppRgb;
            }
            else
            {
                var pxarr = Formats.Where(f => f.coreFmt == origFmt).ToArray();
                if (pxarr.Length > 0)
                {
                    var px = pxarr.First();
                    gdiFmt  = px.gdiFmt;
                    coreFmt = px.coreFmt;
                }
            }
        }

        Bitmap bitmap = new Bitmap(info.imgWidth, info.imgHeight, gdiFmt);
        var    dlock  = bitmap.LockBits(new Rectangle(0, 0, info.imgWidth, info.imgHeight), ImageLockMode.ReadWrite, gdiFmt);
        var    buf    = (byte *)dlock.Scan0;

        BitmapCore.ReadPixels(ref info, coreFmt, pixels, buf, bcrFlags);
        bitmap.UnlockBits(dlock);

        // update bitmap color palette
        var gdipPalette = bitmap.Palette;

        if (info.imgColorTable != null && gdipPalette?.Entries != null && gdipPalette.Entries.Length > 0)
        {
            for (int i = 0; i < info.imgColorTable.Length && i < gdipPalette.Entries.Length; i++)
            {
                var quad = info.imgColorTable[i];
                gdipPalette.Entries[i] = Color.FromArgb(0xFF, quad.rgbRed, quad.rgbGreen, quad.rgbBlue);
            }
            bitmap.Palette = gdipPalette;
        }

        return(bitmap);
    }
示例#7
0
 public PxMap(PixelFormat gdi, BitmapCorePixelFormat core)
 {
     gdiFmt  = gdi;
     coreFmt = core;
 }