使用 SSIS 从 XML 中提取 base64 编码的图像

问题描述

我有一个复杂的场景,客户发送 XML 文件,我应该从这些文件提取一些信息。一个重要的信息是以 base64 编码的图像。

xsdxml 文件,定义了包含 base64 编码图像的元素,如下所示:

   <xs:element name="image" type="xs:base64Binary" nillable="false" minOccurs="0" maxOccurs="unbounded">
      <xs:annotation>
        <xs:documentation xml:lang="en">
          base64 image.
        </xs:documentation>
      </xs:annotation>
    </xs:element> 

在 SSIS 中,我使用 XML Source 组件来提取元素。在组件的“输入和输出属性”中,我将数据类型(在与 base64-image 元素相关的外部/输出列中)定义为 image [DT_IMAGE] 类型。

问题 1: 选择这种数据类型来读取 base64 编码的图像是否正确? byte stream [DT_BYTES] 或只是 string [DT_STR] 怎么样?

接下来,我将组件的输出传递给 Recordset Destination 以将输出存储在类型为 User::xml_image 的 SSIS 变量 Object 中(我这样做是因为可能有多个图片)。

然后将对象变量传递给 Script Task,转换为 DataTable,我试图将“假设第一行/图像”保存到文件系统中。我使用的代码是:

            DataTable table = new DataTable();
            oleAdapter.Fill(table,Dts.Variables["xml_image"].Value);

            Image image;
            BinaryFormatter bf = new BinaryFormatter();
            var ms = new MemoryStream();

            // convert the first image
            bf.Serialize(ms,table.Rows[0]["image"]);
            byte[] bytes = ms.ToArray();

            using (MemoryStream mem = new MemoryStream(bytes))
            {
                mem.Seek(0,SeekOrigin.Begin);
                image = Image.FromStream(mem); // error in this line: Parameter is not valid.
                image.Save("D:\\tepack.jpeg",ImageFormat.Jpeg);
            }

脚本执行直到调用 FromStream 方法并失败并显示错误

参数无效。

Q2:如何修复代码错误,并成功保存图片,考虑以上场景和配置?

解决方法

A1. DT_IMAGE vs DT_BYTES VS DT_STR

根据定义,base64 编码的二进制是 ASCII 字符串数据,因此数据的初始提取将是 DT_STRmaybe

那时,您就拥有了 XML 中的字符,您可以对其进行目视检查以确认是的,我从 XML 中正确地提取了该字段。

下一步是将 base64 编码或 decode 反转为原始二进制位。

A2. Image.FromStream 错误

我不确定 Image 类的来源,但它可能试图将数据转换为不同的图像格式(png 到 jpg 到 bmp 等),但您已经在内存中的位 是你需要的部分。您只需要将该字节数组写入磁盘,类似于

https://www.oreilly.com/library/view/c-cookbook/0596003390/ch02s12.html

byte[] imageBytes = Base64DecodeString(bmpAsString);
fstrm = new FileStream(@"C:\winnt_copy.bmp",FileMode.CreateNew,FileAccess.Write);
BinaryWriter writer = new BinaryWriter(fstrm);
writer.Write(imageBytes);
writer.Close( );
fstrm.Close( );

也许 在线书籍上数据类型的链接指出了数据类型的最大长度,我们看到一个 DT_STR 是 8000 个字符,而 DT_IMAGE/DT_BYTES/DT_TEXT 是 210 万个单位(字符或字节)。由于这些都不是 unicode 数据,因此存储成本都相同,但没有任何表达式语言可以对数据进行操作(空值和长度检查 IIRC 除外),并且数据查看器将集中在那里,因此可能需要进行目视检查要有挑战性。

jpg 是一种压缩文件格式 - 他们丢弃数据以减少字节数。但是 Base64 是反压缩的,因为它会膨胀大小,作为将危险的二进制字符映射到安全的 ascii 字符的一部分。因此,除非您知道源图像非常小,否则很可能会溢出 8000 个字符的边界。

假设通货膨胀率为 1.3,您会看到大约 5970 字节的最大原始大小。一个 6kb 的 jpg 文件可能很小而且质量很低。例如,此图像为 5151 字节

A scene from the film Airplane! The automatic pilot,and Elaine the stewardess are in the cockpit (It's the little room in the front of the plane where the pilots sit,but that's not important right now) smoking

最后的想法 由于我已经输入并考虑了问题域,除非您有充分的理由使用数据流,否则在这种情况下我会避免使用它。相反,使用脚本任务来分解 XML。我认为,如果您不必担心将数据类型拟合到 SSIS 基元类型以及您的所有操作都已经是 .NET 脚本操作这一事实,那么问题就会更少。