PPTX 中图表调整大小的可行解决方案

背景

已观察到,通过 Aspose 组件将 Excel 图表作为 OLE 对象嵌入 PowerPoint 幻灯片后,在首次激活后会被调整为未指定的比例。这种行为导致图表在激活前后在演示文稿中出现明显的视觉差异。Aspose 团队对该问题进行了详细调查并找到了解决方案。本文描述了问题的原因及相应的修复方法。

上一篇文章中,我们介绍了如何使用 Aspose.Cells for C++ 创建 Excel 图表并使用 Aspose.Slides for C++ 将其嵌入 PowerPoint 演示文稿。为了解决对象预览问题,我们将图表图像分配给图表的 OLE 对象帧。在输出的演示文稿中,当双击显示图表图像的 OLE 对象帧时,Excel 图表会被激活。最终用户可以在底层 Excel 工作簿中进行任意更改,然后通过单击激活的工作簿之外的区域返回相应幻灯片。用户返回幻灯片时,OLE 对象帧的大小会发生变化,且调整比例取决于 OLE 对象帧和嵌入的 Excel 工作簿原始大小的差异。

调整大小的原因

由于 Excel 工作簿拥有自己的窗口大小,它会尝试在首次激活时保留原始大小。而 OLE 对象帧也有其自身的尺寸。根据 Microsoft 的说明,当 Excel 工作簿被激活时,Excel 与 PowerPoint 会协商尺寸并在嵌入过程中保持正确的比例。由于 Excel 窗口大小与 OLE 对象帧的大小或位置存在差异,便会产生调整大小的现象。

可行的解决方案

使用 Aspose.Slides for C++ 创建 PowerPoint 演示文稿有两种可能的场景。

场景 1: 基于现有模板创建演示文稿。

场景 2: 从零开始创建演示文稿。

我们在此提供的解决方案适用于两种场景。所有解决方案的核心都是相同的:嵌入的 OLE 对象窗口大小应匹配 PowerPoint 幻灯片中的 OLE 对象帧。下面将讨论此解决方案的两种实现方式。

第一种方法

在此方法中,我们将学习如何设置嵌入的 Excel 工作簿窗口大小,使其与 PowerPoint 幻灯片中 OLE 对象帧的大小相匹配。

场景 1

假设我们已定义模板,想基于该模板创建演示文稿。设模板中索引为 2 的形状用于放置包含嵌入 Excel 工作簿的 OLE 帧。在此场景下,OLE 对象帧的大小是预定义的——与模板中索引为 2 的形状大小相同。我们只需将工作簿的窗口大小设为该形状的大小。以下代码片段实现此目的:

System::SharedPtr<System::IO::MemoryStream> ToSlidesMemoryStream(intrusive_ptr<Aspose::Cells::Systems::IO::MemoryStream> inputStream)
{
    auto outputBuffer = System::MakeArray<uint8_t>(inputStream->GetLength(), inputStream->GetBuffer()->ArrayPoint());
    auto outputStream = System::MakeObject<System::IO::MemoryStream>(outputBuffer);

    return outputStream;
}
// 使用窗口定义图表大小。 
chart->SetSizeWithWindow(true);

auto shape = slide->get_Shape(2);

// 设置工作簿的窗口宽度(单位为英寸),除以 72,因为 PowerPoint 使用每英寸 72 像素。
workbook->GetISettings()->SetWindowWidthInch(shape->get_Width() / 72.f);

// 设置工作簿的窗口高度(单位为英寸)。
workbook->GetISettings()->SetWindowHeightInch(shape->get_Height() / 72.f);

// 将工作簿保存到内存流。
System::SharedPtr<System::IO::MemoryStream> workbookStream = ToSlidesMemoryStream3(workbook->SaveToStream());

System::SharedPtr<IOleEmbeddedDataInfo> dataInfo = System::MakeObject<OleEmbeddedDataInfo>(workbookStream->ToArray(), u"xls");

// 使用嵌入的 Excel 数据创建 OLE 对象框架。
System::SharedPtr<IOleObjectFrame> oleFrame = slide->get_Shapes()->AddOleObjectFrame(
    shape->get_X(), 
    shape->get_Y(), 
    shape->get_Width(), 
    shape->get_Height(),
    dataInfo);

场景 2

假设我们想从零开始创建演示文稿,并在其中加入任意大小的 OLE 对象帧以及嵌入的 Excel 工作簿。以下代码片段在幻灯片上创建一个宽 9.5 英寸、高 4 英寸、左上坐标为 x = 0.5 英寸、y = 1 英寸的 OLE 对象帧。随后将 Excel 工作簿窗口设置为相同的大小——高 4 英寸、宽 9.5 英寸。

// 我们期望的高度。
int32_t desiredHeight = 288; // 4 英寸 (4 * 72)

// 我们期望的宽度。
int32_t desiredWidth = 684; // 9.5 英寸 (9.5 * 72)

// 使用窗口定义图表大小。 
chart->SetSizeWithWindow(true);

// 设置工作簿的窗口宽度(单位为英寸)。
workbook->GetISettings()->SetWindowWidthInch(desiredWidth / 72.f);

// 设置工作簿的窗口高度(单位为英寸)。
workbook->GetISettings()->SetWindowHeightInch(desiredHeight / 72.f);

// 将工作簿保存到内存流。
System::SharedPtr<System::IO::MemoryStream> workbookStream = ToSlidesMemoryStream(workbook->SaveToStream());

System::SharedPtr<IOleEmbeddedDataInfo> dataInfo = System::MakeObject<OleEmbeddedDataInfo>(workbookStream->ToArray(), u"xls");

// 使用嵌入的 Excel 数据创建 OLE 对象框架。
System::SharedPtr<IOleObjectFrame> oleFrame = slide->get_Shapes()->AddOleObjectFrame(
    36.0f,
    72.0f, 
    desiredWidth, 
    desiredHeight,
    dataInfo);

第二种方法

在此方法中,我们将学习如何将嵌入 Excel 工作簿中图表的大小设置为与 PowerPoint 幻灯片中 OLE 对象帧的大小相匹配。当图表大小事先已知且不会变化时,此方法尤为适用。

场景 1

同样假设我们已定义模板,想基于该模板创建演示文稿。设模板中索引为 2 的形状用于放置包含嵌入 Excel 工作簿的 OLE 帧。此时 OLE 帧大小已预定义——与该形状大小相同。我们只需将工作簿中图表的大小设为该形状的大小。以下代码片段实现此目的:

// 在没有窗口的情况下定义图表大小。 
chart->SetSizeWithWindow(false);

auto shape = slide->get_Shape(2);

// 以像素设置图表宽度(乘以 96,因为 Excel 每英寸使用 96 像素)。    
chart->GetIChartObject()->SetWidth((int32_t)(shape->get_Width() / 72.f * 96.f));

// 以像素设置图表高度。
chart->GetIChartObject()->SetHeight((int32_t)(shape->get_Height() / 72.f) * 96.f);

// 定义图表打印尺寸。
chart->SetPrintSize(Aspose::Cells::PrintSizeType::PrintSizeType_Custom);

// 将工作簿保存到内存流。
System::SharedPtr<System::IO::MemoryStream> workbookStream = ToSlidesMemoryStream(workbook->SaveToStream());

System::SharedPtr<IOleEmbeddedDataInfo> dataInfo = System::MakeObject<OleEmbeddedDataInfo>(workbookStream->ToArray(), u"xls");

// 使用嵌入的 Excel 数据创建 OLE 对象框架。
System::SharedPtr<IOleObjectFrame> oleFrame = slide->get_Shapes()->AddOleObjectFrame(
    shape->get_X(), 
    shape->get_Y(), 
    shape->get_Width(),
    shape->get_Height(),
    dataInfo);

场景 2

假设我们从零开始创建演示文稿,并在其中加入任意大小的 OLE 对象帧以及嵌入的 Excel 工作簿。以下代码片段在幻灯片上创建一个宽 9.5 英寸、高 4 英寸、左上坐标为 x = 0.5 英寸、y = 1 英寸的 OLE 对象帧,并将相应图表的大小设置为相同的尺寸:高 4 英寸、宽 9.5 英寸。

// 我们期望的高度。
int32_t desiredHeight = 288; // 4 英寸 (4 * 576)

// 我们期望的宽度。
int32_t desiredWidth = 684; // 9.5 英寸 (9.5 * 576)

// 在没有窗口的情况下定义图表大小。 
chart->SetSizeWithWindow(false);

// 以像素设置图表宽度。    
chart->GetIChartObject()->SetWidth((int32_t)((desiredWidth / 72.f) * 96.f));

// 以像素设置图表高度。
chart->GetIChartObject()->SetHeight((int32_t)((desiredHeight / 72.f) * 96.f));

// 将工作簿保存到内存流。
System::SharedPtr<System::IO::MemoryStream> workbookStream = ToSlidesMemoryStream(workbook->SaveToStream());

System::SharedPtr<IOleEmbeddedDataInfo> dataInfo = System::MakeObject<OleEmbeddedDataInfo>(workbookStream->ToArray(), u"xls");

// 使用嵌入的 Excel 数据创建 OLE 对象框架。
System::SharedPtr<IOleObjectFrame> oleFrame = slide->get_Shapes()->AddOleObjectFrame(
    36.0f, 
    72.0f, 
    desiredWidth, 
    desiredHeight,
    dataInfo);

结论

解决图表调整大小问题有两种方法。选择哪种方法取决于需求和使用场景。无论是基于模板创建演示文稿还是从头创建,两种方法的工作方式相同,并且对 OLE 对象帧的大小没有限制。

常见问答

为什么嵌入的 Excel 图表在 PowerPoint 中激活后会改变大小?

这是因为 Excel 在首次激活时尝试恢复原始窗口大小,而 PowerPoint 中的 OLE 对象帧拥有自己的尺寸。PowerPoint 与 Excel 会协商尺寸以保持宽高比,从而导致调整大小。

是否可以彻底防止此调整大小问题?

可以。通过在嵌入前将 Excel 工作簿窗口大小或图表大小匹配到 OLE 对象帧的尺寸,即可保持图表尺寸一致。

应该采用哪种方法:设置工作簿窗口大小还是设置图表大小?

如果希望保持工作簿的宽高比并可能以后进行调整,请使用方法 1(窗口大小)
如果图表尺寸固定且在嵌入后不会改变,请使用方法 2(图表大小)

这些方法是否适用于基于模板的演示文稿和全新创建的演示文稿?

是的。两种方法在基于模板创建和全新创建的演示文稿中均表现相同。

OLE 对象帧的大小是否有限制?

没有限制。只要 OLE 帧的尺寸能够适当地映射到工作簿或图表尺寸,即可设置为任意大小。

这些方法能否用于其他电子表格程序创建的图表?

示例针对使用 Aspose.Cells 创建的 Excel 图表,但原理同样适用于其他支持 OLE 的电子表格程序,只要它们提供类似的尺寸设置选项。

相关章节