首页 > 解决方案 > 如何在 BYTEA 的 PostgreSQL 数据库中编码 JPG 图像

问题描述

所以我有一些 JPG 图像存储在BYTEAPostgreSQL 数据库表的列中。我想提取二进制文件并将其放入<img\>标签中。这是其中一个文件的第一个位...

mydb=# SELECT LEFT(encode(image_file, 'escape'), 80) FROM image_files WHERE id = '53';                                                                         
                                       left
----------------------------------------------------------------------------------
 x/ffd8ffe000104a46494600010100000100010000ffdb004300100b0c0e0c0a100e0d0e12111013
(1 row)

这个二进制数据非常符合我在实际图像文件中看到的内容(使用 Vim 的“转换为十六进制”)......

在此处输入图像描述

但是当我尝试将其编码为base64(以便我可以通过 XSLT 使用数据以包含在网页中)时,它似乎已损坏。这是我的查询中的一个片段......

xmlelement(NAME "pictures",
    xmlagg(
        xmlelement(NAME "src", CONCAT('data:image/jpg;base64,', encode(image_file, 'base64')))
    )
)

在 HTML 中,我看到...

<img src="data:image/jpg;base64,eC9mZmQ4ZmZlMDAwMTA0YTQ2NDk0NjAwMDEwMTAwMDAwMTAwMDEwMDAwZmZkYjAwNDMwMDEwMGIw+
YzB..."/>

...而不是看到我所期望的...

<img src="data:image/jpg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDABALDA4MChAODQ4SERAT..."/>

我不知何故发现(我不记得怎么做了!)如果我在开头用 '\x' 替换上面的 'x/',我会得到我期待的字符串......

mydb=# SELECT encode('\xffd8ffe000104a46494600010100000100010000ffdb004300100b0c0e0c0a100e0d0e12111013', 'base64');  
                        encode
------------------------------------------------------
 /9j/4AAQSkZJRgABAQAAAQABAAD/2wBDABALDA4MChAODQ4SERAT
(1 row)

所以我想知道,当 PG 尝试将十六进制字节数组编码为 时base64,它是否也可能在字节数组中看到“ x/”,这是否会导致它被丢弃?但对于我的一生,我无法弄清楚如何在查询中纠正这个问题。

我敢肯定这是每天都会发生的事情,现在不应该让我挠头将近一个星期!如果我遗漏了任何内容或需要任何版本信息,请告诉我。

标签: xmlpostgresql

解决方案


首先将您的文件保存到数据库中的任何内容都将它们搞砸了。它们可能保存在 bytea 列中,但它实际上是存储十六进制数字的文本数据,带有 2 个文字字符x/无用且误导性地添加到前面。所以有些东西对二进制进行了十六进制编码,但随后存储了十六进制编码的字符串,就好像它仍然是二进制一样。

您需要切掉前 2 个字节,然后将结果字符串从 bytea 转换回文本。然后将保存十六进制数字的文本转换为真正的二进制,然后返回 base64。

SELECT encode(decode(substring(image_file,3)::text,'hex'),'base64') FROM image_file WHERE id = whatever;

(您实际上也可以在子字符串之前对文本进行强制转换)

但不是每次都进行这种转换,您可能应该重构您的表以保存更合理的数据。“更明智”将意味着存储在 bytea 列中的 bytea 数据,或者(如果您只想处理 base64)存储在文本列中的 base64 数据。


推荐阅读