C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

自前での圧縮Tiffファイル解凍について

[トピック内 2 記事 (1 - 2 表示)]  << 0 >>

■84945 / inTopicNo.1)  自前での圧縮Tiffファイル解凍について
  
□投稿者/ ag (1回)-(2017/08/24(Thu) 16:06:09)

分類:[C#] 

お世話になっております。

現在、別ソフト(ペイントなど)で保存したTiffファイルを解凍するソフトを、C#にて作成しています。
ですが、出力される内容が圧縮前と同じ内容になってしまい、原因が分からない状態です。

下記は、圧縮された画像データを解凍する関数になります。
これにTiffタグを取り除いた画像データ(ushort配列)を渡しています。
この関数の戻り値として返る配列と、引数として渡している配列の内容を比較すると、同一の内容になってしまいます。

private byte[] Decompress(ushort[] lzw)
{
    byte[] src = null;
    
    try
    {
        // 辞書の初期化
        dic = new System.Collections.ArrayList();
        for (int c = 0; c < 256; c++) dic.Add(c.ToString("X").PadLeft(2, '0'));
        dic.Add("CLEAR"); // クリアコード
        dic.Add("END");   // 終了コード

        // 解凍
        int i = 0;
        int n = 0;
        string w = "";  // プレフィックス
        string k = "";  // サフィックス

        // 解凍
        dat = new System.Collections.ArrayList();
        w = dic[lzw[i++]].ToString();
        while (i < lzw.Length)
        {
            if (lzw[i] >= dic.Count)
            {
                dic.Add(w + w.Substring(0, 2));
                k = dic[lzw[i++]].ToString();
                for (int j = 0; j < w.Length; j += 2) dat.Add(w.Substring(j, 2));
                w = k;
            }
            else
            {
                k = dic[lzw[i++]].ToString();
                dic.Add(w + k.Substring(0, 2));
                for (int j = 0; j < w.Length; j += 2) dat.Add(w.Substring(j, 2));
                w = k;
            }
        }
        for (int j = 0; j < w.Length; j += 2) dat.Add(w.Substring(j, 2));

        // 元データの作成
        src = new byte[dat.Count];
        for (i = 0; i < dat.Count; i++) src[i] = System.Convert.ToByte(dat[i].ToString(), 16);
    }
    catch { }
    finally { }

    return src;
}

ご存知の方がいらっしゃいましたら、ご教授頂けると幸いです。
宜しくお願い致します。

引用返信 編集キー/
■84955 / inTopicNo.2)  Re[1]: 自前での圧縮Tiffファイル解凍について
□投稿者/ 魔界の仮面弁士 (1398回)-(2017/08/25(Fri) 12:26:33)
2017/08/25(Fri) 13:48:37 編集(投稿者)

No84945 (ag さん) に返信
> 出力される内容が圧縮前と同じ内容になってしまい

データに問題があるか(無圧縮データだったとか)、
展開コードに問題があるかのいずれかだと思います。


> 圧縮された画像データを解凍する関数になります。

ushort は 256 以上の値を扱えますが、byte はそうではないですよね。
「同じ」ということは、lzw に 255(0xFF) を超える値が無かったということでしょうか。

LZW ということは、初期データは 0〜255 だとしても、文字列が長くなれば、
256 以降のコードも順次追加されていくと思います。
辞書も渡す場合はこの閾値も変化しますが、今回の初期辞書は固定ですよね。

そして引数 lzw 内に 0〜255 の範囲のコードしか含まれていないのであれば
それは非圧縮データなので、展開後も同じデータになるはずです。
辞書がスライドされている場合は別として。


> // 辞書の初期化
> dic = new System.Collections.ArrayList();
初期辞書は、258 パターンの文字列をセットしたものなのですね。
("00"〜"FF" の 256 種に、"CLEAR" と "END" の 2 種を加えたもの)

ところで、何故ジェネリックコレクションを使わないのでしょうか。
ArrayList だと object 型でしか扱えないので、
毎回 ToString することになり、効率が悪そうに思うのですが。


> ですが、出力される内容が圧縮前と同じ内容になってしまい、原因が分からない状態です。
クリアコードと終了コードがまったく処理されていないようですが、含まれない前提でしょうか?

たとえばクリアーコードが来た場合は、辞書を初期時状態にリセットする必要があるはずですが、
現在はそれがないので、コード 256 が渡されてきた場合、ArgumentException で中断されてしまうと思います。

エンコード側がクリアーコードや終了コードを使わない仕様なのだとしたら、
初期辞書にそれを含めておく必要があるかどうかを再確認してください。

もし含まれる仕様なのであれば、デコード部にはそのための処理も
記述するべきかと思います。


たとえば提示いただいたコードに対して
 ushort[] lzw = { 84, 65, 258, 71, 259, 67, 84, 258, 259, 266 };
なデータを渡してみると、展開結果は
 byte[] result = { 84, 65, 84, 65, 71, 65, 84, 67, 84, 84, 65, 65, 84, 65, 84, 65};
になりますね。256 以上の部分が展開されていることが分かると思います。


もしも、クリアコードと終了コードを含まない辞書の場合には、
その 2 つ分だけ、258→256、259→257 のようにコードがずれるので、
 ushort[] lzw = { 84, 65, 256, 71, 257, 67, 84, 256, 257, 264 };
を渡したときに、上記と同じ変換結果が得られる仕組みです。
引用返信 編集キー/

このトピックをツリーで一括表示


トピック内ページ移動 / << 0 >>

このトピックに書きこむ