كيفية العمل مع رسومات PDF في C++

كيفية العمل مع رسومات PDF في C++

Aspose.PDF FOSS for C++ يتضمن مكتبة رسومات متجهية صغيرة API لرسم الأشكال الحرّة مباشرةً على صفحة PDF — منفصلة عن أجهزة الرندرة النقطية للمكتبة (BmpDevice, JpegDevice, TiffDevice)، التي تحول محتوى الصفحة الموجود إلى صور. يشرح هذا الدليل إنشاء حاوية Graph، وإضافة الأشكال Circle، Ellipse، وLine إليها، وتنسيق تلك الأشكال باستخدام GraphInfo، ووضع الـGraph النهائي على صفحة. يتم إضافة المكتبة إلى مشروع عبر CMake.

دليل خطوة بخطوة

الخطوة 1: تثبيت الحزمة

أضف المكتبة كدليل فرعي في CMake واربطها بالهدف aspose_pdf_foss:

add_subdirectory(aspose.pdf-foss-for-cpp)
target_link_libraries(your_app PRIVATE aspose_pdf_foss)

تحقق من حل سلاسل الأدوات والرؤوس عن طريق تجميع برنامج بسيط:

#include <aspose/pdf/document.hpp>
#include <iostream>

int main() {
    Aspose::Pdf::Document doc;
    std::cout << "Linked OK — pages: " << doc.Pages().Count() << "\n";
}

بناء ناجح يطبع pages: 0 يؤكد أن المكتبة مرتبطة بشكل صحيح.


الخطوة 2: استيراد الفئات المطلوبة

قم بتضمين رؤوس المستند، حاوية الشكل، الأشكال الثلاثة الملموسة، وأنواع تنسيقها:

#include <aspose/pdf/document.hpp>
#include <aspose/pdf/drawing/graph.hpp>
#include <aspose/pdf/drawing/circle.hpp>
#include <aspose/pdf/drawing/ellipse.hpp>
#include <aspose/pdf/drawing/line.hpp>
#include <aspose/pdf/graph_info.hpp>
#include <aspose/pdf/border_info.hpp>
#include <aspose/pdf/color.hpp>

using namespace Aspose::Pdf;
using namespace Aspose::Pdf::Drawing;

Graph، Shape، Circle، Ellipse، وLine في مساحة الاسم Aspose::Pdf::Drawing؛ GraphInfo، BorderInfo، وColor مباشرة تحت Aspose::Pdf.


الخطوة 3: إنشاء رسم بياني وإضافته إلى صفحة

Graph هو حاوية تقوم بتموضع نفسها على الصفحة عبر Left()، Top()، Width()، وHeight()، وتحتفظ بالأشكال المرسومة بداخلها عبر Shapes(). بمجرد تكوينها، يتم وضعها على الصفحة عبر Page.Paragraphs().Add()، نفس المجموعة المستخدمة لمحتوى الصفحات الأخرى:

Document doc;
Page page = doc.Pages().Add();

auto graph = std::make_shared<Graph>();
graph->Left(50.0);
graph->Top(50.0);
graph->Width(400.0);
graph->Height(400.0);

page.Paragraphs().Add(graph);

الخطوة 4: رسم دائرة وقطع ناقص

Circle يصف هندسته باستخدام PosX()، PosY()، وRadius(). Ellipse يستخدم صندوق حد بدلاً من ذلك — Left()، Bottom()، Width()، وHeight(). يتم إضافة كليهما إلى Graph عن طريق إلحاقهما، كـ Shape مؤشرات، إلى المتجه الذي تُرجعه Shapes():

auto circle = std::make_unique<Circle>();
circle->PosX(150.0);
circle->PosY(150.0);
circle->Radius(75.0);
graph->Shapes().push_back(std::move(circle));

auto ellipse = std::make_unique<Ellipse>();
ellipse->Left(20.0);
ellipse->Bottom(20.0);
ellipse->Width(120.0);
ellipse->Height(60.0);
graph->Shapes().push_back(std::move(ellipse));

كلا الشكلين يرثان CheckBounds(containerWidth, containerHeight) من Shape، الذي يُبلغ عما إذا كانت هندسة الشكل الحالية تتناسب داخل حاوية بالحجم المحدد:

bool circleFits = circle->CheckBounds(graph->Width(), graph->Height());

الخطوة 5: رسم خط

Line يخزن هندسته بطريقة مختلفة: PositionArray() يحتوي على std::vector<float> مسطّحة من الإحداثيات — زوج x, y لكل نقطة — بدلاً من الخصائص المسماة. مقطع نقطتين يحتاج إلى أربعة قيم: x البداية، y البداية، x النهاية، y النهاية.

auto line = std::make_unique<Line>();
line->PositionArray({0.0f, 0.0f, 400.0f, 400.0f});
graph->Shapes().push_back(std::move(line));

الخطوة 6: تنسيق الأشكال باستخدام GraphInfo وحدود الحاوية

يأتي حد وتعبئة كل شكل من GraphInfo، يتم قراءته وتعيينه عبر Shape.GraphInfo() / GraphInfo(value). يتيح عرض حد الخط (LineWidth()، الافتراضي 1.0f)، لون الحد والتعبئة (Color()، FillColor())، ونمط الشرطية (DashArray()، DashPhase()):

GraphInfo stroke;
stroke.LineWidth(2.0f);
stroke.Color(Color::FromRgb(1.0, 0.0, 0.0));
stroke.FillColor(Color::FromRgb(1.0, 0.9, 0.9));

الحاوية Graph نفسها تحمل BorderInfo، يتم تعيينه عبر Border()، والذي يجمع GraphInfo واحد لكل حافة (Left()، Right()، Top()، Bottom()) بالإضافة إلى RoundedBorderRadius() لإطار الحاوية نفسه:

BorderInfo border{BorderSide::All, 1.5f, Color::Black()};
border.RoundedBorderRadius(6.0);
graph->Border(border);

الخطوة 7: حفظ المستند

doc.Save("graphics.pdf");

المشكلات الشائعة والحلول

شكل قمت بإنشائه لا يظهر أبداً على الصفحة

إنشاء Circle أو Ellipse أو Line بمفرده لا يؤثر إلا عندما يتم إلحاقه بالمتجه الذي يُرجعه Graph المالك في Shapes()، ويتم إضافة ذلك Graph إلى صفحة عبر Page.Paragraphs().Add(). جميع الخطوات الثلاث — الإنشاء، الإلحاق، إضافة الـGraph إلى الصفحة — مطلوبة.

الأشكال تُعرض في الموضع الخاطئ

Graph.Left() وGraph.Top() تحددان موضع الحاوية على الصفحة؛ خصائص الشكل (Circle.PosX()/PosY()، Ellipse.Left()/Bottom()، إحداثيات Line.PositionArray()) تصف الهندسة داخل تلك الحاوية. تحقق من موضع الحاوية وإحداثيات الشكل نفسها عندما يبدو الناتج مزيّفاً.

CheckBounds returns false unexpectedly

CheckBounds(containerWidth, containerHeight) يتحقق من هندسة الشكل نفسها مقابل الأبعاد المُمرَّرة — عادةً أبعاد Graph المالك في Width()/Height()، وليس صندوق الوسائط الكامل للصفحة. تمرير أبعاد خاطئة ينتج سلباً كاذباً حتى عندما يكون الشكل يتناسب فعلياً داخل الـGraph.

A Line لا يظهر، أو يظهر كنقطة واحدة

PositionArray() يحتاج على الأقل إلى زوجين (x, y) — أي أربع قيم float — لوصف مقطع مرئي. المتجه الأقصر لا يُكوّن خطاً.

Confusing Circle with AnnotationType::Circle or CircleAnnotation

المكتبة تحتوي أيضًا على API منفصل لتعليقات PDF، حيث يمثل AnnotationType::Circle وCircleAnnotation تعليقات توضيحية على شكل دائرة. الفئة Circle التي تم تغطيتها في هذا الدليل غير ذات صلة — فهي موجودة في Aspose::Pdf::Drawing وترسم مباشرةً في محتوى الصفحة بدلاً من إضافة كائن تعليقات.

الأسئلة المتكررة

ما الفرق بين GraphInfo و BorderInfo؟

GraphInfo يحدد نمط ضربة واحدة — عرض الخط، اللون، لون التعبئة، ونمط الشرط — ويُستخدم لكل من الأشكال الفردية (من خلال Shape.GraphInfo()) ولكل حافة داخل BorderInfo. BorderInfo يجمع أربع قيم GraphInfo (Left()، Right()، Top()، Bottom()) بالإضافة إلى RoundedBorderRadius() لوصف إطار الحدود الخاص بحاوية Graph.

هل يمكنني تعبئة شكل بلون صلب؟

نعم. GraphInfo.FillColor() يحدد لون التعبئة المستخدم عندما يُرسم الشكل عبر Graph الخاصة به.

هل يخزن Circle صندوقًا محيطًا كما يفعل Ellipse؟

لا. Circle يُظهر PosX()، PosY()، وRadius()؛ Ellipse يُظهر Left()، Bottom()، Width()، وHeight(). لا يشتركان في تمثيل هندسي مشترك بخلاف القاعدة المجردة Shape وتنسيق GraphInfo.

هل يمكن لرسم بياني واحد أن يحتوي على أكثر من شكل؟

نعم. Graph.Shapes() تُعيد مجموعة كاملة من كائنات Shape الموضوعة داخل ذلك Graph — يمكن إلحاق الدوائر والبيضات والخطوط جميعًا بنفس الحاوية.

هل هذا هو نفسه كتحويل صفحة إلى صورة؟

لا. BmpDevice، JpegDevice، وTiffDevice تُحوِّل محتوى الصفحة الحالي إلى صيغ صورة. Graph، Shape، Circle، Ellipse، وLine تُنشئ هندسة متجهة جديدة مباشرةً في محتوى PDF أثناء بناء أو تحرير المستند.

انظر أيضاً

 العربية