/// <summary> /// コンストラクタ /// </summary> public ScanJpeg() { for (int i = 0; i < _dcHDT.Length; i++) { _dcHDT[i] = new HuffmanDecodeTable(); _acHDT[i] = new HuffmanDecodeTable(); } }
/// <summary> /// ブロックデータを読み出す。 /// </summary> /// <param name="qDct">量子化後のDCT係数列格納メモリ</param> /// <param name="qDctIndex">qDctのインデックス</param> /// <param name="pred">直流係数予測値</param> /// <param name="dcHDT">直流係数用ハフマン復号テーブル(DC HDT)</param> /// <param name="acHDT">交流係数用ハフマン復号テーブル(AC HDT)</param> /// <returns>処理結果</returns> private ReturnID ReadBlockData(ref short[] qDct, int qDctIndex, ref short pred, HuffmanDecodeTable dcHDT, HuffmanDecodeTable acHDT) { // 直流係数を復号する。 { // 直流係数と予測値の差分のカテゴリ(=後続のビット数)を復号する。 byte index = dcHDT.CodeToIndexLookUpTable[PeepBits(dcHDT.BitLengthMax)]; if (index > dcHDT.IndexMax) { return(ReturnID.JpegDataErrorUnexpectedData); // 予期せぬJPEGデータ } SkipBits(dcHDT.BitLength[index]); byte dcDiffBitLength = dcHDT.Symbol[index]; if (dcDiffBitLength > 11) { return(ReturnID.JpegDataErrorUnexpectedData); // 予期せぬJPEGデータ } // 後続のビットがある場合 if (dcDiffBitLength != 0) { // 後続のビットを読み出し、直流係数と予測値の差分を求める。 short dcDiff = (short)ReadBits(dcDiffBitLength); if (dcDiff < _positive[dcDiffBitLength]) { dcDiff += _makeNegative[dcDiffBitLength]; } // 直流係数を計算する。この値は次ブロックの直流係数の予測値となる。 pred += dcDiff; } // 後続のビットがない場合は、予測値がそのまま直流係数になるので計算不要。 if (qDct != null) { // 直流係数を量子化後のDCT係数列格納メモリに代入する。 qDct[qDctIndex] = pred; } } // 交流係数を復号する。 for (int k = 1; k < 64;) // ジグザグスキャン順 { // 交流係数符号表(ゼロ係数の連長と非ゼロ係数の振幅の組み合わせ)を復号する。 byte index = acHDT.CodeToIndexLookUpTable[PeepBits(acHDT.BitLengthMax)]; if (index > acHDT.IndexMax) { return(ReturnID.JpegDataErrorUnexpectedData); // 予期せぬJPEGデータ } SkipBits(acHDT.BitLength[index]); byte zeroRun_AcBitLen = acHDT.Symbol[index]; byte zeroRun = (byte)(zeroRun_AcBitLen >> 4); byte acBitLength = (byte)(zeroRun_AcBitLen & 0x0F); if (acBitLength > 10) { return(ReturnID.JpegDataErrorUnexpectedData); // 予期せぬJPEGデータ } // 後続のビットがある場合 if (acBitLength != 0) { k += zeroRun; if (qDct != null) { // 後続のビットを読み出し、非ゼロ交流係数を求める。 short acVal = (short)ReadBits(acBitLength); if (acVal < _positive[acBitLength]) { acVal += _makeNegative[acBitLength]; } // 非ゼロ交流係数を量子化後のDCT係数列格納メモリに代入する。 qDct[qDctIndex + k++] = acVal; } else { // 後続のビットをスキップする。 SkipBits(acBitLength); k++; } } // 後続のビットがない場合 else { if (15 == zeroRun) { k += 16; } else { k = 64; } } } return(ReturnID.Success); }
/// <summary> /// ハフマン復号テーブルを作成する。 /// </summary> /// <param name="dhts">ハフマンテーブル定義補助</param> /// <returns>処理結果</returns> private ReturnID MakeHuffDecTbl(DefineHuffmanTableSub dhts) { if (dhts == null || dhts.Tc > 1 || dhts.Th > 1 || dhts.Total == 0 || dhts.Total > 256) { return(ReturnID.ErrorInvalidParam); // 不正な引数 } // 処理対象となるハフマン復号テーブルを取得する。 HuffmanDecodeTable hdt = dhts.Tc == 0 ? _dcHDT[dhts.Th] : _acHDT[dhts.Th]; // ハフマン復号テーブルをクリアする。 hdt.BitLengthMax = 0; hdt.IndexMax = 0; if (hdt.CodeToIndexLookUpTable != null) { hdt.CodeToIndexLookUpTable = null; } Array.Clear(hdt.BitLength, 0, hdt.BitLength.Length); Array.Clear(hdt.Symbol, 0, hdt.Symbol.Length); // 符号語格納メモリ(符号語テーブル)を確保する。 ushort[] codeTable = new ushort[dhts.Total]; // 符号語長の配列と符号語テーブルに値を代入する。 byte bitLengthMax = 0; ushort code = 0; int bitLengthIndex = 0; int codeTableIndex = 0; for (byte bitLength = 1; bitLength <= 16; bitLength++) { byte numOfCodes = dhts.Li[bitLength - 1]; if (numOfCodes != 0) { bitLengthMax = bitLength; for (byte count = 0; count < numOfCodes; count++) { hdt.BitLength[bitLengthIndex++] = bitLength; codeTable[codeTableIndex++] = code++; } } code <<= 1; } if (bitLengthMax == 0) { return(ReturnID.JpegDataErrorUnexpectedData); // 予期せぬJPEGデータ } // ハフマン復号用のLookUpTableのメモリを確保し、-1で初期化する。 hdt.CodeToIndexLookUpTable = new byte[1 << bitLengthMax]; for (int i = 0; i < hdt.CodeToIndexLookUpTable.Length; i++) { hdt.CodeToIndexLookUpTable[i] = 0xFF; } // ハフマン復号テーブルに適切な値を代入する。 hdt.BitLengthMax = bitLengthMax; hdt.IndexMax = (byte)(dhts.Total - 1); Array.Copy(dhts.Vij, 0, hdt.Symbol, 0, dhts.Total); // ハフマン復号用のLookUpTableに値を代入する。 bitLengthIndex = 0; codeTableIndex = 0; for (ushort wIdx = 0; wIdx < dhts.Total; wIdx++) { // 最大符号語長と各符号語長との差(nLenDiff)を求める。 int nLenDiff = bitLengthMax - hdt.BitLength[bitLengthIndex++]; if (nLenDiff != 0) { // 符号語をMSB側に寄せた値をLUTの最初のインデックスとし、そこから必要な個数(注) // だけ符号語長およびシンボル値の配列のインデックスを代入する。 // (注) 符号語をMSB側に寄せたためにLSB側に空いたビットを埋めるのに必要な個数。 ushort wLUTIdx = (ushort)(codeTable[codeTableIndex++] << nLenDiff); for (int i = 0; i < 1 << nLenDiff; i++) { hdt.CodeToIndexLookUpTable[wLUTIdx + i] = (byte)wIdx; } } else { hdt.CodeToIndexLookUpTable[codeTable[codeTableIndex++]] = (byte)wIdx; } } return(ReturnID.Success); }