ส่งออกงานนำเสนอเป็น XAML ใน C++

ภาพรวม

บทความนี้อธิบายวิธีการส่งออกงานนำเสนอ PowerPoint ไปเป็น XAML ด้วย Aspose.Slides รวมถึงการแนะนำสั้น ๆ เกี่ยวกับ XAML แสดงวิธีบันทึกงานนำเสนอเป็น XAML ด้วยการตั้งค่าเริ่มต้น และสาธิตวิธีปรับแต่งการส่งออกผ่าน XamlOptions, รวมถึงการส่งออกสไลด์ที่ซ่อนอยู่ บทความนี้ยังตอบคำถามทั่วไปบางข้อเกี่ยวกับฟอนต์สำรอง, ความเข้ากันได้ของสแตก XAML, และพฤติกรรมการส่งออกสไลด์ที่ซ่อนอยู่

เกี่ยวกับ XAML

XAML คือภาษามาร์กอัปแบบ XML ที่ใช้ในการอธิบายส่วนติดต่อผู้ใช้ในเฟรมเวิร์กต่าง ๆ เช่น WPF (Windows Presentation Foundation), UWP (Universal Windows Platform) และ Xamarin.Forms

คุณสามารถทำงานกับไฟล์ XAML ในตัวออกแบบแบบวิชวลหรือเขียนและแก้ไขมาร์กอัปโดยตรงได้

ส่งออกงานนำเสนอเป็น XAML ด้วยตัวเลือกเริ่มต้น

ตัวอย่าง C++ ด้านล่างแสดงวิธีการส่งออกงานนำเสนอเป็น XAML ด้วยการตั้งค่าเริ่มต้น:

#include <DOM/Presentation.h>
#include <Export/Xaml/XamlOptions.h>

using namespace Aspose::Slides;
using namespace Aspose::Slides::Export::Xaml;

auto presentation = System::MakeObject<Presentation>(u"pres.pptx");
auto xamlOptions = System::MakeObject<XamlOptions>();
presentation->Save(xamlOptions);

โดยค่าเริ่มต้น สไลด์ที่ส่งออกจะถูกบันทึกในโฟลเดอร์ย่อย pres ของไดเรกทอรีทำงานปัจจุบันของโปรเซส ซึ่งได้จาก Directory::GetCurrentDirectory โฟลเดอร์จะถูกสร้างโดยอัตโนมัติและรูปภาพที่ต้องการก็จะถูกบันทึกไว้ที่นั่นด้วย

ชื่อโฟลเดอร์ผลลัพธ์จะถูกกำหนดจากชื่อไฟล์ต้นทางโดยไม่มีส่วนต่อท้าย สำหรับไฟล์ pres.pptx ไฟล์ผลลัพธ์จะมีชื่อว่า pres/Slide_1.xaml, pres/Slide_2.xaml เป็นต้น แม้ว่าคุณจะระบุพาธแบบเต็มให้กับงานนำเข้า ผลลัพธ์ก็ยังสร้างโฟลเดอร์โดยสัมพันธ์กับไดเรกทอรีทำงานปัจจุบัน แทนที่จะสร้างคู่ข้างกับไฟล์ต้นทาง

ส่งออกงานนำเสนอเป็น XAML ด้วยตัวเลือกที่กำหนดเอง

ใช้อินเทอร์เฟซ IXamlOptions เพื่อควบคุมวิธีที่ Aspose.Slides ส่งออกงานนำเสนอเป็น XAML

เพื่อบันทึกผลลัพธ์ไปยังตำแหน่งที่กำหนดเอง ให้ดำเนินการสร้าง IXamlOutputSaver และส่งอ็อบเจกต์ที่คุณสร้างไปยังเมธอด set_OutputSaver ของ XamlOptions

เพื่อรวมสไลด์ที่ซ่อนอยู่ในผลลัพธ์ XAML ให้ส่งค่า true ไปยังเมธอด set_ExportHiddenSlides, ดังตัวอย่าง C++ ด้านล่าง:

#include <DOM/Presentation.h>
#include <Export/Xaml/XamlOptions.h>

using namespace Aspose::Slides;
using namespace Aspose::Slides::Export::Xaml;

auto presentation = System::MakeObject<Presentation>(u"pres.pptx");
auto xamlOptions = System::MakeObject<XamlOptions>();
xamlOptions->set_ExportHiddenSlides(true);
presentation->Save(xamlOptions);

จับทั้งหมดของศิลปวัตถุ XAML ที่สร้างขึ้น

การส่งออก XAML สามารถสร้างเอกสาร XAML สำหรับแต่ละสไลด์ที่ส่งออกพร้อมกับรูปภาพและทรัพยากรสนับสนุนแยกต่างหาก ส่งอ็อบเจกต์ IXamlOutputSaver ที่กำหนดเองไปยัง XamlOptions::set_OutputSaver เพื่อรับศิลปวัตถุเหล่านี้แทนการใช้ตัวบันทึกไฟล์ระบบเริ่มต้น เริ่มการส่งออกด้วยเมธอด overload ของ Presentation::Save ที่รับ XAML options โดยเฉพาะ

ทำความเข้าใจวงจรการเรียกกลับ (Callback Lifecycle)

ตัวส่งออกจะเรียก IXamlOutputSaver::Save แยกกันสำหรับศิลปวัตถุแต่ละรายการ:

  • path ระบุศิลปวัตถุและอาจรวมไดเรกทอรีสัมพันธ์ไว้ เก็บข้อมูลนี้ไว้เพราะ XAML อาจอ้างอิงทรัพยากรด้วยพาธสัมพันธ์
  • data มีไบต์ของศิลปวัตถุ รูปภาพและทรัพยากรไบนารีอื่น ๆ ไม่ควรถูกแปลงเป็นข้อความ
  • ตัวบันทึกต้องรับผิดชอบในการเก็บหรือทำให้ข้อมูลคงอยู่ก่อนคืนค่า ตัวอย่างจะคัดลอกอาเรย์ไบต์แต่ละอันไปยังหน่วยความจำของแอปพลิเคชัน
  • ถือว่าการส่งออกสำเร็จเท่านั้นเมื่อเมธอดบันทึกงานนำเสนอคืนค่าและทุกการเรียกกลับทำงานสำเร็จ อย่าปกปิดข้อผิดพลาดของการจัดเก็บหรือเริ่มการเขียนในแบ็กกราวด์ที่ไม่ได้ตรวจสอบ หากการคงถาวรเกิดขึ้นต่อมาควรรายงานความสำเร็จโดยรวมหลังจากขั้นตอนนั้นสำเร็จด้วย

เมธอด XamlOptions::set_ExportHiddenSlides ยังใช้กับตัวบันทึกที่กำหนดเองเช่นกัน การตั้งค่าเริ่มต้น false จะไม่รวมเอกสาร XAML ของสไลด์ที่ซ่อนอยู่ การตั้งค่าเป็น true จะรวมสไลด์เหล่านั้นและทรัพยากรที่จำเป็นสำหรับการส่งออก จำนวนทรัพยากรขึ้นอยู่กับงานนำเสนอ; อย่าสมมติว่าจะมีการเรียกกลับหนึ่งครั้งต่อสไลด์หรือเรียงลำดับการเรียกกลับแบบคงที่

ส่งออกไปยังหน่วยความจำและตรวจสอบศิลปวัตถุ

ตัวอย่างเต็มนี้โหลด pres.pptx, รวบรวมศิลปวัตถุทั้งหมดใน Dictionary<String, ArrayPtr<uint8_t», แล้วพิมพ์ชื่อ, ชนิด, และจำนวนไบต์ของแต่ละอัน คงชื่อที่ส่งมาครบถ้วน ชื่อซ้ำจะทำให้การรวบรวมล้มเหลวแทนการเขียนทับโดยเงียบ

#include <DOM/Presentation.h>
#include <Export/Xaml/IXamlOutputSaver.h>
#include <Export/Xaml/XamlOptions.h>
#include <system/array.h>
#include <system/collections/dictionary.h>
#include <system/console.h>
#include <system/string_comparer.h>
#include <system/io/path.h>
#include <system/text/encoding.h>

using namespace Aspose::Slides;
using namespace Aspose::Slides::Export::Xaml;
using namespace System;
using namespace System::Collections::Generic;
using namespace System::IO;
using namespace System::Text;

class InMemoryXamlExample
{
    class MemoryXamlSaver : public IXamlOutputSaver
    {
    public:
        using ArtifactDictionary = Dictionary<String, ArrayPtr<uint8_t>>;
        SharedPtr<ArtifactDictionary> Artifacts = MakeObject<ArtifactDictionary>(StringComparer::get_Ordinal());

        void Save(String path, ArrayPtr<uint8_t> data) override
        {
            auto retainedData = data->Clone();
            Artifacts->Add(path, retainedData);
        }
    };

public:
    static void Run()
    {
        auto saver = MakeObject<MemoryXamlSaver>();
        auto presentation = MakeObject<Presentation>(u"pres.pptx");
        auto options = MakeObject<XamlOptions>();
        options->set_OutputSaver(saver);
        options->set_ExportHiddenSlides(true);
        presentation->Save(options);

        auto inspectXamlText = false;
        for (const auto& artifact : saver->Artifacts)
        {
            auto extension = Path::GetExtension(artifact.get_Key()).ToLowerInvariant();
            auto isXaml = extension == u".xaml";
            auto isImage = extension == u".png" || extension == u".jpg" || extension == u".jpeg" || extension == u".gif" || extension == u".bmp" || extension == u".tif" || extension == u".tiff" || extension == u".svg";
            String kind = isXaml ? u"slide XAML" : isImage ? u"image" : u"supporting resource";
            Console::WriteLine(u"{0}: {1} bytes ({2})", artifact.get_Key(), artifact.get_Value()->get_Length(), kind);

            // ถอดรหัสเฉพาะ XAML เท่านั้น และเมื่อจำเป็นต้องตรวจสอบเป็นข้อความเท่านั้น
            if (isXaml && inspectXamlText)
            {
                auto markup = Encoding::get_UTF8()->GetString(artifact.get_Value());
                Console::WriteLine(markup);
            }
        }
    }
};

เรียก InMemoryXamlExample::Run จากแอปพลิเคชันของคุณ การตรวจสอบส่วนขยายเป็นประโยชน์สำหรับการตรวจสอบ; เก็บศิลปวัตถุทั้งหมดรวมถึงประเภททรัพยากรที่ไม่คุ้นเคย อย่าปลี่ยนแปลงไบต์เมื่อจัดเก็บหรือส่งต่อ ใช้ Encoding::GetString พร้อมการเข้ารหัส UTF-8 เฉพาะสำหรับ XAML ที่ต้องการการประมวลผลเป็นข้อความ

บรรจุศิลปวัตถุที่รวบรวมไว้ในไฟล์ ZIP

ตัวอย่างแยกนี้รวบรวมการส่งออก, ตรวจสอบชื่อ, และเขียนไบต์ต้นฉบับลงในไฟล์ ZIP ชื่อไฟล์ ZIP ที่ไม่ซ้ำกันจะแยกงานส่งออกที่ทำพร้อมกัน รายการใน ZIP ใช้สแลชแบบทแยงและคงไดเรกทอรีสัมพันธ์ ชื่อที่ไม่ปลอดภัยหรือชื่อที่ชนกันหลังการทำให้เป็นมาตรฐานจะทำให้แพคเกจทั้งหมดถูกปฏิเสธก่อนการเขียน

#include <DOM/Presentation.h>
#include <Export/Xaml/IXamlOutputSaver.h>
#include <Export/Xaml/XamlOptions.h>
#include <system/array.h>
#include <system/collections/dictionary.h>
#include <system/console.h>
#include <system/string_comparer.h>
#include <system/guid.h>
#include <system/io/file_access.h>
#include <system/io/file_mode.h>
#include <system/io/file_stream.h>
#include <system/io/path.h>
#include <zip/zip_file.h>

using namespace Aspose::Slides;
using namespace Aspose::Slides::Export::Xaml;
using namespace System;
using namespace System::Collections::Generic;
using namespace System::IO;
using namespace Aspose::Zip;

class ZipXamlExample
{
    class CollectedXamlSaver : public IXamlOutputSaver
    {
    public:
        using ArtifactDictionary = Dictionary<String, ArrayPtr<uint8_t>>;
        SharedPtr<ArtifactDictionary> Artifacts = MakeObject<ArtifactDictionary>(StringComparer::get_Ordinal());

        void Save(String path, ArrayPtr<uint8_t> data) override
        {
            auto retainedData = data->Clone();
            Artifacts->Add(path, retainedData);
        }
    };

public:
    static void Run()
    {
        auto saver = MakeObject<CollectedXamlSaver>();
        auto presentation = MakeObject<Presentation>(u"pres.pptx");
        auto options = MakeObject<XamlOptions>();
        options->set_OutputSaver(saver);
        options->set_ExportHiddenSlides(false);
        presentation->Save(options);

        auto entries = MakeObject<Dictionary<String, ArrayPtr<uint8_t>>>(StringComparer::get_OrdinalIgnoreCase());
        for (const auto& artifact : saver->Artifacts)
        {
            auto entryName = artifact.get_Key().Replace(u'\\', u'/');
            auto segments = entryName.Split(u'/');
            auto unsafeName = entryName.StartsWith(u"/", StringComparison::Ordinal) || entryName.Contains(u":");
            for (const auto& segment : segments)
            {
                unsafeName |= String::IsNullOrWhiteSpace(segment) || segment == u"." || segment == u"..";
            }

            if (unsafeName || entries->ContainsKey(entryName))
            {
                Console::WriteLine(u"Export rejected: unsafe or duplicate artifact name: {0}", artifact.get_Key());
                return;
            }
            entries->Add(entryName, artifact.get_Value());
        }

        auto jobId = Guid::NewGuid();
        auto archivePath = u"xaml-" + jobId.ToString(u"N") + u".zip";
        auto archive = MakeObject<ZipFile>();
        for (const auto& artifact : entries)
        {
            auto fileName = Path::GetFileName(artifact.get_Key());
            auto directoryName = Path::GetDirectoryName(artifact.get_Key()).Replace(u'\\', u'/');
            archive->AddEntry(fileName, directoryName, artifact.get_Value());
        }

        auto output = MakeObject<FileStream>(archivePath, FileMode::CreateNew, FileAccess::Write);
        archive->Save(output);
        output->Close();
        archive->Dispose();

        // การบันทึกจะสรุปไดเรกทอรี ZIP; ปิดไฟล์ก่อนรายงานความสำเร็จ.
        Console::WriteLine(u"Saved {0} artifacts to {1}", entries->get_Count(), archivePath);
    }
};

เรียก ZipXamlExample::Run จากแอปพลิเคชันของคุณ ตัวอย่างใช้ Aspose::Zip::ZipFile จากไลบรารีรันไทม์ C++ เพื่อเขียนไฟล์ ZIP หนึ่งไฟล์; ตัวส่งออกเองจะไม่เขียนไฟล์ XAML หรือรูปภาพแยกออกมา สำหรับการจัดเก็บระยะไกล ให้แทนที่ขั้นตอนการเขียน ZIP ด้วยการอัปโหลดอาเรย์ไบต์ที่รวบรวมไว้ ใช้ตัวระบุงานส่งออกบวกกับชื่อศิลปวัตถุสัมพันธ์เต็มเป็นคีย์บลบ, หรือเก็บตัวระบุงาน, ชื่อสัมพันธ์, และข้อมูลไบนารีในแถวฐานข้อมูล เผยแพร่งานหลังจากการอัปโหลดทั้งหมดเสร็จหรือการทำธุรกรรมฐานข้อมูลคอมมิทแล้ว ทำความสะอาดเอาต์พุตบางส่วนหากการคงถาวรล้มเหลว

สำหรับงานนำเสนอขนาดใหญ่ ตัวบันทึกที่กำหนดเองสามารถคงถาวรศิลปวัตถุแต่ละอันโดยตรงไปยังที่เก็บของแอปพลิเคชันเพื่อหลีกเลี่ยงการเก็บสำเนาเพิ่มเติมของการส่งออกทั้งหมดในหน่วยความจำของแอป ตัวส่งออกยังคงรวบรวมศิลปวัตถุทั้งหมดในหน่วยความจำก่อนเรียกตัวบันทึก ให้การเรียกกลับแต่ละครั้งทำงานแบบซิงโครนัสจากมุมมองของตัวส่งออก: คืนค่าเฉพาะหลังจากปลายทางยอมรับไบต์และให้ความล้มเหลวถึงผู้เรียก

คงชื่อทรัพยากรและตรวจสอบการอ้างอิง

  • ปรับรูปแบบเครื่องหมายคั่นพาธเมื่อปลายทางต้องการ แต่ให้คงไดเรกทอรีสัมพันธ์ อย่าใช้เฉพาะ Path::GetFileName ถ้าหากชื่อที่สร้างทั้งหมดเป็นเอกลักษณ์และการอ้างอิงทรัพยากรยังคงถูกต้อง
  • ใช้การตรวจสอบชื่อเฉพาะปลายทาง เมื่อเขียนไฟล์แยก ให้ปฏิเสธพาธที่เริ่มต้นด้วยรากและส่วนที่เจาะจงการเดินทาง, แก้ไขปลายทางด้วย Path::GetFullPath, และตรวจสอบให้แน่ใจว่ายังคงอยู่ภายใต้ไดเรกทอรีส่งออกที่ตั้งใจไว้, รวมเครื่องหมายคั่นไดเรกทอรีในการตรวจสอบ containment ใช้ไดเรกทอรีที่ควบคุมโดยแอปพลิเคชันโดยไม่มีลิงก์สัญลักษณ์ที่อาจเปลี่ยนเส้นทางการเขียน
  • ใช้ตัวบันทึกและเนมสเปซการจัดเก็บแยกสำหรับแต่ละงานส่งออก ตรวจจับการชนกันหลังจากทำให้เครื่องหมายคั่นเป็นมาตรฐานและตามกฎการพิจารณาเคสของปลายทาง
  • ก่อนการเผยแพร่ ให้พาร์สเอกสาร XAML แต่ละไฟล์เป็น XML และตรวจสอบการอ้างอิงทรัพยากรบนไฟล์ เช่น แอตทริบิวต์ Source หรือ ImageSource ของรูปภาพ แก้ไข URI สัมพัทธ์แต่ละรายการเทียบกับไดเรกทอรีของศิลปวัตถุ XAML ที่เกี่ยวข้อง, ทำให้ชื่อการจัดเก็บที่ได้เป็นมาตรฐาน, และยืนยันว่าคีย์ในดิกชันนารี, รายการ ZIP, หรือวัตถุที่เก็บนั้นมีอยู่ พิจารณา URI ภายนอกและนิพจน์มาร์กอัป XAML แยกต่างหากจากชื่อไฟล์สัมพันธ์

ตัวอย่างเช่น ถ้า pres/Slide_1.xaml อ้างอิง images/image1.png, ทรัพยากรที่เก็บต้องมีอยู่ที่ pres/images/image1.png. การเก็บแค่ image1.png เพียงอย่างเดียวจะทำให้ความสัมพันธ์นี้ขัดแย้ง สำหรับการจัดเก็บในวัตถุ, คงโครงสร้างเดียวกันใต้คีย์งานและทำให้ URL ของทรัพยากรเหล่านั้นเข้าถึงได้สำหรับผู้ใช้ XAML เปิดไฟล์ ZIP ที่เสร็จแล้วเพื่อตรวจสอบชื่อรายการและไบต์ของทรัพยากร, แล้วโหลดสไลด์ตัวอย่างในสภาพแวดล้อม XAML ปลายทางเพื่อยืนยันว่ารูปภาพถูก resolve อย่างถูกต้อง

คำถามที่พบบ่อย

ทำอย่างไรจึงจะรับประกันฟอนต์ที่คาดเดาได้เมื่อตัวฟอนต์ต้นฉบับไม่มีในเครื่อง?

ใช้เมธอด set_DefaultRegularFont ใน XamlOptions — มันจะทำหน้าที่เป็นฟอนต์สำรองระหว่างการส่งออกเมื่อฟอนต์ต้นฉบับหายไป อย่างไรก็ตาม ไม่ได้รับประกันว่า XAML ที่สร้างจะอ้างอิงฟอนต์สำรองหรือว่าฟอนต์จะมีอยู่ในเครื่องปลายทาง ตรวจสอบให้แน่ใจว่าฟอนต์ที่ XAML อ้างอิงพร้อมใช้งานในสภาพแวดล้อมที่จะแสดงผล

XAML ที่ส่งออกออกแบบมาสำหรับ WPF เท่านั้นหรือสามารถใช้ได้กับสแตก XAML อื่นได้ด้วยหรือไม่?

Aspose.Slides ส่งออก XAML ของ WPF ผ่าน API สาธารณะของมัน ความเข้ากันได้กับสแตก XAML อื่น เช่น UWP และ Xamarin.Forms ไม่ได้รับประกัน ควรทดสอบมาร์กอัปที่สร้างในสภาพแวดล้อมเป้าหมายของคุณ

สไลด์ที่ซ่อนอยู่ได้รับการสนับสนุนหรือไม่, และจะป้องกันไม่ให้ส่งออกโดยค่าเริ่มต้นได้อย่างไร?

โดยค่าเริ่มต้น สไลด์ที่ซ่อนอยู่จะไม่ถูกรวม คุณสามารถควบคุมพฤติกรรมนี้ได้ผ่านเมธอด set_ExportHiddenSlides ใน XamlOptions — ปิดการใช้งานเมธอดนี้หากคุณไม่ต้องการส่งออกสไลด์ที่ซ่อนอยู่