工作表尺寸调整的可行解决方案

背景

在文章管理 OLE中,我们解释了如何使用 Aspose.Slides for PHP via Java 向 PowerPoint 演示文稿添加 OLE 帧。为了解决对象预览问题,我们为 OLE 对象帧分配了所选工作表区域的图像。在输出的演示文稿中,当您双击显示工作表图像的 OLE 对象帧时,Excel 工作簿将被激活。最终用户可以对实际的 Excel 工作簿进行任何所需的更改,然后通过点击激活的 Excel 工作簿之外的区域返回幻灯片。用户返回幻灯片时,OLE 对象帧的大小会发生变化。调整大小的因素取决于 OLE 对象帧的大小以及嵌入的 Excel 工作簿的大小。

尺寸调整的原因

由于 Excel 工作簿拥有自己的窗口大小,它在首次激活时会尝试保持原始大小。另一方面,OLE 对象帧也有自己的尺寸。根据 Microsoft 的说法,当 Excel 工作簿被激活时,Excel 和 PowerPoint 会协商尺寸,以确保在嵌入过程中保持正确的比例。尺寸调整是基于 Excel 窗口大小与 OLE 对象帧的大小和位置之间的差异而发生的。

可行的解决方案

有两种可能的解决方案可避免尺寸调整效果。

  • 在 PowerPoint 演示文稿中缩放 OLE 框,使其匹配所选行和列的总高度和宽度。
  • 保持 OLE 框大小不变,并缩放所选的行和列以适应框内。

缩放 OLE 框大小

此方法将 OLE 框的大小设置为匹配嵌入的 Excel 工作表中所选行和列的总高度和宽度。

示例加载现有的 Excel 工作簿,并使用从零开始的索引选择其第一个工作表的前 10 行和 13 列。WorksheetCollection::setOleSize定义显示的范围。预览以 96 DPI 渲染,其像素尺寸使用每英寸 72 点转换为点数。ShapeCollection::addOleObjectFrame将修改后的工作簿嵌入具有这些尺寸的框中。预览通过OleObjectFrame::getSubstitutePictureFormat分配,以替换已保存演示文稿中的“EMBEDDED OLE OBJECT”占位符。

use aspose\cells\SaveFormat as CellsSaveFormat;
use aspose\cells\Workbook;
use aspose\slides\Images;
use aspose\slides\OleEmbeddedDataInfo;
use aspose\slides\Presentation;
use aspose\slides\SaveFormat;
use Java as JavaObject;

$workbook = new Workbook("sample.xlsx");
try {
    $worksheet = $workbook->getWorksheets()->get(0);
    $startRow = 0;
    $rowCount = 10;
    $startColumn = 0;
    $columnCount = 13;
    $lastRow = $startRow + $rowCount - 1;
    $lastColumn = $startColumn + $columnCount - 1;
    $workbook->getWorksheets()->setOleSize($startRow, $lastRow, $startColumn, $lastColumn);
    $cellRange = $worksheet->getCells()->createRange($startRow, $startColumn, $rowCount, $columnCount);

    $imageResolution = 96;
    $imageStream = CreateOleImage($cellRange, $imageResolution);

    // 嵌入修改后的工作簿并将二进制数据保存在 Java 字节数组中。
    $workbookStream = new JavaObject("java.io.ByteArrayOutputStream");
    $workbook->save($workbookStream, CellsSaveFormat::XLSX);
    $workbookBytes = $workbookStream->toByteArray();
    $image = Images::fromStream($imageStream);
    try {
        $frameWidth = java_values($image->getWidth()) * 72.0 / $imageResolution;
        $frameHeight = java_values($image->getHeight()) * 72.0 / $imageResolution;
        $presentation = new Presentation();
        try {
            $slide = $presentation->getSlides()->get_Item(0);
            $dataInfo = new OleEmbeddedDataInfo($workbookBytes, "xlsx");
            $oleFrame = $slide->getShapes()->addOleObjectFrame(10, 10, $frameWidth, $frameHeight, $dataInfo);
            $previewImage = $presentation->getImages()->addImage($image);
            $oleFrame->getSubstitutePictureFormat()->getPicture()->setImage($previewImage);
            $oleFrame->setObjectIcon(false);
            $presentation->save("output.pptx", SaveFormat::Pptx);
        } finally {
            $presentation->dispose();
        }
    } finally {
        $image->dispose();
        $imageStream->close();
    }
} finally {
    $workbook->dispose();
}

预览助手将PageSetup::setPrintArea设置为所选范围,并移除页边距、页眉和页脚。启用ImageOrPrintOptions::setOnlyArea后,SheetRender::toImage将范围渲染为 PNG 图像。该助手返回一个包含 PNG 图像的新输入流,流指针位于开头,以供演示文稿使用。

use aspose\cells\ImageOrPrintOptions;
use aspose\cells\ImageType;
use aspose\cells\SheetRender;
use Java as JavaObject;

function CreateOleImage($cellRange, $imageResolution) {
    $pageSetup = $cellRange->getWorksheet()->getPageSetup();
    $pageSetup->setPrintArea($cellRange->getAddress());
    $pageSetup->setLeftMargin(0);
    $pageSetup->setRightMargin(0);
    $pageSetup->setTopMargin(0);
    $pageSetup->setBottomMargin(0);
    $pageSetup->clearHeaderFooter();

    $imageOptions = new ImageOrPrintOptions();
    $imageOptions->setImageType(ImageType::PNG);
    $imageOptions->setVerticalResolution($imageResolution);
    $imageOptions->setHorizontalResolution($imageResolution);
    $imageOptions->setOnePagePerSheet(true);
    $imageOptions->setOnlyArea(true);

    $worksheet = $cellRange->getWorksheet();
    $sheetRender = new SheetRender($worksheet, $imageOptions);
    $imageStream = new JavaObject("java.io.ByteArrayOutputStream");
    $sheetRender->toImage(0, $imageStream);
    $imageBytes = $imageStream->toByteArray();
    return new JavaObject("java.io.ByteArrayInputStream", $imageBytes);
}

缩放单元格范围大小

此方法将所选行的高度和所选列的宽度进行缩放,以匹配自定义的 OLE 框大小。

示例加载现有的 Excel 工作簿,并使用从零开始的索引选择其第一个工作表的前 10 行和 13 列。WorksheetCollection::setOleSize定义显示的范围,下面的助手将该范围缩放以适应宽 400 点、高 100 点的框。将修改后的工作簿保存到流后,ShapeCollection::addOleObjectFrame按指定大小嵌入其中。通过OleObjectFrame::getSubstitutePictureFormat分配的 96 DPI 渲染的预览,使已保存的演示文稿显示所选单元格而不是默认占位符。

use aspose\cells\SaveFormat as CellsSaveFormat;
use aspose\cells\Workbook;
use aspose\slides\Images;
use aspose\slides\OleEmbeddedDataInfo;
use aspose\slides\Presentation;
use aspose\slides\SaveFormat;
use Java as JavaObject;

$workbook = new Workbook("sample.xlsx");
try {
    $worksheet = $workbook->getWorksheets()->get(0);
    $startRow = 0;
    $rowCount = 10;
    $startColumn = 0;
    $columnCount = 13;
    $lastRow = $startRow + $rowCount - 1;
    $lastColumn = $startColumn + $columnCount - 1;
    $workbook->getWorksheets()->setOleSize($startRow, $lastRow, $startColumn, $lastColumn);
    $cellRange = $worksheet->getCells()->createRange($startRow, $startColumn, $rowCount, $columnCount);
    $frameWidth = 400;
    $frameHeight = 100;
    ScaleCellRange($cellRange, $frameWidth, $frameHeight);

    $imageResolution = 96;
    $imageStream = CreateOleImage($cellRange, $imageResolution);

    // 嵌入修改后的工作簿并将二进制数据保存在 Java 字节数组中。
    $workbookStream = new JavaObject("java.io.ByteArrayOutputStream");
    $workbook->save($workbookStream, CellsSaveFormat::XLSX);
    $workbookBytes = $workbookStream->toByteArray();
    $image = Images::fromStream($imageStream);
    try {
        $presentation = new Presentation();
        try {
            $slide = $presentation->getSlides()->get_Item(0);
            $dataInfo = new OleEmbeddedDataInfo($workbookBytes, "xlsx");
            $oleFrame = $slide->getShapes()->addOleObjectFrame(10, 10, $frameWidth, $frameHeight, $dataInfo);
            $previewImage = $presentation->getImages()->addImage($image);
            $oleFrame->getSubstitutePictureFormat()->getPicture()->setImage($previewImage);
            $oleFrame->setObjectIcon(false);
            $presentation->save("output.pptx", SaveFormat::Pptx);
        } finally {
            $presentation->dispose();
        }
    } finally {
        $image->dispose();
        $imageStream->close();
    }
} finally {
    $workbook->dispose();
}

缩放助手为所选范围计算单独的宽度和高度比例,保持列的相对宽度和行的相对高度。在使用Cells::setColumnWidthInch和Cells::setRowHeightInch应用之前,它先将计算得到的尺寸从点转换为英寸。所选范围的宽度和高度必须非零。

use aspose\cells\CellsUnitType;

// 宽度和高度是单元格范围的预期尺寸(单位:点)。
function ScaleCellRange($cellRange, $width, $height) {
    $rangeWidth = java_values($cellRange->getWidth());
    $rangeHeight = java_values($cellRange->getHeight());
    $cells = $cellRange->getWorksheet()->getCells();
    $columnCount = java_values($cellRange->getColumnCount());
    $rowCount = java_values($cellRange->getRowCount());
    $firstColumn = java_values($cellRange->getFirstColumn());
    $firstRow = java_values($cellRange->getFirstRow());

    for ($i = 0; $i < $columnCount; $i++) {
        $columnIndex = $firstColumn + $i;
        $columnWidth = java_values($cells->getColumnWidth($columnIndex, false, CellsUnitType::POINT));
        $newColumnWidth = $columnWidth * $width / $rangeWidth;
        $widthInInches = $newColumnWidth / 72.0;
        $cells->setColumnWidthInch($columnIndex, $widthInInches);
    }

    for ($i = 0; $i < $rowCount; $i++) {
        $rowIndex = $firstRow + $i;
        $rowHeight = java_values($cells->getRowHeight($rowIndex, false, CellsUnitType::POINT));
        $newRowHeight = $rowHeight * $height / $rangeHeight;
        $heightInInches = $newRowHeight / 72.0;
        $cells->setRowHeightInch($rowIndex, $heightInInches);
    }
}

此预览助手使用SheetRender::toImage渲染调整大小后的范围。它将PageSetup::setPrintArea限制于该范围,移除页边距、页眉和页脚,并返回一个指向开头的 PNG 流。

use aspose\cells\ImageOrPrintOptions;
use aspose\cells\ImageType;
use aspose\cells\SheetRender;
use Java as JavaObject;

function CreateOleImage($cellRange, $imageResolution) {
    $pageSetup = $cellRange->getWorksheet()->getPageSetup();
    $pageSetup->setPrintArea($cellRange->getAddress());
    $pageSetup->setLeftMargin(0);
    $pageSetup->setRightMargin(0);
    $pageSetup->setTopMargin(0);
    $pageSetup->setBottomMargin(0);
    $pageSetup->clearHeaderFooter();

    $imageOptions = new ImageOrPrintOptions();
    $imageOptions->setImageType(ImageType::PNG);
    $imageOptions->setVerticalResolution($imageResolution);
    $imageOptions->setHorizontalResolution($imageResolution);
    $imageOptions->setOnePagePerSheet(true);
    $imageOptions->setOnlyArea(true);

    $worksheet = $cellRange->getWorksheet();
    $sheetRender = new SheetRender($worksheet, $imageOptions);
    $imageStream = new JavaObject("java.io.ByteArrayOutputStream");
    $sheetRender->toImage(0, $imageStream);
    $imageBytes = $imageStream->toByteArray();
    return new JavaObject("java.io.ByteArrayInputStream", $imageBytes);
}

结论

常见问题

为什么嵌入的 Excel 工作表在 PowerPoint 中首次激活时会改变大小?

因为 Excel 在激活时尝试保持原始窗口大小,而 PowerPoint 中的 OLE 对象框有其自身的尺寸。PowerPoint 与 Excel 协商尺寸以保持纵横比,这可能导致尺寸调整。

是否可以完全防止此尺寸调整问题?

可以。通过将 OLE 框缩放以匹配 Excel 单元格范围的大小,或将单元格范围缩放以适应所需的 OLE 框大小,您可以防止不必要的尺寸调整。

我应该使用哪种缩放方法,OLE 框缩放还是单元格范围缩放?

如果您希望保持原始的 Excel 行和列大小,请选择OLE 框缩放。如果您希望在演示文稿中 OLE 框保持固定尺寸,请选择单元格范围缩放。

如果我的演示文稿基于模板,这些解决方案是否有效?

是的。这两种解决方案都适用于基于模板创建的演示文稿以及从头创建的演示文稿。

使用这些方法时 OLE 框的大小是否有限制?

没有。只要适当设置缩放比例,OLE 对象框可以任意大小。

是否有办法避免 PowerPoint 中的“EMBEDDED OLE OBJECT”占位符文本?

可以。通过对目标 Excel 单元格范围进行快照并将其设为 OLE 框的占位图像,您可以用自定义预览图像替代默认占位符。

相关文章

创建 Excel 图表并将其作为 OLE 对象嵌入演示文稿

使用 MS PowerPoint 加载项自动更新 OLE 对象