Пример #1
0
        /// <summary>
        /// Creates a brush with the given dimensions given bit depth, alpha
        /// data, and name.
        /// </summary>
        /// <param name="width">Desired width.</param>
        /// <param name="height">Desired height.</param>
        /// <param name="bitDepth">Bit depth of the data.</param>
        /// <param name="alphaData">
        /// The pixel data, stored only as an alpha channel and flattened to a
        /// 1-d array.
        /// </param>
        /// <param name="name">Desired brush name.</param>
        /// <returns>
        /// An AbrBrush with a bitmap constructed from the alpha data.
        /// </returns>
        private static unsafe AbrBrush CreateSampledBrush(
            int width,
            int height,
            int bitDepth,
            byte[] alphaData,
            string name)
        {
            AbrBrush brush = new AbrBrush(width, height, name);

            BitmapData bd = brush.Image.LockBits(
                new Rectangle(0, 0, width, height),
                ImageLockMode.WriteOnly,
                PixelFormat.Format32bppPArgb);

            try
            {
                fixed(byte *ptr = alphaData)
                {
                    byte *scan0  = (byte *)bd.Scan0.ToPointer();
                    int   stride = bd.Stride;

                    if (bitDepth == 16)
                    {
                        int srcStride = width * 2;
                        for (int y = 0; y < height; y++)
                        {
                            byte *src = ptr + (y * srcStride);
                            byte *dst = scan0 + (y * stride);

                            for (int x = 0; x < width; x++)
                            {
                                ushort val = (ushort)((src[0] << 8) | src[1]);

                                dst[0] = dst[1] = dst[2] = 0;
                                dst[3] = (byte)((val * 10) / 1285);

                                src += 2;
                                dst += 4;
                            }
                        }
                    }
                    else
                    {
                        for (int y = 0; y < height; y++)
                        {
                            byte *src = ptr + (y * width);
                            byte *dst = scan0 + (y * stride);

                            for (int x = 0; x < width; x++)
                            {
                                dst[0] = dst[1] = dst[2] = 0;
                                dst[3] = *src;

                                src++;
                                dst += 4;
                            }
                        }
                    }
                }
            }
            finally
            {
                brush.Image.UnlockBits(bd);
            }

            return(brush);
        }
Пример #2
0
        /// <summary>
        /// Decodes the descriptor-based brushes in version 6 and later.
        /// </summary>
        /// <param name="reader">The reader.</param>
        /// <param name="majorVersion">The major version.</param>
        /// <returns>An <see cref="AbrBrushCollection"/> containing the brushes.</returns>
        /// <exception cref="FormatException">The ABR version is not supported.</exception>
        private static AbrBrushCollection DecodeVersion6(BigEndianBinaryReader reader, short majorVersion)
        {
            short minorVersion = reader.ReadInt16();
            long  unusedDataLength;

            switch (minorVersion)
            {
            case 1:
                // Skip the Int16 bounds rectangle and the unknown Int16.
                unusedDataLength = 10L;
                break;

            case 2:
                // Skip the unknown bytes.
                unusedDataLength = 264L;
                break;

            default:
                throw new FormatException(string.Format(
                                              CultureInfo.CurrentCulture,
                                              Localization.Strings.AbrUnsupportedMinorVersionFormat,
                                              majorVersion, minorVersion));
            }

            BrushSectionParser parser = new BrushSectionParser(reader);

            List <AbrBrush> brushes = new List <AbrBrush>(parser.SampledBrushes.Count);

            long sampleSectionOffset = parser.SampleSectionOffset;

            if (parser.SampledBrushes.Count > 0 && sampleSectionOffset >= 0)
            {
                reader.Position = sampleSectionOffset;

                uint sectionLength = reader.ReadUInt32();

                long sectionEnd = reader.Position + sectionLength;

                while (reader.Position < sectionEnd)
                {
                    uint brushLength = reader.ReadUInt32();

                    // The brush data is padded to 4 byte alignment.
                    long paddedBrushLength = ((long)brushLength + 3) & ~3;

                    long endOffset = reader.Position + paddedBrushLength;

                    string tag = reader.ReadPascalString();

                    // Skip the unneeded data that comes before the Int32 bounds rectangle.
                    reader.Position += unusedDataLength;

                    Rectangle bounds = reader.ReadInt32Rectangle();
                    if (bounds.Width <= 0 || bounds.Height <= 0)
                    {
                        // Skip any brushes that have invalid dimensions.
                        reader.Position += (endOffset - reader.Position);
                        continue;
                    }

                    short depth = reader.ReadInt16();
                    if (depth != 8 && depth != 16)
                    {
                        // Skip any brushes with an unknown bit depth.
                        reader.Position += (endOffset - reader.Position);
                        continue;
                    }

                    SampledBrush sampledBrush = parser.SampledBrushes.FindLargestBrush(tag);
                    if (sampledBrush != null)
                    {
                        BrushCompression compression = (BrushCompression)reader.ReadByte();

                        int height = bounds.Height;
                        int width  = bounds.Width;

                        byte[] alphaData = null;

                        if (compression == BrushCompression.RLE)
                        {
                            short[] compressedRowLengths = new short[height];

                            for (int y = 0; y < height; y++)
                            {
                                compressedRowLengths[y] = reader.ReadInt16();
                            }

                            int alphaDataSize = width * height;
                            int bytesPerRow   = width;

                            if (depth == 16)
                            {
                                alphaDataSize *= 2;
                                bytesPerRow   *= 2;
                            }

                            alphaData = new byte[alphaDataSize];

                            for (int y = 0; y < height; y++)
                            {
                                RLEHelper.DecodedRow(reader, alphaData, y * width, bytesPerRow);
                            }
                        }
                        else if (compression == BrushCompression.None)
                        {
                            int alphaDataSize = width * height;

                            if (depth == 16)
                            {
                                alphaDataSize *= 2;
                            }

                            alphaData = reader.ReadBytes(alphaDataSize);
                        }
                        else
                        {
                            // Skip any brushes with an unknown compression type.
                            reader.Position += (endOffset - reader.Position);
                            continue;
                        }

                        AbrBrush brush = CreateSampledBrush(width, height, depth, alphaData, sampledBrush.Name);

                        brushes.Add(brush);

                        // Some brushes only store the largest item and scale it down.
                        var scaledBrushes = parser.SampledBrushes.Where(i => i.Tag.Equals(tag, StringComparison.Ordinal) && i.Diameter < sampledBrush.Diameter);
                        if (scaledBrushes.Any())
                        {
                            int originalWidth  = brush.Image.Width;
                            int originalHeight = brush.Image.Height;

                            foreach (SampledBrush item in scaledBrushes.OrderByDescending(p => p.Diameter))
                            {
                                Size size = Utils.ComputeBrushSize(originalWidth, originalHeight, item.Diameter);

                                AbrBrush scaledBrush = new AbrBrush(size.Width, size.Height, item.Name);

                                using (Graphics gr = Graphics.FromImage(scaledBrush.Image))
                                {
                                    gr.SmoothingMode     = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
                                    gr.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
                                    gr.PixelOffsetMode   = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;
                                    gr.DrawImage(brush.Image, 0, 0, size.Width, size.Height);
                                }

                                brushes.Add(scaledBrush);
                            }
                        }
                    }

                    long remaining = endOffset - reader.Position;
                    // Skip any remaining bytes until the next sampled brush.
                    if (remaining > 0)
                    {
                        reader.Position += remaining;
                    }
                }
            }

            return(new AbrBrushCollection(brushes));
        }