コード例 #1
0
        private Point FindOuter(Bitmap bmp, int x, int y, int step = 1, int searchWidth = 20)
        {
            var delta = step < 0 ? -1 : 1;
            var max   = delta > 0 ? bmp.Width - x : x;

            if (searchWidth > max)
            {
                searchWidth = max;
            }

            int target;
            var rect = new Rectangle(0, y, bmp.Width, 1);

            using (var data = new LockData(bmp, rect))
            {
                target = Helper.Range(1, searchWidth, Math.Abs(step))
                         .Select(dx => x + delta * dx)
                         .Where(dx => data.IsBlackAt(dx))
                         .DefaultIfEmpty(-1)
                         .First();

                // if possible, move slightly to the left or right to get to the
                // middle of the frame
                while (data.IsBlackAt(target + delta))
                {
                    target += delta;
                }
            }

            return(new Point(target, y));
        }
コード例 #2
0
        private List <Point> FindBlackSquares(Bitmap bmp, IEnumerable <int> horizontal,
                                              IEnumerable <int> vertical, int size = 5)
        {
            var black = new List <Point>();
            var w     = bmp.Width;
            var h     = bmp.Height;

            using (var data = new LockData(bmp))
            {
                foreach (var y in vertical)
                {
                    foreach (var x in horizontal)
                    {
                        if (Helper.Range(-size, size).All(dx =>
                                                          Helper.Range(-size, size).All(dy =>
                                                                                        x + dx < w && x + dx >= 0 &&
                                                                                        y + dy < h && y + dy >= 0 &&
                                                                                        data.IsBlackAt(x + dx, y + dy)
                                                                                        )))
                        {
                            black.Add(new Point(x, y));
                            // since we move outwards from the cursor, we can safely
                            // break here without risking not to hit the actual item
                            // frame
                            break;
                        }
                    }
                }
            }

            return(black);
        }
コード例 #3
0
        // extracts the actual title from a title frame
        public static Bitmap ExtractItemTitle(Bitmap bmp)
        {
            // first, flood-fill the actual item frame to remove it
            using (var data = new LockData(bmp))
            {
                var w = data.Width;
                var h = data.Height;

                // we start at all border points to make sure we remove the
                // full border, and not just a part of it
                for (var x = 0; x < w; x++)
                {
                    TraverseFill(data, x, 0);
                    TraverseFill(data, x, h - 1);
                }

                for (var y = 0; y < h; y++)
                {
                    TraverseFill(data, 0, y);
                    TraverseFill(data, w - 1, y);
                }
            }

            // then, convert the image to grayscale and reduce the brightness
            // by 0.26 to get rid of the background color gradient
            var gray = ConvertToGrayscale(bmp);

            // we detect the name by simply looking for any non-black pixels
            // that are left after flood-filling the outer frame and removing
            // the name background
            // "inner" refers to the rectangle containing only the item name
            int innerTop, innerLeft, innerBottom, innerRight;

            using (var data = new LockData(gray))
            {
                var w = data.Width;
                var h = data.Height;

                innerTop    = Helper.Range(0, h - 1).First(y => !data.IsRowBlack(y));
                innerBottom = Helper.Range(h - 1, 0, -1).First(y => !data.IsRowBlack(y));

                innerLeft = Helper.Range(0, w - 1).First(x =>
                                                         !data.IsColumnBlack(x, innerTop, innerBottom));
                innerRight = Helper.Range(w - 1, 0, -1).First(x =>
                                                              !data.IsColumnBlack(x, innerTop, innerBottom));
            }

            var nameFrame = new Rectangle(innerLeft, innerTop,
                                          innerRight - innerLeft + 1, innerBottom - innerTop + 1);

            // and copy the name with font anti-aliasing
            return(CopyName(bmp, gray, nameFrame));
        }
コード例 #4
0
        // extracts the actual title from a title frame
        public static Bitmap ExtractItemTitle(Bitmap bmp)
        {
            // first, flood-fill the actual item frame to remove it
            using (var data = new LockData(bmp))
            {
                var w = data.Width;
                var h = data.Height;

                // we start at all border points to make sure we remove the
                // full border, and not just a part of it
                for (var x = 0; x < w; x++)
                {
                    TraverseFill(data, x, 0);
                    TraverseFill(data, x, h - 1);
                }

                for (var y = 0; y < h; y++)
                {
                    TraverseFill(data, 0, y);
                    TraverseFill(data, w - 1, y);
                }
            }

            // then, convert the image to grayscale and reduce the brightness
            // by 0.26 to get rid of the background color gradient
            var gray = ConvertToGrayscale(bmp);

            // we detect the name by simply looking for any non-black pixels
            // that are left after flood-filling the outer frame and removing
            // the name background
            // "inner" refers to the rectangle containing only the item name
            int innerTop, innerLeft, innerBottom, innerRight;
            using (var data = new LockData(gray))
            {
                var w = data.Width;
                var h = data.Height;

                innerTop = Helper.Range(0, h - 1).First(y => !data.IsRowBlack(y));
                innerBottom = Helper.Range(h - 1, 0, -1).First(y => !data.IsRowBlack(y));

                innerLeft = Helper.Range(0, w - 1).First(x =>
                    !data.IsColumnBlack(x, innerTop, innerBottom));
                innerRight = Helper.Range(w - 1, 0, -1).First(x =>
                    !data.IsColumnBlack(x, innerTop, innerBottom));
            }

            var nameFrame = new Rectangle(innerLeft, innerTop,
                innerRight - innerLeft + 1, innerBottom - innerTop + 1);

            // and copy the name with font anti-aliasing
            return CopyName(bmp, gray, nameFrame);
        }
コード例 #5
0
        public static Bitmap ExtractTitleFrame(Bitmap bmp)
        {
            int left, right, top, bottom;

            using (var data = new LockData(bmp))
            {
                var b = data.Height - 1;
                // first, remove the black border to the left and right
                left = Helper.Range(0, data.Width - 1).First(x =>
                                                             !data.IsColumnBlack(x, 0, b, MaxSkip));
                // for the right border, we can't check from top to bottom because
                // linked items have a non-black [X] at the top right, so we only
                // check the bottom half
                right = Helper.Range(data.Width - 2, 0, -1).First(x =>
                                                                  !data.IsColumnBlack(x, data.Height / 2, b, MaxSkip)) + 1;

                // to separate the title from the actual item, simplify move down
                // from the first non-black row until everything is black again.
                // we don't check the full width to work around the [X] on linked
                // items again. additionally, we skip a few pixels to the left,
                // as there's sometimes some semi-black border left
                top = Helper.Range(0, b).First(y =>
                                               data.IsRowNonBlack(y, left + 2, data.Width / 2)) - 1;

                // this is the first black row below the title, so the the title
                // height is given as bottom - top, not bottom - top + 1
                bottom = Helper.Range(top + 1, b).First(y =>
                                                        data.IsRowBlack(y, left, right));

                // remove any left-over semi-black border columns
                left = Helper.Range(left, data.Width - 1).First(x =>
                                                                data.IsColumnNonBlack(x, top + 1, bottom - 1));
                right = Helper.Range(right, 0, -1).First(x =>
                                                         data.IsColumnNonBlack(x, top + 1, bottom - 1)) + 1;
            }

            var width  = right - left;
            var height = bottom - top;

            var targetFrame = new Rectangle(left, top, width, height);

            var title = new Bitmap(width, height, PixelFormat.Format24bppRgb);

            using (Graphics g = Graphics.FromImage(title))
            {
                g.DrawImage(bmp, new Rectangle(0, 0, width, height), targetFrame,
                            GraphicsUnit.Pixel);
            }

            return(title);
        }
コード例 #6
0
        private Rectangle SelectFrame(Bitmap bmp, Point p)
        {
            var skip = 0;

            var top    = 0;
            var bottom = 0;

            var rect = new Rectangle(p.X, 0, 1, bmp.Height);

            using (var data = new LockData(bmp, rect))
            {
                if (!data.IsBlackAt(0, p.Y))
                {
                    return(new Rectangle());
                }

                top = Helper.Range(p.Y, 0, -1)
                      .TakeWhile(y => data.IsBlackAt(0, y) ||
                                 skip++ < MaxSkip)
                      .Last(y => data.IsBlackAt(0, y));

                skip   = 0;
                bottom = Helper.Range(p.Y, bmp.Height - 1)
                         .TakeWhile(y => data.IsBlackAt(0, y) ||
                                    skip++ < MaxSkip)
                         .Last(y => data.IsBlackAt(0, y));
            }

            var border = FindBorder(bmp, new Point(p.X, bottom));
            var left   = border.Left;

            // verify the left border is indeed black
            var leftRect = new Rectangle(left, 0, 1, bmp.Height);

            using (var data = new LockData(bmp, leftRect))
            {
                if (!data.IsColumnBlack(0, top, bottom, MaxSkip))
                {
                    return(new Rectangle());
                }
            }

            return(new Rectangle(left, top, border.Width, bottom - top + 1));
        }
コード例 #7
0
        unsafe private static Bitmap CopyName(Bitmap source, Bitmap mapper, Rectangle srcRect)
        {
            var w    = srcRect.Width;
            var h    = srcRect.Height;
            var name = new Bitmap(w, h, source.PixelFormat);

            var destRect = new Rectangle(0, 0, w, h);

            using (var dest = new LockData(name, destRect, ImageLockMode.ReadWrite))
                using (var src = new LockData(source, srcRect))
                    using (var map = new LockData(mapper, srcRect))
                    {
                        for (var x = 0; x < w; x++)
                        {
                            for (var y = 0; y < h; y++)
                            {
                                if (map.IsBlackAt(x, y))
                                {
                                    continue;
                                }

                                // copy the matching and all neighboring pixels to get
                                // some kind of font anti-aliasing
                                var points = from dx in Helper.Range(-1, 1)
                                             from dy in Helper.Range(-1, 1)
                                             let fy                   = y + dy
                                                               let fx = x + dx
                                                                        where fy >= 0 && fy < h && fx >= 0 && fx < w
                                                                        select new { dx, dy };

                                foreach (var d in points)
                                {
                                    var dx = x + d.dx;
                                    var dy = y + d.dy;
                                    dest[dx, dy] = src[dx, dy];
                                }
                            }
                        }
                    }

            return(name);
        }
コード例 #8
0
        unsafe private static void TraverseFill(LockData data, int x, int y)
        {
            if (x < 0 || x >= data.Width)
            {
                return;
            }
            if (y < 0 || y >= data.Height)
            {
                return;
            }
            if (data.IsBlackAt(x, y))
            {
                return;
            }

            data.SetBlack(x, y);

            TraverseFill(data, x - 1, y);
            TraverseFill(data, x + 1, y);
            TraverseFill(data, x, y - 1);
            TraverseFill(data, x, y + 1);
        }
コード例 #9
0
        private Rectangle FindBorder(Bitmap bmp, Point p)
        {
            int left, right;
            var rect = new Rectangle(0, p.Y, bmp.Width, 1);

            using (var data = new LockData(bmp, rect))
            {
                if (!data.IsBlackAt(p.X))
                {
                    return(new Rectangle());
                }

                left = Helper.Range(p.X, 0, -1)
                       .TakeWhile(x => data.IsBlackAt(x))
                       .Last();

                right = Helper.Range(p.X, bmp.Width - 1)
                        .TakeWhile(x => data.IsBlackAt(x))
                        .Last();
            }

            return(new Rectangle(left, p.Y, right - left + 1, 0));
        }
コード例 #10
0
        private Point FindOuter(Bitmap bmp, int x, int y, int step = 1, int searchWidth = 20)
        {
            var delta = step < 0 ? -1 : 1;
            var max = delta > 0 ? bmp.Width - x : x;
            if (searchWidth > max) searchWidth = max;

            int target;
            var rect = new Rectangle(0, y, bmp.Width, 1);
            using (var data = new LockData(bmp, rect))
            {
                target = Helper.Range(1, searchWidth, Math.Abs(step))
                    .Select(dx => x + delta * dx)
                    .Where(dx => data.IsBlackAt(dx))
                    .DefaultIfEmpty(-1)
                    .First();

                // if possible, move slightly to the left or right to get to the
                // middle of the frame
                while (data.IsBlackAt(target + delta))
                    target += delta;
            }

            return new Point(target, y);
        }
コード例 #11
0
        private Rectangle SelectFrame(Bitmap bmp, Point p)
        {
            var skip = 0;

            var top = 0;
            var bottom = 0;

            var rect = new Rectangle(p.X, 0, 1, bmp.Height);
            using (var data = new LockData(bmp, rect))
            {
                if (!data.IsBlackAt(0, p.Y)) return new Rectangle();

                top = Helper.Range(p.Y, 0, -1)
                        .TakeWhile(y => data.IsBlackAt(0, y) ||
                            skip++ < MaxSkip)
                        .Last(y => data.IsBlackAt(0, y));

                skip = 0;
                bottom = Helper.Range(p.Y, bmp.Height - 1)
                        .TakeWhile(y => data.IsBlackAt(0, y) ||
                            skip++ < MaxSkip)
                        .Last(y => data.IsBlackAt(0, y));
            }

            var border = FindBorder(bmp, new Point(p.X, bottom));
            var left = border.Left;

            // verify the left border is indeed black
            var leftRect = new Rectangle(left, 0, 1, bmp.Height);
            using (var data = new LockData(bmp, leftRect))
            {
                if (!data.IsColumnBlack(0, top, bottom, MaxSkip))
                    return new Rectangle();
            }

            return new Rectangle(left, top, border.Width, bottom - top + 1);
        }
コード例 #12
0
        private Rectangle FindBorder(Bitmap bmp, Point p)
        {
            int left, right;
            var rect = new Rectangle(0, p.Y, bmp.Width, 1);
            using (var data = new LockData(bmp, rect))
            {
                if (!data.IsBlackAt(p.X)) return new Rectangle();

                left = Helper.Range(p.X, 0, -1)
                    .TakeWhile(x => data.IsBlackAt(x))
                    .Last();

                right = Helper.Range(p.X, bmp.Width - 1)
                    .TakeWhile(x => data.IsBlackAt(x))
                    .Last();
            }

            return new Rectangle(left, p.Y, right - left + 1, 0);
        }
コード例 #13
0
        private List<Point> FindBlackSquares(Bitmap bmp, IEnumerable<int> horizontal,
            IEnumerable<int> vertical, int size = 5)
        {
            var black = new List<Point>();
            var w = bmp.Width;
            var h = bmp.Height;

            using (var data = new LockData(bmp))
            {
                foreach (var y in vertical)
                {
                    foreach (var x in horizontal)
                    {
                        if (Helper.Range(-size, size).All(dx =>
                            Helper.Range(-size, size).All(dy =>
                                x + dx < w && x + dx >= 0 &&
                                y + dy < h && y + dy >= 0 &&
                                data.IsBlackAt(x + dx, y + dy)
                            )))
                        {
                            black.Add(new Point(x, y));
                            // since we move outwards from the cursor, we can safely
                            // break here without risking not to hit the actual item
                            // frame
                            break;
                        }
                    }
                }
            }

            return black;
        }
コード例 #14
0
        private static unsafe void TraverseFill(LockData data, int x, int y)
        {
            if (x < 0 || x >= data.Width) return;
            if (y < 0 || y >= data.Height) return;
            if (data.IsBlackAt(x, y)) return;

            data.SetBlack(x, y);

            TraverseFill(data, x - 1, y);
            TraverseFill(data, x + 1, y);
            TraverseFill(data, x, y - 1);
            TraverseFill(data, x, y + 1);
        }
コード例 #15
0
        private static unsafe Bitmap CopyName(Bitmap source, Bitmap mapper, Rectangle srcRect)
        {
            var w = srcRect.Width;
            var h = srcRect.Height;
            var name = new Bitmap(w, h, source.PixelFormat);

            var destRect = new Rectangle(0, 0, w, h);

            using (var dest = new LockData(name, destRect, ImageLockMode.ReadWrite))
            using (var src = new LockData(source, srcRect))
            using (var map = new LockData(mapper, srcRect))
            {
                for (var x = 0; x < w; x++)
                {
                    for (var y = 0; y < h; y++)
                    {
                        if (map.IsBlackAt(x, y))
                            continue;

                        // copy the matching and all neighboring pixels to get
                        // some kind of font anti-aliasing
                        var points = from dx in Helper.Range(-1, 1)
                                        from dy in Helper.Range(-1, 1)
                                        let fy = y + dy
                                        let fx = x + dx
                                        where fy >= 0 && fy < h && fx >= 0 && fx < w
                                        select new { dx, dy };

                        foreach (var d in points)
                        {
                            var dx = x + d.dx;
                            var dy = y + d.dy;
                            dest[dx, dy] = src[dx, dy];
                        }
                    }
                }
            }

            return name;
        }
コード例 #16
0
        public static Bitmap ExtractTitleFrame(Bitmap bmp)
        {
            int left, right, top, bottom;
            using (var data = new LockData(bmp))
            {
                var b = data.Height - 1;
                // first, remove the black border to the left and right
                left = Helper.Range(0, data.Width - 1).First(x =>
                    !data.IsColumnBlack(x, 0, b, MaxSkip));
                // for the right border, we can't check from top to bottom because
                // linked items have a non-black [X] at the top right, so we only
                // check the bottom half
                right = Helper.Range(data.Width - 2, 0, -1).First(x =>
                    !data.IsColumnBlack(x, data.Height / 2, b, MaxSkip)) + 1;

                // to separate the title from the actual item, simplify move down
                // from the first non-black row until everything is black again.
                // we don't check the full width to work around the [X] on linked
                // items again. additionally, we skip a few pixels to the left,
                // as there's sometimes some semi-black border left
                top = Helper.Range(0, b).First(y =>
                    data.IsRowNonBlack(y, left + 2, data.Width / 2)) - 1;

                // this is the first black row below the title, so the the title
                // height is given as bottom - top, not bottom - top + 1
                bottom = Helper.Range(top + 1, b).First(y =>
                    data.IsRowBlack(y, left, right));

                // remove any left-over semi-black border columns
                left = Helper.Range(left, data.Width - 1).First(x =>
                    data.IsColumnNonBlack(x, top + 1, bottom - 1));
                right = Helper.Range(right, 0, -1).First(x =>
                    data.IsColumnNonBlack(x, top + 1, bottom - 1)) + 1;
            }

            var width = right - left;
            var height = bottom - top;

            var targetFrame = new Rectangle(left, top, width, height);

            var title = new Bitmap(width, height, PixelFormat.Format24bppRgb);
            using (Graphics g = Graphics.FromImage(title))
            {
                g.DrawImage(bmp, new Rectangle(0, 0, width, height), targetFrame,
                    GraphicsUnit.Pixel);
            }

            return title;
        }