Пример #1
0
        public void Blend(IarImage overlay)
        {
            int pixel_size = Info.Stride / (int)Info.Width;

            if (pixel_size < 4)
            {
                return;
            }
            var self = new Rectangle(-Info.OffsetX, -Info.OffsetY, (int)Info.Width, (int)Info.Height);
            var src  = new Rectangle(-overlay.Info.OffsetX, -overlay.Info.OffsetY,
                                     (int)overlay.Info.Width, (int)overlay.Info.Height);
            var blend = Rectangle.Intersect(self, src);

            if (blend.IsEmpty)
            {
                return;
            }
            src.X      = blend.Left - src.Left;
            src.Y      = blend.Top - src.Top;
            src.Width  = blend.Width;
            src.Height = blend.Height;
            if (src.Width <= 0 || src.Height <= 0)
            {
                return;
            }

            int x   = blend.Left - self.Left;
            int y   = blend.Top - self.Top;
            int dst = y * Info.Stride + x * pixel_size;
            int ov  = src.Top * overlay.Info.Stride + src.Left * pixel_size;

            for (int row = 0; row < src.Height; ++row)
            {
                for (int col = 0; col < src.Width; ++col)
                {
                    int src_pixel = ov + col * pixel_size;
                    int src_alpha = overlay.Data[src_pixel + 3];
                    if (src_alpha > 0)
                    {
                        int dst_pixel = dst + col * pixel_size;
                        if (0xFF == src_alpha || 0 == m_output[dst_pixel + 3])
                        {
                            Buffer.BlockCopy(overlay.Data, src_pixel, m_output, dst_pixel, pixel_size);
                        }
                        else
                        {
                            m_output[dst_pixel + 0] = (byte)((overlay.Data[src_pixel + 0] * src_alpha
                                                              + m_output[dst_pixel + 0] * (0xFF - src_alpha)) / 0xFF);
                            m_output[dst_pixel + 1] = (byte)((overlay.Data[src_pixel + 1] * src_alpha
                                                              + m_output[dst_pixel + 1] * (0xFF - src_alpha)) / 0xFF);
                            m_output[dst_pixel + 2] = (byte)((overlay.Data[src_pixel + 2] * src_alpha
                                                              + m_output[dst_pixel + 2] * (0xFF - src_alpha)) / 0xFF);
                            m_output[dst_pixel + 3] = (byte)Math.Max(src_alpha, m_output[dst_pixel + 3]);
                        }
                    }
                }
                dst += Info.Stride;
                ov  += overlay.Info.Stride;
            }
        }
Пример #2
0
        IarImage CombineImage(IarImage overlay, IarArchive iarc)
        {
            using (var input = new BinMemoryStream(overlay.Data))
            {
                var dir        = (List <Entry>)iarc.Dir;
                int base_index = input.ReadInt32();
                if (base_index >= dir.Count)
                {
                    throw new InvalidFormatException("Invalid base image index");
                }
                int diff_y     = input.ReadInt32();
                int diff_count = input.ReadInt32();

                var    overlay_info = overlay.Info;
                int    pixel_size   = overlay_info.BPP / 8;
                var    base_image   = new IarImage(iarc, dir[base_index]);
                byte[] output       = base_image.Data;
                if (overlay_info.Height != base_image.Info.Height || overlay_info.Stride != base_image.Info.Stride)
                {
                    int    src_height = (int)Math.Min(overlay_info.Height, base_image.Info.Height);
                    int    src_stride = Math.Min(overlay_info.Stride, base_image.Info.Stride);
                    byte[] src        = base_image.Data;
                    output = new byte[overlay_info.Height * overlay_info.Stride];
                    int dst_pos = 0;
                    if (base_image.Info.OffsetY < overlay_info.OffsetY)
                    {
                        dst_pos += (-base_image.Info.OffsetY + overlay_info.OffsetY) * overlay_info.Stride;
                    }
                    if (base_image.Info.OffsetX < overlay_info.OffsetX)
                    {
                        dst_pos += (-base_image.Info.OffsetX + overlay_info.OffsetX) * pixel_size;
                    }
                    for (int y = 0; y < src_height; ++y)
                    {
                        Buffer.BlockCopy(src, y * base_image.Info.Stride, output, dst_pos, src_stride);
                        dst_pos += overlay_info.Stride;
                    }
                }
                int dst = diff_y * overlay_info.Stride;
                for (int i = 0; i < diff_count; ++i)
                {
                    int chunk_count = input.ReadUInt16();
                    int x           = 0;
                    for (int j = 0; j < chunk_count; ++j)
                    {
                        int skip_count = pixel_size * input.ReadUInt16();
                        int copy_count = pixel_size * input.ReadUInt16();

                        x += skip_count;
                        input.Read(output, dst + x, copy_count);
                        x += copy_count;
                    }
                    dst += overlay_info.Stride;
                }
                return(new IarImage(overlay_info, output, overlay.Palette));
            }
        }
Пример #3
0
        public override Stream OpenEntry(ArcFile arc, Entry entry)
        {
            var iarc = arc as IarArchive;

            if (null == iarc)
            {
                return(base.OpenEntry(arc, entry));
            }
            try
            {
                int flags = arc.File.View.ReadUInt16(entry.Offset);

                var image = new IarImage(iarc, entry);
                if (0 != (flags & 0x1000))
                {
                    image = CombineLayers(image, iarc);
                }
                else if (0 != (flags & 0x800))
                {
                    image = CombineImage(image, iarc);
                }
                if (null == image)
                {
                    return(base.OpenEntry(arc, entry));
                }

                // internal 'IAR SAS5' format
                var header = new byte[0x28 + image.Info.PaletteSize];
                using (var mem = new MemoryStream(header))
                    using (var writer = new BinaryWriter(mem))
                    {
                        writer.Write(0x00524149); // 'IAR'

                        writer.Write(0x35534153); // 'SAS5'
                        writer.Write(image.Info.Width);
                        writer.Write(image.Info.Height);
                        writer.Write(image.Info.OffsetX);
                        writer.Write(image.Info.OffsetY);
                        writer.Write(image.Info.BPP);
                        writer.Write(image.Info.Stride);
                        writer.Write(image.Info.PaletteSize);
                        writer.Write(image.Data.Length);
                        if (null != image.Palette)
                        {
                            writer.Write(image.Palette, 0, image.Palette.Length);
                        }
                        return(new PrefixStream(header, new MemoryStream(image.Data)));
                    }
            }
            catch (Exception X)
            {
                Trace.WriteLine(X.Message, entry.Name);
                return(base.OpenEntry(arc, entry));
            }
        }
Пример #4
0
        IarImage CombineLayers(IarImage layers, IarArchive iarc)
        {
            layers.Info.Stride = (int)layers.Info.Width * 4;
            layers.Info.BPP    = 32;
            var pixels = new byte[layers.Info.Stride * (int)layers.Info.Height];
            var output = new IarImage(layers.Info, pixels);

            using (var mem = new MemoryStream(layers.Data))
                using (var input = new BinaryReader(mem))
                {
                    int offset_x = 0, offset_y = 0;
                    var dir = (List <Entry>)iarc.Dir;
                    while (input.BaseStream.Position < input.BaseStream.Length)
                    {
                        int cmd = input.ReadByte();
                        switch (cmd)
                        {
                        case 0x21:
                            offset_x += input.ReadInt16();
                            offset_y += input.ReadInt16();
                            break;

                        case 0x00:
                        case 0x20:
                        {
                            int index = input.ReadInt32();
                            if (index < 0 || index >= dir.Count)
                            {
                                throw new InvalidFormatException("Invalid image layer index");
                            }
                            var layer = new IarImage(iarc, dir[index]);
                            layer.Info.OffsetX -= offset_x;
                            layer.Info.OffsetY -= offset_y;
                            if (0x20 == cmd)
                            {
                                output.ApplyMask(layer);
                            }
                            else
                            {
                                output.Blend(layer);
                            }
                        }
                        break;

                        default:
                            Trace.WriteLine(string.Format("Unknown layer type 0x{0:X2}", cmd), "IAR");
                            break;
                        }
                    }
                    return(output);
                }
        }
Пример #5
0
        public void ApplyMask(IarImage mask)
        {
            int pixel_size = Info.Stride / (int)Info.Width;

            if (pixel_size < 4 || mask.Info.BPP != 8)
            {
                return;
            }
            var self        = new Rectangle(-Info.OffsetX, -Info.OffsetY, (int)Info.Width, (int)Info.Height);
            var mask_region = new Rectangle(-mask.Info.OffsetX, -mask.Info.OffsetY,
                                            (int)mask.Info.Width, (int)mask.Info.Height);
            var masked = Rectangle.Intersect(self, mask_region);

            if (masked.IsEmpty)
            {
                return;
            }
            mask_region.X      = masked.Left - mask_region.Left;
            mask_region.Y      = masked.Top - mask_region.Top;
            mask_region.Width  = masked.Width;
            mask_region.Height = masked.Height;
            if (mask_region.Width <= 0 || mask_region.Height <= 0)
            {
                return;
            }

            int x   = masked.Left - self.Left;
            int y   = masked.Top - self.Top;
            int dst = y * Info.Stride + x * pixel_size;
            int src = mask_region.Top * mask.Info.Stride + mask_region.Left;

            for (int row = 0; row < mask_region.Height; ++row)
            {
                int dst_pixel = dst + 3;
                for (int col = 0; col < mask_region.Width; ++col)
                {
                    m_output[dst_pixel] = mask.Data[src + col];
                    dst_pixel          += pixel_size;
                }
                dst += Info.Stride;
                src += mask.Info.Stride;
            }
        }
Пример #6
0
        public override Stream OpenEntry(ArcFile arc, Entry entry)
        {
            var iarc = arc as IarArchive;
            if (null == iarc)
                return base.OpenEntry (arc, entry);
            try
            {
                int flags = arc.File.View.ReadUInt16 (entry.Offset);

                var image = new IarImage (iarc, entry);
                if (0 != (flags & 0x1000))
                    image = CombineLayers (image, iarc);
                else if (0 != (flags & 0x800))
                    image = CombineImage (image, iarc);
                if (null == image)
                    return base.OpenEntry (arc, entry);

                // internal 'IAR SAS5' format
                var header = new byte[0x28+image.Info.PaletteSize];
                using (var mem = new MemoryStream (header))
                using (var writer = new BinaryWriter (mem))
                {
                    writer.Write (0x00524149); // 'IAR'
                    writer.Write (0x35534153); // 'SAS5'
                    writer.Write (image.Info.Width);
                    writer.Write (image.Info.Height);
                    writer.Write (image.Info.OffsetX);
                    writer.Write (image.Info.OffsetY);
                    writer.Write (image.Info.BPP);
                    writer.Write (image.Info.Stride);
                    writer.Write (image.Info.PaletteSize);
                    writer.Write (image.Data.Length);
                    if (null != image.Palette)
                        writer.Write (image.Palette, 0, image.Palette.Length);
                    return new PrefixStream (header, new MemoryStream (image.Data));
                }
            }
            catch (Exception X)
            {
                Trace.WriteLine (X.Message, entry.Name);
                return base.OpenEntry (arc, entry);
            }
        }
Пример #7
0
        public void Blend(IarImage overlay)
        {
            int pixel_size = Info.Stride / (int)Info.Width;
            if (pixel_size < 4)
                return;
            var self = new Rectangle (-Info.OffsetX, -Info.OffsetY, (int)Info.Width, (int)Info.Height);
            var src = new Rectangle (-overlay.Info.OffsetX, -overlay.Info.OffsetY,
                                     (int)overlay.Info.Width, (int)overlay.Info.Height);
            var blend = Rectangle.Intersect (self, src);
            if (blend.IsEmpty)
                return;
            src.X = blend.Left - src.Left;
            src.Y = blend.Top - src.Top;
            src.Width = blend.Width;
            src.Height= blend.Height;
            if (src.Width <= 0 || src.Height <= 0)
                return;

            int x = blend.Left - self.Left;
            int y = blend.Top - self.Top;
            int dst = y * Info.Stride + x * pixel_size;
            int ov = src.Top * overlay.Info.Stride + src.Left * pixel_size;
            for (int row = 0; row < src.Height; ++row)
            {
                for (int col = 0; col < src.Width; ++col)
                {
                    int src_pixel = ov + col*pixel_size;
                    int src_alpha = overlay.Data[src_pixel+3];
                    if (src_alpha > 0)
                    {
                        int dst_pixel = dst + col*pixel_size;
                        if (0xFF == src_alpha || 0 == m_output[dst_pixel+3])
                        {
                            Buffer.BlockCopy (overlay.Data, src_pixel, m_output, dst_pixel, pixel_size);
                        }
                        else
                        {
                            m_output[dst_pixel+0] = (byte)((overlay.Data[src_pixel+0] * src_alpha
                                                     + m_output[dst_pixel+0] * (0xFF - src_alpha)) / 0xFF);
                            m_output[dst_pixel+1] = (byte)((overlay.Data[src_pixel+1] * src_alpha
                                                     + m_output[dst_pixel+1] * (0xFF - src_alpha)) / 0xFF);
                            m_output[dst_pixel+2] = (byte)((overlay.Data[src_pixel+2] * src_alpha
                                                     + m_output[dst_pixel+2] * (0xFF - src_alpha)) / 0xFF);
                            m_output[dst_pixel+3] = (byte)Math.Max (src_alpha, m_output[dst_pixel+3]);
                        }
                    }
                }
                dst += Info.Stride;
                ov  += overlay.Info.Stride;
            }
        }
Пример #8
0
        public void ApplyMask(IarImage mask)
        {
            int pixel_size = Info.Stride / (int)Info.Width;
            if (pixel_size < 4 || mask.Info.BPP != 8)
                return;
            var self = new Rectangle (-Info.OffsetX, -Info.OffsetY, (int)Info.Width, (int)Info.Height);
            var mask_region = new Rectangle (-mask.Info.OffsetX, -mask.Info.OffsetY,
                                             (int)mask.Info.Width, (int)mask.Info.Height);
            var masked = Rectangle.Intersect (self, mask_region);
            if (masked.IsEmpty)
                return;
            mask_region.X = masked.Left - mask_region.Left;
            mask_region.Y = masked.Top - mask_region.Top;
            mask_region.Width = masked.Width;
            mask_region.Height= masked.Height;
            if (mask_region.Width <= 0 || mask_region.Height <= 0)
                return;

            int x = masked.Left - self.Left;
            int y = masked.Top - self.Top;
            int dst = y * Info.Stride + x * pixel_size;
            int src = mask_region.Top * mask.Info.Stride + mask_region.Left;
            for (int row = 0; row < mask_region.Height; ++row)
            {
                int dst_pixel = dst+3;
                for (int col = 0; col < mask_region.Width; ++col)
                {
                    m_output[dst_pixel] = mask.Data[src+col];
                    dst_pixel += pixel_size;
                }
                dst += Info.Stride;
                src += mask.Info.Stride;
            }
        }
Пример #9
0
        IarImage CombineLayers(IarImage layers, IarArchive iarc)
        {
            layers.Info.Stride = (int)layers.Info.Width * 4;
            layers.Info.BPP = 32;
            var pixels = new byte[layers.Info.Stride * (int)layers.Info.Height];
            var output = new IarImage (layers.Info, pixels);
            using (var mem = new MemoryStream (layers.Data))
            using (var input = new BinaryReader (mem))
            {
                int offset_x = 0, offset_y = 0;
                var dir = (List<Entry>)iarc.Dir;
                while (input.BaseStream.Position < input.BaseStream.Length)
                {
                    int cmd = input.ReadByte();
                    switch (cmd)
                    {
                    case 0x21:
                        offset_x += input.ReadInt16();
                        offset_y += input.ReadInt16();
                        break;

                    case 0x00:
                    case 0x20:
                        {
                            int index = input.ReadInt32();
                            if (index < 0 || index >= dir.Count)
                                throw new InvalidFormatException ("Invalid image layer index");
                            var layer = new IarImage (iarc, dir[index]);
                            layer.Info.OffsetX -= offset_x;
                            layer.Info.OffsetY -= offset_y;
                            if (0x20 == cmd)
                                output.ApplyMask (layer);
                            else
                                output.Blend (layer);
                        }
                        break;

                    default:
                        Trace.WriteLine (string.Format ("Unknown layer type 0x{0:X2}", cmd), "IAR");
                        break;
                    }
                }
                return output;
            }
        }
Пример #10
0
        IarImage CombineImage(IarImage overlay, IarArchive iarc)
        {
            using (var mem = new MemoryStream (overlay.Data))
            using (var input = new BinaryReader (mem))
            {
                var dir = (List<Entry>)iarc.Dir;
                int base_index = input.ReadInt32();
                if (base_index >= dir.Count)
                    throw new InvalidFormatException ("Invalid base image index");
                int diff_y      = input.ReadInt32();
                int diff_count  = input.ReadInt32();

                var overlay_info = overlay.Info;
                var base_image = new IarImage (iarc, dir[base_index]);
                byte[] output = base_image.Data;
                if (overlay_info.Height != base_image.Info.Height || overlay_info.Stride != base_image.Info.Stride)
                {
                    int src_height = (int)Math.Min (overlay_info.Height, base_image.Info.Height);
                    int src_stride = Math.Min (overlay_info.Stride, base_image.Info.Stride);
                    byte[] src = base_image.Data;
                    output = new byte[overlay_info.Height * overlay_info.Stride];
                    int dst_pos = 0;
                    for (int y = 0; y < src_height; ++y)
                    {
                        Buffer.BlockCopy (src, y * base_image.Info.Stride, output, dst_pos, src_stride);
                        dst_pos += overlay_info.Stride;
                    }
                }
                int pixel_size = overlay_info.BPP / 8;
                int dst = diff_y * overlay_info.Stride;
                for (int i = 0; i < diff_count; ++i)
                {
                    int chunk_count = input.ReadUInt16();
                    int x = 0;
                    for (int j = 0; j < chunk_count; ++j)
                    {
                        int skip_count = pixel_size * input.ReadUInt16();
                        int copy_count = pixel_size * input.ReadUInt16();

                        x += skip_count;
                        input.Read (output, dst+x, copy_count);
                        x += copy_count;
                    }
                    dst += overlay_info.Stride;
                }
                return new IarImage (overlay_info, output, overlay.Palette);
            }
        }