0

スプレッドシートが生成された後、openxmlを使用してclosedxmlによって生成されたExcelドキュメントに画像を追加しようとしています(closedxmlには現在画像を挿入する方法がないため)。

Excelファイルを正しく生成でき、正常に開きますが、画像を挿入してExcelで開こうとすると、エラーが発生します。

小さなコンソールアプリを使用しましたが、エラーが

Error 1
Description: The element has unexpected child element 'http://schemas.openxmlfor
mats.org/spreadsheetml/2006/main:drawing'.
Path: /x:worksheet[1]
Part: /xl/worksheets/sheet.xml
-------------------------------------------

スプレッドシートは次のようになります。

<?xml version="1.0" encoding="utf-8"?>
<x:worksheet xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:x="http://schemas.openxmlformats.org/spreadsheetml/2006/main">
    <x:sheetPr>
        <x:outlinePr summaryBelow="1" summaryRight="1" />
    </x:sheetPr>
    <x:dimension ref="A1:M4" />
    <x:sheetViews>
        <x:sheetView tabSelected="0" workbookViewId="0" />
    </x:sheetViews>
    <x:sheetFormatPr defaultRowHeight="15" />
    <x:cols>
        ...
    </x:cols>
    <x:sheetData>
        ...
    </x:sheetData>
    <x:printOptions horizontalCentered="0" verticalCentered="0" headings="0" gridLines="0" />
    <x:pageMargins left="0.75" right="0.75" top="0.75" bottom="0.5" header="0.5" footer="0.75" />
    <x:pageSetup paperSize="1" scale="100" pageOrder="downThenOver" orientation="default" blackAndWhite="0" draft="0" cellComments="none" errors="displayed" />
    <x:headerFooter />
    <x:tableParts count="0" />
    <x:drawing r:id="R701e4d0efd7143ee" />
</x:worksheet>

取って

 
セクションアウトにより、ファイルを正しく検証できるようです。

また、空白のExcelドキュメントを手動で作成して画像を追加しようとしましたが、非常によく似ています。

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="x14ac" xmlns:x14ac="http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac">
    <dimension ref="A1"/>
    <sheetViews>
        <sheetView tabSelected="1" workbookViewId="0">
            <selection activeCell="D14" sqref="D14"/>
        </sheetView>
    </sheetViews>
    <sheetFormatPr defaultRowHeight="15" x14ac:dyDescent="0.25"/>
    <sheetData/>
    <pageMargins left="0.7" right="0.7" top="0.75" bottom="0.75" header="0.3" footer="0.3"/>
    <drawing r:id="rId1"/>
</worksheet>

私が気づいたことの1つは、生成されたもののように名前空間(x)がないことですが、それが問題を引き起こしているかどうかはわかりません。

誰かが私が欠けているものを見ることができますか?

画像の挿入に使用するコードは次のとおりです。

public static void InsertImage(this Worksheet ws, long x, long y, long? width, long? height, string sImagePath)
{
    try
    {
        var wsp = ws.WorksheetPart;
        var dp = default(DrawingsPart);
        var imgp = default(ImagePart);
        var wsd = default(WorksheetDrawing);

        var ipt = default(ImagePartType);
        switch (sImagePath.Substring(sImagePath.LastIndexOf('.') + 1).ToLower())
        {
            case "png":
                ipt = ImagePartType.Png;
                break; // TODO: might not be correct. Was : Exit Select

                break;
            case "jpg":
            case "jpeg":
                ipt = ImagePartType.Jpeg;
                break; // TODO: might not be correct. Was : Exit Select

                break;
            case "gif":
                ipt = ImagePartType.Gif;
                break; // TODO: might not be correct. Was : Exit Select

                break;
            default:
                return;
        }

        if (wsp.DrawingsPart == null)
        {
            //----- no drawing part exists, add a new one

            dp = wsp.AddNewPart<DrawingsPart>();
            imgp = dp.AddImagePart(ipt, wsp.GetIdOfPart(dp));
            wsd = new WorksheetDrawing();
        }
        else
        {
            //----- use existing drawing part

            dp = wsp.DrawingsPart;
            imgp = dp.AddImagePart(ipt);
            dp.CreateRelationshipToPart(imgp);
            wsd = dp.WorksheetDrawing;
        }

        using (var fs = new FileStream(sImagePath, FileMode.Open))
        {
            imgp.FeedData(fs);
        }

        var imageNumber = 1;
        if (imageNumber == 1)
        {
            var drawing = new Drawing();
            drawing.Id = dp.GetIdOfPart(imgp);
            ws.Append(drawing);
        }

        var nvdp = new NonVisualDrawingProperties();
        nvdp.Id = new UInt32Value(Convert.ToUInt32(1024 + imageNumber));
        nvdp.Name = "Picture " + imageNumber.ToString();
        nvdp.Description = "Picture";
        var picLocks = new PictureLocks();
        picLocks.NoChangeAspect = true;
        picLocks.NoChangeArrowheads = true;
        var nvpdp = new NonVisualPictureDrawingProperties();
        nvpdp.PictureLocks = picLocks;
        var nvpp = new NonVisualPictureProperties();
        nvpp.NonVisualDrawingProperties = nvdp;
        nvpp.NonVisualPictureDrawingProperties = nvpdp;

        var stretch = new Stretch();
        stretch.FillRectangle = new FillRectangle();

        var blipFill = new BlipFill();
        var blip = new Blip();
        blip.Embed = dp.GetIdOfPart(imgp);
        blip.CompressionState = BlipCompressionValues.Print;
        blipFill.Blip = blip;
        blipFill.SourceRectangle = new SourceRectangle();
        blipFill.Append(stretch);

        var t2d = new Transform2D();
        var offset = new Offset();
        offset.X = 0;
        offset.Y = 0;
        t2d.Offset = offset;
        var bm = new Bitmap(sImagePath);

        var extents = new Extents();

        if (width == null)
        {
            extents.Cx = Convert.ToInt64(bm.Width)*
                         Convert.ToInt64(Math.Truncate(Convert.ToSingle(914400)/bm.HorizontalResolution));
        }
        else
        {
            extents.Cx = width;
        }

        if (height == null)
        {
            extents.Cy = Convert.ToInt64(bm.Height)*
                         Convert.ToInt64(Math.Truncate(Convert.ToSingle(914400)/bm.VerticalResolution));
        }
        else
        {
            extents.Cy = height;
        }

        bm.Dispose();
        t2d.Extents = extents;
        var sp = new ShapeProperties();
        sp.BlackWhiteMode = BlackWhiteModeValues.Auto;
        sp.Transform2D = t2d;
        var prstGeom = new PresetGeometry();
        prstGeom.Preset = ShapeTypeValues.Rectangle;
        prstGeom.AdjustValueList = new AdjustValueList();
        sp.Append(prstGeom);
        sp.Append(new NoFill());

        var picture = new Picture();
        picture.NonVisualPictureProperties = nvpp;
        picture.BlipFill = blipFill;
        picture.ShapeProperties = sp;

        var pos = new Position();
        pos.X = x;
        pos.Y = y;
        var ext = new Extent();
        ext.Cx = extents.Cx;
        ext.Cy = extents.Cy;
        var anchor = new AbsoluteAnchor();
        anchor.Position = pos;
        anchor.Extent = ext;
        anchor.Append(picture);
        anchor.Append(new ClientData());
        wsd.Append(anchor);
        wsd.Save(dp);
    }
    catch (Exception ex)
    {
        // or do something more interesting if you want
        throw ex;
    }
}

public static void InsertImage(MemoryStream stream, long x, long y, string sImagePath)
{
    using (var mySpreadsheet = SpreadsheetDocument.Open(stream, true))
    {
        var workbookPart = mySpreadsheet.WorkbookPart;
        var sheets = mySpreadsheet.WorkbookPart.Workbook.GetFirstChild<Sheets>().Elements<Sheet>();
        var relationshipId = sheets.First().Id.Value;
        var worksheetPart = (WorksheetPart) mySpreadsheet.WorkbookPart.GetPartById(relationshipId);
        var workSheet = worksheetPart.Worksheet;
        //Dim sheets As worksheetpart = mySpreadsheet.WorkbookPart.Workbook.
        // For each sheet, display the sheet information.
        long width = 9525*193;
        long height = 9525*80;
        InsertImage(workSheet, x, y, width, height, sImagePath);
    }
}
4

5 に答える 5

2

はははは、これを見たときはビックリしました。私は文字通りまったく同じことをしています。

クローズド XML を使用してスプレッドシートを生成し、Vincent のコードを使用して画像を挿入しています。

残念ながら、私は同じ問題を抱えていますが、imageNumberが1として宣言されていることとは関係ありません

ただし、回避策を見つけました:

画像を挿入したら、閉じた xml を使用してドキュメントを再度開き、再度保存します。

これだけ使ってる

workbook = new XLWorkbook(filepath);
workbook.save();

その後、問題なく開くはずです。

これが同様の問題を抱えている他の人に役立つことを願っています

編集:

このセグメントを変更することで、この問題を完全に修正できました。

var imageNumber = dp.ImageParts.Count<ImagePart>();
if (imageNumber == 1)
{
    var drawing = new Drawing();
    drawing.Id = dp.GetIdOfPart(imgp);
    ws.Append(drawing);
}

ws.Append(drawing);に変更

ws.InsertBefore(drawing, ws.Last)

それから、私にとっては最後の子供の直前に置きます<x:tableParts count="0"/>

その後に置くことが問題の原因のようです

于 2014-04-22T10:24:09.987 に答える
1

問題は、imageNumber を 1 に割り当てたことにある可能性があります。

var imageNumber = 1;

これが役立つかもしれません:

var imageNumber = dp.ImageParts.Count<ImagePart>();

また、このコードは、私がブログ投稿に投稿したものと疑わしいほど似ています。それで大丈夫です。また、SpreadsheetLightが役立つ場合もあります。これは ClosedXml のようなスプレッドシート ライブラリであり、画像をうまく挿入できます。免責事項: 私は SpreadsheetLight を書きました。

于 2012-10-09T14:28:32.910 に答える
1

同様の問題がありました。OpenXML 生産性向上ツールを使用して、ClosedXML で作成されたドキュメントと Excel に画像を配置したドキュメントとを比較したところ、ClosedXML がいくつかの要素ノードを挿入したことがわかりました。それらは無効ではありませんが、描画要素を含むシートを無効にしているように見えます. これらの要素を削除すると、画像を含むスプレッドシートが Excel で正常に開きます。 それは klugeですが、機能しています。このコードは、InsertImage メソッドの先頭にあります。

    //Remove superfluous worksheet elements. These break the inlcusion of the logo image.
    var element = ws.FirstChild;
    do
    {
        if(element.LocalName == null)
            continue;
        switch (element.LocalName)
        {
            case "pageSetup":
            case "headerFooter":
            case "tableParts":
                var prevElement = element;
                element = element.NextSibling();
                ws.RemoveChild<OpenXmlElement>(prevElement);
                break;
            default:
                element = element.NextSibling();
                break;
        }
    }
    while(element != null);
    // End of element removal

HTH

アンガス

于 2013-11-01T17:51:13.230 に答える
0

新しい Excel ファイルに書き込む場合は、次のコードで問題ありません。

if( dp.ImageParts.Count<ImagePart>() == 1 )
{
    var drawing = new Drawing();
    drawing.Id = dp.GetIdOfPart(imgp);
    ws.Append(drawing);
}

ただし、既に描画セクションがある可能性のある既存のファイルに書き込んでいる場合 (ただし、画像はありません...図形は描画セクションの一部であるように見えます)、これによりドキュメントが検証に失敗し、完全に開くことさえできなくなります。 .

次のようにしてこれを修正しました。

if (dp.ImageParts.Count<ImagePart>() == 1)
{
    Drawing drawing = workSheet.GetFirstChild<Drawing>();
    if (drawing == null)
    {
        drawing = new Drawing();
        drawing.Id = dp.GetIdOfPart(imgp);
        workSheet.InsertAfter(drawing, workSheet.LastChild);
    }
}

ワークシートごとに描画セクションが 1 つしかないようです...残念ながらすぐには明らかにならなかったため、問題を突き止めるのにしばらく時間がかかりました。

于 2015-05-12T18:21:35.343 に答える
0

OpenXml は、理解するのが最も簡単なことではありません。

彼らがあなたに教えていないことの 1 つは、要素の順序がしばしば重要であるということです。tableParts前述のように、インデックス番号は原因ではありません。要素が要素の前に来るように、xml タグを並べ替える必要がありますdrawing

または、TableParts がないため、要素を完全に削除することもできます

だからあなたの例から

<?xml version="1.0" encoding="utf-8"?>
<x:worksheet xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:x="http://schemas.openxmlformats.org/spreadsheetml/2006/main">
    <x:sheetPr>
        <x:outlinePr summaryBelow="1" summaryRight="1" />
    </x:sheetPr>
    <x:dimension ref="A1:M4" />
    <x:sheetViews>
        <x:sheetView tabSelected="0" workbookViewId="0" />
    </x:sheetViews>
    <x:sheetFormatPr defaultRowHeight="15" />
    <x:cols>
        ...
    </x:cols>
    <x:sheetData>
        ...
    </x:sheetData>
    <x:printOptions horizontalCentered="0" verticalCentered="0" headings="0" gridLines="0" />
    <x:pageMargins left="0.75" right="0.75" top="0.75" bottom="0.5" header="0.5" footer="0.75" />
    <x:pageSetup paperSize="1" scale="100" pageOrder="downThenOver" orientation="default" blackAndWhite="0" draft="0" cellComments="none" errors="displayed" />
    <x:headerFooter />
    <x:drawing r:id="R701e4d0efd7143ee" />
    <x:tableParts count="0" />
</x:worksheet>
于 2015-02-24T09:52:49.440 に答える