تبدیل ارائه‌های PowerPoint به Markdown در PHP

بررسی کلی

Aspose.Slides for PHP via Java می‌تواند ارائه‌های PPT و PPTX را به Markdown برای مستندات، سایت‌های ثابت، مهاجرت محتوا و گردش‌کارهای کنترل نسخه تبدیل کند. می‌توانید یک نوع Markdown را انتخاب کنید، رندر محتوی اسلایدها را کنترل کنید و محل ذخیره‌سازی تصاویر صادر شده و نحوه ارجاع آنها در Markdown تولید شده را تعیین کنید.

به طور پیش‌فرض، خروجی Markdown فقط متن است. برای خروجی محتوی تصویری، نوع خروجی را با متد MarkdownSaveOptions::setExportType به مقدار Sequential یا Visual از شمارش‌گر MarkdownExportType تنظیم کنید. Sequential موارد اسلاید را به طور جداگانه و به ترتیب رندر می‌کند، در حالی که Visual موارد گروه‌بندی شده را برای حفظ رابطه بصری آنها با هم نگه می‌دارد. مقدار TextOnly هیچ منبع تصویری تولید نمی‌کند، بنابراین فراخوانی‌های ذخیره‌سازی تصویر در این حالت اجرا نمی‌شوند.

تبدیل یک ارائه به Markdown

فایل منبع را با کلاس Presentation بارگذاری کنید و سپس متد Presentation::save را با مقدار Md از شمارش‌گر SaveFormat فراخوانی کنید.

use aspose\slides\Presentation;
use aspose\slides\SaveFormat;

$inputPath = __DIR__ . DIRECTORY_SEPARATOR . "presentation.pptx";
$outputPath = __DIR__ . DIRECTORY_SEPARATOR . "presentation.md";
$presentation = new Presentation($inputPath);
try {
    $presentation->save($outputPath, SaveFormat::Md);
} finally {
    $presentation->dispose();
}

انتخاب یک نوع Markdown

متد MarkdownSaveOptions::setFlavor مشخص می‌کند که کدام مشخصات Markdown برای خروجی استفاده شود. شمارش‌گر Flavor شامل CommonMark، GitHub Flavored Markdown و دیگر واریانت‌های پشتیبانی‌شده است.

مثال زیر یک ارائه را به صورت CommonMark صادر می‌کند:

use aspose\slides\Flavor;
use aspose\slides\MarkdownSaveOptions;
use aspose\slides\Presentation;
use aspose\slides\SaveFormat;

$inputPath = __DIR__ . DIRECTORY_SEPARATOR . "presentation.pptx";
$outputPath = __DIR__ . DIRECTORY_SEPARATOR . "presentation.md";
$presentation = new Presentation($inputPath);
try {
    $options = new MarkdownSaveOptions();
    $options->setFlavor(Flavor::CommonMark);

    $presentation->save($outputPath, SaveFormat::Md, $options);
} finally {
    $presentation->dispose();
}

صادرات تصاویر با رفتار پیش‌فرض ذخیره‌سازی محلی

کلاس MarkdownSaveOptions دو متد برای پیکربندی ذخیره‌سازی محلی تصاویر فراهم می‌کند:

  • setBasePath مسیر پایه برای سند Markdown و منابع آن را تعیین می‌کند.
  • setImagesSaveFolderName زیرپوشه تصاویر را مشخص می‌کند. مقدار پیش‌فرض آن Images است.

مثال زیر محتوی تصویری را رندر می‌کند، تصاویر را در output/assets می‌نویسد و مراجع نسبی تصویر را در سند Markdown ایجاد می‌کند:

use aspose\slides\MarkdownExportType;
use aspose\slides\MarkdownSaveOptions;
use aspose\slides\Presentation;
use aspose\slides\SaveFormat;

$inputPath = __DIR__ . DIRECTORY_SEPARATOR . "presentation.pptx";
$outputDirectory = __DIR__ . DIRECTORY_SEPARATOR . "output";
if (!is_dir($outputDirectory)) {
    mkdir($outputDirectory, 0777, true);
}

$presentation = new Presentation($inputPath);
try {
    $options = new MarkdownSaveOptions();
    $options->setExportType(MarkdownExportType::Visual);
    $options->setBasePath($outputDirectory);
    $options->setImagesSaveFolderName("assets");

    $markdownPath = $outputDirectory . DIRECTORY_SEPARATOR . "presentation.md";
    $presentation->save($markdownPath, SaveFormat::Md, $options);
} finally {
    $presentation->dispose();
}

این رفتار همچنین به‌عنوان بازگشت‌پذیری عمل می‌کند وقتی یک هندلر ذخیره‌سازی تصویر سفارشی مقدار false برمی‌گرداند.

سفارشی‌سازی ذخیره‌سازی تصویر و لینک‌های Markdown

از متد MarkdownSaveOptions::setImageSaving برای ثبت یک کال‌بک برای منابع bitmap و metafile غیر‑SVG که در طول صادرات Markdown ایجاد می‌شوند، استفاده کنید. کال‑بک MarkdownImageSavingHandler یک شیء IImage، مقدار ImageFormat و لینک تولید شده Markdown را به صورت آرایه‌ای جاوا با یک عنصر دریافت می‌کند. تصویر را با فرمت ارائه شده ذخیره یا بارگذاری کنید و $link[0] را با مرجعی که باید در خروجی Markdown ظاهر شود، جایگزین کنید.

منابعی که در قالب SVG صادر می‌شوند به‌صورت جداگانه پردازش می‌شوند. یک کال‑بک با متد MarkdownSaveOptions::setSvgImageSaving ثبت کنید. کال‑بک MarkdownSvgImageSavingHandler یک شیء ISvgImage و آرایه یک عنصری $link دریافت می‌کند. SVG هیچ آرگومان ImageFormat ندارد؛ داده‌های XML آن را از متد ISvgImage::getSvgData بنویسید یا بارگذاری کنید. بسته به حالت صادرات و گروه‌بندی بصری، یک SVG در ارائه منبع می‌تواند رستر شود یا با محتویات دیگر ترکیب شود؛ منبع غیر‑SVG حاصل سپس به کال‑بک ذخیره‌سازی تصویر پاس داده می‌شود. هر دو کال‑بک را زمانی که هر منبع بصری صادر شده نیاز به پردازش سفارشی دارد، ثبت کنید.

در PHP via Java، هر کال‑بک را در یک کلاس PHP پیاده‌سازی کنید و از java_closure برای نمایش آن شیء به عنوان اینترفیس مربوطه در جاوا استفاده کنید.

مقدار بازگشتی هندلر تعیین می‌کند که چه کسی تصویر را پردازش می‌کند:

  • پس از ذخیره، بارگذاری، تبدیل یا هر پردازش دیگری تصویر و اختصاص یک مقدار معتبر به $link[0]، true بازگردانید. Aspose.Slides این مقدار را در سند Markdown می‌نویسد و ذخیره‌سازی محلی پیش‌فرض را انجام نمی‌دهد.
  • false بازگردانید تا Aspose.Slides تصویر را به صورت محلی ذخیره کند و لینک آن را بر اساس مقادیری که با MarkdownSaveOptions::setBasePath و MarkdownSaveOptions::setImagesSaveFolderName تنظیم شده‌اند، تولید کند.

ذخیره تصاویر در یک پوشه منبع CDN و استفاده از URLهای خارجی

مثال زیر پوشه cdn-origin/presentations/quarterly-report را به‌عنوان یک پوشه منبع CDN سوار یا همگام‌سازی‌شده در نظر می‌گیرد. هر هندلر نام فایل تولید شده را استخراج می‌کند، تصویر را در آن پوشه سفارشی ذخیره می‌کند و مرجع محلی تولید شده را با یک URL عمومی CDN جایگزین می‌کند. خود نمونه هیچ آپلود شبکه‌ای انجام نمی‌دهد: URL فقط زمانی معتبر می‌شود که پوشه به‌عنوان منبع CDN سوار شود یا فایل‌های آن به CDN منتشر شوند. برای ذخیره‌سازی شیء، نوشتن به سیستم فایل را با عملیات بارگذاری SDK ذخیره‌سازی جایگزین کنید و $link[0] را فقط پس از موفقیت‌آمیز شدن بارگذاری اختصاص دهید.

use aspose\slides\MarkdownExportType;
use aspose\slides\MarkdownSaveOptions;
use aspose\slides\Presentation;
use aspose\slides\SaveFormat;

define("JAVA_PREFER_VALUES", 1);
require_once("http://localhost:8080/JavaBridge/java/Java.inc");
require_once("lib/aspose.slides.php");

function getFileNameFromLink($generatedLink)
{
    $urlCompatibleLink = str_replace("\\", "/", java_values($generatedLink));
    return basename($urlCompatibleLink);
}

function buildPublicUrl($publicBaseUrl, $fileName)
{
    return rtrim($publicBaseUrl, "/") . "/" . rawurlencode($fileName);
}

class CustomImageSavingHandler
{
    private $storageDirectory;
    private $publicBaseUrl;

    function __construct($storageDirectory, $publicBaseUrl)
    {
        $this->storageDirectory = $storageDirectory;
        $this->publicBaseUrl = $publicBaseUrl;
    }

    function invoke($image, $format, $link)
    {
        if (java_values($image->getWidth()) < 128 || java_values($image->getHeight()) < 128) {
            return false;
        }

        $fileName = getFileNameFromLink($link[0]);
        $storagePath = $this->storageDirectory . DIRECTORY_SEPARATOR . $fileName;
        $image->save($storagePath, $format);
        $link[0] = buildPublicUrl($this->publicBaseUrl, $fileName);
        return true;
    }
}

class CustomSvgImageSavingHandler
{
    private $storageDirectory;
    private $publicBaseUrl;

    function __construct($storageDirectory, $publicBaseUrl)
    {
        $this->storageDirectory = $storageDirectory;
        $this->publicBaseUrl = $publicBaseUrl;
    }

    function invoke($svgImage, $link)
    {
        $fileName = getFileNameFromLink($link[0]);
        $storagePath = $this->storageDirectory . DIRECTORY_SEPARATOR . $fileName;
        $outputStream = null;
        try {
            $outputStream = new Java("java.io.FileOutputStream", $storagePath);
            $outputStream->write($svgImage->getSvgData());
        } catch (Throwable $exception) {
            fwrite(STDERR, "Could not save the SVG image: " . $exception->getMessage() . PHP_EOL);
            return false;
        } finally {
            if ($outputStream !== null) {
                $outputStream->close();
            }
        }

        $link[0] = buildPublicUrl($this->publicBaseUrl, $fileName);
        return true;
    }
}

$inputPath = __DIR__ . DIRECTORY_SEPARATOR . "presentation.pptx";
$outputDirectory = __DIR__ . DIRECTORY_SEPARATOR . "output";
$publicBaseUrl = "https://cdn.example.com/presentations/quarterly-report";
$storageDirectory = __DIR__ . DIRECTORY_SEPARATOR . "cdn-origin" . DIRECTORY_SEPARATOR . "presentations" . DIRECTORY_SEPARATOR . "quarterly-report";
if (!is_dir($outputDirectory)) {
    mkdir($outputDirectory, 0777, true);
}
if (!is_dir($storageDirectory)) {
    mkdir($storageDirectory, 0777, true);
}

$presentation = new Presentation($inputPath);
try {
    $options = new MarkdownSaveOptions();
    $options->setExportType(MarkdownExportType::Visual);
    $options->setBasePath($outputDirectory);
    $options->setImagesSaveFolderName("fallback-images");

    $imageSavingHandler = java_closure(new CustomImageSavingHandler($storageDirectory, $publicBaseUrl), null, java('com.aspose.slides.MarkdownSaveOptions$MarkdownImageSavingHandler'));
    $svgImageSavingHandler = java_closure(new CustomSvgImageSavingHandler($storageDirectory, $publicBaseUrl), null, java('com.aspose.slides.MarkdownSaveOptions$MarkdownSvgImageSavingHandler'));
    $options->setImageSaving($imageSavingHandler);
    $options->setSvgImageSaving($svgImageSavingHandler);

    $markdownPath = $outputDirectory . DIRECTORY_SEPARATOR . "presentation.md";
    $presentation->save($markdownPath, SaveFormat::Md, $options);
} finally {
    $presentation->dispose();
}

هندلر bitmap عمداً برای تصاویر کوچکتر از 128 × 128 پیکسل false برمی‌گرداند، بنابراین Aspose.Slides این تصاویر را در output/fallback-images با رفتار پیش‌فرض ذخیره می‌کند. منابع bitmap و metafile بزرگ‌تر، همراه با منابع SVG، توسط کد سفارشی پردازش می‌شوند. به‌عنوان مثال، مرجع محلی تولید شده‌ای مانند fallback-images/image1.png به https://cdn.example.com/presentations/quarterly-report/image1.png تبدیل می‌شود. هندلرها فقط هنگام نوشتن فایل‌ها از مسیرهای سیستم‌عامل استفاده می‌کنند؛ لینک‌های نوشته‌شده در Markdown از اسلش‌های جلو (/) و نام‌های فایل URL‑escaped استفاده می‌کنند. همان قاعده را هنگام ساخت لینک‌های نسبی اعمال کنید: از / استفاده کنید، نه جداکنندهٔ مخصوص پلتفرم.

سوالات متداول

آیا یک هندلر می‌تواند هم تصاویر رستر و هم تصاویر SVG را پردازش کند؟

خیر. برای منابع bitmap و metafile صادر شده از MarkdownSaveOptions::setImageSaving استفاده کنید و برای منابع صادرشده به‌صورت SVG از MarkdownSaveOptions::setSvgImageSaving استفاده کنید. اولی یک شیء IImage و مقدار ImageFormat را فراهم می‌کند؛ دومی یک شیء ISvgImage که دادهٔ SVG آن را می‌توان با ISvgImage::getSvgData خواند. یک SVG منبع که در طول صادرات رستر می‌شود، به‌جای این، توسط کال‑بک ذخیره‌سازی تصویر پردازش می‌شود.

وقتی یک هندلر ذخیره‌سازی تصویر false برمی‌گرداند چه اتفاقی می‌افتد؟

Aspose.Slides از رفتار پیش‌فرض ذخیره‌سازی محلی خود استفاده می‌کند. مکان تصویر و مرجع تولید شده توسط مقادیری که با MarkdownSaveOptions::setBasePath و MarkdownSaveOptions::setImagesSaveFolderName تنظیم شده‌اند، کنترل می‌شود.

آیا یک هندلر می‌تواند بدون ذخیرهٔ تصویر به‌صورت محلی یک URL ارائه دهد؟

بله. هندلر می‌تواند تصویر را به ذخیره‌سازی شیء بارگذاری کند یا به سرویس دیگری منتقل کند، URL حاصل را به $link[0] اختصاص دهد و true برگرداند. هندلر باید پردازش را به‌طور کامل خود انجام دهد؛ بازگرداندن true جلوگیری از ذخیره‌سازی محلی پیش‌فرض می‌کند.

چرا صادرات Markdown یک InvalidOperationException از یک هندلر پرتاب می‌کند؟

این استثنا زمانی رخ می‌دهد که هندلر true برگرداند اما لینک معتبری ارائه ندهد. قبل از برگرداندن true مسیر نسبی یا URL خارجی که باید در Markdown نوشته شود را به $link[0] اختصاص دهید.

کدام جداکنندهٔ مسیر باید در لینک‌های تصویر استفاده شود؟

در لینک‌های Markdown و URLها از اسلش‌های جلو (/) استفاده کنید. DIRECTORY_SEPARATOR فقط برای مسیرهای سیستم‌فایل به‌کار رود و سپس مرجع Markdown را به‌طور جداگانه ساخت یا نرمال کنید.

آیا پیوندهای ابرمتن در طول صادرات Markdown حفظ می‌شوند؟

بله. پیوندهای متنی hyperlinks به‌عنوان لینک‌های استاندارد Markdown حفظ می‌شوند. transitions اسلاید و animations تبدیل نمی‌شوند.

آیا می‌توان ارائه‌ها را به‌صورت هم‌زمان به Markdown تبدیل کرد؟

می‌توانید فایل‌های ارائه مختلف را به‌صورت هم‌زمان پردازش کنید، اما نباید همان نمونهٔ Presentation را بین رشته‌ها به اشتراک بگذارید. راهنمایی‌های multithreading را دنبال کنید و برای هر فایل یک نمونهٔ جداگانه استفاده کنید.