اشتراک‌ها
HarfBuzz 10‌ منتشر شد
کتابخانه‌ی گرافیکی چندسکویی SkiaSharp، از «حرف‌باز» برای نمایش صحیح متون راست به چپ، کمک می‌گیرد. SkiaSharp در پشت صحنه از کتابخانه‌ی Skia استفاده می‌کند که موتور گرافیکی مرورگر کروم است.
HarfBuzz 10‌ منتشر شد
مطالب
فارسی نویسی با SkiaSharp
تا نگارش 4x دات نت که فقط از ویندوز پشتیبانی می‌کند، از وابستگی System.Drawing.Common برای انجام امور روزمره‌ی گرافیکی استفاده می‌شد؛ چون در پشت صحنه، محصور کننده‌ی امکانات بومی گرافیکی ویندوز است. همچنین از زمان ارائه‌ی دات نت Core چندسکویی، تا نگارش 5 دات نت، این وابستگی، در لینوکس، به کمک کتابخانه‌ی جانبی به نام libgdiplus پشتیبانی می‌شد که البته هیچگاه پشتیبانی رسمی را از طرف مایکروسافت پیدا نکرد؛ چون libgdiplus متشکل از چند ده‌هزار سطر کد نوشته شده‌ی به زبان C است که به‌خوبی آزمایش نشده و همچنین برای کارکرد کامل آن نیز به کتابخانه‌های جانبی دیگری مانند pango نیاز است تا برای مثال از نمایش متون فارسی پشتیبانی کند. Libgdiplus در حقیقت بازمانده‌ای از دوران Mono است که مایکروسافت در نگارش 6 دات نت، آن‌را منسوخ شده اعلام کرد و در نگارش 7 دات نت، دیگر از آن پشتیبانی نمی‌کند. یعنی تمام برنامه‌هایی که از وابستگی System.Drawing.Common استفاده می‌کنند، قابل انتقال به دات نت 7 چندسکویی نیستند؛ البته هنوز هم می‌توان از System.Drawing.Common در ویندوز، بدون مشکل استفاده کرد. اما در صورت استفاده‌، برنامه‌ی شما در لینوکس اجرا نخواهد شد و یک چنین برنامه‌هایی با استثناهای TypeInitializationException و PlatformNotSupportedException در زمان اجرا، خاتمه خواهند یافت.
در حال حاضر توصیه‌ی مایکروسافت ، عدم استفاده‌ی از System.Drawing.Common و جایگزینی آن با یکی از کتابخانه‌های زیر است:
- SkiaSharp
- Microsoft.Maui.Graphics

البته پیشتر در این لیست توصیه شده، کتابخانه‌ی SixLabors.ImageSharp.Drawing هم وجود داشت که به علت تغییر مجوز آن، به یک مجوز نیمه تجاری، نیمه سورس باز، از لیست فوق حذف شده‌است.


مشکل فارسی نویسی با SkiaSharp

اگر سعی کنیم با استفاده از مثال‌های متداول SkiaSharp، یک متن فارسی را نمایش دهیم، به خروجی زیر خواهیم رسید:
// crate a surface
var info = new SKImageInfo(256, 256);
using var surface = SKSurface.Create(info);
// the the canvas and properties
var canvas = surface.Canvas;

// make sure the canvas is blank
canvas.Clear(SKColors.White);

// draw some text
using var typeface = SKTypeface.FromFamilyName("Tahoma");
using var paint = new SKPaint
    {
      Color = SKColors.Black,
      IsAntialias = true,
      Style = SKPaintStyle.Fill,
      TextAlign = SKTextAlign.Center,
      TextSize = 24,
      Typeface = typeface,
    };
var coord = new SKPoint(info.Width / 2, (info.Height + paint.TextSize) / 2);
canvas.DrawText("آزمایش", coord, paint);

// save the file
using var image = surface.Snapshot();
using var data = image.Encode(SKEncodedImageFormat.Png, 100);
using var stream = File.OpenWrite("farsi-text-1.png");
data.SaveTo(stream);
قطعه کد فوق برای اجرا، نیاز به وابستگی زیر را دارد:
<ItemGroup>
   <PackageReference Include="SkiaSharp" Version="2.88.3" />
</ItemGroup>
که در آن، در ابتدا یک Canvas برای نقاشی ایجاد شده و سپس متنی بر روی آن نمایش داده می‌شود و در آخر این نتیجه را در یک فایل ذخیره می‌کنیم؛ با این خروجی:

همانطور که مشاهده می‌کنید، حروف فارسی در آن از هم جدا هستند و همچنین از چپ به راست نمایش داده شده‌است.


رفع مشکل فارسی نویسی با SkiaSharp

برای رفع مشکل فوق، نیاز است از افزونه‌ی «حرف باز» این کتابخانه استفاده کرد که روش نصب آن به صورت زیر است:
<ItemGroup>
   <PackageReference Include="SkiaSharp" Version="2.88.3" />
   <PackageReference Include="SkiaSharp.HarfBuzz" Version="2.88.3" />
</ItemGroup>
اینبار تنها تفاوت مورد نیاز جهت نمایش صحیح حروف فارسی، استفاده از SKShaper جهت شکل دادن به متن نهایی است و استفاده از متد DrawShapedText آن به صورت زیر:
// crate a surface
var info = new SKImageInfo(256, 256);
using var surface = SKSurface.Create(info);
// the the canvas and properties
var canvas = surface.Canvas;

// make sure the canvas is blank
canvas.Clear(SKColors.White);

// draw some text
using var typeface = SKTypeface.FromFamilyName("Tahoma");
using var shaper = new SKShaper(typeface);
using var paint = new SKPaint
  {
      Color = SKColors.Black,
      IsAntialias = true,
      Style = SKPaintStyle.Fill,
      TextAlign = SKTextAlign.Center,
      TextSize = 24,
      Typeface = typeface,
  };
var coord = new SKPoint(info.Width / 2, (info.Height + paint.TextSize) / 2);
canvas.DrawShapedText(shaper, "آزمایش", coord, paint);

// save the file
using var image = surface.Snapshot();
using var data = image.Encode(SKEncodedImageFormat.Png, 100);
using var stream = File.OpenWrite("farsi-text-2.png");
data.SaveTo(stream);
که خروجی صحیح زیر را تولید می‌کند:

اشتراک‌ها
پروژه PDFium
موتور رندر کردن PDF در مرورگر کروم است که اخیرا سورس باز شده.
پروژه PDFium
نظرات مطالب
تبدیل html به pdf با کیفیت بالا
نمونه‌ی دیگری هم که از موتور کروم برای تهیه‌ی PDF و Screenshot استفاده می‌کند، « puppeteer-sharp » است که معادل کتابخانه‌ی بسیار معروف و موفق « puppeteer » نودجی‌اس است.
نظرات مطالب
تبدیل html به pdf با کیفیت بالا
یک نکته‌ی تکمیلی:
پروژه‌ی wkhtmltopdf خاتمه یافته و دیگر نگهداری نمی‌شود. اگر به دنبال یک جایگزین با کیفیت برای آن هستید، مرورگر کروم، قابلیت تبدیل توکار HTML به PDF را دارد که بر این اساس کتابخانه‌ی ChromiumHtmlToPdf به‌وجود آمده و در پشت صحنه از همان موتور کروم برای تبدیل HTML به PDF با کیفیت بسیار بالا استفاده می‌کند. این کتابخانه همچنین قابلیت تهیه‌ی screenshot از صفحه‌ی وب را هم دارد.

یک نمونه مثال: تبدیل یک فایل HTML به PDF
using (var converter = new Converter())
{
   converter.ConvertToPdf(new ConvertUri(SourcePath),
                               "output.pdf",
                               new PageSettings(PaperFormat.A4)
                               {
                                   DisplayHeaderFooter = true,
                                   HeaderTemplate = header,
                                   FooterTemplate = footer,
                                   PrintBackground = true,
                               });
   converter.ConvertToImage(new ConvertUri(tempSourcePath),
                                 "output.png",
                                 new PageSettings(PaperFormat.A6));
}
در اینجا SourcePath به مسیر کامل فایل HTML اشاره می‌کند. مزیت این روش، خواندن خودکار فایل‌های css، js و تصاویر محلی ذکر شده‌ی در فایل HTML است. می‌شود بجای SourcePath، از خود محتوای رشته‌ای فایل HTML هم استفاده کرد. در این حالت باید css و js و غیره را Inline کنید و داخل فایل قرار دهید.
یک نمونه مثال از header و footer قابل استفاده‌ی در اینجا را هم مشاهده می‌کنید:
    var header = """
<div class="text center" style="color: lightgray;border-bottom: solid lightgray 0.1px; width: 100%; font-family: 'Samim'; font-size:7px;">
<span class="title"></span>
</div>
""";
    var footer = """
<div class="text center" style="color: lightgray; font-family: 'Samim'; font-size:7px;">
<span class="pageNumber"></span>/<span class="totalPages"></span>
</div>
""";
برای مثال ذکر 1/10 در پایین تمام صفحات (تعداد کل صفحات/شماره صفحه جاری) به صورت فوق است (در آدرس داده شده، برای مثال totalPages را جستجو کنید تا با روش تعریف این ثوابت ویژه آشنا شوید). متاسفانه مرورگر کروم در این دو قسمت header و footer، محدودیت‌های زیادی را اعمال می‌کند و فونت‌های سفارشی را فقط در صورت نصب در سیستم عامل می‌خواند و پردازش می‌کند و اگر می‌خواهید تصویری را در اینجا نمایش دهید، باید آن‌را base64 کرده و inline کنید.

روش استفاده‌ی از آن در برنامه‌های وب ASP.NET Core
می‌توانید ورودی HTML خود را به صورت زیر به آن داده و byte array نهایی را بدون نیاز به ذخیره سازی به صورت فایل، از یک اکشن متد، بازگشت دهید:
 var HTML = "<HTML code>";
 using (Converter converter = new Converter())
 using (MemoryStream stream = new MemoryStream())
 {
     // This is necessary when running on Docker
     converter.AddChromeArgument("--no-sandbox");

     // Create PDF out of HTML string
     converter.ConvertToPdf(html, stream, new ChromeHtmlToPdfLib.Settings.PageSettings());

     // Return file to user
     return File(stream.ToArray(), MediaTypeNames.Application.Pdf, "Report.pdf");
 }
اشتراک‌ها
اضافه شدن پشتیبانی از رندر زبان‌های راست به چپ به ImageSharp.Drawing

در دات نت 6، فضای نام و بسته‌ی System.Drawing.Common صرفا مختص به ویندوز شده و دیگر برای سایر سیستم عامل‌ها توسعه داده نمی‌شود. بجای آن، بسته‌های چندسکویی دیگری را توصیه کرده‌اند که مهم‌ترین مشکل آن‌ها، عدم امکان رندر متون راست به چپ، توسط آن‌ها است ... این پشتیبانی اخیرا به ImageSharp.Drawing اضافه شده‌است.

اضافه شدن پشتیبانی از رندر زبان‌های راست به چپ به ImageSharp.Drawing
مطالب
معرفی و راهنمایی جهت انتخاب پلتفرم‌های توسعه‌ی رابط کاربری جدید مایکروسافت
اگر به تکنولوژی‌های شرکت مایکروسافت علاقمند باشید و اخبار آن را دنبال کرده باشید قطعا در جریان هستید که علاوه بر تکنولوژی‌های قدیمی (WPF, UWP, Xamarin) تکنولوژی‌های جدیدی (Project Reunion, Maui, WinUI, Uno, Xaml Island) نیز بصورت همزمان در حال توسعه هستند. اکثر این تکنولوژی‌ها شبیه و نزدیک به هم هستند و برای کسی که تازه کار باشد ممکن است دچار سردرگمی شود و چون بصورت همزمان در حال توسعه می‌باشند ممکن سوالاتی برای شما پیش بیاید. در این مطلب هر کدام از این تکنولوژی‌ها را معرفی کرده و در انتخاب صحیح به شما کمک خواهیم کرد.

ساخت برنامه با WPF
به کمک تکنولوژی WPF میتوانیم نرم افزارهای دسکتاپ را توسعه دهیم. WPF همچنان پشتیبانی میشود و در سال‌های اخیر بصورت متن باز نیز منتشر شده‌است. اگر نیاز دارید که برنامه شما در ویندوز‌های 7 تا ویندوز 11 اجرا شود، میتوانید از WPF استفاده کنید. لازم به ذکر است که برنامه‌های WPF به عنوان Win32 یا Desktop نیز شناخته میشوند.

ساخت برنامه با UWP
UWP بعد از WPF و با انتشار ویندوز 10 معرفی شد. علت انتشار، هماهنگی برنامه‌ها با سیستم عامل ویندوز 10 و امنیت بیشتر بود. به‌طور فنی برنامه‌ای که بصورت UWP ساخته میشود، همان WPF است؛ با این تفاوت که داخل SandBox اجرا میشود و با محیط خارج ارتباطی ندارد. بدلیل مسائل امنیتی، بسیاری از کارهای ساده و مهم در UWP غیرممکن (البته راه حل‌هایی نیز وجود دارد) می‌باشد و نیاز به دسترسی کاربر دارد. به عنوان مثال، API‌های system.Io.File یا Process قابل استفاده نمی‌باشند.
نرم افزارهایی که با UWP ساخته میشوند فقط بر روی ویندوز 10 به بالا قابلیت اجرایی دارند و توزیع آن از طریق استور مایکروسافت امکان پذیر است. در صورت نیاز به توزیع دستی (فایل نصبی)، توسعه دهنده باید فایل نصبی را بصورت دیجیتال، امضاء کند که دردسر‌های خودش را دارد.

ساخت برنامه با Xamarin
اگر نیاز دارید که برای سیستم عامل اندروید و مک برنامه بنویسید، زامارین میتواند به شما کمک کند.

ساخت برنامه با WinUI
بعد از معرفی UWP نیاز به یک فریمورک رابط کاربری قوی جهت جذب کاربران به سمت UWP احساس شد. در نتیجه مایکروسافت فریمورک WinUI را ایجاد کرد. WinUI در 2 نسخه در حال توسعه می‌باشد:

WinUI 2.X
این نسخه از WinUI فقط قابلیت استفاده در برنامه‌های مبتنی بر UWP را دارد. اخیرا نسخه 2.6 آن منتشر شده که شامل تغییرات بصری عظیمی می‌باشد. لازم به ذکر است که ویندوز 11 که اخیرا معرفی شد، بر پایه WinUI 2.6 ایجاد شده است.

WinUI 3.X
این نسخه از WinUI قابلیت استفاده در پلتفرم‌های دیگر را محیا می‌کند و هم اکنون بصورت پیش نمایش است و بر پایه WinUI 2.5 می‌باشد. در 3 ماهه آخر سال 2021 تمامی استایل‌ها بر پایه نسخه 2.6 خواهد بود.
 

پلتفرم Uno
پلتفرم اونو توسط مایکروسافت ایجاد نشده، اما توسط آن پشتیبانی میشود. شما به کمک پلتفرم اونو میتوانید به کمک WinUI 3، برنامه‌های خود را در ویندوز 7 (به کمک موتور رندر Skia ) تا ویندوز 11، لینوکس (به کمک Skia)، مک و حتی موبایل اجرا کنید.

پلتفرم Maui
مائویی در واقع نسل بعدی زامارین می‌باشد و بصورت تک پروژه‌ای ایجاد شده‌است. در زامارین شما برای هر پلتفرم (ویندوز، اندروید، مک و...) یک پروژه جداگانه داشتید، اما در مائویی فقط یک پروژه واحد وجود دارد. پس اگر نیاز دارید که برای گوشی‌های همراه برنامه نویسی کنید، میتوانید از مائویی استفاده کنید. لازم به ذکر است به کمک مائویی میتوانید برای لینوکس و مک هم برنامه ایجاد کنید. اما بدلیل وجود WinUI در سایر پلتفرم‌ها، بهتر است از مائویی فقط برای ایجاد برنامه‌های موبایل استفاده کنید.
 

پلتفرم Project Reunion
اخیرا نام این پروژه به Windows App SDK تغییر یافته‌است. به کمک این پروژه میتوانید از WinUI 3 در برنامه‌های WPF و سایر تکنولوژی‌های Desktop استفاده کنید و کل برنامه خود را مدرن کنید. لازم به ذکر است که برنامه‌های ساخته شده توسط Reunion فقط در ویندوز 10 به بالا اجرا میشوند. در حال حاضر جهت اجرای برنامه نیاز هست که برنامه بصورت MSIX پکیج بشود. در نسخه 1.0 که تا چند ماه آینده منتشر خواهد شد، نیازی به پکیج کردن نخواهد بود.

پلتفرم Xaml Island
این پلتفرم در واقع پلی است که میتوانید از کنترل‌های UWP یا WinUI در برنامه‌های دسکتاپ (WPF) استفاده کنید. تفاوت این پلتفرم با Reunion در این است که شما فقط میتوانید بخشی از برنامه خود را مدرن کنید و قسمت‌های مدرن شده در ویندوز‌های پایین‌تر از ویندوز 10، کار نخواهند کرد. اما در Reunion تمام بخش‌های برنامه شما مدرن خواهد شد.

سخن آخر اینکه اگر نیاز به برنامه‌های موبایل دارید، بهتر است از مائویی استفاده کنید بدلیل اینکه:
  • نسل بعدی زامارین است
  • از دات نت 6 به بالا استفاده می‌کند
  • روان، سریع و انعطاف پذیر است
  • خطاهای بسیار کمتری دارد
  • مخصوص موبایل طراحی شده است
  • تجربه بیشتری نسبت به سایر پلتفرم‌ها دارد

اگر نیاز به اجرای برنامه بصورت کراس پلتفرم دارید (ویندوز/لینوکس/مک) بهتر است از Uno استفاده کنید بدلیل اینکه:
  • مخصوص کراس پلتفرم طراحی شده
  • از WinUI 3 استفاده می‌کند
  • برای ویندوز 10 به بالا از تکنولوژی UWP و برای ویندوز 7 و لینوکس از Skia استفاده می‌کند

اگر نیاز دارید برنامه شما فقط در ویندوز 10 به بالا اجرا شود بهتر است از Project Reunion استفاده کنید بدلیل اینکه:
  • از WinUI 3 استفاده می‌کند
  • تمام ویژگی‌های UWP را دارد
  • محدودیت‌های UWP را ندارد
  • بصورت Full Trust اجرا میشود
  • پیچیدگی‌های UWP را ندارد
  • از پلتفرم WPF برای اجرا استفاده می‌کند

اگر نیاز دارید که برنامه شما در ویندوز 7 به بالا اجرا شود و در ویندوز 10 ظاهر مدرن‌تری به خود بگیرد بهتر است از Xaml Island استفاده کنید بدلیل اینکه:
  • فقط بخشی از برنامه را مدرن می‌کند
  • قسمت‌های مدرن شده در نسخه‌های قبل ویندوز 10 اجرا نمیشود

نظرات مطالب
فارسی نویسی با SkiaSharp
یک نکته‌ی تکمیلی: وابستگی‌های مورد نیاز جهت کار با SkiaSharp بر روی لینوکس و همچنین Containers

برای کار با این کتابخانه در محیط‌های لینوکسی نیاز به نصب دو بسته‌ی زیر هم هست:
PM> Install-Package SkiaSharp.NativeAssets.Linux.NoDependencies
PM> Install-Package HarfBuzzSharp.NativeAssets.Linux
همچنین فایل csproj. را هم باید به صورت زیر جهت بارگذاری صحیح وابستگی‌های native آن ویرایش کرد:
<Target Name="CopyFilesAfterPublish" AfterTargets="AfterPublish">
    <Copy SourceFiles="$(TargetDir)runtimes/linux-x64/native/libSkiaSharp.so" DestinationFolder="$([System.IO.Path]::GetFullPath('$(PublishDir)'))/bin/" />
    <Copy SourceFiles="$(TargetDir)runtimes/linux-x64/native/libHarfBuzzSharp.so" DestinationFolder="$([System.IO.Path]::GetFullPath('$(PublishDir)'))/bin/" />    
</Target>