今すぐ修復
- ファイルをドロップ
- 修復はローカルで実行
- 結果をダウンロード
.png として保存したスクリーンショットが開かないとき、ビューアーはたいてい、この形式が正確にチェックできる何かに対して厳格になっています。Windows フォト(Windows Photos)は "It looks like we don't support this file format"(このファイル形式はサポートされていないようです)や "This file can't be opened"(このファイルを開けません)と表示し、macOS のプレビュー(Preview)はファイルが "may be damaged or use a file format Preview doesn't recognize"(破損しているか、プレビューが認識できない形式を使っている可能性があります)と表示します。libpng ベースのツールは IDAT: CRC error、IHDR: CRC error、あるいは Not a PNG file を投げます。上にファイルをドロップすると、ツールはブラウザ内でそれをチャンクごとにたどり—各 CRC を検証し、8 バイトのシグネチャと IHDR のジオメトリを確認し、DEFLATE ストリームを生き残っている限りデコードして—実際にそこにあるものの周りに有効なファイルを書き直します。何もアップロードされません。スクリーンショットには銀行の残高、非公開のメッセージ、医療ポータルが写っていることも多く、チェックのためにあなたのマシンから外に出る必要は決してありません。
PNG スクリーンショットはどう組み立てられているか
すべての PNG は同じ 8 バイトのシグネチャ—89 50 4E 47 0D 0A 1A 0A—で始まります。これは意図的にいくつもの仕掛けを詰め込んだ指紋です。上位ビットの立ったバイト 0x89 は 7 ビットしか通さないチャンネルを検出し、0D 0A と単独の 0A は改行コードの変換を検出し、1A(DOS のファイル終端)は不用意な type コマンドが以降を吐き出すのを止めます。その後に一連のチャンクが続き、それぞれが整然としたパッケージになっています。4 バイトのビッグエンディアンの長さ、4 バイトの ASCII タイプ、データ、そして標準の反転多項式 0xEDB88320 を用いてタイプとデータ(長さは決して含めません)に対して計算された 4 バイトの CRC-32 です。
3 つのチャンクが画像を担います。IHDR が最初に来て、常に 13 バイトです。幅(u32)、高さ(u32)、続いてビット深度、カラータイプ、圧縮方式、フィルター方式、インターレース方式を表す各 1 バイトです。現代の OS のスクリーンショットはほぼ必ず 8 ビット、非インターレース、カラータイプ 2(トゥルーカラー)または 6(アルファ付きトゥルーカラー)です。IDAT は画像を保持し、ときに連続する複数の IDAT チャンクに分割されます。その内部には、DEFLATE で圧縮されたフィルター済みスキャンラインの zlib ストリーム(ヘッダーバイト 0x78)が収まっています。各行の先頭には 0〜4 のフィルターバイト(None, Sub, Up, Average, Paeth)が付き、上から下へと書き込まれます。IEND は空の終端マーカーで、固定の CRC AE 42 60 82 を持ちます。
スクリーンショットには、見覚えのある補助チャンクも含まれます—最初の文字が小文字であることが、それらが任意であることを示します—たとえば pHYs(ピクセル密度。Retina のキャプチャがその倍率を報告できるようにします)、iCCP や sRGB(カラープロファイル)、tEXt/eXIf(キャプチャツールが刻むメタデータ)などです。これらは 1 ピクセルも失うことなく破損したり欠落したりできます。デコーダーは、理解できない補助チャンクをどれでも読み飛ばしてよいことになっているからです。
きれいで決定論的に直せる破損
各チャンクが自己検証するため、PNG の破損のうち丸ごと 1 群は、当て推量ではなく分かりきった答えを持ちます。
- チェックサムが誤り、データは正しい。 最も多い誤警報です。チャンクのバイトは無傷なのに、保存されている CRC がもはや一致しないため、厳格なデコーダー(や
pngcheck)はCRC error in chunk IDATでファイルを拒否します。データから CRC-32 を再計算して書き戻せば、ゼロの損失でファイルは再び有効になります—誤っていたのはチェックサムだけだったのです。 - 寸法のゼロ化や破損。 IHDR の幅や高さがゼロになっていると、どのデコーダーもキャンバスを確保できず、ファイルは開きません。しかし IHDR は、数値が正しかった当時に計算された独自の CRC を持っています。これにより、修復はジオメトリを総当たりで求められます。候補となる幅/高さの値を試し、それぞれについてチャンクの CRC を再計算し、保存されている値と一致したところで止めます。元の寸法は計算からそのまま導き出されます—当て推量はありません。
- 改行 / テキストモードによる文字化け。 ASCII モードの FTP クライアント、チャットのブリッジ、あるいはファイルをテキストとして書き直したスクリプトを通ったスクリーンショットは、すべての
0D 0Aを単独の0Aに(またはその逆に)置き換え、ファイル全体のバイトを破損させます。シグネチャはまさにこれを検出するよう設計されており、置換が一貫している場合は 1 バイト単位で元に戻せます。 - IEND の欠落や破損。 それ以外は完全でありながら末尾の終端マーカーを失ったファイルは、「不完全なファイル」の警告を発します。有効な IEND を書き直せば、既にすべて揃っている画像を厳格なデコーダーが受け入れられるようになります。
行を失わせる破損
正直な限界は、ピクセルデータそのものが失われたところから始まります。そしてスクリーンショットはその両方に見舞われます。
切り詰め—上部は戻る。 これはスクリーンショットが壊れる最も一般的な形です。ディスクが一杯になって中断した保存、スマホを抜いたときに途切れたコピー、80 パーセントで止まったクラウド同期などです。ファイルの前半は無傷で、末尾—通常は IEND を含みます—は単に存在しません。スキャンラインは上から下へと書き込まれるため、切り詰められた PNG は画像の上部として救出されます。データが終わるところまでの本物のピクセルです。修復は有効なトレーラーを書き直し、デコーダーがファイルを受け入れて生き残った分を描けるようにします。切断より下の行は破損しているのではなく、存在しません。だからどんなツールもそれらを返せません—結果は正直な部分復元です。
IDAT の途中での破損—下部はノイズ。 破損が末尾ではなく DEFLATE ストリームの内部に落ちた場合、回復不能になる理由は DEFLATE そのものにあります。これは各部分が直前の内容に依存する 1 本の連続したストリームで、再同期できる定期的なマーカーがありません。デコーダーはひとたび不良バイトに当たると流れを見失い(zlib は incorrect data check / invalid distance too far back を報告します)、それ以降のすべてはノイズとしてデコードされます。途中で 1 バイト反転しただけで、1 行だけでなくその下のすべての行を失いかねません—画像は当たった箇所より上はきれいで、下はゴミになります。だからこそスクリーンショットは、鮮明な上部とにじんだ、あるいは灰色の下半分とともに開くのです。切り詰められた JPEG が与えるのと同じ形の結果です。
これを、インデックスをデータと分けて保持する形式—QuickTime 動画の moov、SQLite の b-tree—と比べてみてください。そちらではマップを再構築すればファイル全体が救われます。PNG はピクセルを 1 本の分割不能な DEFLATE ストリームに保持するため、途中の傷は切断より下では永続的です。
修復できるものとできないもの
修復できる
- 保存された CRC-32 が、それ以外は無傷なデータともはや一致しないチャンク—CRC を再計算し、ファイルは損失ゼロで有効になります
- ゼロ化または破損した IHDR の幅/高さ。チャンク自身の保存された CRC に対して候補を総当たりして復元します
- ASCII モードの転送や、ファイルをテキストとして書き直したスクリプトによる改行 / テキストモードの文字化け(CR-LF ↔ LF)
- 画像データはそれ以外完全なファイルにおける、欠落または不正な IEND 終端マーカー
- 切り詰められたスクリーンショット。実際に書き込まれた上部の行は本物のピクセルとしてデコードされて戻ります
修復できない
- IDAT の途中の被弾より下の画像の行—DEFLATE は再同期できないため、破損したバイト以降はすべてノイズです
- 切り詰められたファイルにおける切断より下の行—それらのピクセルは一度も書き込まれておらず、どんなツールもでっち上げられません
- 0 バイト、あるいはすべてゼロとして読み取られるファイル—再構築すべき画像がありません(それは修復ではなくデータ復旧の仕事です)
- 破損後に別のアプリが再エンコードまたは再圧縮したスクリーンショット—誤ったピクセルがもう焼き付いています
- 文字化けした下半分のピクセル単位で正確な復元—修復は正直な部分復元を返すのであって、灰色の行を取り戻すわけではありません
修復が失敗した場合、その理由(データの欠落か構造の破損か)をお伝えします。失敗した修復に料金が請求されることはありません。