gpt4 book ai didi

c# - 将 OLE 对象从一张幻灯片复制到另一张幻灯片会损坏生成的 PowerPoint

转载 作者:行者123 更新时间:2023-12-03 17:20:04 25 4
gpt4 key购买 nike

我有将一张 PowerPoint 幻灯片的内容复制到另一张幻灯片的代码。下面是如何处理图像的示例。

foreach (OpenXmlElement element in sourceSlide.CommonSlideData.ShapeTree.ChildElements.ToList())
{
string elementType = element.GetType().ToString();

if (elementType.EndsWith(".Picture"))
{
// Deep clone the element.
elementClone = element.CloneNode(true);
var picture = (Picture)elementClone;

// Get the picture's original rId
var blip = picture.BlipFill.Blip;
string rId = blip.Embed.Value;

// Retrieve the ImagePart from the original slide by rId
ImagePart sourceImagePart = (ImagePart)sourceSlide.SlidePart.GetPartById(rId);

// Add the image part to the new slide, letting OpenXml generate the new rId
ImagePart targetImagePart = targetSlidePart.AddImagePart(sourceImagePart.ContentType);

// And copy the image data.
targetImagePart.FeedData(sourceImagePart.GetStream());

// Retrieve the new ID from the target image part,
string id = targetSlidePart.GetIdOfPart(targetImagePart);

// and assign it to the picture.
blip.Embed.Value = id;

// Get the shape tree that we're adding the clone to and append to it.
ShapeTree shapeTree = targetSlide.CommonSlideData.ShapeTree;
shapeTree.Append(elementClone);
}
这段代码工作正常。对于像Graphic Frames这样的其他场景,它看起来有点不同,因为每个Graphic Frames可以包含多个图片对象。
// Go thru all the Picture objects in this GraphicFrame.
foreach (var sourcePicture in element.Descendants<Picture>())
{
string rId = sourcePicture.BlipFill.Blip.Embed.Value;
ImagePart sourceImagePart = (ImagePart)sourceSlide.SlidePart.GetPartById(rId);
var contentType = sourceImagePart.ContentType;

var targetPicture = elementClone.Descendants<Picture>().First(x => x.BlipFill.Blip.Embed.Value == rId);
var targetBlip = targetPicture.BlipFill.Blip;

ImagePart targetImagePart = targetSlidePart.AddImagePart(contentType);
targetImagePart.FeedData(sourceImagePart.GetStream());
string id = targetSlidePart.GetIdOfPart(targetImagePart);
targetBlip.Embed.Value = id;
}
现在我需要对 OLE 对象做同样的事情。
// Go thru all the embedded objects in this GraphicFrame.
foreach (var oleObject in element.Descendants<OleObject>())
{
// Get the rId of the embedded OLE object.
string rId = oleObject.Id;

// Get the EmbeddedPart from the source slide.
var embeddedOleObj = sourceSlide.SlidePart.GetPartById(rId);

// Get the content type.
var contentType = embeddedOleObj.ContentType;

// Create the Target Part. Let OpenXML assign an rId.
var targetObjectPart = targetSlide.SlidePart.AddNewPart<EmbeddedObjectPart>(contentType, null);

// Get the embedded OLE object data from the original object.
var objectStream = embeddedOleObj.GetStream();

// And give it to the ObjectPart.
targetObjectPart.FeedData(objectStream);

// Get the new rId and assign it to the OLE Object.
string id = targetSlidePart.GetIdOfPart(targetObjectPart);
oleObject.Id = id;
}
但它没有用。生成的 PowerPoint 已损坏。
我究竟做错了什么?

注意:除了 rId 之外的所有代码都有效在 OLE 对象中处理。我知道它有效,因为如果我只是通过原始 rId从源对象到目标对象部分,像这样:
var targetObjectPart = targetSlide.SlidePart
.AddNewPart<EmbeddedObjectPart>(contentType, rId);
只要 rId,它就会正常运行目标幻灯片中尚不存在,这显然不会像我需要的那样每次都起作用。
源幻灯片和目标幻灯片来自不同的 PPTX 文件。我们使用的是 OpenXML,而不是 Office Interop。

最佳答案

由于您没有提供完整的代码,因此很难判断出了什么问题。
我的猜测是您没有修改正确的对象。
在您的图片代码示例中,您正在创建和修改 elementClone .
在 ole 对象的代码示例中,您正在使用和修改 oleObject (它是 element 的后代)并且从上下文中不清楚它是源文档的一部分还是目标文档的一部分。

你可以试试这个最小的例子:

  • c:\testdata\input.pptx 使用带有一个嵌入 ole 对象的新 pptx
  • c:\testdata\output.pptx 使用新的 pptx(空白)

  • 运行代码后,我能够在输出文档中打开嵌入的 ole 对象。
    using DocumentFormat.OpenXml.Presentation;
    using DocumentFormat.OpenXml.Packaging;
    using System.Linq;

    namespace ooxml
    {
    class Program
    {
    static void Main(string[] args)
    {
    CopyOle("c:\\testdata\\input.pptx", "c:\\testdata\\output.pptx");
    }

    private static void CopyOle(string inputFile, string outputFile)
    {
    using (PresentationDocument sourceDocument = PresentationDocument.Open(inputFile, true))
    {
    using (PresentationDocument targetDocument = PresentationDocument.Open(outputFile, true))
    {
    var sourceSlidePart = sourceDocument.PresentationPart.SlideParts.First();
    var targetSlidePart = targetDocument.PresentationPart.SlideParts.First();


    foreach (var element in sourceSlidePart.Slide.CommonSlideData.ShapeTree.ChildElements)
    {
    //clones an element, does not copy the actual relationship target (e.g. ppt\embeddings\oleObject1.bin)
    var elementClone = element.CloneNode(true);

    //for each cloned OleObject, fix its relationship
    foreach(var clonedOleObject in elementClone.Descendants<OleObject>())
    {
    //find the original EmbeddedObjectPart in the source document
    //(we can use the id from the clonedOleObject to do that, since it contained the same id
    // as the source ole object)
    var sourceObjectPart = sourceSlidePart.GetPartById(clonedOleObject.Id);

    //create a new EmbeddedObjectPart in the target document and copy the data from the original EmbeddedObjectPart
    var targetObjectPart = targetSlidePart.AddEmbeddedObjectPart(sourceObjectPart.ContentType);
    targetObjectPart.FeedData(sourceObjectPart.GetStream());

    //update the relationship target on the clonedOleObject to point to the newly created EmbeddedObjectPath
    clonedOleObject.Id = targetSlidePart.GetIdOfPart(targetObjectPart);
    }

    //add cloned element to the document
    targetSlidePart.Slide.CommonSlideData.ShapeTree.Append(elementClone);
    }
    targetDocument.PresentationPart.Presentation.Save();
    }
    }
    }
    }
    }

    至于故障排除, OOXML Tools chrome 扩展很有帮助。
    它允许比较两个文档的结构,因此更容易分析出了什么问题。
    例子:
  • 如果您只克隆所有元素,您会看到/ppt/embeddings/* 和/ppt/media/* 将丢失
    enter image description here
  • 或者您可以检查关系是否正确(例如,输入文档使用“rId1”来引用嵌入数据,而输出文档使用“R3a2fa0c37eaa42b5”)
    enter image description here
    enter image description here
  • 关于c# - 将 OLE 对象从一张幻灯片复制到另一张幻灯片会损坏生成的 PowerPoint,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63675627/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com