4

スペースを節約するためにgzipで圧縮されたbase64文字列としてファイルからPostgreSQLデータベースに画像データを保存しようとしています。次のコードを使用して画像をエンコードしています。

@file = File.open("#{Rails.root.to_s}/public/" << @ad_object.image_url).read
@base64 = Base64.encode64(@file)
@compressed = ActiveSupport::Gzip.compress(@base64)
@compressed.force_encoding('UTF-8')
@ad_object.imageData = @compressed

オブジェクトを保存しようとすると、次のエラーが発生します。

ActiveRecord::StatementInvalid (PG::Error: ERROR:  invalid byte sequence for encoding "UTF8": 0x8b

Railsコンソールでは、gzip圧縮はデータをASCII8ビットエンコーディングとして出力します。内部エンコーディングと外部エンコーディングをUTF-8に設定しようとしましたが、結果は変わりません。この圧縮データをUTF-8文字列にするにはどうすればよいですか?

4

1 に答える 1

5

これは、いくつかの理由であまり意味がありません。

  1. gzipはバイナリエンコーディングです。出力はバイナリであり、base64は非8ビットクリーンプロトコルを介して送信するためだけのものであるため、base64で何かをエンコードしてからgzipすることにはまったく意味がありません。ファイルを直接gzipで圧縮するだけです。

  2. ほとんどの画像データは、PNGやJPEGなどのコーデックですでに圧縮されており、gzipよりも画像データの圧縮がはるかに効率的です。それを圧縮すると、通常、画像が少し大きくなります。Gzipは、損失ファイルのPNG形式ほど効率的な画像データにはなりません。そのため、画像データが非圧縮の場合、PNGはgzipで圧縮するのではなく圧縮します。

  3. バイナリデータを表す場合、テキストではないため、テキストエンコーディングの問題は実際にはありません。utf-8は有効ではなく、システムにそれを伝えようとすると、さらに問題が発生します。

base64エンコーディングとgzipの手順を完全に廃止します。muが短すぎると言うので、Railsbinaryフィールドを使用して、Railsにバイナリデータのエンコードと送信を処理させます。

byteaデータベースのフィールドを使用して、PNGまたはJPEG画像を直接保存するだけです。これらは伝送用に16進エンコードされており、バイナリの2倍のスペースを必要としますが、バイナリ形式でディスクに保存されます。PostgreSQLbyteaは、圧縮の恩恵を受ける場合、ディスク上のフィールドを自動的に圧縮しますが、ほとんどの画像データは圧縮しません。

画像のサイズを最小化するには、PNG可逆圧縮やJPEG写真などの適切な圧縮形式を選択します。圧縮前に可能な限り画像をダウンサンプリングし、許容可能な品質を生成する最も強力な圧縮を使用します(JPEGなどの不可逆コーデックの場合)。gzip / LZMA/etcで画像をさらに圧縮しようとしないでください。何も達成されません。

16進数が有線でエスケープされるため、送信時にデータのサイズは2倍になります。これを解決するには、PostgreSQLバイナリプロトコル(困難で複雑)またはバイナリクリーンサイドバンドを使用して画像データを送信する必要があります。hexPg gemがSSL圧縮をサポートしている場合は、SSL圧縮を使用してプロトコルトラフィックを圧縮できます。これにより、エスケープのコストが大幅に削減されます。

サイズを最小限に抑える必要がある場合は、PotsgreSQLワイヤープロトコルを使用して画像をデバイスに送信しません。絶対最小サイズ以上のパフォーマンスと信頼性を実現するように設計されています。

于 2012-10-30T00:14:42.517 に答える