OpenXml 图像关系不存在 [英] OpenXml image relationship doesn't exist

查看:48
本文介绍了OpenXml 图像关系不存在的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是一家大公司的实习生,他的任务是处理以前实习生的项目,该项目显然在某些时候有效,但现在它坏了.该程序的作用是从文档中取出一堆文本和图像并将它们插入到模板文档中.问题是,大约一半的图像没有形成关系,我得到红色 X图像无法显示"空框.我一直在使用生产力工具进行一些挖掘,我发现有几个重复的 ID,以及很多不存在的关系,尽管查看他的代码我不确定是什么原因造成的.以下是他复制图片的两种方法:

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. 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. 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);
                }
            }
        }
    }

我尝试在文档上调用 Save() 和 Close().我什至尝试调用 Dispose().using(WordprocessingDocument foo = WordprocessingDocument.Open(bar, false){} 似乎也没有帮助.我现在不太担心重复的 ID,但我不知道为什么只一些关系正在形成,而另一些尚未形成.这是一个庞大的项目,因此浏览其中一些可能非常棘手.

I've tried calling Save() and Close() on the documents. I even tried calling 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.

可能还值得一提的是,图像在某个时刻停止形成关系.这不是随机的.大约 2/3 处的图像都不起作用.

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.

这是更新的方法集

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);
                }
            }
        }
    }

这是我的发现的更新.

  • 整个文档中总共有 25 个 blip.
  • targetBlip.Embed.Value != sourceBlip.Embed.Value 在大多数情况下或者可能是别的什么?
  • 包含图片的元素从源文档中克隆,然后保存到目标文档中.
  • 正在读取所有元素.包含关系破裂的图片的表格存在并填充了其他内容,因此它不会缺少这些元素.
  • 重复的 ID 是因为目标文档包含几张图片,所以当我复制其他图片时,其中一些 ID 是重复的.这不是我现在关心的问题.
  • There are 25 total blips in the entire document.
  • targetBlip.Embed.Value != sourceBlip.Embed.Value in most cases or maybe it's something else?
  • 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. This isn't my concern for now.

推荐答案

无法将源文档中的图像按原样添加到目标文档中;图像在其父文档中具有唯一的 id/编号,如果已经存在具有相同 id 的图像,则该图像可能与目标文档冲突.替换下面一行

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. Replace the following line

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

下面的那个.这里嵌入了一个全新的图像文件并分配了一个新的 ID.

with the one below. Here a whole new image file gets embedded and gets a new id assigned.

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

目标文档中的 id 必须是唯一的,这一点很重要.我分享了一些(旧的(er))代码片段,关于我如何处理将图像从一个文档合并到另一个文档.(这是一个更完整/复杂的实现的片段,其中检测到重复图像并防止多次插入.)

It's important that the ids in the target document are unique. 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.)

它首先迭代源文档中的所有绘图,并构建一个列表以及它们在此源文档中的原始 ID.然后将所有图像插入到目标文档中;这样做时,目标文档中的新 ID 会映射到每个项目.

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. 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 进行更新;该列表包含原始源 ID 和新目标 ID.(这听起来很奇怪,但对我来说,当时只有这给出了预期的结果.)

Each drawing in the source document gets updated with the id as in the target document; the list contains both orginal source and new target ids. (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;
        }
    }
}

这篇关于OpenXml 图像关系不存在的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆