مقال تقني

مجموعات Blend mode وأقنعة Luminosity في عرض PDF

يعرض HotPDF مجموعة شفافية PDF مرسومة بنمط دمج غير Normal بترك المجموعة تحسب دمجها بنفسها: Cb(1 − α) + α·B(Cb, Cs)، مستخدماً alpha المجموعة التي يتتبعها أو يستردها من مرّة على أسود ومرّة على أبيض. ومنذ v2.770.0 تختار خاصية THotPDF.RenderColorimetricLuminosityMasks أيضاً هل تقرأ أقنعة الـ soft mask اللمعانية اللون كـ RGB موزون، مثل العارضات الشائعة، أم كـ CIE Y كما يصف ISO 32000-1

التغيّران جاءا من النوع نفسه من الملفات: صفحة مُصدَّرة من أداة تصميم، تجلس فيها صورة منتج فوق ظل ساقط ناعم. الظل Form XObject مرسوم بوصفه مجموعة شفافية بـ /BM /Multiply، وتلاشيه قناع soft mask لمعاني. في العارضات الأخرى يظهر الظل رمادياً فاتحاً محايداً. وفي إصدارات HotPDF الأقدم كان يخرج أسود تقريباً ومصبوغاً نحو لون الخلفية. خللان منفصلان متراكبَان فوق بعضهما، ويستحقان التفكيك لأن أي عارض ينمو من تصميم "الكائنات المعتمة أولاً" سيصطدم بهما معاً

لماذا يُعرض ظل Multiply الساقط معتماً أكثر من اللازم؟

يُعرض ظل Multiply معتماً أكثر من اللازم عندما يدمج العارض النتيجة المركَّبة للمجموعة بدلاً من لون المجموعة و alpha الخاصَين بها. بكسلات ذلك التسمير الشفافة جزئياً تحوي الخلفية أصلاً، فدمجها مع الخلفية يضاعف الخلفية بنفسها. الدمج Normal بشفافية ما عملي خطي وينجو من هذا الخطأ دون أن يُلاحَظ؛ أما Multiply و Screen و Darken وكل نمط غير خطي آخر فلا ينجو

كان خط عرض HotPDF يعالج أنماط الدمج أصلاً لكل كائن مرسوم بنموذج بسيط وسريع. قبل رسم كائن، يلتقط العارض لقطة للبكسلات المتأثرة؛ وبعد الرسم، يقارن صورتي "قبل" و"بعد" ويعامل لون "بعد" بوصفه مصدراً معتماً Cs، محسباً B(Cb, Cs) ومركّباً إياه بالشفافية الحالية. لمسار معبأ أو محرف أو صورة معتمة، ذلك صحيح تماماً: المصدر معتم فعلاً داخل شكله، والشكل هو موضع تغيّر البكسلات

مجموعة الشفافية تكسر ذلك الافتراض. تعرّف ISO 32000-1 §11.4 المجموعة بوصفها شيئاً يُركَّب أولاً في نتيجته الخاصة، بلونه الخاص و alpha الخاص به، ثم يُدمج مع الخلفية بوصفه كائناً واحداً فقط. حيثما يكون الظل معتماً بنسبة 30 بالمئة، تحمل صورة "بعد" نحو 0.3 من لون الظل زائد 0.7 من الصفحة تحته. أطعم ذلك إلى Multiply بوصفه مصدراً معتماً وتصبح المعادلة خلفيةً مضروبةً في (قيمة تحوي الخلفية أصلاً): فيتعتّم الظل ويلتقط تدرج لون الخلفية. لا شيء ينهار، ولا تشتعل تشخيصات، والصفحة ببساطة تبدو خطأ، وهذا أسوأ طريقة لفشل عارض

كيف يترك HotPDF مجموعة الشفافية تدمج بنفسها

منذ v2.769.3، ينقل HotPDF الدمج لمجموعة مرسومة تحت نمط دمج غير Normal من المسار العام لكل كائن إلى عارض المجموعة نفسه. تحسب المجموعة Cb(1 − α) + α·B(Cb, Cs) مباشرة من لونها الخاص و alpha الخاص بها ولقطة الخلفية الملتقطة لمعامل Do، ثم تعلّم النتيجة بوصفها مدموجة مسبقاً حتى يكتفي Do المحيط بتركيبها مع الشفافية الحالية بدلاً من دمجها مرة ثانية. الكائنات العادية تبقى على النموذج السريع للقبل والبعد، والمجموعات تحت دمج Normal غير متأثرة لأن الحالة الخطية لم تكن خاطئة قط

والجزء الصعب هو alpha. المجموعة المعزولة (/I true) تبدأ من خلفية شفافة تماماً، فيتتبع العارض لها أصلاً مستوى alpha منفصلاً ويستطيع قراءة α مباشرة. أما المجموعة غير المعزولة فتُركَّب فوق ما هو موجود على الصفحة وليس لها مستوى alpha خاص. يستردها HotPDF برسم المجموعة مرتين، مرة على أسود ومرة على أبيض:

  • على الأسود، ينتهي كل بكسل إلى α·Cs
  • على الأبيض، ينتهي البكسل نفسه إلى α·Cs + (1 − α)
  • الطرح يعطي α = 1 − (white − black)، ثم Cs = black / α

يعمل هذا لأن كل تركيب Normal يجريه العارض، بما في ذلك GDI AlphaBlend للصور ذات الأقنعة الناعمة والحواف المنعمة بالـ anti-aliasing، خطي في الخلفية. للحيلة شرط مسبق مع ذلك: يجب أن يدمج محتوى المجموعة نفسه بشكل طبيعي. إذا ضبطت موارد ExtGState الخاصة بالمجموعة /BM غير Normal، لم تختلف المرّتان بعدئذٍ بحد خطي نظيف، فيفصل HotPDF المجموعة لا ويتراجع إلى السلوك السابق. الفحص يغطي موارد المجموعة الخاصة فقط، لا النماذج المتداخلة. والتكلفة حقيقية أيضاً: تلك الصفحات تُعرض أبطأ قليلاً لأن المجموعة تُرسم مرتين. تُحفظ الأقنعة الناعمة المبنية داخل المجموعة حتى تنتهي المرّتان، فتصطدم المرّة الثانية بمخزن الأقنعة بدلاً من إعادة بنائها

// توضيح استرداد الـ alpha لكل قناة (القيم 0..1).
// Black = المجموعة مرسومة على خلفية سوداء، White = على خلفية بيضاء.
procedure RecoverGroupPixel(Black, White: Double;
  out Alpha, Source: Double);
begin
  Alpha := 1.0 - (White - Black);
  if Alpha < 0.0 then Alpha := 0.0;
  if Alpha > 1.0 then Alpha := 1.0;
  if Alpha > 0.0 then
    Source := Black / Alpha   // إلغاء الضرب المسبق
  else
    Source := 0.0;            // شفاف تماماً: اللون بلا أهمية
end;

// دمج Multiply، ثم تركيب المجموعة Cb(1 - a) + a * B(Cb, Cs)
function CompositeMultiply(Backdrop, Source, Alpha: Double): Double;
begin
  Result := Backdrop * (1.0 - Alpha) + Alpha * (Backdrop * Source);
end;

الكود أعلاه توضيح للرياضيات، وليس واجهة برمجية من HotPDF؛ يفعل العارض الشيء نفسه لكل قناة ولكل بكسل داخل THotPDF.RenderLoadedPageToBitmap. عملياً، يفقد alpha المسترد من مرّتَي 8 بت الدقة كلما اقترب من الصفر، فتحمل الحواف الخافتة جداً بعض ضجيج التكميم، وهو سبب كون القسمة ذات معنى فقط حيثما يكون alpha أعلى من الصفر بوضوح

نمط الدمج يعود إلى Normal داخل المجموعة

نمط الدمج، مثل الـ alpha الثابت والقناع الناعم، ينطبق على مجموعة الشفافية ككل لا على كل كائن داخلها، فيجب أن يبدأ محتوى المجموعة من دمج Normal (ISO 32000-1 §11.6.6). كان HotPDF يصفّر الشفافية والقناع الناعم عند دخول المجموعة سابقاً لكنه يترك نمط الدمج وحده. كانت النتيجة داخل مجموعة معزولة درامية: المحتوى يضاعف نفسه في الخلفية الابتدائية الفارغة للمجموعة، وهي سوداء، فترسم المجموعة كلها سوداء

ينطبق التصفير نفسه عند بناء قناع ناعم. إذا ضبط ExtGState واحد كلاً من /BM /Multiply و /SMask، فيجب رسم مجموعة القناع بدمج Normal؛ وإلا تحوّلت مجموعة قناع بيضاء إلى سوداء وأخفت بالضبط ما كان من المفترض أن يُظهره القناع. كلا التصفيرين جزء من v2.769.3، وكلاهما غير مرئي في المستندات البسيطة، وهكذا عاشا طوال ذلك الوقت

ما القيمة التي ينبغي أن يأخذها قناع luminosity ناعم للرمادي المتوسط؟

تحت ISO 32000-1، ينبغي لقناع luminosity ناعم تستخدم مجموعته فضاء دمج قائماً على CIE أن يأخذ CIE 1931 Y، والـ Y لرمادي sRGB متوسط بقيمة 0.5 لا يتجاوز نحو 0.21 لأن الـ Y ضوء خطي. تحل العارضات الشائعة لون المجموعة بدلاً من ذلك إلى RGB وتوزن القيم المشفَّرة بنحو 0.30 / 0.59 / 0.11، وهو ما يعطي نحو 0.5 للرمادي نفسه. ومنذ v2.770.0 يعتمد HotPDF افتراضياً التوزين المتوافق مع العارضات ويوفر THotPDF.RenderColorimetricLuminosityMasks لقراءة المواصفة

الفجوة ليست أكاديمية. التلاشي في تصدير أداة تصميم عادةً تدرج في مجموعة ICCBased أو معايَرة، والتدرجات الوسطى هي بالضبط موضع أكبر انفراق بين الـ Y الخطي والرمادي المشفَّر بغاما. مع CIE Y، يمرر قناع رمادي متوسط خُمس الظل فقط بدلاً من نصفه، فتخرج الظلال الساقطة والـ vignettes أفتح بوضوح مما في كل عارض آخر سيفتح فيه العميل الملف. أن تكون صائباً بحرف المعيار وخطأً بعيون الجميع صفقة سيئة لقيمة افتراضية، فالافتراضي يتبع العارضات والوضع الصارم يبعد خاصية واحدة

var
  Pdf: THotPDF;
  Bmp: TBitmap;
begin
  Pdf := THotPDF.Create(nil);
  try
    if Pdf.LoadFromFile('catalog-page.pdf') > 0 then
    begin
      // الافتراضي (False): أقنعة الـ luminosity توزن اللون المحلول
      // مثل DeviceRGB، مطابقةً لما تعرضه العارضات الشائعة.
      // True: خذ CIE Y عندما تمتلك مجموعة القناع فضاءً قائماً على CIE.
      Pdf.RenderColorimetricLuminosityMasks := False;
      Bmp := Pdf.RenderLoadedPageToBitmap(0, 150);
      if Bmp <> nil then
      try
        Bmp.SaveToFile('catalog-page-viewer.bmp');
      finally
        Bmp.Free;
      end;
    end;
  finally
    Pdf.Free;
  end;
end;

الخاصية تهم فقط عندما يكون فضاء دمج مجموعة القناع قائماً على CIE: CalGray أو CalRGB أو Lab أو ICCBased. الأقنعة التي تستخدم مجموعتها DeviceGray أو DeviceRGB أو DeviceCMYK تُعرض تماماً كما كانت تحت أي من الضبطين، لأن تحويل فضاء الجهاز إلى رمادي واحد في الوضعين

المزالق: /BC و /CS ومخزن العرض

قناع الـ luminosity الناعم لا يزيد اتساقاً على خلفيته: لون /BC الذي يملأ منطقة القناع خارج المجموعة يجب أن يُحوَّل بالقاعدة نفسها المستخدمة للرسم داخل المجموعة. غيّر HotPDF كليهما معاً في v2.770.0. تحويل الرسم بـ RGB موزون والخلفية بـ CIE Y ينتج درزة مرئية حيث ينتهي الصندوق المحيط للمجموعة، وهو خلل سهل الإحداث عندما تمر الخلفية عبر مساعد مختلف عن المحتوى

عزوات المجموعة أيضاً يجب أن تكون صالحة قبل حدوث أي من هذا. يقرأ HotPDF فضاء الدمج من مدخل /CS الخاص بالمجموعة ويشترط أن يحمل /BC رقماً واحداً بالضبط لكل مكوّن من ذلك الفضاء: ثلاثة لفضاء قائم على RGB، وأربعة لـ CMYK، وواحد للرمادي. الـ /CS المفقود أو /BC بخطأ في العدد يجعل القناع يفشل قبل تنفيذ المجموعة، فيُرسم الرسم غير مقنَّع بدلاً من أن يُقنَّع بخلفية مخمَّنة. وفضاءات Separation و DeviceN و NChannel ليست فضاءات دمج مشروعة، فيمر رسم ألوان spot داخل مجموعة قناع عبر تحويل tint الخاص به إلى الفضاء البديل قبل حساب اللمعان

أخيراً، الضبط يغيّر البكسلات، فهو جزء من مفتاح المخزن. الصور النقطية المعروضة مع RenderColorimetricLuminosityMasks مفعَّلاً ومطفَّأً تُخزَّن منفصلة في مخزنَي عرض الذاكرة والقرص معاً، وتبديل الخاصية بين استدعاءات THotPDF.RenderLoadedPageToBitmapCached لا يعيد أبداً صورة نقطية من الوضع الآخر. ملاحظة تشغيلية واحدة: أدخل v2.769.3 انحداراً خاصاً بـ Win64 تعذّر فيه عرض صفحات ذات مجموعة شفافية لم تضبط قناعاً ناعماً خاصاً بها؛ أُصلح في v2.770.1، فينبغي للتطبيقات ذات 64 بت استخدام ذلك الإصدار أو الأحدث

// بروفة جنباً إلى جنب: اعرض الصفحة نفسها في الوضعين.
// كل وضع يُخزَّن تحت مفتاحه الخاص، فالاستدعاءات المتكررة رخيصة.
Pdf.RenderColorimetricLuminosityMasks := False;
ViewerBmp := Pdf.RenderLoadedPageToBitmapCached(PageIndex, 96);

Pdf.RenderColorimetricLuminosityMasks := True;
StrictBmp := Pdf.RenderLoadedPageToBitmapCached(PageIndex, 96);

// ... اعرض كليهما ثم حررهما: الاستدعاءات المخزنة تعيد نسخاً يملكها المستدعي
ViewerBmp.Free;
StrictBmp.Free;

للواجهة البرمجية الأوسع للعرض، بما في ذلك اختيار الـ DPI ومخزن الصفحات وما لا يزال العارض يقربه، انظر عرض صفحة PDF إلى TBitmap في Delphi عبر HotPDF. وإذا كانت مشكلتك في الاتجاه المعاكس، إزالة الشفافية من ملف للطباعة أو الأرشفة بدلاً من رسمها، فإن الأقنعة الناعمة وتسطيح الشفافية في PDFlibPas تغطي تلك الجهة

الأسئلة الشائعة

هل يعرض HotPDF أنماط دمج PDF داخل مجموعات الشفافية بشكل صحيح؟

نعم، منذ v2.769.3. المجموعة المرسومة بـ Multiply أو أي نمط دمج غير Normal تدمج لونها الخاص و alpha الخاص بها مع الخلفية، ويبدأ محتواها من دمج Normal كما يشترط ISO 32000-1 §11.6.6

لماذا يعرض HotPDF المجموعات غير المعزولة مرتين؟

المجموعة غير المعزولة لا تمتلك مستوى alpha خاصاً بها. يرسمها HotPDF على الأسود وعلى الأبيض ويسترد الـ alpha بالصيغة 1 − (white − black)، وهي تكلف بعض السرعة لكنها تجعل ظلال Multiply صحيحة

هل ينبغي ضبط RenderColorimetricLuminosityMasks على True؟

اتركه False ليطابق ما تعرضه عارضات PDF الشائعة. اضبطه على True فقط عندما تحتاج قراءة CIE Y لـ ISO 32000-1 لمجموعات أقنعة قائمة على CIE، مثلاً في مقارنة مطابقة

مجموعات الشفافية بأنماط الدمج وأقنعة الـ luminosity الناعمة وعارض الصفحات الذي يرسمها جزء من HotPDF Delphi Component، مكتبة VCL أصلية لـ Delphi و C++Builder تنشئ مستندات PDF وتحررها وتعرضها دون DLL خارجي