【问题标题】:Font size of graphics.DrawString on an image does not same with result image图像上 graphics.DrawString 的字体大小与结果图像不同
【发布时间】:2019-12-30 07:02:53
【问题描述】:

我正在处理在图像上绘制字符串的任务。
但结果图像与我写下的源代码不同。

下图显示字体大小差异。

红色文字以NanumSquare字体18px在窗口油漆中书写。
红色文字下方的黑色文字date也是NanumSquare字体18px。它是用 C# 源代码编写的。

以下是我的源代码。 C#。

static void Main(string[] args)
{
    DrawTextToImageSave("webPrint_back.png");
}
public static void DrawTextToImageSave(string path)
{
    //png to bitmap
    Image Dummy = Image.FromFile(path);
    using (Bitmap bitmap = (Bitmap)Dummy)
    {//load the image file


        using (Graphics graphics = Graphics.FromImage(bitmap))
        {

            graphics.TextRenderingHint = TextRenderingHint.AntiAliasGridFit;

            var titleFont = new Font("NanumSquareOTF ExtraBold", 25);
            var bodyFont = new Font("NanumSquareOTF Regular", 25);
            graphics.DrawString("DATE", titleFont, System.Drawing.Brushes.Black, new PointF(401.5f, 863.5f)); //comment 1
            graphics.DrawString(DateTime.Now.ToString("yyyy.MM.dd"), bodyFont, System.Drawing.Brushes.Black, new PointF(345, 885f));

            graphics.DrawString("LOCATION", titleFont, System.Drawing.Brushes.Black, new PointF(344, 919.5f));
            graphics.DrawString(System.DateTime.Now.ToString("yyyyMMddHHmmss") , bodyFont, System.Drawing.Brushes.Black, new PointF(267f, 946f));

            WriteableBitmap bitmapimg = Generator128Code("STACKOVERFLOW", 110, 110);
            bitmapimg = resize_image(bitmapimg, 1.4); //comment 2

            var stream = new MemoryStream();

            var encoder = new JpegBitmapEncoder();
            encoder.Frames.Add(BitmapFrame.Create(bitmapimg));
            encoder.Save(stream);

            byte[] buffer = stream.GetBuffer();
            var qrBitmap = new System.Drawing.Bitmap(new MemoryStream(buffer));

            graphics.DrawImage(qrBitmap, 485f, 855f);
        }

        bitmap.Save( "output_WebPrintBack.png", ImageFormat.Png);
    }
}

参见评论 1。我预计它会准确地绘制 18px 字体。但事实并非如此。
我在用 zxing 绘制 qrcode 时也遇到了同样的问题。
如果没有 comment2 代码,我会得到 ~90 px 二维码大小。

public static WriteableBitmap Generator128Code(string contents, int width, int height)
{
    if (string.IsNullOrEmpty(contents))
    {
        return null;
    }

    EncodingOptions options = null;
    BarcodeWriter writer = null;
    options = new QrCodeEncodingOptions
    {
        CharacterSet = "UTF-8",
        Width = width,
        Height = height,
        ErrorCorrection = ErrorCorrectionLevel.H,
        Margin = 0
    };
    writer = new BarcodeWriter
    {
        Format = BarcodeFormat.QR_CODE,
        Options = options
    };

    WriteableBitmap bitmap = writer.Write(contents);

    return bitmap;
}

static WriteableBitmap resize_image(WriteableBitmap img, double scale)
{
    BitmapSource source = img;

    var s = new ScaleTransform(scale, scale);

    var res = new TransformedBitmap(img, s);

    return convert_BitmapSource_to_WriteableBitmap(res);
}

static WriteableBitmap  convert_BitmapSource_to_WriteableBitmap(BitmapSource source)
{
    // Calculate stride of source
    int stride = source.PixelWidth * (source.Format.BitsPerPixel / 8);

    // Create data array to hold source pixel data
    byte[] data = new byte[stride * source.PixelHeight];

    // Copy source image pixels to the data array
    source.CopyPixels(data, stride, 0);

    // Create WriteableBitmap to copy the pixel data to.      
    WriteableBitmap target = new WriteableBitmap(source.PixelWidth
        , source.PixelHeight, source.DpiX, source.DpiY
        , source.Format, null);

    // Write the pixel data to the WriteableBitmap.
    target.WritePixels(new Int32Rect(0, 0
        , source.PixelWidth, source.PixelHeight)
        , data, stride, 0);

    return target;
}

将 x 1.4 乘以它的大小,我可以得到我想要的类似结果。
为什么会出现这种差异?
原始图像的大小也是 638px * 1010px。下图是原图。

感谢您的阅读。我为我糟糕的英语水平道歉。

编辑

以下源代码可通过 Console .net 框架执行。
我用这个源代码重试,但结果是一样的。 :( ...
以下源代码是完整的源代码。 您需要名为“webPrint_back.png”的 png 文件。和大小 638x1010 。 https://dummyimage.com/

using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Drawing.Text;
using System.IO;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using ZXing;
using ZXing.Common;
using ZXing.QrCode;
using ZXing.QrCode.Internal;
using BarcodeWriter = ZXing.Presentation.BarcodeWriter;

namespace bitmapTest
{
    class Program
    {
        static void Main(string[] args)
        {
            DrawTextToImageSave("webPrint_back.png");
        }
        public static void DrawTextToImageSave(string path)
        {
            //png to bitmap
            Image Dummy = Image.FromFile(path);
            using (Bitmap bitmap = (Bitmap)Dummy)
            {//load the image file


                using (Graphics graphics = Graphics.FromImage(bitmap))
                {

                    graphics.TextRenderingHint = TextRenderingHint.AntiAliasGridFit;

                    var titleFont = new Font("NanumSquareOTF ExtraBold", 18);
                    var bodyFont = new Font("NanumSquareOTF Regular", 18);
                    graphics.DrawString("DATE", titleFont, System.Drawing.Brushes.Black, new PointF(401.5f, 863.5f)); //comment 1
                    graphics.DrawString(DateTime.Now.ToString("yyyy.MM.dd"), bodyFont, System.Drawing.Brushes.Black, new PointF(345, 885f));

                    graphics.DrawString("LOCATION", titleFont, System.Drawing.Brushes.Black, new PointF(344, 919.5f));
                    graphics.DrawString(System.DateTime.Now.ToString("yyyyMMddHHmmss") , bodyFont, System.Drawing.Brushes.Black, new PointF(267f, 946f));

                    WriteableBitmap bitmapimg = Generator128Code("STACKOVERFLOW", 110, 110);
                    bitmapimg = resize_image(bitmapimg, 1.4); //comment 2

                    var stream = new MemoryStream();

                    var encoder = new JpegBitmapEncoder();
                    encoder.Frames.Add(BitmapFrame.Create(bitmapimg));
                    encoder.Save(stream);

                    byte[] buffer = stream.GetBuffer();
                    var qrBitmap = new System.Drawing.Bitmap(new MemoryStream(buffer));

                    graphics.DrawImage(qrBitmap, 485f, 855f);
                }

                bitmap.Save( "output_WebPrintBack.png", ImageFormat.Png);
            }
        }

        public static WriteableBitmap Generator128Code(string contents, int width, int height)
        {
            if (string.IsNullOrEmpty(contents))
            {
                return null;
            }

            EncodingOptions options = null;
            BarcodeWriter writer = null;
            options = new QrCodeEncodingOptions
            {
                CharacterSet = "UTF-8",
                Width = width,
                Height = height,
                ErrorCorrection = ErrorCorrectionLevel.H,
                Margin = 0
            };
            writer = new BarcodeWriter
            {
                Format = BarcodeFormat.QR_CODE,
                Options = options
            };

            WriteableBitmap bitmap = writer.Write(contents);

            return bitmap;
        }

        static WriteableBitmap resize_image(WriteableBitmap img, double scale)
        {
            BitmapSource source = img;

            var s = new ScaleTransform(scale, scale);

            var res = new TransformedBitmap(img, s);

            return convert_BitmapSource_to_WriteableBitmap(res);
        }

        static WriteableBitmap  convert_BitmapSource_to_WriteableBitmap(BitmapSource source)
        {
            // Calculate stride of source
            int stride = source.PixelWidth * (source.Format.BitsPerPixel / 8);

            // Create data array to hold source pixel data
            byte[] data = new byte[stride * source.PixelHeight];

            // Copy source image pixels to the data array
            source.CopyPixels(data, stride, 0);

            // Create WriteableBitmap to copy the pixel data to.      
            WriteableBitmap target = new WriteableBitmap(source.PixelWidth
                , source.PixelHeight, source.DpiX, source.DpiY
                , source.Format, null);

            // Write the pixel data to the WriteableBitmap.
            target.WritePixels(new Int32Rect(0, 0
                , source.PixelWidth, source.PixelHeight)
                , data, stride, 0);

            return target;
        }

    }
}

【问题讨论】:

  • 如果你能分享minimal reproducible example,那就太棒了。我无法按原样重现该问题,因为当我将您提供的代码复制并粘贴到控制台应用程序中时,它无法编译(例如,resize_image 缺失)。
  • @mjwills 谢谢,我编辑了我的帖子。我检查了一下,效果很好。但需要 png 文件“webPrint_back.png”

标签: c# wpf bitmap system.drawing


【解决方案1】:

我发现导致字体大小小于我预期的因素。
首先,我发布的源代码不适用于“24 位深度”(没有透明背景)的 PNG 文件。
但是具有“32 位深度”(具有透明背景)的 PNG 文件,Fontsize 效果很好。
我不知道为什么会发生。

第二,用zxing.net nuget制作的条码。内部有其边框的填充。问题是填充大小取决于字符串长度。更长的字符串长度使条形码尺寸更小,填充更大。

以下来源是我对条形码 zxing.net nuget 的解决方案

WriteableBitmap bitmapimg = Generator128Code(StaticCommon.localConfigModel.cardBack_QRText, 110, 110);

var stream = new MemoryStream();

var encoder = new JpegBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(bitmapimg));
encoder.Save(stream);

byte[] buffer = stream.GetBuffer();
var qrBitmap = new System.Drawing.Bitmap(new MemoryStream(buffer));

RectangleF recF = new RectangleF(new PointF(477f, 852f), new SizeF(130, 130));


//ZXING  PADDING value, padding size depends on QR encoded string length, so I divide with integer 30 and use remainder  
int len = StaticCommon.localConfigModel.cardBack_QRText.Length;
int pad = (int)len / 30;
if (len % 30 > 0) pad++;
RectangleF srecF = new RectangleF(pad * 6f, pad * 6f, 110f - pad * 12f, 110 - pad * 12f);

graphics.DrawImage(qrBitmap, recF, srecF, GraphicsUnit.Pixel);

我用工程方法解决了我的问题,但我希望有人用理论方法解决这个问题。所以我仍然没有解决这个问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-10-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-10
    相关资源
    最近更新 更多