クロスブラウザーデータURIの問題について

ウェブサイトの最適化を追求して、最適化されたファイルのサイズを犠牲にすることなく、リクエストの数を減らしたいと思いました。
目標は、さまざまな最適化設定を使用して、さまざまな形式の画像を1つのファイルに転送することです。
ツールとして、データuriとgzip cssファイルを選択しました。 ただし、データURIを使用するIEは非常にうまく機能しません。 しかし、それらにはmhtmlが含まれています。 既存の実装は私の要件を満たしていませんでした、なぜなら 1つのファイルを2回転送する必要がありました。1つはIEの場合はmhtmlで、もう1つは他の全員の場合はデータURIで転送します。 解決策を探して、私はbolkの記事に出会いました 。この記事では、jpeg形式の解決策と、gifおよびpngの理論計算について説明しました。 ほぼ3週間の喫煙マナの後、私はgifとpngのソリューションを実装し、3つの形式すべてのプロセスを自動化することができました。

BASE64


画像はbase64で送信されるため、このエンコードに関連するいくつかのポイントを強調する価値があります。


考慮すべき情報:
英語版ウィキペディアのBase64



Jpeg


JPEGのセクション形式: [ヘッダー] [データ]

C jpegは単純であり、 bolkによって記述されています
HEXエディターを開きます。
FF D8 -IE用のJPEGヘッダー
FF E0 -APP0セクションのアナウンス。画像データまですべてが隠されていますが、
; Background-color:url(data:image / jpeg; base64、 ”-これは他のブラウザで見られます。
IEがこの行をデコードすると、何にも影響しないゴミが判明します
FF D8-他のブラウザーのJPEGの始まり
画像データ 」-すべてのブラウザでこの場所が既に表示されています


ポイントは、CSSの行が次のようになることです。



IEで次のように復号化されます。



他の人は彼女を次のように見ました:



base64の特性により、文字列が正しく暗号化/復号化されるように、一定数の文字を追加で送信する必要があります。 CSSの前後に挿入されます。 数は経験的に計算され選択されました:
/ 9j / 4AA0; background-image:url(データ:image / jpeg; base64; 00、

このプロセスを自動化する私のスクリプト:
#!/usr/bin/ruby
require 'base64'
# :
a= "/9j/4AA0;background-image:url(data:image/jpeg;base64;00,"

#
b=Base64.encode64( File .open( "#{ARGV[0]}" , 'r' ){|f| f.read})

#
File .open( 'temp' , 'w' ){|i| i.write( "#{Base64.decode64(a)}#{Base64.decode64(b)}" )}

# base64
#cat test | base64 | tr -d "\n" > jpeg64.txt
File .open( 'temp2' , 'w' ){|o| o.write(Base64.encode64( File .open( 'temp' , 'r' ){|f| f.read}))}
# File .delete( 'temp' )

c= File .open( 'temp2' , 'r' ){|f| f.read}.gsub(/\/9j\/4AA0backgroundimageurldataimage\/jpegbase6400/, "/9j/4AA0;background-image:url(data:image/jpeg;base64;00," ).gsub(/\n/, "" )

File .open( 'out_jpeg64' , 'w' ){|s| s.write( "#{c}\);" )}
File .delete( 'temp2' )
# css
# cat output64 | tr -d "\n"
# mhtml!!!


* This source code was highlighted with Source Code Highlighter .


考慮すべき情報:
ウィキペディアのJPEG



GIF


この形式では、物事はそれほど良くありません。

できること:


2番目のオプションを選択しました。これにより、base64文字列が読みやすくなり、アニメーション化されていないgifを変換できます。

多かれ少なかれGIFセクションの標準バージョン: [ヘッダー] [サイズ] [データ] [00]

多くのGIFには正しいフィールド順序がありません。 たとえば、 「convert jpeg gif」を作成すると 、結果のファイルはスクリプトによって適切に処理されません。 GIMPを使用します。
最初の13バイトは削減できないinfaです。 さらに、11バイトは複雑で、グローバルカラーテーブルを記述します。 00に変更します
カラーテーブルを切り取ります (14バイトからワイヤまで-21 FE xx、xxはコメントサイズ)
cssと最初の13バイトでコメントします。
カラーテーブルを切り取ります (14バイトからワイヤまで-21 FE xx、xxはコメントサイズ)
1文字の「内部コメント」
カラーテーブルを切り取ります (14バイトからワイヤまで-21 FE xx、xxはコメントサイズ)
2c 00 00 00 00-イメージ記述子。 10バイト目は複雑で、ローカルカラーテーブルを記述しています。 11番目のバイトから転送されるものすべて(ローカルカラーテーブルの宣言、並べ替えられた\いいえ、ローカルカラーテーブルのサイズ)、さらにフォーマット仕様を転送します。
カラーテーブルを挿入する
続きの画像記述子


ポイントは、CSSの行が次のようになることです。



すべての編集の前にファイルが次のように見えたという事実にもかかわらず:



プロセスを自動化するスクリプト:
#!/usr/bin/ruby
# CONVERT INCORRECTLY TRANSFER DATA. USE GIMP INSTEAD
# USE: ./GIF_SCRIPT.RB [GIF_FILE]
require 'base64'

# OPEN GIF FILE IN HEX
orig= File .open( "#{ARGV[0]}" , 'r' ){|f| f.read.unpack( "H*" )}.to_s

# FUTURE HEADER
header=orig[0..25]

# GREP GENERAL COLOR TABLE
# [26..1565]/6 = 256 BYTE (MAX SIZE OF COLOR TABLE)
color_table=orig[26..1565][/(.*)21fe/,1]
if color_table. class == NilClass
color_table=orig[26..1575][/(.*?)2c0000/,1]
end

# FOR DEBUGING
#puts color_table
#puts color_table.length
puts "COLORS IN PALLETE: #{color_table.length/6}"

# GIF IMAGE DATA
data=orig[/2c0000.*/]

# SAVE 11 BYTE 'S INFO AND ADOPT IT FOR LOCAL COLOR TABLE
eleven=header[20..21].to_i(16).to_s(2)
local_mix="10#{eleven.split("")[4].to_s}00#{eleven.split("")[5..7].to_s}".to_i(2).to_s(16)

# 11 BYTE TO ZERO
header[20..21]="00"
# DECLARE LOCAL COLOR TABLE
data[18..19]=local_mix

# MAGIC COMMENT
comment=Base64.decode64(";background-image:url(data:image/gif;base64;pzd,").unpack("H*").to_s

# WRITE ALL IN ONE FILE
var=header+"21fe313030"+comment+header+"21fe013000"+data[0..19]+color_table+data[20..-1]
File.open('
out .gif ',' w '){|f| f.write(var.to_a.pack("H*"))}

# ENCODE FILE TO BASE64 WITH "\n" REMOVING
File.open('
temp ',' w '){|o| o.write(Base64.encode64(File.open(' out .gif ',' r '){|f| f.read}).gsub(/\n/,""))}

# MAKE STRING CSS READEABLE
c=File.open('
temp ',' r '){|f| f.read}.gsub(/backgroundimageurldataimage\/gifbase64pzd/,";background-image:url(data:image/gif;base64;pzd,").gsub(/\n/,"")
File.delete('
temp ')

# JUST PASTE TEXT FROM THIS FILE TO CSS
File.open('
out_gif64 ',' w'){|s| s.write( "#{c}\);" )}


* This source code was highlighted with Source Code Highlighter .



アニメーションgif用のスクリプトはありません。 アニメーション化されたCSSスプライトを使用する方が良いと思います。

理論計算:



考慮すべき情報:
GIFカラーテーブル
GIF仕様



PNG


gifの後は静かな天国です。 セクションのサイズは無制限で、4バイトのヘッダーがあり、検索に非常に便利です。 比較のために、gifの場合はほぼ1日中頭を悩ませてスクリプトを非難しましたが、pngの場合は1時間ですべてを行いました。

PNGのセクションの形式: [サイズ(4バイト)] [データ] [CRC(4バイト)]

そして、いくつかの落とし穴がありました。 CRCはIEにとって非常に重要です。CRCが壊れている場合、IEは画像を表示しません。 残りのすべてに、彼は並行して深くbeatられたりされません。

多くのPNGの構造は正しくありません。いずれの場合も、 optipngを実行するまでスクリプトは機能しません。 画像の最適化に加えて、このプログラムはフィールドを正しい順序に配置します。 また、PhotoshopがsRGBフィールドを時々カットし、保存されたpngが常に処理されるわけではないことに気付きました。

CSSはtEXtセクションで非表示になります

PNGはoptipngですぐに最適化する必要があり、tExtがIHDRのすぐ後ろになるように切り刻む必要があります。
Keyword00はtEXtセクションで渡される必要があり、その長さはセクションの全長で考慮されます。 この「コメント」があります

一般注文:
Ihdr
tExt
その他のサービス情報
データ



それは:



次のようになりました:



スクリプトはよくコメントされており、仕様から多くを学ぶことができます。

IE6は透明度を認識しません。必要な背景色を設定することでbKGDで修正できる場合があります。

次に、 `optipng -fix FILE`を実行して、tEXtセクションのCRCを修正します

プロセスを自動化するスクリプト:
#!/usr/bin/ruby
#
#!!!! RUN optipng FIRST !!!!
#
# USE: ./PNG_SCRIPT.RB [PNG_FILE]
require 'base64'
# OPEN GIF FILE IN HEX
orig= File .open( "#{ARGV[0]}" , 'r' ){|f| f.read.unpack( "H*" )}.to_s

#ihdr=orig[0..65]
ihdr=orig[/(.*?)73524742/,1][0..-9]

#sRGB - 73 52 47 42 & -4b (8 characters)
#srgb_phys=orig[66..171]
#check for tEXt existence
if orig[/74455874/]. class == NilClass
srgb_phys=orig[/(.{8}73524742.*?)49444154/,1][0..-9]
else
srgb_phys=orig[/(.{8}73524742.*?)74455874/,1][0..-9]
end

#srgb_phys=orig[/(.{8}73524742.*?)74455874/,1][0..-9]

#tEXt - 74 45 58 74 –њ–Њ—–ї–µ–і–љ–Є–µ 8 –љ–∞–і–Њ –Љ–µ–љ——— –љ–∞ CRC 00000000
#text=orig[172..245]
#text=orig[/(.{8}74455874.*?)49444154/,1][0..-9]

#IDAT - 49444154
#data=orig[246..-1]
data=orig[/.{8}49444154.*/]

#MAGIC COMMENT
comment=Base64.decode64( ";background-image:url(data:image/png;base64;pzd," ).unpack( "H*" ).to_s

###### OUTER PNG
# "00000059" + "74455874" + "436f6d6d656e7400"
# tEXt_length + 'tEXt' + 'Comment.'
# "3030" - two zero for base64 balance
###### INNER PNG
# "00000008" + "74455874" + "436f6d6d656e7400" + "00000000"
# min_tEXt_length + 'tEXt' + 'Comment.' + blank CRC
#
# CRC field one for two PNG 's
# IE can'
t live without it, but others feel indifferently
var =ihdr+ "00000059" + "74455874" + "436f6d6d656e7400" + "3030" +comment+ihdr+ "00000008" + "74455874" + "436f6d6d656e7400" + "00000000" +srgb_phys+data

File .open( 'out.png' , 'w' ){|f| f.write( var .to_a.pack( "H*" ))}

# CRC FIX
puts "optipng -fix started..."
`optipng -fix out .png`
puts "optipng -fix completed"

# ENCODE FILE TO BASE64 WITH "\n" REMOVING
File .open( 'temp' , 'w' ){|o| o.write(Base64.encode64( File .open( 'out.png' , 'r' ){|f| f.read}).gsub(/\n/, "" ))}

# MAKE STRING CSS READEABLE
c= File .open( 'temp' , 'r' ){|f| f.read}.gsub(/backgroundimageurldataimage\/pngbase64pzd/, ";background-image:url(data:image/png;base64;pzd," ).gsub(/\n/, "" )
File .delete( 'temp' )

# JUST PASTE TEXT FROM THIS FILE TO CSS
File .open( 'out_png64' , 'w' ){|s| s.write( "#{c}\);" )}


* This source code was highlighted with Source Code Highlighter .


考慮すべき情報:
PNGの基本
PNG仕様



Mhtml


MHTMLを使用する場合は、CSSを完全に編集し、セクションに分割する必要があります(アーカイブ内の例)。
/*
Content-Type: multipart/related; boundary="_"

--_
Content-Type: text/css;

*/
html, body {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
}

#half_logo {
/*
--_
Content-Location:logo
Content-Transfer-Encoding:base64
Content-Type: image/png;*/

iVBORw0KGgoAAAANSUhEUgAAAT4AAAA3CAMAAACintZ+AAAAWXRFWHRDb21tZW50ADAw;background-image:url(data:image/png;base64;pzd,iVBORw0K...);

/*
--_
Content-Type: text/css;

*/
background-image: url(mhtml:http://192.168.1.2/test.css!logo) !ie;
/*
--_--
*/

* This source code was highlighted with Source Code Highlighter .


ソースとスクリプトでアーカイブする
作業現場の例

FF 3.6、Opera 10.10、クロム、クロム、IE6-8でテスト済み

PS:この記事の著者は、私の親友であるBanderlogです。 私は彼の要求に応じて記事を投稿します;したがって、jabber:banderlog@jabber.com.uaで直接質問することをお勧めします
PPS:記事の投稿中にスクリプトで地獄のような間違いが行われたという事実が2日目に明らかになったことは奇妙です。 3つすべてが同じでした。

Source: https://habr.com/ru/post/J90761/


All Articles