简体   繁体   English

OpenXml图像关系不存在

[英]OpenXml image relationship doesn't exist

I'm an intern at a large company who got tasked with working on a previous intern's project that apparently worked at some point, but now it's broken. 我是一家大公司的实习生,他的任务是从事以前的实习生项目,该项目显然在某个时候可以工作,但现在已经坏了。 What the program does, is it takes a bunch of text and images out of a document and inserts them into a template document. 该程序的作用是从文档中取出一堆文本和图像,然后将它们插入模板文档中。 The problem is, about half of the images aren't forming relationships and I'm getting the red X "Image cannot be displayed" empty box. 问题是,大约一半的图像没有形成关联,我得到了红色的X“图像无法显示”空白框。 I've been doing some digging with the productivity tool, and I found out that there are a couple duplicate IDs, as well as quite a few non-existent relationships, although looking at his code I'm not sure what might be causing that. 我一直在使用生产力工具进行一些挖掘,发现有几个重复的ID,以及相当多的不存在的关系,尽管查看他的代码,我不确定是什么原因导致的。 Here are his 2 methods for copying images: 这是他的两种复制图像的方法:

internal static void CopyImages(OpenXmlElement oldTable, OpenXmlElement newTable,
        WordprocessingDocument testData, WordprocessingDocument testReport)
    {
        List<Blip> sourceBlips = DocumentHelper.GetAllBlips(oldTable);
        List<Blip> targetBlips = DocumentHelper.GetAllBlips(newTable);

        foreach (Blip sourceBlip in sourceBlips)
        {
            foreach (Blip targetBlip in targetBlips)
            {
                if (targetBlip.Embed.Value == sourceBlip.Embed.Value)
                {
                    if (testData.MainDocumentPart.GetPartById(sourceBlip.Embed.Value) is ImagePart imagePart)
                    {
                        ImagePart newImagePart = testReport.MainDocumentPart.AddPart(imagePart);

                        targetBlip.Embed.Value = testReport.MainDocumentPart.GetIdOfPart(newImagePart);
                        break;
                    }
                }
            }
        }
    }

    internal static void CopyEmbeddedVisioImages(OpenXmlElement oldTable, OpenXmlElement newTable,
        WordprocessingDocument testData, WordprocessingDocument testReport)
    {
        List<EmbeddedObject> sourceObjects = oldTable.Descendants<EmbeddedObject>().ToList();
        List<EmbeddedObject> targetObjects = newTable.Descendants<EmbeddedObject>().ToList();

        foreach (EmbeddedObject targetobj in targetObjects)
        {
            foreach (EmbeddedObject sourceObj in sourceObjects)
            {
                if (testData.MainDocumentPart.GetPartById(sourceObj.Descendants<ImageData>()
                                .FirstOrDefault().RelationshipId) is ImagePart oldImagePart)
                {
                    ImagePart newImagePart = testReport.MainDocumentPart.AddPart(oldImagePart);

                    targetobj.Descendants<ImageData>().FirstOrDefault().RelationshipId =
                    testReport.MainDocumentPart.GetIdOfPart(newImagePart);
                }


                if (testData.MainDocumentPart.GetPartById(sourceObj.Descendants<OleObject>()
                                .FirstOrDefault().Id) is OpenXmlPart openXmlPart)
                {
                    EmbeddedObjectPart newEmbeddedObj = (EmbeddedObjectPart)testReport.MainDocumentPart.AddPart(openXmlPart);

                    targetobj.Descendants<OleObject>().FirstOrDefault().Id =
                                testReport.MainDocumentPart.GetIdOfPart(newEmbeddedObj);
                }
            }
        }
    }

I've tried calling Save() and Close() on the documents. 我试过在文档上调用Save()和Close()。 I even tried calling Dispose(). 我什至尝试调用Dispose()。 using(WordprocessingDocument foo = WordprocessingDocument.Open(bar, false){} doesn't seem to help either. I'm not too worried about the duplicate IDs for now, but I have no idea why only some of the relationships are being formed while others are not. This is a massive project so navigating through some of it can be pretty tricky. using(WordprocessingDocument foo = WordprocessingDocument.Open(bar, false){}似乎也无济于事。我现在不太担心重复的ID,但我不知道为什么仅形成某些关系而其他项目则不是。这是一个庞大的项目,因此浏览其中的某些项目可能会非常棘手。

Edit: It's probably also worth mentioning that the images stop forming relationships at a certain point. 编辑:可能还值得一提的是,图像在特定点处停止形成关系。 It isn't random. 这不是随机的。 About 2/3 of the way down none of the images work. 大约2/3的图像都无法工作。

Here's the updated set of methods 这是更新的方法集

internal static void CopyImages(OpenXmlElement oldTable, OpenXmlElement newTable,
        WordprocessingDocument testData, WordprocessingDocument testReport)
    {
        List<Blip> sourceBlips = DocumentHelper.GetAllBlips(oldTable);
        List<Blip> targetBlips = DocumentHelper.GetAllBlips(newTable);

        foreach (Blip sourceBlip in sourceBlips)
        {
            foreach (Blip targetBlip in targetBlips)
            {
                if (targetBlip.Embed.Value == sourceBlip.Embed.Value)
                {
                    if (testData.MainDocumentPart.GetPartById(sourceBlip.Embed.Value) is ImagePart imagePart)
                    {
                        //ImagePart newImagePart = testReport.MainDocumentPart.AddPart(imagePart);
                        ImagePart newImagePart = testReport.MainDocumentPart.AddImagePart(imagePart.ContentType);
                        newImagePart.FeedData(imagePart.GetStream(FileMode.Open, FileAccess.Read));
                        targetBlip.Embed.Value = testReport.MainDocumentPart.GetIdOfPart(newImagePart);
                        break;
                    }
                }
            }
        }
    }

    internal static void CopyEmbeddedVisioImages(OpenXmlElement oldTable, OpenXmlElement newTable,
        WordprocessingDocument testData, WordprocessingDocument testReport)
    {
        List<EmbeddedObject> sourceObjects = oldTable.Descendants<EmbeddedObject>().ToList();
        List<EmbeddedObject> targetObjects = newTable.Descendants<EmbeddedObject>().ToList();

        foreach (EmbeddedObject targetobj in targetObjects)
        {
            foreach (EmbeddedObject sourceObj in sourceObjects)
            {
                if (testData.MainDocumentPart.GetPartById(sourceObj.Descendants<ImageData>()
                                .FirstOrDefault().RelationshipId) is ImagePart oldImagePart)
                {
                    //ImagePart newImagePart = testReport.MainDocumentPart.AddPart(oldImagePart);
                    ImagePart newImagePart = testReport.MainDocumentPart.AddImagePart(oldImagePart.ContentType);
                    newImagePart.FeedData(oldImagePart.GetStream(FileMode.Open, FileAccess.Read));

                    targetobj.Descendants<ImageData>().FirstOrDefault().RelationshipId =
                    testReport.MainDocumentPart.GetIdOfPart(newImagePart);
                }


                if (testData.MainDocumentPart.GetPartById(sourceObj.Descendants<OleObject>()
                                .FirstOrDefault().Id) is OpenXmlPart openXmlPart)
                {
                    EmbeddedObjectPart newEmbeddedObj = (EmbeddedObjectPart)testReport.MainDocumentPart.AddPart(openXmlPart);

                    targetobj.Descendants<OleObject>().FirstOrDefault().Id =
                                testReport.MainDocumentPart.GetIdOfPart(newEmbeddedObj);
                }
            }
        }
    }

Here's an update on my findings. 这是我的发现的最新信息。

  • There are 25 total blips in the entire document. 整个文档中总共有25个blip。
  • targetBlip.Embed.Value != sourceBlip.Embed.Value in most cases or maybe it's something else? 在大多数情况下, targetBlip.Embed.Value != sourceBlip.Embed.Value还是其他呢?
  • Elements containing pictures are cloned from source doc and then saved into target doc. 包含图片的元素将从源文档中克隆,然后保存到目标文档中。
  • All elements are being read. 正在读取所有元素。 Tables containing pictures with broken relationships exist and are filled with other content, so it's not like it's missing those elements. 存在包含关系破裂的图片的表,并且表中填充了其他内容,因此这并不意味着缺少这些元素。
  • The duplicate IDs are due to the target document containing a couple images to begin with, so when I copy over the other images, some of those IDs are duplicated. 重复的ID是由于目标文档中包含几个图像,因此,当我在其他图像上进行复制时,其中一些ID是重复的。 This isn't my concern for now. 我现在不关心这个。

Images from a source document can't be added as-is into a target document; 源文档中的图像不能按原样添加到目标文档中; an image has a unique id/number within its parent document and this one might conflict with the target document if one already exists with that same id. 一幅图像在其父文档中具有唯一的ID /编号,如果已经存在具有相同ID的图像,则该图像可能与目标文档冲突。 Replace the following line 替换以下行

ImagePart newImagePart = testReport.MainDocumentPart.AddPart(imagePart);

with the one below. 与下面的一个。 Here a whole new image file gets embedded and gets a new id assigned. 在这里,将嵌入一个全新的图像文件并分配一个新的ID。

ImagePart newImagePart = testReport.MainDocumentPart.AddImagePart(oldImagePart.ContentType);
newImagePart.FeedData(oldImagePart.GetStream(FileMode.Open, FileAccess.Read));

It's important that the ids in the target document are unique. 目标文档中的ID必须唯一,这一点很重要。 I share some (old(er)) code fragments about how I handled to merge images from one document into another. 我共享一些(旧的)代码片段,这些片段涉及我如何处理将图像从一个文档合并到另一个文档中。 (This is a fragment of a more complete/complex implementation where duplicate images are being detected and prevented from being inserted more than once.) (这是更完整/复杂的实现的一部分,其中检测到重复图像并防止多次插入。)

It starts by iterating over all Drawings in the source document and building a list of these together with their original id as in this source document. 首先,要遍历源文档中的所有工程图,并像本源文档中一样,将这些工程图及其原始ID一起构建起来。 Then all images get inserted into the target document; 然后,所有图像都将插入到目标文档中。 while doing so the new id as in the target document gets mapped to each item. 同时将目标文档中的新ID映射到每个项目。

Each drawing in the source document gets updated with the id as in the target document; 源文档中的每个图形都使用与目标文档中相同的ID进行更新; the list contains both orginal source and new target ids. 该列表同时包含原始来源ID和新目标ID。 (This sounds bizarre, but for me at that moment only this gave the expected result.) (这听起来很奇怪,但对我而言,这仅能达到预期的效果。)

Only after the image merge has completed, the content (paragraphs and tables) get merged into the target document, which consists of adding clones of these items. 仅在图像合并完成之后,内容(段落和表格)才会合并到目标文档中,该目标文档包括添加这些项目的副本。

public class DocumentMerger
{
    private readonly WordprocessingDocument _targetDocument;

    public DocumentMerger(WordprocessingDocument targetDocument)
    {
        this._targetDocument = targetDocument;
    }    

    public void Merge(WordprocessingDocument sourceDocument)
    {
        ImagesMerger imagesMerger = new ImagesMerger(this._targetDocument);
        this._imagesMerger.Merge(sourceDocument);

        // Merge the content; paragraphs and tables.

        this._targetDocumentPart.Document.Save();
    }    
}


public class ImageInfo
{
    private String _id;
    private ImagePart _image;
    private readonly String _originalId;

    private ImageInfo(ImagePart image, String id)
    {  
        this._id = id;
        this._image = image;
        this._originalId = id;
    }

    public String Id 
    { 
        get { return this._id; } 
    }

    public ImagePart Image
    {
        get { return this._image; }
    }

    public String OriginalId
    {
        get { return this._originalId; }
    }

    public static ImageInfo Create(MainDocumentPart documentPart, ImagePart image)
    {
        String id = documentPart.GetIdOfPart(image);
        ImageInfo r = new ImageInfo(image, id);
        return r;
    }    

    public void Reparent(MainDocumentPart documentPart)
    {   
        ImagePart newImage = documentPart.AddImagePart(this._image.ContentType);                
        newImage.FeedData(this._image.GetStream(FileMode.Open, FileAccess.Read));
        String newId = documentPart.GetIdOfPart(newImage);                        
        this._id = newId;
        this._image = newImage;                
    }    
}


public class ImagesMerger 
{
    private readonly IList<ImageInfo> _imageInfosOfTheTargetDocument = new List<ImageInfo>();        
    private readonly MainDocumentPart _targetDocumentPart;

    public ImagesMerger(WordprocessingDocument targetDocument)
    {
        this._targetDocumentPart = targetDocument.MainDocumentPart;
    }

    public void Merge(WordprocessingDocument sourceDocument)
    {
        MainDocumentPart sourceDocumentPart = sourceDocument.MainDocumentPart;
        IList<ImageInfo> imageInfosOfTheSourceDocument = this.getImageInfos(sourceDocumentPart);
        if (0 == imageInfosOfTheSourceDocument.Count) { return; }

        this.addTheImagesToTheTargetDocument(imageInfosOfTheSourceDocument);
        this.rereferenceTheImagesToTheirCorrespondingImageParts(sourceDocumentPart, imageInfosOfTheSourceDocument);
    }

    private void addTheImagesToTheTargetDocument(IList<ImageInfo> imageInfosOfTheSourceDocument)
    {
        for (Int32 i = 0, j = imageInfosOfTheSourceDocument.Count; i < j; i++)
        {
            imageInfoOfTheSourceDocument.Reparent(this._targetDocumentPart);
            this._imageInfosOfTheTargetDocument.Add(imageInfoOfTheSourceDocument);                    
        }            
    }

    private IList<ImageInfo> getImageInfos(MainDocumentPart documentPart)
    {
        List<ImageInfo> r = new List<ImageInfo>();

        foreach (ImagePart image in documentPart.ImageParts)
        {
            ImageInfo imageInfo = ImageInfo.Create(documentPart, image);
            r.Add(imageInfo);
        }

        return r;
    }

    private void rereferenceTheImagesToTheirCorrespondingImageParts(MainDocumentPart sourceDocumentPart, IList<ImageInfo> imageInfosOfTheSourceDocument)
    {
        IEnumerable<Drawing> images = sourceDocumentPart.Document.Body.Descendants<Drawing>();

        foreach (Drawing image in images)
        {
            Blip blip = image.Inline.Graphic.GraphicData.Descendants<Blip>().FirstOrDefault();
            String originalId = blip.Embed.Value;

            ImageInfo imageInfo = imageInfosOfTheSourceDocument.FirstOrDefault(o => o.OriginalId._Equals(originalId));
            blip.Embed.Value = imageInfo.Id;
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM