مقاله فنی

صادرکردن یک بازه سلولی اکسل به‌عنوان یک تصویر با HotXLS

گاهی خروجی یک سند نیست، یک عکس از یک جدول است. یک بلوک خلاصه در یک ایمیل وضعیت، یک پنل KPI رندرشده در یک داشبورد، یک بندانگشتی کنار یک نتیجه جستجو: همه آن‌ها سلول‌ها را می‌خواهند و هیچ‌کدام کاغذ را نمی‌خواهند. TXLSCellImageExporter در HotXLS یک مستطیل سلولی کلاسیک یا XLSX می‌گیرد و یک PNG یا JPEG فشرده تولید می‌کند بدون اندازه صفحه، بدون حاشیه‌ها، بدون سرببرگ یا پانویس، بدون عناوین چاپ و بدون شکستگی صفحه. تفکیک‌پذیری، مقیاس، فرمت و کیفیت JPEG قابل پیکربندی‌اند، آبجکت‌ها، خطوط شبکه و کادرهای سلول کلیدهای مستقل دارند، پس‌زمینه می‌تواند یک رنگ یا شفاف باشد، و نوشتن فایل از یک جایگزینی اتمیک در همان پوشه می‌گذرد که اگر چیزی شکست بخورد هدف موجود را دست‌نخورده می‌گذارد

دلیل اینکه این به exporter خودش نیاز دارد نه به یک پرچم روی مسیر چاپ این است که صفحه‌بندی یک لایه اختیاری نیست که بتوان خاموشش کرد. همان چیزی است که خط لوله صفحه برایش وجود دارد

چرا بازه را از طریق خط لوله چاپ رندر نکنیم؟

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

exporter سلولی مستطیل را اندازه می‌گیرد، یک bitmap دقیقاً به همان اندازه تخصیص می‌دهد، سلول‌ها را درونش می‌کشد، و رمزگذاری می‌کند. هیچ صفحه‌ای نیست، پس چیزی نیست که پیکربندی‌اش کنید تا حذف شود. برای مواردی که واقعاً کاغذ می‌خواهید، مسیر صادرات PDF ابزار درست است و در مقاله صادرات PDF کاربرگ پوشش داده شده است

TXLSCellImageExporter به‌ازای هر بازه سلولی یک تصویر را اندازه می‌گیرد، می‌کشد و رمزگذاری می‌کند در حالی که خط لوله چاپ بازه را در شکستگی‌های صفحه می‌شکند
خط لوله صفحه هندسه کاغذ را میان شما و سلول‌ها می‌گذارد؛ exporter سلولی در هیچ نقطه‌ای از مسیر صفحه ندارد

پیش از رندر اندازه بگیرید

Measure ابعاد پیکسلی‌ای را که تنظیمات فعلی تولید می‌کردند بدون رمزگذاری هیچ‌چیز برمی‌گرداند. این به دو دلیل اهمیت دارد. یک قالب HTML یا ایمیل معمولاً پیش از وجود تصویر به ابعادش نیاز دارد، تا جعبه را رزرو کند و از جابه‌جایی چیدمان اجتناب کند. و سرویسی که بازه‌های انتخابی کاربر را رندر می‌کند راهی لازم دارد تا یک درخواست پوچ را پیش از تخصیص برایش رد کند

uses
  lxHandleX, lxPagination;

var
  Book: TXLSXWorkbook;
  Sheet: TXLSXWorksheet;
  Exporter: TXLSCellImageExporter;
  Summary: TXLSXRange;
  W, H, Bytes: Integer;
begin
  Book := TXLSXWorkbook.Create;
  try
    Book.Open('quarter.xlsx');
    Sheet := Book.Sheets.ByPos[0];
    Summary := Sheet.Range['A1:F20'];

    Exporter := TXLSCellImageExporter.Create;
    try
      Exporter.ImageFormat := xpifPng;   // PNG خط‌های نازک را شفاف نگه می‌دارد
      Exporter.DPI := 96;
      Exporter.Scale := 2.0;             // خروجی با چگالی رتینا
      Exporter.IncludeGridlines := False;
      Exporter.IncludeCellBorders := True;
      Exporter.TransparentBackground := True;
      Exporter.MaxPixels := 40 * 1000 * 1000;
      Exporter.MaxBytes := 8 * 1024 * 1024;

      if not Exporter.Measure(Summary, W, H) then
        raise Exception.Create('range exceeds the configured budget');
      // W و H اکنون معلوم‌اند؛ پیش از رمزگذاری جعبه چیدمان را رزرو کن
      Bytes := Exporter.Save(Summary, 'summary.png');
      if Bytes <= 0 then
        raise Exception.Create('image export failed, previous file kept');
    finally
      Exporter.Free;
    end;
  finally
    Book.Free;
  end;
end;

بودجه‌ها، چون مقیاس ضرب می‌کند

MaxPixels و MaxBytes تزئین دفاعی نیستند. تعداد پیکسل با مربع ضریب مقیاس و با مربع نسبت تفکیک‌پذیری رشد می‌کند، پس بازه‌ای که در ۹۶ DPI یک ۱۲۰۰در۸۰۰ معقول است تقریباً در ۶۰۰ DPI به ۴۷ مگاپیکسل می‌رسد، و کاربری که به‌جای یک بلوک خلاصه کل بازه استفاده‌شده را انتخاب کند یک مرتبه بزرگی دیگر رویش می‌افزاید. بدون سقف حالت شکست یک تخصیص است که فرایند نمی‌تواند برآورده کند، که هر چیز دیگری را که آن فرایند انجام می‌داد سرنگون می‌کند

با یک سقف درخواست شکست می‌خورد و فراخواننده انتخاب می‌کند: رد کن، مقیاس را کم کن، یا بازه را باریک کن. آن برای یک سرور گزارش موضع بسیار بهتری است، و همان استدلال پشت بودجه‌های صریح در رمزگشای متافایل است که در مقاله رمزگشای کران‌دار EMF و WMF توصیف شده است

جریان بودجه برای TXLSCellImageExporter در HotXLS: Measure نخست اندازه پیکسل را برمی‌گرداند، سپس MaxPixels و MaxBytes تخصیص و اندازه خروجی را کران می‌زنند
مردودی پیش از تخصیص رخ می‌دهد، و شکست بودجه بایتی تصویر قبلی را برای فراخواننده دست‌نخورده می‌گذارد

جایگزینی اتمیک، و اینکه چرا پوشه اهمیت دارد

Save به یک نام فایل درون هدف نمی‌نویسد. یک فایل موقت در همان پوشه می‌نویسد، درونش رمزگذاری می‌کند، و فقط بعد هدف را جایگزین می‌کند. اگر رمزگذاری شکست بخورد، اگر بودجه در میانه راه رد شود، یا اگر فرایند کشته شود، تصویر قبلی هنوز آنجاست و هنوز معتبر است. پس داشبوردی که کاشی‌هایش را طبق زمان‌بندی دوباره تولید می‌کند هرگز یک PNG ناقص نشان نمی‌دهد، که نشانه معمول نوشتن ساده‌لوحانه‌ای است که مقصد را باز می‌کند و شروع به جریان می‌کند

جزئیات همان-پوشه تصادفی نیست. یک جایگزینی اتمیک فقط درون یک حجم اتمیک است، چون میان حجم‌ها سیستم‌عامل باید کپی کند و بعد حذف، که پنجره‌ای را که می‌خواستید ببندید دوباره برمی‌گرداند. هر پیاده‌سازی از این الگو که فایل موقتش را در پوشه temp سیستمی می‌گذارد روی دستگاهی که خروجی روی درایو دیگری زندگی می‌کند اتمیک نیست

Save مربوط به TXLSCellImageExporter درون یک فایل موقت در همان پوشه رمزگذاری می‌کند، سپس هدف را اتمیک جایگزین می‌کند؛ شکست‌ها تصویر قبلی را معتبر می‌گذارند
فایل موقت باید کنار هدف زندگی کند چون یک جایگزینی اتمیک فقط درون یک حجم کار می‌کند

رخدادهای paint روی canvas واقعی می‌کشند

هم exporter بازه و هم exporter صفحه رخدادهای paint آغازین و پایانی آشکار می‌کنند، و آن‌ها یک زمینه کامل فقط‌خواندنی دریافت می‌کنند نه صرفاً یک هندل canvas. TXLSPagePaintContext canvas زنده، کران‌های پیکسلی، اندازه صفحه بر حسب point، تفکیک‌پذیری و مقیاس واقعاً در حال استفاده، شماره صفحه سند، شماره صفحه درون‌کاربرگی، تعداد کل صفحات، نام sheet و کاربرگ مبدأ را در هر دو گونه کلاسیک و XLSX حمل می‌کند. همین برای کشیدن یک watermark که درست مقیاس می‌شود، یا یک مُهر صفحه که می‌داند در اجرا کجاست کافی است

procedure TReportJob.StampDraft(Sender: TObject;
  const AContext: TXLSPagePaintContext);
begin
  // مقیاس-آگاه، پس مهر در 1x و 3x یکسان به‌نظر می‌رسد
  AContext.Canvas.Font.Height := Round(-48 * AContext.Scale);
  AContext.Canvas.Font.Color := clSilver;
  AContext.Canvas.Brush.Style := bsClear;
  AContext.Canvas.TextOut(AContext.Bounds.Left + Round(24 * AContext.Scale),
    AContext.Bounds.Top + Round(24 * AContext.Scale), 'DRAFT');
end;

Exporter.AfterPaint := Job.StampDraft;

سه رفتار ارزش اتکا دارند. رخدادها دقیقاً به‌ازای هر فریم رندرشده یک‌بار می‌آتشند، شامل هر فریم یک TIFF چندصفحه‌ای، پس شمارنده‌ای که در handler افزایش می‌یابد قابل اعتماد است. حین اندازه‌گیری ساکت می‌مانند، پس handlerی با اثر جانبی برای یک خروجی دو بار اجرا نمی‌شود. و اگر رخداد آغازین پرتاب کند، رخداد پایانی آتش نمی‌گیرد و هیچ بایت تصویر جزئی نوشته نمی‌شود، پس یک استثنا در کد ترسیم خودتان نمی‌تواند فایلی نیمه‌مهرشده تولید کند

انتخاب فرمت

PNG برای هر چیزی که متن‌محور است. JPEG یک تبدیل بلوکی اعمال می‌کند که لرزش مرئی دور خط‌های نازک پرکنتراست تولید می‌کند، که دقیقاً کادرهای سلول و متن کوچک همان‌اند، و مصنوع‌ها در تنظیمات کیفی که یک عکس را بی‌نقص نشان می‌دهد زنده می‌مانند. JPEG جای خودش را وقتی می‌گیرد که بازه توسط عکس‌های تعبیه‌شده مسلط باشد و اندازه فایل بیشتر از وفاداری لبه اهمیت داشته باشد. پس‌زمینه‌های شفاف PNG می‌طلبند، چون JPEG کانال آلفا ندارد، پس کاشی‌ای که قرار است روی سطح رنگی بنشیند انتخاب را به‌جای شما کرده است

اگر بازه شما سلول‌های ادغام‌شده دارد، خروجی را با sheet مقایسه کنید: ناحیه‌های ادغام‌شده با پهنای ستون‌ها جوری تعامل می‌کنند که مردم را غافلگیر می‌کند، و قواعد چیدمان در مقاله سلول‌های ادغام‌شده و قالب‌های گزارش پوشش داده شده است. HotXLS فرمت‌های XLS، XLSX، ODS و CSV را از Delphi و C++Builder بدون وابستگی به Excel می‌خواند و می‌نویسد، و سطح کامل exporter در صفحه محصول HotXLS Delphi spreadsheet component مستند شده است