简体   繁体   中英

Font size of graphics.DrawString on an image does not same with result image

I'm working on a task that draw a string on an image.
but the result image is not same with source code that I wrote down.

following image shows the font size difference.

。

red text is written in NanumSquare font 18px in window paint.
and the black text date below red text is also NanumSquare font 18px. It is written with C# source code.

following is my source code. 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);
    }
}

see comment 1 . I expect it draws exactly 18px font. but It does not.
I have also same problem on drawing qrcode with zxing.
without comment2 code I get a ~90 px qr code size. qrcodeSize

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;
}

with multiplying x 1.4 with its size, I can get similar result that I want.
why this difference has occured?
size of origin image is also 638px * 1010px. following image is origin image.

原始图片

thank you for reading. and I apologize my poor English skill.

Edit

following source is executable with Console .net framework.
I retry with this source code but the result was same. :( ...
following source code is full source code. you need png file that named "webPrint_back.png". and size 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;
        }

    }
}

I found the factor that makes font size is smaller than I expected.
First, source code that I posted works bad with PNG File with "24 bit depth"(without transparent background).
but PNG file with "32 bit depth"(with transparent background), Fontsize works well.
I don't know why It happened.

Second, the barcode made with zxing.net nuget. internally has padding with its border. the problem is that padding size depends on string length. longer string length makes more smaller barcode size and more bigger padding.

following source is my solution for barcode 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);

I solved my problem with engineering way, but I hope someone solve this problem with theoretical way. so I remain this question unsolved.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM