- طول عکس خروجی نهایی 250 پیکسل است.
- فونت متن 10 پیکسل هست و عرض هر خط 17 پیکسل.
- حداکثر تعداد خطِ نمایش متن، 3 خط است و اگر متن برای نمایش، به 3 خط بیشتر نیاز داشت، اضافهی متن را به صورت 3 نقطه نمایش میدهیم (مثل عکس بالا).
- عرض بارکد 50 پیکسل است.
- فاصله بین بارکد و متن 5 پیکسل است.
public static class BarcodeHelper { public static string GenerateBarcodeWithText(string input, string textBelow) { // barcode: 50 pixels // margin: top 5 pixels // height of each text line is 17 pixels // text: maximum 3 lines // each 30 letters is: 1 line var eachLineHeight = 17; var eachLineLetters = 30; var maximumLines = 3; var maximumTextHeight = eachLineHeight * maximumLines; var resultWidth = 250; var barcodeHeight = 50; var textY = barcodeHeight + 5; // each 30 letters is: 1 line for example input length is 150 letters and for show 100 letters we need (150 / 30) 5 lines // each line is 17 pixels and text height will be (17 * 5) 102 pixels var textHeight = (textBelow.Length / eachLineLetters) * eachLineHeight; // if height of text be greater than (eachLineHeight * maximumLines) we use maximum text height (eachLineHeight * maximumLines) textHeight = textHeight > maximumTextHeight ? maximumTextHeight : textHeight; // if text height be less than 1 line we set 1 line height (17 pixels) to the text height // text height minimum is equal 1 linle (17 pixels) textHeight = textHeight < eachLineHeight ? eachLineHeight : textHeight; var resultHeight = textY + textHeight; } }
چون ما از Bitmap و Image استفاده میکنیم، پس به پکیچ System.Drawing.Common نیاز داریم:
<ItemGroup> <PackageReference Include="System.Drawing.Common" Version="6.0.0" /> </ItemGroup>
اولین کاری که انجام میدهیم، یک Bitmap را ایجاد میکنیم و بعد یک مستطیل را به اندازهی خود Bitmap ایجاد میکنیم و با کلاس Graphics، به نارنجی، رنگش میکنیم و داخل Bitmap میریزیم و در نهایت عکس ایجاد شده را در حافظهی رم ذخیره میکنیم.
- Bitmap فضایی را در اختیار ما قرار میدهد که داخلش هر چیزی را ترسیم کنیم.
- Graphics به ما کمک میکند که عملیات گرافیکی را نظیر رنگ آمیزی، ترسیم عکس و ... روی یک شیء انجام دهیم.
- MemoryStream برای ذخیره سازی موقت در حافظهی رم به کار میاد؛ عکس ایجاد شدهی تا این لحظه را که یک مستطیل نارنجی رنگ هست، در داخل رم ذخیره میکنیم.
#region MainBitmap var mainBitmap = new Bitmap(resultWidth, resultHeight); using var rectangleGraphics = Graphics.FromImage(mainBitmap); { var rectangle = new Rectangle(0, 0, resultWidth, resultHeight); rectangleGraphics.FillRectangle(Brushes.OrangeRed, rectangle); } using var rectangleStream = new MemoryStream(); { mainBitmap.Save(rectangleStream, ImageFormat.Png); } #endregion
خروجی تا این لحظه:
حالا باید بارکد را ایجاد کنیم و عکس خروجی بارکد را داخل این مستطیل بریزیم؛ برای اینکار از کتابخانه BarcodeLib استفاده میکنیم:
private static Bitmap GenerateBarcodeImage(string input, int width, int height) { var barcodeInstance = new Barcode(); var barcodeImage = barcodeInstance.Encode(BarcodeLib.TYPE.CODE39, input, Color.Black, Color.OrangeRed, width, height); using var barcodeStream = new MemoryStream(); { barcodeImage.Save(barcodeStream, ImageFormat.Png); } return (Bitmap)Image.FromStream(barcodeStream); }
و الان این عکس بارکد را داخل مستطیل اصلی میریزیم و هر دو را Merge میکنیم:
#region Barcode var barcodeImage = GenerateBarcodeImage(input, resultWidth, barcodeHeight); #endregion #region MergedRectangleAndBarcode var newMainBitmap = (Bitmap)Image.FromStream(rectangleStream); var newBarcodeBitmap = barcodeImage; using var newRectangleGraphics = Graphics.FromImage(newMainBitmap); { newRectangleGraphics.DrawImage(newBarcodeBitmap, 0, 0); } using var mergedRectangleAndBarcodeStream = new MemoryStream(); { newMainBitmap.Save(mergedRectangleAndBarcodeStream, ImageFormat.Png); } #endregion
خروجی تا این لحظه :
حالا باید 5 پیکسل از پایین بارکد فاصله بگیریم و متن را بنویسیم.
برای اینکار از یک مستطیل کمک میگیریم. یعنی یک مستطیل بدون هیچ رنگ و Border ـی را پایین این بارکد ایجاد میکنیم، چرا؟ دلیل این است که میخواهیم متنمان را به صورت وسط چین، از راست و چپ، و وسط از بالا و پایین قرار بدیم و برای اینکار میگیم این نسبت وسط چین بودن از راست و چپ، وسط بودن از بالا و پایین را از مستطیل پایین بارکد کمک بگیر، خلاصهاش میشود اینکه از مستطیلِ پایینِ بارکد برای وسط چین بودن متن از راست و چپ و وسط بودن از بالا و پایین استفاده میکنیم.
#region WriteText var barcodeBitmap = (Bitmap)Image.FromStream(mergedRectangleAndBarcodeStream); using var graphics = Graphics.FromImage(barcodeBitmap); { using var font = new Font("Tahoma", 10); { var rect = new Rectangle(0, textY, resultWidth, textHeight); var sf = new StringFormat(); sf.Alignment = StringAlignment.Center; sf.Trimming = StringTrimming.EllipsisCharacter; sf.FormatFlags = StringFormatFlags.DirectionRightToLeft; sf.LineAlignment = StringAlignment.Center; graphics.DrawString(textBelow, font, Brushes.Black, rect, sf); //graphics.DrawRectangle(Pens.Green, rect); } } using var finalStream = new MemoryStream(); { barcodeBitmap.Save(finalStream, ImageFormat.Png); } #endregion
graphics.DrawString میگوید textBelow را با font تاهوما و با رنگ سیاه، داخل rect (مستطیل) و با این تنظیماتِ متن بریز.
Alignment متن را وسط چین میکند (این وسط چین شدن نسبت به مستطیل پایین بارکد است که هیچ رنگ و Border ـی ندارد) .
LineAlignment متن را از بالا و پایین میارد وسط (این وسط شدن نسبت به مستطیل پایین بارکد است که هیچ رنگ و Border ـی ندارد).
EllipsisCharacter اگر متن طولانی باشد، اضافه متن را به صورت سه نقطه نمایش میدهد.
DirectionRightToLeft متن را RTL میکند.
خروجی نهایی:
عکس نهایی به صورت Stream ذخیره شدهاست، آنرا به فرمت Base64 تبدیل میکنیم و برگشت میزنیم.
return Convert.ToBase64String(finalStream.ToArray());
برای نمایش یک آرایه بایتی که به فرمت Base64 تبدیل شده، به این روش عمل میکنیم:
<img src="data:image/png;base64, @BarcodeHelper.GenerateBarcodeWithText("barcode text", "below text")" />
چون برای ایجاد بارکد از تایپ 39 استفاده کردهایم و تایپ 39 فقط حروف بزرگ انگلیسی را پشتیبانی میکند، پس برای اینکه دچار خطا نشویم، میتوانیم ابتدای متدمان، از این کد استفاده کنیم:
// Type 39 doesn't support lower case letters, for prevent exception, we convert all input letters to upper case // more details: https://www.dntips.ir/newsarchive/details/18019 input = input.ToUpperInvariant();
همچنین جهت تشخیص خودکار راست به چک بودن متن پایین بارکد، میتوان از متد ContainsFarsi در پکیج DNTPersianUtils.Core استفاده کرد:
if (textBelow.ContainsFarsi()) sf.FormatFlags = StringFormatFlags.DirectionRightToLeft;