Visual Studio 2019のC#にて、中のxmlを直接叩いてODSを出力する。コードのサンプルです。

表題の通り
Visual Studio 2019のC#にて、中のxmlを直接叩いてODSを出力する。
コードのサンプルでございます。

odsは、LibreOfficeや、OpenOfficeなどで使用できるファイル形式で
それぞれが、インストールされていない環境下でも、作成できます。
また、odsは、Microsoft Excelでも扱えますが、ずれが生じたりします。


尚、Microsoft Excelで扱うxlsxは、
内部は、似たようなxmlをzipでアーカイブしたものなので
[参考サイト]
[java - How to create and write to Excel file (.xlsx)? - Stack Overflow](https://stackoverflow.com/questions/50738119/how-to-create-and-write-to-excel-file-xlsx/50886486)
上記のサイト様を参考にして、
xmlの内容になるよう書き換えれば、xlsxファイルを、
Excelが存在しない環境下でも、作成できるようになります。



特段、NuGetなど他のプラグインや
別途外部dllを必要としないようにしています。

要は、バイナリを以下のように、直接叩いています。
<b>1.</b>ods内部のxmlのファイルの記述
<b>2.</b>xmlファイルを無圧縮でzipにアーカイブ。
<b>3.</b>画像は、メモリにJpeg形式で保存した上でアーカイブ。

※アーカイブするファイルの順番には、決まった順番があります。
※私は素人ですし
今回のコードは、あくまで最低限の動作する部分にとどめていますので、汚いです。
例外処理や、解放など至らぬ点が、多々ございます。ご了承ください。
もし実際に参考にされる際は、必要個所を必ず訂正してからにしてください。

下の画像は、今回コードでの作成例です。
![参考画像](https://blog-imgs-130.fc2.com/o/y/k/oyk3865b/2019071518070673a.jpg)


[コード作成参考サイト]
[[VBA]CRC-32の計算 言語: VB.NET](https://code.msdn.microsoft.com/office/VBACRC-32-dad7d087)
[C#实现crc32函数 - 时间是把杀刀猪 - CSDN博客](https://blog.csdn.net/ciaos/article/details/12490911)
[A CRC32 implementation in C# - Sanity Free Coding - C&#35;, .NET, PHP](http://sanity-free.org/12/crc32_implementation_in_csharp.html)

```c#:CreateODS.cs
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Drawing;

class CreateODS
{   //LibreOfficeや、OpenOfficeなどで使用できるODS形式を作成する。
    //Excelでも、扱えるが、ズレたりします。。。

    //グローバル変数用

    //■Local file header関係+++++++++++++++++++++++++++++++++++++++++++++++
    //Local file headerの識別子 4bytes(0x04034b50)
    readonly byte[] local_file_header_signature = BitConverter.GetBytes(Convert.ToInt32(0x4034B50));

    //解凍に最低必要なバージョン 2bytes 今回は、ver.1.0で、無圧縮を指定(Default value)→0x000A 
    readonly byte[] version_needed_to_extract = BitConverter.GetBytes(Convert.ToInt16(0xA));

    //オプションフラグと、圧縮方法 2+2bytes{今回はオプションもなく、圧縮もしないので、0を指定共に0x0000}
    readonly byte[] general_purpose_and_compression_method = BitConverter.GetBytes(Convert.ToInt32(0x0));

    //ファイル更新時間 2bytes (秒数は偶数のみ指定可能)
    readonly byte[] last_mod_file_time = new byte[2] { 0, 0 }; //00:00:00固定とする。

    //ファイル更新年月日 2bytes
    readonly byte[] last_mod_file_date = new byte[2] { 147, 76 }; //2018/4/19固定とする。

    //CRC-32 4bytes{アーカイブ前の生ファイルから生成するCRC32}
    byte[] crc_32;
    List<Int32> ary_crc_32s = null; //zip内の各ファイルの、CRC-32を格納。

    //圧縮後のファイルサイズ 4bytes{今回は無圧縮なので圧縮前の値と同値}
    //圧縮前のファイルサイズ 4bytes
    byte[] uncompressed_size;
    List<Int32> ary_uncompressed_sizes = null; //zip内の各ファイルの、圧縮前のファイルサイズを格納。

    //アーカイブ前のファイル名のサイズを格納する 2bytes
    string file_name; //ファイル名
    byte[] file_name_ary; // ファイル名のバイナリ
    List<string> ary_file_name_arys = null; //zip内の各ファイルの、ファイル名のバイナリを格納。
    byte[] file_name_length; //ファイル名のバイナリサイズ

    //拡張フィールドのサイズ 2bytes{今回は、指定しないので0x0000}
    readonly byte[] extra_field_length = BitConverter.GetBytes(Convert.ToInt16(0x0));


    //■Central file header関係+++++++++++++++++++++++++++++++++++++++++++++++
    //Central file headerの識別子 4bytes(0x02014b50)
    readonly byte[] central_file_header_signature = BitConverter.GetBytes(Convert.ToInt32(0x2014B50));

    //作成したバージョン　1+1bytes{今回は、ver.1.0で、無圧縮を指定(Default value)→0x000A }
    readonly byte[] version_made_by = BitConverter.GetBytes(Convert.ToInt16(0xA));

    //ファイルの属性などの情報　2+2+2+4bytes　→　今回は無視するのですべて0
    readonly byte[] file_attributes_etc = new byte[10] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };

    //対応するファイルのlocal file header信号のある位置　4bytes
    //出力zipの各local_file_header signatureの、バイト開始位置を示す4バイトのバイナリ配列を格納。
    List<Int32> relative_offset_of_local_header = null;


    //■End of central directory record関係+++++++++++++++++++++++++++++++++++++++++++++++
    //End of central directory record 4bytes(0x06054b50)
    readonly byte[] end_of_central_dir_signature = BitConverter.GetBytes(Convert.ToInt32(0x6054B50));

    //ディスク分割情報　2+2bytes{ディスク分割はしていないのですべて0}
    readonly byte[] number_of_this_disk = BitConverter.GetBytes(Convert.ToInt32(0x0));

    //アーカイブしたファイルの個数 2+2bytes{ディスク分割はしていないので同じ内容の重複}
    byte[] total_number_of_entries;

    //全Central file headerに要したの合計バイト数 4bytes
    byte[] size_of_the_central_directory;

    //最初のCentral file headerの記述されたバイト位置 4bytes
    long offset_of_start_of_central_directory_int;
    byte[] offset_of_start_of_central_directory;

    //zipファイルへのコメントのサイズ 2bytes{今回は、指定しないので0x0000}
    readonly byte[] ZIP_file_comment_length = BitConverter.GetBytes(Convert.ToInt16(0x0));

    //◆zipファイル入出力など、取扱関係+++++++++++++++++++++++++++++
    //出力zipのバイナリ一時格納用。
    List<byte> ary_zip_file = null;



    //■アーカイブする文字列関係+++++++++++++++++++++++++++++++++++++++++++++++
    //OpenDocument Spreadsheetであることを示す
    readonly string mimetype_xml = "application/vnd.oasis.opendocument.spreadsheet";

    //ドキュメントの印刷情報など
    readonly string styles_xml = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>" +
        "<office:document-styles xmlns:table=\"urn:oasis:names:tc:opendocument:xmlns:table:1.0\" xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\" xmlns:text=\"urn:oasis:names:tc:opendocument:xmlns:text:1.0\" " +
            "xmlns:style=\"urn:oasis:names:tc:opendocument:xmlns:style:1.0\" xmlns:draw=\"urn:oasis:names:tc:opendocument:xmlns:drawing:1.0\" xmlns:fo=\"urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0\" " +
            "xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns:dc=\"http://purl.org/dc/elements/1.1/\" xmlns:number=\"urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0\" xmlns:svg=\"urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0\" " +
            "xmlns:of=\"urn:oasis:names:tc:opendocument:xmlns:of:1.2\" office:version=\"1.2\">" +
        "<office:font-face-decls><style:font-face style:name=\"ＭＳ Ｐゴシック\" svg:font-family=\"ＭＳ Ｐゴシック\"/></office:font-face-decls>" +
        "<office:styles><number:number-style style:name=\"N0\"><number:number number:min-integer-digits=\"1\"/></number:number-style><style:style style:name=\"Default\" style:family=\"table-cell\" style:data-style-name=\"N0\">" +
        "<style:table-cell-properties style:vertical-align=\"middle\" fo:background-color=\"transparent\"/>" +
        "<style:text-properties fo:color=\"#000000\" style:font-name=\"ＭＳ Ｐゴシック\" style:font-name-asian=\"ＭＳ Ｐゴシック\" style:font-name-complex=\"ＭＳ Ｐゴシック\" fo:font-size=\"11pt\" style:font-size-asian=\"11pt\" style:font-size-complex=\"11pt\"/></style:style>" +
        "<style:style style:family=\"graphic\" style:name=\"Graphics\"/><style:default-style style:family=\"graphic\">" +
        "<style:graphic-properties draw:fill=\"solid\" draw:fill-color=\"#000000\" draw:opacity=\"100%\" draw:stroke=\"solid\" svg:stroke-width=\"0.01389in\" svg:stroke-color=\"#ffffff\" svg:stroke-opacity=\"100%\" draw:stroke-linejoin=\"miter\" svg:stroke-linecap=\"butt\"/>" +
        "</style:default-style></office:styles>" +
        "<office:automatic-styles><style:page-layout style:name=\"pm1\">" +
        "<style:page-layout-properties fo:margin-top=\"0.3cm\" fo:margin-bottom=\"0.3cm\" fo:margin-left=\"0.7cm\" fo:margin-right=\"0.7cm\" style:print-orientation=\"portrait\" style:print-page-order=\"ttb\" style:first-page-number=\"continue\" style:scale-to=\"100%\" style:table-centering=\"both\" style:print=\"objects charts drawings\"/>" +
        "<style:header-style><style:header-footer-properties fo:min-height=\"0.45cm\" fo:margin-left=\"0.7cm\" fo:margin-right=\"0.7cm\" fo:margin-bottom=\"0cm\"/></style:header-style>" +
        "<style:footer-style><style:header-footer-properties fo:min-height=\"0.45cm\" fo:margin-left=\"0.7cm\" fo:margin-right=\"0.7cm\" fo:margin-top=\"0cm\"/></style:footer-style></style:page-layout></office:automatic-styles>" +
        "<office:master-styles><style:master-page style:name=\"mp1\" style:page-layout-name=\"pm1\">" +
        "<style:header><text:p>ヘッダー文字列</text:p></style:header><style:header-left style:display=\"false\"/>" +
        "<style:footer><text:p>フッター文字列</text:p></style:footer><style:footer-left style:display=\"false\"/>" +
        "</style:master-page></office:master-styles></office:document-styles>";

    //このシートで使用するファイル一覧
    readonly string META_INF_manifest_xml_header = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>" +
        "<manifest:manifest xmlns:manifest=\"urn:oasis:names:tc:opendocument:xmlns:manifest:1.0\"><manifest:file-entry manifest:full-path=\"/\" manifest:media-type=\"application/vnd.oasis.opendocument.spreadsheet\"/>" +
        "<manifest:file-entry manifest:full-path=\"styles.xml\" manifest:media-type=\"text/xml\"/>" +
        "<manifest:file-entry manifest:full-path=\"content.xml\" manifest:media-type=\"text/xml\"/>";

    //画像指定用
    readonly string META_INF_manifest_xml_image = "<manifest:file-entry manifest:full-path=\"media/image1.jpeg\" manifest:media-type=\"image/jpeg\"/>";
    readonly string META_INF_manifest_xml_footer = "<manifest:file-entry manifest:full-path=\"meta.xml\" manifest:media-type=\"text/xml\"/></manifest:manifest>";


    //シートの内容すべてを格納するxml
    //※列幅、行高、画像のサイズの単位は、cmで統一。
    readonly string content_xml_header = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>" +
        "<office:document-content xmlns:table=\"urn:oasis:names:tc:opendocument:xmlns:table:1.0\" xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\" xmlns:text=\"urn:oasis:names:tc:opendocument:xmlns:text:1.0\" " +
            "xmlns:style=\"urn:oasis:names:tc:opendocument:xmlns:style:1.0\" xmlns:draw=\"urn:oasis:names:tc:opendocument:xmlns:drawing:1.0\" xmlns:fo=\"urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0\" " +
            "xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns:dc=\"http://purl.org/dc/elements/1.1/\" xmlns:number=\"urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0\" xmlns:svg=\"urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0\" " +
            "xmlns:of=\"urn:oasis:names:tc:opendocument:xmlns:of:1.2\" office:version=\"1.2\">" +
        "<office:font-face-decls><style:font-face style:name=\"ＭＳ Ｐゴシック\" svg:font-family=\"ＭＳ Ｐゴシック\"/></office:font-face-decls><office:automatic-styles>";

    //このシートで使用するセルの書式設定を格納
    readonly string content_xml_cell_style = "<style:style style:name=\"ce1\" style:family=\"table-cell\" style:parent-style-name=\"Default\" style:data-style-name=\"N0\"/>" + //標準スタイル
        "<style:style style:name=\"ce2\" style:family=\"table-cell\" style:parent-style-name=\"Default\" style:data-style-name=\"N0\"><style:table-cell-properties style:vertical-align=\"middle\" style:repeat-content=\"false\"/><style:paragraph-properties fo:text-align=\"center\"/><style:text-properties fo:font-size=\"12pt\" style:font-size-asian=\"12pt\" style:font-size-complex=\"12pt\"/></style:style>" + //サブタイトル書式
        "<style:style style:name=\"ce3\" style:family=\"table-cell\" style:parent-style-name=\"Default\" style:data-style-name=\"N0\"><style:table-cell-properties fo:border=\"thin solid #000000\" style:vertical-align=\"middle\" style:repeat-content=\"false\"/><style:paragraph-properties fo:text-align=\"center\"/></style:style>" + //肩書用
        "<style:style style:name=\"ce4\" style:family=\"table-cell\" style:parent-style-name=\"Default\" style:data-style-name=\"N0\"><style:table-cell-properties style:vertical-align=\"middle\" style:repeat-content=\"false\"/><style:paragraph-properties fo:text-align=\"center\"/><style:text-properties fo:font-size=\"16pt\" style:font-size-asian=\"16pt\" style:font-size-complex=\"16pt\"/></style:style>" + //タイトル用
        "<style:style style:name=\"ce5\" style:family=\"table-cell\" style:parent-style-name=\"Default\" style:data-style-name=\"N0\"><style:table-cell-properties fo:border=\"thin solid #000000\" style:vertical-align=\"middle\" style:repeat-content=\"false\"/><style:paragraph-properties fo:text-align=\"start\" fo:margin-left=\"0.353cm\"/></style:style>"; //本文用

    //列の幅
    readonly string content_xml_column_style = "<style:style style:name=\"co1\" style:family=\"table-column\"><style:table-column-properties fo:break-before=\"auto\" style:column-width=\"11.5cm\"/></style:style>" + //1列目の設定
        "<style:style style:name=\"co2\" style:family=\"table-column\"><style:table-column-properties fo:break-before=\"auto\" style:column-width=\"2.0cm\"/></style:style>"; //2～4列目の設定

    //行の高さ
    readonly string content_xml_row_style = "<style:style style:name=\"ro1\" style:family=\"table-row\"><style:table-row-properties style:row-height=\"0.48cm\" style:use-optimal-row-height=\"false\" fo:break-before=\"avoid\"/></style:style>" + //タイトル・肩書の行高
        "<style:style style:name=\"ro2\" style:family=\"table-row\"><style:table-row-properties style:row-height=\"1.06cm\" style:use-optimal-row-height=\"false\" fo:break-before=\"avoid\"/></style:style>" + //タイトル下部・押印枠上部
        "<style:style style:name=\"ro3\" style:family=\"table-row\"><style:table-row-properties style:row-height=\"0.5cm\" style:use-optimal-row-height=\"false\" fo:break-before=\"avoid\"/></style:style>" + //サブタイトル・押印枠下部
        "<style:style style:name=\"ro4\" style:family=\"table-row\"><style:table-row-properties style:row-height=\"0.48cm\" style:use-optimal-row-height=\"true\" fo:break-before=\"avoid\"/></style:style>" + //タイトルと本文の間隔
        "<style:style style:name=\"ro5\" style:family=\"table-row\"><style:table-row-properties style:row-height=\"0.85cm\" style:use-optimal-row-height=\"false\" fo:break-before=\"avoid\"/></style:style>" + //本文用
        "<style:style style:name=\"ro6\" style:family=\"table-row\"><style:table-row-properties style:row-height=\"0.48cm\" style:use-optimal-row-height=\"false\" fo:break-before=\"page\"/></style:style>"; //タイトル用（改行付き）

    //表全体
    readonly string content_xml_table_style = "<style:style style:name=\"ta1\" style:family=\"table\" style:master-page-name=\"mp1\"><style:table-properties table:display=\"true\" style:writing-mode=\"lr-tb\"/></style:style>";

    //画像
    readonly string content_xml_graphics_style = "<style:style style:family=\"graphic\" style:name=\"a0\" style:parent-style-name=\"Graphics\"><style:graphic-properties draw:fill=\"none\" draw:stroke=\"none\"/></style:style>";

    //スタイルフッター・シート本体開始
    readonly string content_xml_span1 = "</office:automatic-styles>" +
        "<office:body><office:spreadsheet><table:calculation-settings table:case-sensitive=\"false\" table:search-criteria-must-apply-to-whole-cell=\"true\" table:use-wildcards=\"true\" table:use-regular-expressions=\"false\" table:automatic-find-labels=\"false\"/>" +
        "<table:table table:name=\"Sheet1\" table:style-name=\"ta1\">" + //シート名
        "<table:table-column table:style-name=\"co1\" table:default-cell-style-name=\"ce1\"/>" + //1行目の書式設定
        "<table:table-column table:style-name=\"co2\" table:number-columns-repeated=\"3\" table:default-cell-style-name=\"ce1\"/>"; //2→4行目の書式設定

    //フッター。
    readonly string content_xml_footer = "</table:table></office:spreadsheet></office:body></office:document-content>";

    //更新日時など
    readonly string meta_xml = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>" +
        "<office:document-meta xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\" xmlns:meta=\"urn:oasis:names:tc:opendocument:xmlns:meta:1.0\" xmlns:dc=\"http://purl.org/dc/elements/1.1/\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" office:version=\"1.2\">" +
        "<office:meta><meta:generator>photoreport.attachment.style</meta:generator>" +
        "<meta:initial-creator>TageSP</meta:initial-creator><dc:creator>TageSP</dc:creator>" +
        "<meta:creation-date>" +
            DateTime.UtcNow.ToString("yyyy-MM-dd") + "T" +
            DateTime.UtcNow.ToString("hh:mm:ss") + "Z" +
        "</meta:creation-date><dc:date>" +
            DateTime.UtcNow.ToString("yyyy-MM-dd") + "T" +
            DateTime.UtcNow.ToString("hh:mm:ss") + "Z" +
        "</dc:date></office:meta></office:document-meta>";



    public async System.Threading.Tasks.Task create_ods(string[] imagepath, string filepath)
    {


        if (System.IO.File.Exists(filepath))
        {   //上書きする前に削除する
            try
            {
                System.IO.File.Delete(filepath);
            }
            catch { }
        }

        //◎使用する各配列の初期化++++++++++++++++++++++++++
        ary_Clear(ref ary_zip_file, false);
        ary_crc_32s = new List<Int32> { };
        ary_uncompressed_sizes = new List<Int32> { };
        ary_file_name_arys = new List<string> { };
        relative_offset_of_local_header = new List<Int32> { };

        //zipは、無圧縮で自分でバイナリを打っていく。
        using (System.IO.FileStream fs = new System.IO.FileStream(filepath, System.IO.FileMode.Create, System.IO.FileAccess.Write))
        {
            StringBuilder sheetdata = new StringBuilder();
            sheetdata.Clear();

            for (int i = 0; i <= 5; i++)
            {
                //実際に格納するバイナリを格納する
                byte[] moto_bs = null;

                //順番に従った格納をする。
                if (i == 0)
                {   //アーカイブの先頭はmimetype固定。
                    moto_bs = System.Text.Encoding.UTF8.GetBytes(mimetype_xml);
                    file_name = "mimetype";
                }
                else if (i == 1)
                {   //印刷設定
                    moto_bs = System.Text.Encoding.UTF8.GetBytes(styles_xml);
                    file_name = "styles.xml";
                }
                else if (i == 2)
                {   //使用するファイルのリスト
                    sheetdata.Append(META_INF_manifest_xml_header);
                    sheetdata.Append(META_INF_manifest_xml_image);
                    sheetdata.Append(META_INF_manifest_xml_footer);
                    moto_bs = System.Text.Encoding.UTF8.GetBytes(sheetdata.ToString());
                    sheetdata.Clear();
                    file_name = "META-INF/manifest.xml";

                }
                else if (i == 3)
                {   //シート本文
                    sheetdata.Append(content_xml_header);
                    sheetdata.Append(content_xml_cell_style);
                    sheetdata.Append(content_xml_column_style);
                    sheetdata.Append(content_xml_row_style);
                    sheetdata.Append(content_xml_table_style);
                    sheetdata.Append(content_xml_graphics_style);
                    sheetdata.Append(content_xml_span1);

                    //本文は別処理
                    sheetdata.Append(content_xml_make_main());

                    //フッターで閉じる
                    sheetdata.Append(content_xml_footer);

                    moto_bs = System.Text.Encoding.UTF8.GetBytes(sheetdata.ToString());
                    file_name = "content.xml";
                }
                else if (i == 4)
                {   //更新日時など
                    moto_bs = System.Text.Encoding.UTF8.GetBytes(meta_xml);
                    file_name = "meta.xml";
                }
                else if (i == 5)
                {   //挿入画像
                    using (Bitmap bitmap = new Bitmap(imagepath[0]))
                    {
                        using (var baos = new MemoryStream())
                        {   //今回は、とりあえず1つだけ画像を適用する。  
                            bitmap.Save(baos, System.Drawing.Imaging.ImageFormat.Jpeg);
                            moto_bs = ((MemoryStream)baos).ToArray();
                        }
                    }
                    file_name = "media/image1.jpeg";
                }




                //■Local file headerの作成------------ここから-----------------
                //●予めlocal_file_header_signatureの記述位置を格納しておく(4バイト)
                relative_offset_of_local_header.Add(Convert.ToInt32(fs.Length)); //つまり現在のファイルサイズ

                //○local_file_header_signatureの記述(4バイト)
                ary_zip_file.AddRange(local_file_header_signature);

                //○解凍に必要なバージョンの記述(2バイト)
                ary_zip_file.AddRange(version_needed_to_extract);

                //○オプションフラグと、圧縮方法の記述(2+2バイト)
                ary_zip_file.AddRange(general_purpose_and_compression_method);

                //ファイルの更新時刻を格納(2バイト)//////////////////////////////////
                ary_zip_file.AddRange(last_mod_file_time);

                //○ファイルの更新年月日を格納(2バイト)//////////////////////////////////
                ary_zip_file.AddRange(last_mod_file_date);


                //○CRC32(4バイト)
                //元ファイルのバイナリからCRC-32を取得する。
                crc_32 = await CRC_32_Checksum(moto_bs); //計算に時間がかかるので、待機させる
                ary_zip_file.AddRange(crc_32);
                //再計算が面倒なので、central file headerに再利用するために記憶しておく。
                ary_crc_32s.Add(BitConverter.ToInt32(crc_32, 0));


                //○圧縮後のファイルサイズの取得(4バイト)｛無圧縮なので圧縮後のサイズと同値｝
                uncompressed_size = BitConverter.GetBytes(Convert.ToInt32(moto_bs.Length));
                ary_zip_file.AddRange(uncompressed_size);

                //○圧縮前のファイルサイズの取得(4バイト)
                ary_zip_file.AddRange(uncompressed_size);
                //再計算が面倒なので、central file headerに再利用するために記憶しておく。
                ary_uncompressed_sizes.Add(Convert.ToInt32(moto_bs.Length));

                //○圧縮前のファイル名のサイズの取得(2バイト)
                //文字列をUTF-8コードとしてバイナリ化する
                file_name_ary = System.Text.Encoding.UTF8.GetBytes(file_name);

                //文字列長を取得する。
                file_name_length = BitConverter.GetBytes(Convert.ToInt16(file_name_ary.Length));
                ary_zip_file.AddRange(file_name_length); //格納

                //○拡張フィールドのサイズ指定(2バイト){今回は指定なし}
                ary_zip_file.AddRange(extra_field_length); //格納


                //○アーカイブ前のファイル名の格納
                ary_zip_file.AddRange(file_name_ary);
                //file_name_aryに再利用するために記憶しておく。
                ary_file_name_arys.Add(file_name);

                try
                { //一旦、書き貯めたバイト型配列の内容をファイルに出力する
                    fs.Write((byte[])ary_zip_file.ToArray(), 0, ary_zip_file.Count);
                    fs.Flush();
                }
                catch { }
                ary_zip_file.Clear(); //初期化
                //■Local file headerの作成------------ここまで-----------------
                await System.Threading.Tasks.Task.Delay(10);


                //■ファイル本体のバイナリを書き込む
                try
                { //ファイルに出力する
                    fs.Write(moto_bs, 0, moto_bs.Length);
                    fs.Flush();
                }
                catch { }
                await System.Threading.Tasks.Task.Delay(10);//これがないと、書き込み途中で放棄される？？

                //初期化
                Array.Clear(moto_bs, 0, moto_bs.Length);
                Array.Clear(crc_32, 0, crc_32.Length);
                Array.Clear(file_name_length, 0, file_name_length.Length);
                Array.Clear(file_name_ary, 0, file_name_ary.Length);
            }


            //★中盤戦。central file headerの記述********************************************
            //予め最初のCentral file headerの記述開始バイト位置を記憶しておく
            offset_of_start_of_central_directory_int = fs.Length;
            offset_of_start_of_central_directory = BitConverter.GetBytes(Convert.ToInt32(offset_of_start_of_central_directory_int));


            //各ファイル分ループ
            for (int i = 0; i < ary_file_name_arys.Count; i++)
            {
                byte[] bs;
                //■central file headerの作成------------ここから-----------------
                //○central_file_header_signatureの記述(4バイト)
                ary_zip_file.AddRange(central_file_header_signature);

                //○zipを作った時のバージョンとOSの記述(1+1バイト)
                ary_zip_file.AddRange(version_made_by);

                //○解凍に必要なバージョンの記述(2バイト)
                ary_zip_file.AddRange(version_needed_to_extract);

                //○オプションフラグと圧縮方法の記述(2+2バイト)
                ary_zip_file.AddRange(general_purpose_and_compression_method);

                //○ファイルの更新時刻(2バイト)[固定値]
                ary_zip_file.AddRange(last_mod_file_time);

                //○ファイルの更新年月日(2バイト)[固定値]
                ary_zip_file.AddRange(last_mod_file_date);

                //○CRC-32(4バイト)
                //https://www.morgantechspace.com/2013/08/convert-object-to-byte-array-and-vice.html
                ary_zip_file.AddRange(BitConverter.GetBytes(ary_crc_32s[i]));


                //○圧縮後のファイルサイズ(4バイト) {今回は、無圧縮なので、圧縮前のファイルサイズを流用}
                bs = BitConverter.GetBytes(ary_uncompressed_sizes[i]);
                ary_zip_file.AddRange(bs);

                //○圧縮前のファイルサイズ(4バイト)
                ary_zip_file.AddRange(bs);
                Array.Clear(bs, 0, bs.Length);//初期化

                //○ファイル名のサイズ(2バイト)
                byte[] name_bs = System.Text.Encoding.UTF8.GetBytes(ary_file_name_arys[i]);
                ary_zip_file.AddRange(BitConverter.GetBytes(Convert.ToInt16(name_bs.Length)));


                //○拡張フィールドのサイズ(2バイト)
                ary_zip_file.AddRange(extra_field_length);

                //○ファイルの属性などの情報(2+2+2+4バイト)
                ary_zip_file.AddRange(file_attributes_etc);

                //○対応するファイルのlocal File header信号のある位置(4バイト)
                bs = BitConverter.GetBytes(relative_offset_of_local_header[i]);
                ary_zip_file.AddRange(bs);
                Array.Clear(bs, 0, bs.Length);//初期化


                //○アーカイブ前のファイル名の格納
                ary_zip_file.AddRange(name_bs);
                Array.Clear(name_bs, 0, name_bs.Length);//初期化

                try
                { //一旦、書き貯めたバイト型配列の内容をファイルに出力する
                    fs.Write((byte[])ary_zip_file.ToArray(), 0, ary_zip_file.Count);
                    fs.Flush();
                }
                catch { }
                ary_zip_file.Clear(); //初期化
                //■central file headerの作成------------ここまで-----------------
                await System.Threading.Tasks.Task.Delay(10);
            }

            //◎使用する各配列の一旦、クリア++++++++++++++++++++++++++
            ary_crc_32s.Clear();
            ary_uncompressed_sizes.Clear();
            relative_offset_of_local_header.Clear();


            //★終盤戦End of central directory recordの記述********************************************
            //全Central file headerに要したの合計バイト数を予め算出しておく
            size_of_the_central_directory = BitConverter.GetBytes(
                Convert.ToInt32(fs.Length - offset_of_start_of_central_directory_int));

            //■End of central directory recordの作成------------ここから-----------------
            //○end_of_central_dir_signatureの記述(4バイト)
            ary_zip_file.AddRange(end_of_central_dir_signature);

            //○ディスク分割情報(2+2バイト)
            ary_zip_file.AddRange(number_of_this_disk);

            //○アーカイブしたファイルの個数(2+2バイト){同じ内容を重複して格納}
            total_number_of_entries = BitConverter.GetBytes(Convert.ToInt16(ary_file_name_arys.Count));
            ary_zip_file.AddRange(total_number_of_entries);
            ary_zip_file.AddRange(total_number_of_entries); //※重複分

            //○全Central file headerに要したの合計バイト数を格納(4バイト)
            ary_zip_file.AddRange(size_of_the_central_directory);

            //○最初のCentral file headerの記述されたバイト位置(4バイト)
            ary_zip_file.AddRange(offset_of_start_of_central_directory);

            //○ファイルへのコメントのサイズ(2バイト){今回はなし}
            ary_zip_file.AddRange(ZIP_file_comment_length);

            try
            { //一旦、書き貯めたバイト型配列の内容をファイルに出力する
                fs.Write((byte[])ary_zip_file.ToArray(), 0, ary_zip_file.Count);
                fs.Flush();
                await System.Threading.Tasks.Task.Delay(10);//これがないと、書き込み途中で放棄される？？
            }
            catch { }
            ary_zip_file.Clear(); //初期化
            //■End of central directory recordの作成------------ここまで-----------------


            //初期化
            Array.Clear(total_number_of_entries, 0, total_number_of_entries.Length);
            Array.Clear(size_of_the_central_directory, 0, size_of_the_central_directory.Length);//初期化
            Array.Clear(offset_of_start_of_central_directory, 0, offset_of_start_of_central_directory.Length);//初期化


            //◎使用する各配列の念のためクリア++++++++++++++++++++++++++
            ary_crc_32s.Clear();
            ary_uncompressed_sizes.Clear();
            relative_offset_of_local_header.Clear();

            //◎配列の初期化2++++++++++++++++++++++++++
            ary_Clear(ref ary_zip_file, true);
            ary_file_name_arys.Clear();

            //■後処理
            fs.Close(); //ファイルを閉じる 
        }


    }


    public string title_string = "タイトル";
    public string subtitle_string = "サブタイトル";
    public string[] seal_string;
    public string[] main_string;

    public StringBuilder content_xml_make_main()
    {   //content.xmlの本文を作成する場所
        StringBuilder xmldata = new StringBuilder();

        //◆1行目（タイトル・肩書）
        xmldata.Append("<table:table-row table:style-name=\"ro1\">");
        //1列目{2行目と結合}
        xmldata.Append("<table:table-cell office:value-type=\"string\" table:number-columns-spanned=\"1\" table:number-rows-spanned=\"2\" table:style-name=\"ce4\"><text:p>" +
            title_string +
            "</text:p></table:table-cell>");

        //2列目(空白)
        xmldata.Append("<table:table-cell table:style-name=\"ce1\"/>");

        //3列目(肩書1)
        xmldata.Append("<table:table-cell office:value-type=\"string\" table:style-name=\"ce3\"><text:p>" +
            seal_string[0] +
            "</text:p></table:table-cell>");
        //4列目(肩書2)
        xmldata.Append("<table:table-cell office:value-type=\"string\" table:style-name=\"ce3\"><text:p>" +
            seal_string[1] +
            "</text:p></table:table-cell>");

        //1行目おわり
        xmldata.Append("</table:table-row>");


        //◆2行目（押印枠）
        xmldata.Append("<table:table-row table:style-name=\"ro2\">");
        //1列目は、1行目との結合で遮蔽されている
        xmldata.Append("<table:covered-table-cell/>");
        //2列目(空白)
        xmldata.Append("<table:table-cell table:style-name=\"ce1\"/>");
        //3列目(押印枠1){3行目と結合}
        xmldata.Append("<table:table-cell office:value-type=\"string\" table:number-columns-spanned=\"1\" table:number-rows-spanned=\"2\" table:style-name=\"ce3\"/>");
        //4列目(押印枠1){3行目と結合}
        xmldata.Append("<table:table-cell office:value-type=\"string\" table:number-columns-spanned=\"1\" table:number-rows-spanned=\"2\" table:style-name=\"ce3\"/>");
        xmldata.Append("</table:table-row>");

        //◆3行目（サブタイトル）
        xmldata.Append("<table:table-row table:style-name=\"ro3\">");
        //1列目（サブタイトル）
        xmldata.Append("<table:table-cell office:value-type=\"string\" table:style-name=\"ce2\"><text:p>" +
            subtitle_string +
            "</text:p></table:table-cell>");
        //2列目(空白)
        xmldata.Append("<table:table-cell table:style-name=\"ce1\"/>");
        //3、4列目は、2行目との結合で遮蔽されている
        xmldata.Append("<table:covered-table-cell/>");
        xmldata.Append("<table:covered-table-cell/>");
        xmldata.Append("</table:table-row>");

        //◆4行目（全て空白）
        xmldata.Append("<table:table-row table:style-name=\"ro4\"/>");

        //◆5→14行目（本文）{10行分}
        for (int i = 0; i < 10; i++)
        {
            xmldata.Append("<table:table-row table:style-name=\"ro5\">");
            if (i == 0)
            {
                //1行目は写真の挿入
                xmldata.Append("<table:table-cell office:value-type=\"string\" table:number-columns-spanned=\"1\" table:number-rows-spanned=\"10\" table:style-name=\"ce3\">" +
                    "<text:p/>" + //文字はなし
                    "<draw:frame draw:z-index=\"1\" draw:id=\"id0\" draw:style-name=\"a0\" draw:name=\"pic_image1\" svg:x=\"0.5cm\" svg:y=\"0.1cm\" svg:width=\"10.5cm\" svg:height=\"8.3cm\" style:rel-width=\"scale\" style:rel-height=\"scale\">" +
                    "<draw:image xlink:href=\"media/image1.jpeg\" xlink:type=\"simple\" xlink:show=\"embed\" xlink:actuate=\"onLoad\"/>" +
                    "<svg:title/><svg:desc/></draw:frame></table:table-cell>");
            }
            else
            {
                //上のセルと結合
                xmldata.Append("<table:covered-table-cell/>");
            }

            //コメント本文の記述
            xmldata.Append("<table:table-cell office:value-type=\"string\" table:number-columns-spanned=\"3\" table:number-rows-spanned=\"1\" table:style-name=\"ce3\"><text:p>" +
                main_string[i] +
                "</text:p></table:table-cell>");

            //右2行は結合により遮蔽されている。
            xmldata.Append("<table:covered-table-cell table:number-columns-repeated=\"2\"/>");
            xmldata.Append("</table:table-row>");

        }

        return xmldata;
    }

    public void ary_Clear(ref List<byte> ary, bool Clear_only_flg)
    {
        //指定した配列の初期化をする
        if (ary != null)
        {
            ary.Clear();
            ary = null;
        }
        //初期化のみの場合→出る
        if (Clear_only_flg) { return; }

        //新たに配列をセットしなおす
        ary = new List<byte>();
    }

    private async System.Threading.Tasks.Task<byte[]> CRC_32_Checksum(byte[] bytes)
    {
        //★CRC32の計算をするところ  
        //UIntegerの方法では、上手くできないのですorz  
        //また、返数をByte()でなく、Long型にすると、値が狂います。  

        //https://code.msdn.microsoft.com/office/VBACRC-32-dad7d087  
        //https://blog.csdn.net/ciaos/article/details/12490911
        //http://sanity-free.org/12/crc32_implementation_in_csharp.html

        //計算に時間がかかるので、待機させる
        System.Threading.Tasks.Task<byte[]> uploadTask = System.Threading.Tasks.Task.Factory.StartNew<byte[]>(
        () => {
            //■CRC32のテーブル情報の事前生成  
            uint[] crc32Table = new UInt32[256];
            //CRC-32 の除数0x104c11db7を、予めビットの並び順を左右逆転させた値(0xEDB88320) を使用する。
            uint poly = 0xedb88320;

            uint temp = 0;
            for (uint i = 0; i < crc32Table.Length; ++i)
            {
                temp = i;
                for (int j = 8; j > 0; --j)
                {
                    if ((temp & 1) == 1) //&で、andのビット演算
                    {
                        temp = (uint)((temp >> 1) ^ poly); //^で、xorのビット演算
                    }
                    else
                    {
                        temp >>= 1; //÷(2の1乗)と同じ効果  
                    }
                }
                crc32Table[i] = temp;
            }


            //初期化  
            uint crc = 0xffffffff;

            //■渡されたファイルのバイナリから、CRC-32を算出して返す 
            for (int i = 0; i < bytes.Length; ++i)
            {   //■計算の引き合いに出すテーブルのインデックス番号の算出  
                byte index = (byte)(((crc) & 0xff) ^ bytes[i]);

                //■次のビットにスライドする。  
                //→(crc >> 8)は、crcを(2の8乗)で割っていることと同義  
                crc = (uint)((crc >> 8) ^ crc32Table[index]);
            }

            //ビット反転後バイト配列に変換して返す
            return BitConverter.GetBytes(~crc); //^で、notのビット演算
        });

        return await uploadTask;
    }
}

```

例えば、
以下のようなコードで、ファイルを選択して
変換することが出来ます。


```c#:Form1.cs
        private async void Form1_Load(object sender, EventArgs e)
        {   //ここは適当に記述しています。
            using (OpenFileDialog fileDialog = new OpenFileDialog())
            {   //PDFに直接変換したい画像ファイルを複数選択できるようにしている。
                fileDialog.Filter = "画像データ (*.bmp;*jpeg;*.jpg;*.png)|*.bmp;*jpeg;*.jpg;*.png";
                fileDialog.Multiselect = true;

                //「開く」ボタンが選択された時の処理
                if (fileDialog.ShowDialog() == DialogResult.OK)
                {   
                    //変換したい画像のリストを取得
                    string[] fileName = fileDialog.FileNames;  //こんな感じで選択されたファイルのパスが取得できる

                    //PDFは、今回は仮に、最初のファイルと同じフォルダに「test.pdf」として生成される。
                    CreateODS cls = new CreateODS();

                    //入力する文字を横着して、ここにて指定。
                    cls.title_string = "ここにタイトル";
                    cls.subtitle_string = "ここにサブタイトル";
                    cls.seal_string =　new string[] { "肩書1", "肩書2" };
                    //本文のところ。
                    cls.main_string =　new string[] { "以下、本文です", "今日は晴れ",
                        "湿度は高め", "温度も高め", "いわゆる猛暑日", "とても暑い",
                        "困ったものです", "しかし、", "これも夏", "楽しまねば"};

                    await cls.create_ods(fileName,
                        Path.Combine(Path.GetDirectoryName(fileName[0]), "test.ods"));

                    //おしまいのメッセージ
                    MessageBox.Show("END");
                }
            }

            //さようなら
            Application.Exit();
        }

```

以上のコードを実行すると
指定した画像のフォルダに、odsが生成されてあると思います。