首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在c#中放大条形码图像的最佳无损方式是什么?

在c#中放大条形码图像的最佳无损方式是什么?
EN

Stack Overflow用户
提问于 2022-02-09 19:13:02
回答 3查看 165关注 0票数 2

这些年来,我多次遇到这个问题,我仍然希望有一种简单的方法可以做到这一点,而我已经错过了。我经常用条形码。它们通常是由白色背景上的黑点或线条组成的。条形码阅读器通常工作更快和更准确,当边缘是脆,然后大小的线条或点是精确的。

大多数条形码生成算法将给你一个紧凑的条形码,通常最小的元素大小是一个像素。一个典型的QR代码可以适用于21×21网格。如果在大多数打印机上打印像素到像素,这将太小,并且通常会被放大。放大的结果取决于所使用的方法,虽然有时您有选择,但通常没有使图像合适的选项。即使是直接打印,也常常会给你希望的灰色工艺品或抖动的形式。我发现最一致的方法是在其他地方(如Microsoft、lightburn和其他几个仍然让我头疼的地方)使用图片之前进行缩放。

下面我将介绍我尝试过的,并展示结果。我把它限制在位图上,只是因为在这里使用向量不是我当前项目所需要的东西。

我目前最好的分辨率不是很好,它是缓慢的,虽然我可以通过锁定位图中的位来提高速度,但我希望有人有一个非常简单的答案,这一次我在我的搜索中完全错过了。

下面是GIMP中一个简单的QR代码的图片。

问题是,如果它被放大了,它最终会看起来像这样:

下面,我创建了一个小测试程序,通过我所知道的所有不同的模式,然后生成一个图像矩阵,我已经在下面复制。我目前使用的版本是模式99,它涉及检查每个像素并绘制一个正方形。

有人有更好的主意吗?

代码语言:javascript
复制
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media.Imaging;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;

namespace PSWpfCommon.Images
{
    public partial class WPFImageHelper
    {

        public class Test
        {
            public int smode = 0;
            public int imode = 0;
            public int mode = 0;
            public string title = "";
            public Test(int s, int i, int m, string t)
            {
                smode = s;
                imode = i;
                mode = m;
                title = t;
            }
        }

        public static Bitmap TestImage()
        {
            byte[] img =
             {
           0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44,
           0x52, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x15, 0x08, 0x06, 0x00, 0x00, 0x00, 0xA9,
           0x17, 0xA5, 0x96, 0x00, 0x00, 0x00, 0xCF, 0x49, 0x44, 0x41, 0x54, 0x38, 0xCB, 0x9D, 0x54,
           0x5B, 0x0E, 0xC3, 0x30, 0x08, 0xB3, 0xAB, 0xDC, 0xFF, 0xCA, 0xDE, 0xC7, 0xD4, 0x88, 0x7A,
           0x3C, 0xD2, 0x21, 0x55, 0xAD, 0x48, 0xA0, 0xC6, 0x80, 0x09, 0x40, 0x28, 0x4C, 0x12, 0x48,
           0xEE, 0x6F, 0x00, 0x20, 0xF9, 0xF0, 0x67, 0xB6, 0x62, 0x40, 0xB4, 0x98, 0xAC, 0x4A, 0x50,
           0xC5, 0x2D, 0x4F, 0xE2, 0x97, 0x23, 0xB2, 0xEE, 0xE7, 0x31, 0xEE, 0xC2, 0xA1, 0x75, 0x89,
           0xD3, 0xF2, 0x27, 0x73, 0x5E, 0x8F, 0x93, 0x56, 0x01, 0x53, 0xA2, 0xEC, 0x7C, 0x39, 0x2F,
           0x19, 0xCA, 0x58, 0x7A, 0xA4, 0xA0, 0x8A, 0xA3, 0x0E, 0x6A, 0x7A, 0x5B, 0xFE, 0x45, 0x12,
           0xF1, 0xF1, 0x44, 0x59, 0x73, 0xFC, 0x5E, 0x8C, 0x25, 0xF9, 0xED, 0xBE, 0xA4, 0x47, 0x49,
           0xDD, 0x18, 0x79, 0xF9, 0x25, 0xA7, 0xD9, 0xA6, 0x74, 0xE3, 0xE3, 0x48, 0x9D, 0xE3, 0x55,
           0xA1, 0x98, 0xB8, 0xCC, 0x16, 0xE4, 0xF6, 0x5F, 0xBE, 0xDF, 0x8E, 0x74, 0x42, 0x9F, 0x4D,
           0xC0, 0x0F, 0xA7, 0xFE, 0x76, 0x14, 0x5D, 0x65, 0xDB, 0x3F, 0xA9, 0x54, 0xC7, 0x9D, 0x8B,
           0xCD, 0x7D, 0x3E, 0xAA, 0xD4, 0x24, 0x77, 0x99, 0x7F, 0x54, 0xA9, 0xAA, 0x69, 0x7E, 0x3F,
           0xCE, 0xEA, 0xFA, 0x67, 0x9B, 0x3A, 0x2A, 0x24, 0x9D, 0x49, 0x9F, 0x23, 0x99, 0x64, 0x71,
           0x9D, 0xA8, 0x51, 0xC5, 0x6F, 0x36, 0x21, 0x5B, 0xF9, 0x3B, 0x95, 0xAA, 0x1A, 0x52, 0xAD,
           0xB1, 0x24, 0x7C, 0x00, 0x22, 0x8E, 0xDE, 0x4C, 0xC4, 0x8F, 0x11, 0x7F, 0x00, 0x00, 0x00,
           0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82,
             };

            Bitmap qr;
            using (var ms = new MemoryStream(img))
            {
                qr = new Bitmap(ms);
            }

            int factor = 4;

            var l = new List<Test>();
            for (int i = 0; i <= 7; i++)
                for (int s = 0; s <= 4; s++)
                    l.Add(new Test(s, i, 0, $"s={s} i={i}"));

            l.Add(new Test(2, 8, 99, $"Mode 99"));


            Bitmap fullimage = new Bitmap(((qr.Width * factor) + 20) * 5, ((qr.Height * factor) + 20) * 9);


            fullimage.SetResolution(72, 72);
            var font = new Font("Arial", 10);

            using (var grPhoto = Graphics.FromImage(fullimage))
            using (var blackbrush = new SolidBrush(System.Drawing.Color.Black))
            using (var whitebrush = new SolidBrush(System.Drawing.Color.White))
            {
                grPhoto.InterpolationMode = InterpolationMode.High;

                grPhoto.FillRectangle(whitebrush, 0, 0, fullimage.Width, fullimage.Height);

                foreach (var t in l)
                {
                    var newqr = GrowImage(qr, factor: 4, mode: t.mode, imode: t.imode, smode: t.smode);

                    grPhoto.DrawImage(newqr,
                        t.smode * ((qr.Width * factor) + 20),
                        t.imode * ((qr.Height * factor) + 20));
                    grPhoto.DrawString(t.title, font, blackbrush,
                        t.smode * ((qr.Width * factor) + 20),
                        (t.imode + 1) * ((qr.Height * factor) + 20) - 20);

                }
            }

            fullimage.Save(@"c:\temp\newqr.png", ImageFormat.Png);

            return null;
        }

        public static Bitmap GrowImage(Bitmap im, int factor = 4, int mode = 1, int imode = 0, int smode = 0, int border = 2)
        {
            bool translate = true;

            var bmPhoto = new Bitmap(im.Width * factor + 2 * border, im.Height * factor + border * 2, PixelFormat.Format24bppRgb);

            bmPhoto.SetResolution(72, 72);

            using (var grPhoto = Graphics.FromImage(bmPhoto))
            using (var blackbrush = new SolidBrush(System.Drawing.Color.Black))
            using (var whitebrush = new SolidBrush(System.Drawing.Color.White))
            {
                grPhoto.FillRectangle(whitebrush, 0, 0, bmPhoto.Width, bmPhoto.Height);

                switch (smode)
                {
                    case 0:
                        grPhoto.SmoothingMode = SmoothingMode.Default;
                        break;
                    case 1:
                        grPhoto.SmoothingMode = SmoothingMode.AntiAlias;
                        break;
                    case 2:
                        grPhoto.SmoothingMode = SmoothingMode.HighQuality;
                        break;
                    case 3:
                        grPhoto.SmoothingMode = SmoothingMode.HighSpeed;
                        break;
                    case 4:
                        grPhoto.SmoothingMode = SmoothingMode.None;
                        break;
                    default:
                        break;
                }
                switch (imode)
                {
                    case 0:
                        grPhoto.InterpolationMode = InterpolationMode.Default;
                        break;
                    case 1:
                        grPhoto.InterpolationMode = InterpolationMode.Bicubic;
                        break;
                    case 2:
                        grPhoto.InterpolationMode = InterpolationMode.Bilinear;
                        break;
                    case 3:
                        grPhoto.InterpolationMode = InterpolationMode.High;
                        break;
                    case 4:
                        grPhoto.InterpolationMode = InterpolationMode.HighQualityBicubic;
                        break;
                    case 5:
                        grPhoto.InterpolationMode = InterpolationMode.HighQualityBilinear;
                        break;
                    case 6:
                        grPhoto.InterpolationMode = InterpolationMode.Low;
                        break;
                    case 7:
                        grPhoto.InterpolationMode = InterpolationMode.NearestNeighbor;
                        break;
                    default:
                        break;
                }

                switch (mode)
                {
                    case 99:
                        // These are what worked best for me...
                        grPhoto.SmoothingMode = SmoothingMode.None;
                        grPhoto.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor;


                        for (int x = 0; x < im.Width; x++)
                            for (int y = 0; y < im.Height; y++)
                            {
                                var g = im.GetPixel(x, y);
                                if (g.R < 120 && g.B < 120) // Just being really lazy here... if the pixel has not much blue and not much red I'll treat it as black
                                {
                                    grPhoto.FillRectangle(blackbrush, border + factor * x, border + factor * y, factor, factor);

                                }
                            }
                        translate = false;
                        break;
                    default:
                        break;
                }

                if (translate) // If we used mode 99, don't draw the image
                    grPhoto.DrawImage(im, new System.Drawing.Rectangle(border, border, im.Width * factor, im.Height * factor), 0, 0, im.Width, im.Height, System.Drawing.GraphicsUnit.Pixel);
            }

            return bmPhoto;
        }
    }
}

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2022-02-09 21:20:53

这就是我如何用Bitmap和最近邻抽样一次调整一个DrawImage的大小。

在您的示例中,我准备了原始位图,每个逻辑点对应于模式的几何尺寸(例如,在21×21),然后使用下面提供的代码使用Interpolationmode.NearestNeighbor抽样将该位图调整为可打印/可显示的输出格式。

设置PixelOffsetMode.HighQuality很重要。(除非您想将坐标调整为-0.5f,-0.5f,这太烦人了,所以不要麻烦)。

代码语言:javascript
复制
public static Bitmap Resize(this Bitmap oldBitmap, int newWidth, int newHeight)
{
    Bitmap newBitmap = new Bitmap(newWidth, newHeight, oldBitmap.PixelFormat);
    using (Graphics g = Graphics.FromImage(newBitmap)) {
        RectangleF dst = new RectangleF(0, 0, newWidth, newHeight);
        RectangleF src = new RectangleF(0, 0, oldBitmap.Width, oldBitmap.Height);
        g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor;
        g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;
        g.DrawImage(oldBitmap, dst, src, GraphicsUnit.Pixel);
    }
    return newBitmap;
}
票数 1
EN

Stack Overflow用户

发布于 2022-02-09 19:27:56

您可以使用像ImageTracer.NET这样的库将图像转换为矢量图像,然后它将按照您的需要进行缩放:

https://github.com/MiYanni/ImageTracer.NET

票数 1
EN

Stack Overflow用户

发布于 2022-02-09 20:18:39

首先,我觉得奇怪的是,您的生成器不允许您指定单元格大小/模数。再检查一下手册。

要从单个像素单元格/模数中获取所需的内容,可以使用任何大小为原始图像的精确倍数的图像放大函数,使用最近的邻居重采样规则,而不使用其他方法。

如果找不到这样的函数,那么编写一个复制图像的函数,同时将每个像素复制为NxN正方形(在锁位下)是一件很容易的事情。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71055395

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档