コード例 #1
0
ファイル: PackFile.cs プロジェクト: Blade3575/packmule
        /// <summary>
        /// Saves this instance, aka overwrites the file header.
        /// </summary>
        public void Save()
        {
            var head = new FileHeader
            {
                Signature  = PackCommon.Header,
                Revision   = Revision,
                EntryCount = Count,
                Path       = Root,
                Ft1        = Created.ToFileTime(),
                Ft2        = Modified.ToFileTime()
            };

            var pkgHead = new PackageHeader
            {
                EntryCount      = Count,
                InfoHeaderSize  = 0,
                DataSectionSize = (uint)(_source.Length - _dataStart),
                BlankSize       = 0,
                Zero            = new byte[16]
            };

            var infos = new List <Tuple <byte[], PackageItemInfo> >();

            foreach (var e in _entries.Values)
            {
                var info = new PackageItemInfo
                {
                    CompressedSize   = e.SizeInPack,
                    DecompressedSize = e.DecompressedSize,
                    IsCompressed     = e.IsCompressed,
                    Offset           = (uint)e.DataOffset,
                    Seed             = e.CryptoSeed,
                    CreationTime     = e.CreatedDate.ToFileTime(),
                    CreationTime2    = e.CreatedDate.ToFileTime(),
                    LastAccessTime   = e.AccessDate.ToFileTime(),
                    ModifiedTime     = e.ModifiedDate.ToFileTime(),
                    ModifiedTime2    = e.ModifiedDate.ToFileTime(),
                };

                var bytes = PackCommon.EncodeName(e.Name.PadRight(e.MaxNameLength, '\0'));

                infos.Add(Tuple.Create(bytes, info));
                pkgHead.InfoHeaderSize += bytes.Length + StructUtil.SizeOf <PackageItemInfo>();
            }

            pkgHead.BlankSize = (int)(_dataStart -
                                      (StructUtil.SizeOf <FileHeader>() + StructUtil.SizeOf <PackageHeader>() +
                                       pkgHead.InfoHeaderSize));

            pkgHead.InfoHeaderSize += pkgHead.BlankSize;

            _source.Position = 0;
            head.WriteToStream(_source);
            pkgHead.WriteToStream(_source);
            foreach (var i in infos)
            {
                _source.Write(i.Item1, 0, i.Item1.Length);
                i.Item2.WriteToStream(_source);
            }
        }
コード例 #2
0
        public void SettingUpdate(Setting setting)
        {
            if (setting == PumpTargetSetting)
            {
                byte pwm = (byte)setting.Value;
                if (pwm == 99)
                {
                    pwm = 100;            // For some reason, setting it to 99 doesn't work...
                }
                pwm = (pwm < 0 ? (byte)0 : (pwm > 100) ? (byte)100 : pwm);
                Write(SET_PUMP_TARGET_MAP[pwm]);
            }
            else if (setting == RgbControl)
            {
                ColorSpace[] value = setting.Value as ColorSpace[];
                if (value == null)
                {
                    return;
                }

                int i = 0;

                SuperLedSetting ledSetting = new SuperLedSetting();
                ledSetting.Register = 0x22;
                ledSetting.Opcode   = 0x10;
                ledSetting.Channel  = 0x02;

                ledSetting.Colour00 = value[i++];
                ledSetting.Colour01 = value[i++];
                ledSetting.Colour02 = value[i++];
                ledSetting.Colour03 = value[i++];
                ledSetting.Colour04 = value[i++];
                ledSetting.Colour05 = value[i++];
                ledSetting.Colour06 = value[i++];
                ledSetting.Colour07 = value[i++];
                ledSetting.Colour08 = value[i++];
                ledSetting.Colour09 = value[i++];
                ledSetting.Colour10 = value[i++];
                ledSetting.Colour12 = value[i++];
                ledSetting.Colour13 = value[i++];
                ledSetting.Colour14 = value[i++];
                ledSetting.Colour15 = value[i++];

                byte[] data = StructUtil.StructureToByteArray(ledSetting);
                Write(data);

                ledSetting          = new SuperLedSetting();
                ledSetting.Register = 0x22;
                ledSetting.Opcode   = 0x11;
                ledSetting.Channel  = 0x02;

                data = StructUtil.StructureToByteArray(ledSetting);
                Write(data);

                data = new byte[] { 0x22, 0xa0, 0x02, 0x00, 0x00, 0x08, 0x00, 0x00, 0x80, 0x00, 0x32, 0x00, 0x00, 0x01 };

                Write(data);
            }
        }
コード例 #3
0
    public static unsafe byte[] GetBytes(BitmapSource bitmap, uint bcrFlags)
    {
        uint stride = StructUtil.CalcStride((ushort)bitmap.Format.BitsPerPixel, bitmap.PixelWidth);

        byte[] buffer = new byte[stride * bitmap.PixelHeight];
        bitmap.CopyPixels(buffer, (int)stride, 0);

        var clrs = bitmap.Palette == null ? null : bitmap.Palette.Colors.Select(c => new RGBQUAD {
            rgbRed = c.R, rgbBlue = c.B, rgbGreen = c.G
        }).ToArray();

        BITMAP_WRITE_REQUEST req = new BITMAP_WRITE_REQUEST
        {
            dpiX          = bitmap.DpiX,
            dpiY          = bitmap.DpiY,
            imgWidth      = bitmap.PixelWidth,
            imgHeight     = bitmap.PixelHeight,
            imgStride     = stride,
            imgTopDown    = true,
            imgColorTable = clrs,
        };

        BITMASKS masks = default;

        uint getBitmask(IList <byte> mask)
        {
            uint result = 0;
            int  shift  = 0;

            for (int i = 0; i < mask.Count; i++)
            {
                result = result | (uint)(mask[i] << shift);
                shift += 8;
            }
            return(result);
        }

        if (bitmap.Format.Masks != null && bitmap.Format.Masks.Count == 3)
        {
            var wpfmasks = bitmap.Format.Masks;
            masks.maskBlue  = getBitmask(wpfmasks[0].Mask);
            masks.maskGreen = getBitmask(wpfmasks[1].Mask);
            masks.maskRed   = getBitmask(wpfmasks[2].Mask);
        }
        else if (bitmap.Format.Masks != null && bitmap.Format.Masks.Count == 4)
        {
            var wpfmasks = bitmap.Format.Masks;
            masks.maskBlue  = getBitmask(wpfmasks[0].Mask);
            masks.maskGreen = getBitmask(wpfmasks[1].Mask);
            masks.maskRed   = getBitmask(wpfmasks[2].Mask);
            masks.maskAlpha = getBitmask(wpfmasks[3].Mask);
        }

        fixed(byte *ptr = buffer)
        return(BitmapCore.WriteToBMP(ref req, ptr, masks, (ushort)bitmap.Format.BitsPerPixel, bcrFlags));
    }
コード例 #4
0
        /// <summary>
        /// Outputs the pack file to the given stream.
        /// </summary>
        /// <param name="dst">The DST.</param>
        public void SaveTo(Stream dst)
        {
            var head = new FileHeader
            {
                Signature  = PackCommon.Header,
                Revision   = Revision,
                EntryCount = _entries.Count,
                Path       = Root,
                Ft1        = DateTime.UtcNow.ToFileTimeUtc(),
                Ft2        = DateTime.UtcNow.ToFileTimeUtc()
            };

            var pkgHead = new PackageHeader
            {
                EntryCount      = _entries.Count,
                InfoHeaderSize  = 0,
                DataSectionSize = (uint)_bodyStream.Position,
                BlankSize       = 0,
                Zero            = new byte[16]
            };

            var infos = new List <Tuple <byte[], PackageItemInfo> >();

            foreach (var e in _entries)
            {
                var info = new PackageItemInfo()
                {
                    CompressedSize   = e.SizeInPack,
                    DecompressedSize = e.DecompressedSize,
                    IsCompressed     = e.IsCompressed,
                    Offset           = (uint)e.DataOffset,
                    Seed             = e.CryptoSeed,
                    CreationTime     = e.CreatedDate.ToFileTime(),
                    CreationTime2    = e.CreatedDate.ToFileTime(),
                    ModifiedTime     = e.ModifiedDate.ToFileTime(),
                    ModifiedTime2    = e.ModifiedDate.ToFileTime(),
                    LastAccessTime   = e.AccessDate.ToFileTime()
                };

                var bytes = PackCommon.EncodeName(e.Name);

                infos.Add(Tuple.Create(bytes, info));
                pkgHead.InfoHeaderSize += bytes.Length + StructUtil.SizeOf <PackageItemInfo>();
            }

            head.WriteToStream(dst);
            pkgHead.WriteToStream(dst);
            foreach (var i in infos)
            {
                dst.Write(i.Item1, 0, i.Item1.Length);
                i.Item2.WriteToStream(dst);
            }

            _bodyStream.Position = 0;
            _bodyStream.CopyTo(dst);
        }
コード例 #5
0
        /// <summary>
        /// Reads the package infos.
        /// </summary>
        /// <param name="packageHeader">The package header.</param>
        /// <exception cref="System.Exception">Entry ' + name + ' is corrupted!</exception>
        private void ReadPackageInfos(PackageHeader packageHeader)
        {
            var infoHeader = new byte[packageHeader.InfoHeaderSize];

            _source.Read(infoHeader, 0, infoHeader.Length);

            var ptr = 0;

            for (var i = 0; i < packageHeader.EntryCount; i++)
            {
                int nameSectionLength;
                if (infoHeader[ptr] < 4)
                {
                    nameSectionLength = 0x10 * (infoHeader[ptr] + 1);
                }
                else if (infoHeader[ptr] == 4)
                {
                    nameSectionLength = 0x60;
                }
                else
                {
                    nameSectionLength = BitConverter.ToInt32(infoHeader, ptr + 1) + 5;
                }

                var lengthSize = (infoHeader[ptr] > 4 ? 5 : 1);

                var nameStart     = ptr + lengthSize;
                var maxNameLength = nameSectionLength - lengthSize - 1;                 // 1 for the trailing \0, which we don't care about.

                var name = Encoding.UTF8.GetString(infoHeader, nameStart, maxNameLength).TrimEnd('\0');

                ptr += nameSectionLength;

                var info = infoHeader.GetStruct <PackageItemInfo>(ptr);

                if (info.Zero != 0)
                {
                    throw new Exception("Entry '" + name + "' is corrupted!");
                }

                _entries[name.NormalizePath()] = new PackEntry(info, name, maxNameLength);

                ptr += StructUtil.SizeOf <PackageItemInfo>();
            }
        }
コード例 #6
0
ファイル: BitmapCore.cs プロジェクト: clowd/bmplib
    public static byte[] WriteToBMP(ref BITMAP_WRITE_REQUEST info, byte *sourceBufferStart, BITMASKS masks, ushort nbits, uint bcwFlags)
    {
        bool skipFileHeader = (bcwFlags & BC_WRITE_SKIP_FH) > 0;
        bool forceV5        = (bcwFlags & BC_WRITE_V5) > 0;
        bool forceInfo      = (bcwFlags & BC_WRITE_VINFO) > 0;

        if (forceV5 && forceInfo)
        {
            throw new ArgumentException("ForceV5 and ForceInfo flags can not be used at the same time.");
        }

        // NOT SUPPORTED RIGHT NOW
        bool iccEmbed = false;

        byte[] iccProfileData = new byte[0];

        var hasAlpha = masks.maskAlpha != 0;

        if (nbits < 16 && (info.imgColorTable == null || info.imgColorTable.Length == 0))
        {
            throw new InvalidOperationException("A indexed bitmap must have a color table / palette.");
        }

        //int dpiToPelsPM(double dpi)
        //{
        //    if (Math.Round(dpi) == 96d) return 0;
        //    return (int)Math.Round(dpi / 0.0254d);
        //}

        uint paletteSize = info.imgColorTable == null ? 0 : (uint)info.imgColorTable.Length;

        var fhSize   = (uint)Marshal.SizeOf <BITMAPFILEHEADER>();
        var quadSize = (uint)Marshal.SizeOf <RGBQUAD>();

        byte[] buffer;
        uint   pxOffset, pxSize;

        // BI_BITFIELDS is not valid for 24bpp, so if the masks are not RGB we need to use a V5 header.
        //var nonStandard24bpp = nbits == 24 && !BitmapCorePixelFormat2.Bgr24.IsMatch(24, masks);

        BitmapCompressionMode compr = BitmapCompressionMode.BI_RGB;

        // some parsers do not respect the v5 header masks unless BI_BITFIELDS is used...
        // this is true of Chrome (only for 16bpp) and is also true of FireFox (16 and 32bpp)
        if (nbits == 16 || nbits == 32)
        {
            compr = BitmapCompressionMode.BI_BITFIELDS;
        }

        // write V5 header if embedded color profile or has alpha data
        if (forceV5 || hasAlpha || iccEmbed)
        {
            var v5Size = (uint)Marshal.SizeOf <BITMAPV5HEADER>();
            // Typical structure:
            // - BITMAPFILEHEADER (Optional)
            // - BITMAPV5HEADER
            // - * Note, never write BI_BITFIELDS at the end of a V5 header, these masks are contained within the header itself
            // - Color Table (Optional)
            // - Pixel Data
            // - Embedded Color Profile (Optional)

            var fh = new BITMAPFILEHEADER
            {
                bfType = BFH_BM,
            };

            var v5 = new BITMAPV5HEADER
            {
                bV5Size          = v5Size,
                bV5Planes        = 1,
                bV5BitCount      = nbits,
                bV5Height        = info.imgTopDown ? -info.imgHeight : info.imgHeight,
                bV5Width         = info.imgWidth,
                bV5Compression   = compr,
                bV5XPelsPerMeter = 0,
                bV5YPelsPerMeter = 0,

                bV5RedMask   = masks.maskRed,
                bV5GreenMask = masks.maskGreen,
                bV5BlueMask  = masks.maskBlue,
                bV5AlphaMask = masks.maskAlpha,

                bV5ClrImportant = paletteSize,
                bV5ClrUsed      = paletteSize,
                bV5SizeImage    = (uint)(info.imgStride * info.imgHeight),

                bV5CSType = ColorSpaceType.LCS_sRGB,
                bV5Intent = Bv5Intent.LCS_GM_IMAGES,
            };

            uint offset = skipFileHeader ? 0 : fhSize;
            offset += v5Size;
            offset += paletteSize * quadSize;

            // fh offset points to beginning of pixel data
            fh.bfOffBits = pxOffset = offset;
            pxSize       = v5.bV5SizeImage;

            offset += v5.bV5SizeImage;

            if (iccEmbed)
            {
                v5.bV5CSType      = ColorSpaceType.PROFILE_EMBEDDED;
                v5.bV5ProfileData = offset;
                v5.bV5ProfileSize = (uint)iccProfileData.Length;
                offset           += v5.bV5ProfileSize;
            }

            // fh size must be total file size
            fh.bfSize = offset;

            buffer = new byte[offset];
            offset = 0;

            if (!skipFileHeader)
            {
                StructUtil.SerializeTo(fh, buffer, ref offset);
            }

            StructUtil.SerializeTo(v5, buffer, ref offset);

            if (info.imgColorTable != null)
            {
                foreach (var p in info.imgColorTable)
                {
                    StructUtil.SerializeTo(p, buffer, ref offset);
                }
            }

            Marshal.Copy((IntPtr)sourceBufferStart, buffer, (int)offset, (int)v5.bV5SizeImage);
            offset += v5.bV5SizeImage;

            if (iccEmbed)
            {
                Buffer.BlockCopy(iccProfileData, 0, buffer, (int)offset, iccProfileData.Length);
            }
        }
        else
        {
            var infoSize = (uint)Marshal.SizeOf <BITMAPINFOHEADER>();
            // Typical structure:
            // - BITMAPFILEHEADER (Optional)
            // - BITMAPINFOHEADER
            // - BI_BITFIELDS (Optional)
            // - Color Table (Optional)
            // - Pixel Data

            // this would be ideal, we can specify transparency in VINFO headers... but many applications incl FireFox do not support this.
            // if (hasAlpha) compr = BitmapCompressionMode.BI_ALPHABITFIELDS;

            var fh = new BITMAPFILEHEADER
            {
                bfType = BFH_BM,
            };

            var vinfo = new BITMAPINFOHEADER
            {
                bV5Size          = infoSize,
                bV5Planes        = 1,
                bV5BitCount      = nbits,
                bV5Height        = info.imgTopDown ? -info.imgHeight : info.imgHeight,
                bV5Width         = info.imgWidth,
                bV5Compression   = compr,
                bV5XPelsPerMeter = 0,
                bV5YPelsPerMeter = 0,

                bV5ClrImportant = paletteSize,
                bV5ClrUsed      = paletteSize,
                bV5SizeImage    = (uint)(info.imgStride * info.imgHeight),
            };

            uint offset = skipFileHeader ? 0 : fhSize;
            offset += infoSize;

            if (compr == BitmapCompressionMode.BI_BITFIELDS)
            {
                offset += sizeof(uint) * 3;
            }

            offset += paletteSize * quadSize;

            // fh offset points to beginning of pixel data
            fh.bfOffBits = pxOffset = offset;
            pxSize       = vinfo.bV5SizeImage;

            offset += vinfo.bV5SizeImage;

            // fh size must be total file size
            fh.bfSize = offset;

            buffer = new byte[offset];
            offset = 0;

            if (!skipFileHeader)
            {
                StructUtil.SerializeTo(fh, buffer, ref offset);
            }

            StructUtil.SerializeTo(vinfo, buffer, ref offset);

            if (compr == BitmapCompressionMode.BI_BITFIELDS)
            {
                Buffer.BlockCopy(masks.BITFIELDS(), 0, buffer, (int)offset, sizeof(uint) * 3);
                offset += sizeof(uint) * 3;
            }

            if (info.imgColorTable != null)
            {
                foreach (var p in info.imgColorTable)
                {
                    StructUtil.SerializeTo(p, buffer, ref offset);
                }
            }

            Marshal.Copy((IntPtr)sourceBufferStart, buffer, (int)offset, (int)vinfo.bV5SizeImage);
        }

        return(buffer);
    }
コード例 #7
0
ファイル: BitmapCore.cs プロジェクト: clowd/bmplib
    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
            }
        }
    }
コード例 #8
0
ファイル: BitmapCore.cs プロジェクト: clowd/bmplib
    public static void ReadHeader(byte *source, int sourceLength, out BITMAP_READ_DETAILS info, uint bcrFlags)
    {
        var ptr = source;

        if ((sourceLength) < 12) // min header size
        {
            throw new InvalidOperationException(ERR_HEOF);
        }

        bool hasFileHeader = StructUtil.ReadU16(ptr) == BFH_BM;
        var  size_fh       = Marshal.SizeOf <BITMAPFILEHEADER>();

        int offset = 0;
        var fh     = default(BITMAPFILEHEADER);

        if (hasFileHeader)
        {
            var fhsize = Marshal.SizeOf <BITMAPFILEHEADER>();
            if (offset + fhsize > sourceLength)
            {
                throw new InvalidOperationException(ERR_HEOF);
            }

            fh      = StructUtil.Deserialize <BITMAPFILEHEADER>(ptr);
            ptr    += fhsize;
            offset += fhsize;
        }

        // we'll just unpack all the various header types we support into a standard BMPV5 header
        // this makes subsequent code easier to maintain as it only needs to refer to one place

        if ((sourceLength - offset) < 12) // min header size
        {
            throw new InvalidOperationException(ERR_HEOF);
        }

        var  header_size = StructUtil.ReadU32(ptr);
        var  bi          = default(BITMAPV5HEADER);
        bool is_os21x_   = false;

        if (header_size == 12)
        {
            var bich = StructUtil.Deserialize <BITMAPCOREHEADER>(ptr);
            bi.bV5Size     = bich.bcSize;
            bi.bV5Width    = bich.bcWidth;
            bi.bV5Height   = bich.bcHeight;
            bi.bV5Planes   = bich.bcPlanes;
            bi.bV5BitCount = bich.bcBitCount;

            bi.bV5CSType = ColorSpaceType.LCS_sRGB;
            is_os21x_    = true;
        }
        else if (/*header_size == 14 || */ header_size == 16 || header_size == 42 || header_size == 46 || header_size == 64)
        {
            var biih = StructUtil.Deserialize <BITMAPINFOHEADER>(ptr);
            bi.bV5Size     = biih.bV5Size;
            bi.bV5Width    = biih.bV5Width;
            bi.bV5Height   = biih.bV5Height;
            bi.bV5Planes   = biih.bV5Planes;
            bi.bV5BitCount = biih.bV5BitCount;

            if (header_size > 16)
            {
                bi.bV5Compression   = biih.bV5Compression;
                bi.bV5SizeImage     = biih.bV5SizeImage;
                bi.bV5XPelsPerMeter = biih.bV5XPelsPerMeter;
                bi.bV5YPelsPerMeter = biih.bV5YPelsPerMeter;
                bi.bV5ClrUsed       = biih.bV5ClrUsed;
                bi.bV5ClrImportant  = biih.bV5ClrImportant;
            }

            // https://www.fileformat.info/mirror/egff/ch09_05.htm (G31D)
            if (bi.bV5Compression == (BitmapCompressionMode)3 && bi.bV5BitCount == 1)
            {
                bi.bV5Compression = BitmapCompressionMode.OS2_HUFFMAN1D;
            }

            else if (bi.bV5Compression == (BitmapCompressionMode)4 && bi.bV5BitCount == 24)
            {
                bi.bV5Compression = BitmapCompressionMode.OS2_RLE24;
            }

            bi.bV5CSType = ColorSpaceType.LCS_sRGB;
        }
        else if (header_size == 40)
        {
            var biih = StructUtil.Deserialize <BITMAPINFOHEADER>(ptr);
            bi.bV5Size          = biih.bV5Size;
            bi.bV5Width         = biih.bV5Width;
            bi.bV5Height        = biih.bV5Height;
            bi.bV5Planes        = biih.bV5Planes;
            bi.bV5BitCount      = biih.bV5BitCount;
            bi.bV5Compression   = biih.bV5Compression;
            bi.bV5SizeImage     = biih.bV5SizeImage;
            bi.bV5XPelsPerMeter = biih.bV5XPelsPerMeter;
            bi.bV5YPelsPerMeter = biih.bV5YPelsPerMeter;
            bi.bV5ClrUsed       = biih.bV5ClrUsed;
            bi.bV5ClrImportant  = biih.bV5ClrImportant;

            bi.bV5CSType = ColorSpaceType.LCS_sRGB;
        }
        else if (header_size == 52 || header_size == 56)
        {
            var biih = StructUtil.Deserialize <BITMAPV3INFOHEADER>(ptr);
            bi.bV5Size          = biih.bV5Size;
            bi.bV5Width         = biih.bV5Width;
            bi.bV5Height        = biih.bV5Height;
            bi.bV5Planes        = biih.bV5Planes;
            bi.bV5BitCount      = biih.bV5BitCount;
            bi.bV5Compression   = biih.bV5Compression;
            bi.bV5SizeImage     = biih.bV5SizeImage;
            bi.bV5XPelsPerMeter = biih.bV5XPelsPerMeter;
            bi.bV5YPelsPerMeter = biih.bV5YPelsPerMeter;
            bi.bV5ClrUsed       = biih.bV5ClrUsed;
            bi.bV5ClrImportant  = biih.bV5ClrImportant;
            bi.bV5RedMask       = biih.bV5RedMask;
            bi.bV5GreenMask     = biih.bV5GreenMask;
            bi.bV5BlueMask      = biih.bV5BlueMask;

            if (header_size == 56) // 56b header adds alpha mask
            {
                bi.bV5AlphaMask = biih.bV5AlphaMask;
            }

            bi.bV5CSType = ColorSpaceType.LCS_sRGB;
        }
        else if (header_size == 108)
        {
            var biih = StructUtil.Deserialize <BITMAPV4HEADER>(ptr);
            bi.bV5Size          = biih.bV5Size;
            bi.bV5Width         = biih.bV5Width;
            bi.bV5Height        = biih.bV5Height;
            bi.bV5Planes        = biih.bV5Planes;
            bi.bV5BitCount      = biih.bV5BitCount;
            bi.bV5Compression   = biih.bV5Compression;
            bi.bV5SizeImage     = biih.bV5SizeImage;
            bi.bV5XPelsPerMeter = biih.bV5XPelsPerMeter;
            bi.bV5YPelsPerMeter = biih.bV5YPelsPerMeter;
            bi.bV5ClrUsed       = biih.bV5ClrUsed;
            bi.bV5ClrImportant  = biih.bV5ClrImportant;
            bi.bV5RedMask       = biih.bV5RedMask;
            bi.bV5GreenMask     = biih.bV5GreenMask;
            bi.bV5BlueMask      = biih.bV5BlueMask;
            bi.bV5AlphaMask     = biih.bV5AlphaMask;
            bi.bV5CSType        = biih.bV5CSType;
            bi.bV5Endpoints_1x  = biih.bV5Endpoints_1x;
            bi.bV5Endpoints_1y  = biih.bV5Endpoints_1y;
            bi.bV5Endpoints_1z  = biih.bV5Endpoints_1z;
            bi.bV5Endpoints_2x  = biih.bV5Endpoints_2x;
            bi.bV5Endpoints_2y  = biih.bV5Endpoints_2y;
            bi.bV5Endpoints_2z  = biih.bV5Endpoints_2z;
            bi.bV5Endpoints_3x  = biih.bV5Endpoints_3x;
            bi.bV5Endpoints_3y  = biih.bV5Endpoints_3y;
            bi.bV5Endpoints_3z  = biih.bV5Endpoints_3z;
            bi.bV5GammaRed      = biih.bV5GammaRed;
            bi.bV5GammaGreen    = biih.bV5GammaGreen;
            bi.bV5GammaBlue     = biih.bV5GammaBlue;
        }
        else if (header_size == 124)
        {
            bi = StructUtil.Deserialize <BITMAPV5HEADER>(ptr);
        }
        else
        {
            throw new NotSupportedException($"Bitmap header size '{header_size}' not known / supported.");
        }

        ptr    += header_size;
        offset += (int)header_size;

        ushort nbits = bi.bV5BitCount;

        //if (bi.bV5Planes != 1)
        //    throw new NotSupportedException($"Bitmap bV5Planes of '{bi.bV5Planes}' is not supported.");

        // we don't support linked profiles, custom windows profiles, etc - so default to sRGB instead of throwing...

        if (bi.bV5CSType != ColorSpaceType.LCS_CALIBRATED_RGB && bi.bV5CSType != ColorSpaceType.PROFILE_EMBEDDED)
        {
            bi.bV5CSType = ColorSpaceType.LCS_sRGB;
        }

        uint maskR = 0;
        uint maskG = 0;
        uint maskB = 0;
        uint maskA = 0;

        bool hasAlphaChannel       = false;
        bool skipVerifyBppAndMasks = false;

        switch (bi.bV5Compression)
        {
        case BitmapCompressionMode.BI_BITFIELDS:

            var rgb = StructUtil.Deserialize <MASKTRIPLE>(ptr);
            maskR   = rgb.rgbRed;
            maskG   = rgb.rgbGreen;
            maskB   = rgb.rgbBlue;
            offset += Marshal.SizeOf <MASKTRIPLE>();

            break;

        case BitmapCompressionMode.BI_ALPHABITFIELDS:

            var rgba = StructUtil.Deserialize <MASKQUAD>(ptr);
            maskR   = rgba.rgbRed;
            maskG   = rgba.rgbGreen;
            maskB   = rgba.rgbBlue;
            maskA   = rgba.rgbAlpha;
            offset += Marshal.SizeOf <MASKQUAD>();

            hasAlphaChannel = true;
            break;

        case BitmapCompressionMode.BI_RGB:
            switch (nbits)
            {
            case 32:
                // windows wrongly uses the 4th byte of BI_RGB 32bit dibs as alpha
                // but we need to do it too if we have any hope of reading alpha data
                maskB = 0xff;
                maskG = 0xff00;
                maskR = 0xff0000;
                maskA = 0xff000000;         // fake transparency?
                break;

            case 24:
                maskB = 0xff;
                maskG = 0xff00;
                maskR = 0xff0000;
                break;

            case 16:
                maskB = 0x001f;
                maskG = 0x03e0;
                maskR = 0x7c00;
                // we can check for transparency in 16b RGB but it is slower and is very uncommon
                // maskA = 0x8000; // fake transparency?
                break;
            }
            break;

        case BitmapCompressionMode.BI_JPEG:
        case BitmapCompressionMode.BI_PNG:
        case BitmapCompressionMode.BI_RLE4:
        case BitmapCompressionMode.BI_RLE8:
        case BitmapCompressionMode.OS2_RLE24:
            if (bi.bV5Height < 0)
            {
                throw new NotSupportedException("Top-down bitmaps are not supported with RLE/JPEG/PNG compression.");
            }
            skipVerifyBppAndMasks = true;
            break;

        case BitmapCompressionMode.OS2_HUFFMAN1D:
            if (bi.bV5Height < 0)
            {
                throw new NotSupportedException("Top-down bitmaps are not supported with Huffman1D compression.");
            }
            if (bi.bV5BitCount != 1)
            {
                throw new NotSupportedException("Huffman1D compression is only supported with 1bpp bitmaps");
            }
            skipVerifyBppAndMasks = true;
            break;

        default:
            throw new NotSupportedException($"Bitmap with bV5Compression of '{bi.bV5Compression.ToString()}' is not supported.");
        }

        // lets use the v3/v4/v5 masks if present instead of RGB
        // according to some readers (FIREFOX!) these masks are only valid if the compression mode is
        // BI_BITFIELDS, meaning they might write garbage here when the compression is RGB
        if (bi.bV5Size >= 52 && bi.bV5Compression == BitmapCompressionMode.BI_BITFIELDS)
        {
            if (bi.bV5RedMask != 0)
            {
                maskR = bi.bV5RedMask;
            }
            if (bi.bV5BlueMask != 0)
            {
                maskB = bi.bV5BlueMask;
            }
            if (bi.bV5GreenMask != 0)
            {
                maskG = bi.bV5GreenMask;
            }
        }

        // if an alpha mask has been provided in the header, lets use it.
        if (bi.bV5Size >= 56 && bi.bV5AlphaMask != 0)
        {
            maskA           = bi.bV5AlphaMask;
            hasAlphaChannel = true;
        }

        // try to infer alpha if 32bpp & no alpha mask was set (ie, BI_BITFIELDS)
        // this will only be used if the PRESERVE_FAKE_ALPHA flag is set
        if (maskA == 0 && nbits == 32)
        {
            maskA = (maskB | maskG | maskR) ^ 0xFFFFFFFF;
        }

        bool smBit = nbits == 1 || nbits == 2 || nbits == 4 || nbits == 8;
        bool lgBit = nbits == 16 || nbits == 24 || nbits == 32;

        if (!skipVerifyBppAndMasks)
        {
            if (!lgBit && !smBit)
            {
                throw new NotSupportedException($"Bitmap with bits per pixel of '{nbits}' are not valid.");
            }

            if (lgBit && maskR == 0 && maskB == 0 && maskG == 0)
            {
                throw new NotSupportedException($"Bitmap (bbp {nbits}) color masks could not be determined, this usually indicates a malformed bitmap file.");
            }
        }

        // The number of entries in the palette is either 2n (where n is the number of bits per pixel) or a smaller number specified in the header
        // always allocate at least 256 entries so we can ignore bad data which seeks past the end of palette data.
        var pallength = nbits < 16 ? (1 << nbits) : 0;

        if (bi.bV5ClrUsed > 0)
        {
            pallength = (int)bi.bV5ClrUsed;
        }

        if (pallength > 256) // technically the max is 256..? some bitmaps have invalidly/absurdly large palettes
        {
            if (hasFileHeader)
            {
                // if we have a file header, we can correct our pixel data offset below, so the only
                // important thing is that we don't read too many colors.
                pallength = 256;
            }
            else
            {
                throw new NotSupportedException("Bitmap has an oversized/invalid color palette.");
            }
        }

        RGBQUAD[] palette = new RGBQUAD[pallength];
        var       clrSize = is_os21x_ ? Marshal.SizeOf <RGBTRIPLE>() : Marshal.SizeOf <RGBQUAD>();

        for (int i = 0; i < palette.Length; i++)
        {
            if (is_os21x_)
            {
                var small = StructUtil.Deserialize <RGBTRIPLE>(ptr);
                palette[i] = new RGBQUAD {
                    rgbBlue = small.rgbBlue, rgbGreen = small.rgbGreen, rgbRed = small.rgbRed
                };
            }
            else
            {
                palette[i] = StructUtil.Deserialize <RGBQUAD>(ptr);
            }
            ptr += clrSize;
        }

        offset += pallength * clrSize;

        // For RGB DIBs, the image orientation is indicated by the biHeight member of the BITMAPINFOHEADER structure.
        // If biHeight is positive, the image is bottom-up. If biHeight is negative, the image is top-down.
        // DirectDraw uses top-down DIBs. In GDI, all DIBs are bottom-up.
        // Also, any DIB type that uses a FOURCC in the biCompression member, should express its biHeight as a positive number
        // no matter what its orientation is, since the FOURCC itself identifies a compression scheme whose image orientation
        // should be understood by any compatible filter. Common YUV formats such as UYVY, YV12, and YUY2 are top-down oriented.
        // It is invalid to store an image with these compression types in bottom-up orientation.
        // The sign of biHeight for such formats must always be set positive

        var  width   = bi.bV5Width;
        var  height  = bi.bV5Height;
        bool topDown = false;

        if (height < 0)
        {
            height  = -height;
            topDown = true;
        }

        if (width < 0)
        {
            throw new NotSupportedException("Bitmap with negative width is not allowed");
        }

        uint source_stride = StructUtil.CalcStride(nbits, width);
        uint dataOffset    = hasFileHeader ? fh.bfOffBits : (uint)offset;
        uint dataSize      = bi.bV5SizeImage > 0 ? bi.bV5SizeImage : (source_stride * (uint)height);

        if (dataOffset + dataSize > sourceLength)
        {
            throw new InvalidOperationException(ERR_HEOF);
        }

        var  profileSize   = bi.bV5ProfileSize;
        uint profileOffset = (hasFileHeader ? (uint)size_fh : 0) + bi.bV5ProfileData;

        if (profileOffset + profileSize > sourceLength)
        {
            throw new InvalidOperationException(ERR_HEOF);
        }

        var masks = new BITMASKS
        {
            maskRed   = maskR,
            maskGreen = maskG,
            maskBlue  = maskB,
            maskAlpha = maskA,
        };

        var fmt = BitmapCorePixelFormat.Formats.SingleOrDefault(f => f.IsMatch(nbits, masks));

        // currently we only support RLE -> Bgra32
        if (bi.bV5Compression == BitmapCompressionMode.BI_RLE4 || bi.bV5Compression == BitmapCompressionMode.BI_RLE8 || bi.bV5Compression == BitmapCompressionMode.OS2_RLE24)
        {
            fmt = null;
        }

        double pixelPerMeterToDpi(int pels)
        {
            if (pels == 0)
            {
                return(96);
            }
            return(pels * 0.0254d);
        }

        mscms.SafeProfileHandle clrsource = null;
        mscms.mscmsIntent       clrintent = mscms.mscmsIntent.INTENT_PERCEPTUAL;

        bool ignoreColorProfile = (bcrFlags & BC_READ_IGNORE_COLOR_PROFILE) > 0;

        if (!ignoreColorProfile)
        {
            try
            {
                if (bi.bV5CSType == ColorSpaceType.LCS_CALIBRATED_RGB)
                {
                    clrsource = mscms.CreateProfileFromLogicalColorSpace(bi);
                }
                else if (bi.bV5CSType == ColorSpaceType.PROFILE_EMBEDDED)
                {
                    clrsource = mscms.OpenProfile((source + profileOffset), profileSize);
                }

                switch (bi.bV5Intent)
                {
                case Bv5Intent.LCS_GM_BUSINESS:
                    clrintent = mscms.mscmsIntent.INTENT_RELATIVE_COLORIMETRIC;
                    break;

                case Bv5Intent.LCS_GM_GRAPHICS:
                    clrintent = mscms.mscmsIntent.INTENT_SATURATION;
                    break;

                case Bv5Intent.LCS_GM_ABS_COLORIMETRIC:
                    clrintent = mscms.mscmsIntent.INTENT_ABSOLUTE_COLORIMETRIC;
                    break;
                }

                if (clrsource != null && fmt != null && fmt.MscmsFormat.HasValue && fmt.IsIndexed)
                {
                    // transform color table if indexed image
                    palette = mscms.TransformColorsTo_sRGB(clrsource, palette, clrintent);
                }
            }
            catch
            {
                // ignore color profile errors
            }
        }

        info = new BITMAP_READ_DETAILS
        {
            dibHeader   = bi,
            bbp         = nbits,
            compression = bi.bV5Compression,
            dpiX        = pixelPerMeterToDpi(bi.bV5XPelsPerMeter),
            dpiY        = pixelPerMeterToDpi(bi.bV5YPelsPerMeter),

            cMasks     = masks,
            cIndexed   = smBit,
            cTrueAlpha = hasAlphaChannel,

            imgColorTable = palette,
            imgHeight     = height,
            imgTopDown    = topDown,
            imgWidth      = width,
            imgDataOffset = dataOffset,
            imgDataSize   = dataSize,
            imgStride     = source_stride,
            imgSourceFmt  = fmt,

            colorProfile       = clrsource,
            colorProfileIntent = clrintent,
        };
    }
コード例 #9
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;
                }
            }
        }
    }
コード例 #10
0
    public static void ReadIndexedTo32(ref BITMAP_READ_DETAILS info, byte *sourceBufferStart, byte *destBufferStart)
    {
        var palette     = info.imgColorTable;
        var nbits       = info.bbp;
        var width       = info.imgWidth;
        var height      = info.imgHeight;
        var upside_down = info.imgTopDown;

        uint source_stride = StructUtil.CalcStride(nbits, width);
        uint dest_stride   = StructUtil.CalcStride(32, width);

        RGBQUAD color;
        int     pal = palette.Length;
        byte    i4;
        byte *  source;
        uint *  dest;
        int     y, x, w, h = height, nbytes = (nbits / 8);

        if (nbits == 1)
        {
            while (--h >= 0)
            {
                y      = height - h - 1;
                dest   = (uint *)(destBufferStart + ((upside_down ? y : h) * dest_stride));
                source = sourceBufferStart + (y * source_stride);
                for (x = 0; x < source_stride - 1; x++)
                {
                    i4 = *source++;
                    for (int bit = 7; bit >= 0; bit--)
                    {
                        color = palette[(i4 & (1 << bit)) >> bit];
                        *dest++ = (uint)((color.rgbBlue) | (color.rgbGreen << 8) | (color.rgbRed << 16) | (0xFF << 24));
                    }
                }

                // last bits in a row might not make up a whole byte
                i4 = *source++;
                for (int bit = 7; bit >= 8 - (width - ((source_stride - 1) * 8)); bit--)
                {
                    color = palette[(i4 & (1 << bit)) >> bit];
                    *dest++ = (uint)((color.rgbBlue) | (color.rgbGreen << 8) | (color.rgbRed << 16) | (0xFF << 24));
                }
            }
        }
        else if (nbits == 2)
        {
            var px_remain = width % 4;
            if (px_remain == 0)
            {
                px_remain = 4;
            }

            while (--h >= 0)
            {
                y      = height - h - 1;
                dest   = (uint *)(destBufferStart + ((upside_down ? y : h) * dest_stride));
                source = sourceBufferStart + (y * source_stride);
                for (x = 0; x < source_stride - 1; x++)
                {
                    i4 = *source++;

                    color = palette[((i4 & 0b_1100_0000) >> 6) % pal];
コード例 #11
0
ファイル: IBitmapConverter.cs プロジェクト: clowd/bmplib
 /// <inheritdoc/>
 public TBitmap Read(Stream stream, BitmapReaderFlags pFlags) => Read(StructUtil.ReadBytes(stream), pFlags);
コード例 #12
0
ファイル: IBitmapConverter.cs プロジェクト: clowd/bmplib
 /// <inheritdoc/>
 public TBitmap Read(Stream stream) => Read(StructUtil.ReadBytes(stream));
コード例 #13
0
ファイル: ClipboardHandle.cs プロジェクト: clowd/bmplib
        /// <summary>
        /// Set clipboard format to the current clipboard. This will clear the clipboard
        /// if this is the first call to "Set" since the clipboard handle was opened.
        /// </summary>
        public virtual void SetFormat(ClipboardFormat format, Stream stream)
        {
            var bytes = StructUtil.ReadBytes(stream);

            SetFormatObject(format.Id, bytes, new BytesDataConverter());
        }