/// <summary> /// Create a copy by value. /// </summary> /// <returns> /// The newly created copy /// </returns> public InterWaveBlock Duplicate() { InterWaveBlock retval = null; try { short[][][] pdata = (short[][][])this._PData.Clone(); for (int i = 0; i < pdata.Length; i++) { if (pdata[i] != null) { pdata[i] = (short[][])pdata[i].Clone(); for (int j = 0; j < pdata[i].Length; j++) { if (pdata[i][j] != null) { pdata[i][j] = new short[pdata[i][j].Length]; pdata[i][j].CopyTo(pdata[i][j], 0); } } } } retval = new InterWaveBlock { PData = pdata }; } catch { } return(retval); }
public InterWaveMap(int width, int height) { Width = width; Height = height; BlockWidth = ((width + 0x20) - 1) & unchecked ((int)0xffffffe0); BlockHeight = ((height + 0x20) - 1) & unchecked ((int)0xffffffe0); BlockNumber = (BlockWidth * BlockHeight) / 1024; Blocks = new InterWaveBlock[BlockNumber]; for (int i = 0; i < Blocks.Length; i++) { Blocks[i] = new InterWaveBlock(); } }
/// <summary> /// Estimates image quality in dB. /// </summary> /// <param name="frac"></param> /// <returns></returns> public unsafe float EstimateDecibel(float frac) { int i, j; float *q; // Fill norm arrays float[] normLo = new float[16]; float[] normHi = new float[10]; GCHandle iw = GCHandle.Alloc(iw_norm, GCHandleType.Pinned); // -- lo coefficients q = (float *)iw.AddrOfPinnedObject(); for (i = j = 0; i < 4; j++) { normLo[i++] = *q++; } for (j = 0; j < 4; j++) { normLo[i++] = *q; } q += 1; for (j = 0; j < 4; j++) { normLo[i++] = *q; } q += 1; for (j = 0; j < 4; j++) { normLo[i++] = *q; } q += 1; // -- hi coefficients normHi[0] = 0; for (j = 1; j < 10; j++) { normHi[j] = *q++; } float[] xMse = new float[_Map.BlockNumber]; for (int blockno = 0; blockno < _Map.BlockNumber; blockno++) { float vMse = 0.0f; // Iterate over bands for (int bandno = 0; bandno < 10; bandno++) { int fbucket = _BandBuckets[bandno].Start; int nbucket = _BandBuckets[bandno].Size; InterWaveBlock blk = _Map.Blocks[blockno]; InterWaveBlock eblk = _EMap.Blocks[blockno]; float norm = normHi[bandno]; for (int buckno = 0; buckno < nbucket; buckno++) { short[] pcoeff = blk.GetBlock(fbucket + buckno); short[] epcoeff = eblk.GetBlock(fbucket + buckno); if (pcoeff != null) { if (epcoeff != null) { for (i = 0; i < 16; i++) { if (bandno == 0) { norm = normLo[i]; } float delta = (float)(pcoeff[i] < 0 ? -pcoeff[i] : pcoeff[i]); delta = delta - epcoeff[i]; vMse = vMse + norm * delta * delta; } } else { for (i = 0; i < 16; i++) { if (bandno == 0) { norm = normLo[i]; } float delta = (float)(pcoeff[i]); vMse = vMse + norm * delta * delta; } } } } } xMse[blockno] = vMse / 1024; } // Compute partition point int n = 0; int m = _Map.BlockNumber - 1; int p = (int)Math.Floor(m * (1.0 - frac) + 0.5); p = (p > m ? m : (p < 0 ? 0 : p)); float pivot = 0; // Partition array while (n < p) { int l = n; int h = m; if (xMse[l] > xMse[h]) { float tmp = xMse[l]; xMse[l] = xMse[h]; xMse[h] = tmp; } pivot = xMse[(l + h) / 2]; if (pivot < xMse[l]) { float tmp = pivot; pivot = xMse[l]; xMse[l] = tmp; } if (pivot > xMse[h]) { float tmp = pivot; pivot = xMse[h]; xMse[h] = tmp; } while (l < h) { if (xMse[l] > xMse[h]) { float tmp = xMse[l]; xMse[l] = xMse[h]; xMse[h] = tmp; } while (xMse[l] < pivot || (xMse[l] == pivot && l < h)) { l++; } while (xMse[h] > pivot) { h--; } } if (p >= l) { n = l; } else { m = l - 1; } } // Compute average mse float mse = 0; for (i = p; i < _Map.BlockNumber; i++) { mse = mse + xMse[i]; } mse = mse / (_Map.BlockNumber - p); // Return float factor = 255 << iw_shift; float decibel = (float)(10.0 * Math.Log(factor * factor / mse) / 2.302585125); return(decibel); }
/// <summary> /// Encodes a sequence of buckets in a given block. /// </summary> /// <param name="zp"></param> /// <param name="bit"></param> /// <param name="band"></param> /// <param name="blk"></param> /// <param name="eblk"></param> /// <param name="fbucket"></param> /// <param name="nbucket"></param> public void EncodeBuckets(IDataCoder zp, int bit, int band, InterWaveBlock blk, InterWaveBlock eblk, int fbucket, int nbucket) { // compute state of all coefficients in all buckets int bbstate = EncodePrepare(band, fbucket, nbucket, blk, eblk); // code root bit if ((nbucket < 16) || (bbstate & Active) != 0) { bbstate |= New; } else if ((bbstate & Unk) != 0) { zp.Encoder((bbstate & New) != 0 ? 1 : 0, ref _CtxRoot); } // code bucket bits if ((bbstate & New) != 0) { for (int buckno = 0; buckno < nbucket; buckno++) { // Code bucket bit if ((_BucketState[buckno] & Unk) != 0) { // Context int ctx = 0; if (band > 0) { int k = (fbucket + buckno) << 2; short[] b = eblk.GetBlock(k >> 4); if (b != null) { k = k & 0xf; if (b[k] != 0) { ctx += 1; } if (b[k + 1] != 0) { ctx += 1; } if (b[k + 2] != 0) { ctx += 1; } if (ctx < 3 && b[k + 3] != 0) { ctx += 1; } } } if ((bbstate & Active) != 0) { ctx |= 4; } // Code zp.Encoder((_BucketState[buckno] & New) != 0 ? 1 : 0, ref _CtxBucket[band][ctx]); } } } // code new active coefficient (with their sign) if ((bbstate & New) != 0) { int thres = _QuantHigh[band]; sbyte[] cstate = _CoefficientState; for (int buckno = 0, cidx = 0; buckno < nbucket; buckno++, cidx += 16) { if ((_BucketState[buckno] & New) != 0) { int i; int gotcha = 0; const int maxgotcha = 7; for (i = 0; i < 16; i++) { if ((cstate[i + cidx] & Unk) != 0) { gotcha += 1; } } short[] pcoeff = blk.GetBlock(fbucket + buckno); short[] epcoeff = eblk.GetInitializedBlock(fbucket + buckno); // iterate within bucket for (i = 0; i < 16; i++) { if ((cstate[i] & Unk) != 0) { // Prepare context int ctx = 0; if (gotcha >= maxgotcha) { ctx = maxgotcha; } else { ctx = gotcha; } if ((_BucketState[buckno] & Active) != 0) { ctx |= 8; } // Code zp.Encoder((cstate[i] & New) != 0 ? 1 : 0, ref _CtxStart[ctx]); if ((cstate[i] & New) != 0) { // Code sign zp.IWEncoder((pcoeff[i] < 0) ? true : false); // Set encoder state if (band == 0) { thres = _QuantLow[i]; } epcoeff[i] = (short)(thres + (thres >> 1)); } if ((cstate[i] & New) != 0) { gotcha = 0; } else if (gotcha > 0) { gotcha -= 1; } } } } } } // code mantissa bits if ((bbstate & Active) != 0) { int thres = _QuantHigh[band]; sbyte[] cstate = _CoefficientState; for (int buckno = 0, cidx = 0; buckno < nbucket; buckno++, cidx += 16) { if ((_BucketState[buckno] & Active) != 0) { short[] pcoeff = blk.GetBlock(fbucket + buckno); short[] epcoeff = eblk.GetInitializedBlock(fbucket + buckno); for (int i = 0; i < 16; i++) { if ((cstate[i] & Active) != 0) { // get coefficient int coeff = pcoeff[i]; int ecoeff = epcoeff[i]; if (coeff < 0) { coeff = -coeff; } // get band zero thresholds if (band == 0) { thres = _QuantLow[i]; } // compute mantissa bit int pix = 0; if (coeff >= ecoeff) { pix = 1; } // encode second or lesser mantissa bit if (ecoeff <= 3 * thres) { zp.Encoder(pix, ref _CtxMant); } else { zp.IWEncoder(!!(pix != 0)); } // adjust epcoeff epcoeff[i] = (short)(ecoeff - (pix != 0 ? 0 : thres) + (thres >> 1)); } } } } } }
/// <summary> /// Function computes the states prior to encoding the buckets /// </summary> /// <param name="band"></param> /// <param name="fbucket"></param> /// <param name="nbucket"></param> /// <param name="blk"></param> /// <param name="eblk"></param> /// <returns></returns> public unsafe int EncodePrepare(int band, int fbucket, int nbucket, InterWaveBlock blk, InterWaveBlock eblk) { int bbstate = 0; // compute state of all coefficients in all buckets if (band != 0) { // Band other than zero int thres = _QuantHigh[band]; GCHandle hCoeffState = GCHandle.Alloc(_CoefficientState, GCHandleType.Pinned); sbyte * cstate = (sbyte *)hCoeffState.AddrOfPinnedObject(); for (int buckno = 0; buckno < nbucket; buckno++, cstate += 16) { short[] pcoeff = blk.GetBlock(fbucket + buckno); short[] epcoeff = eblk.GetBlock(fbucket + buckno); int bstatetmp = 0; if (null != pcoeff) { bstatetmp = Unk; // cstate[i] is not used and does not need initialization } else if (null != epcoeff) { for (int i = 0; i < 16; i++) { int cstatetmp = Unk; if ((int)(pcoeff[i]) >= thres || (int)(pcoeff[i]) <= -thres) { cstatetmp = New | Unk; } cstate[i] = (sbyte)cstatetmp; bstatetmp |= cstatetmp; } } else { for (int i = 0; i < 16; i++) { int cstatetmp = Unk; if (epcoeff[i] != 0) { cstatetmp = Active; } else if ((int)(pcoeff[i]) >= thres || (int)(pcoeff[i]) <= -thres) { cstatetmp = New | Unk; } cstate[i] = (sbyte)cstatetmp; bstatetmp |= cstatetmp; } } _BucketState[buckno] = (sbyte)bstatetmp; bbstate |= bstatetmp; } } else { // Band zero ( fbucket==0 implies band==zero and nbucket==1 ) short[] pcoeff = blk.GetInitializedBlock(0); short[] epcoeff = eblk.GetInitializedBlock(0); sbyte[] cstate = _CoefficientState; for (int i = 0; i < 16; i++) { int thres = _QuantLow[i]; int cstatetmp = cstate[i]; if (cstatetmp != Zero) { cstatetmp = Unk; if (epcoeff[i] != 0) { cstatetmp = Active; } else if ((int)(pcoeff[i]) >= thres || (int)(pcoeff[i]) <= -thres) { cstatetmp = New | Unk; } } cstate[i] = (sbyte)cstatetmp; bbstate |= cstatetmp; } _BucketState[0] = (sbyte)bbstate; } return(bbstate); }
public void DecodeBuckets(IDataCoder coder, int bit, int band, InterWaveBlock blk, int fbucket, int nbucket) { int thres = _QuantHigh[band]; int bbstate = 0; sbyte[] cstate = _CoefficientState; int cidx = 0; for (int buckno = 0; buckno < nbucket; buckno++, cidx += 16) { int bstatetmp = 0; short[] pcoeff = blk.GetBlock(fbucket + buckno); if (pcoeff == null) { bstatetmp = 8; } else { for (int i = 0; i < 16; i++) { int cstatetmp = cstate[cidx + i] & 1; if (cstatetmp == 0) { if (pcoeff[i] != 0) { cstatetmp |= 2; } else { cstatetmp |= 8; } } cstate[cidx + i] = (sbyte)cstatetmp; bstatetmp |= cstatetmp; } } _BucketState[buckno] = (sbyte)bstatetmp; bbstate |= bstatetmp; } if (nbucket < 16 || (bbstate & 2) != 0) { bbstate |= 4; } else if ((bbstate & 8) != 0) { if (coder.Decoder(ref _CtxRoot) != 0) { bbstate |= 4; } } if ((bbstate & 4) != 0) { for (int buckno = 0; buckno < nbucket; buckno++) { if ((_BucketState[buckno] & 8) != 0) { int ctx = 0; //if (!DjVuOptions.NOCTX_BUCKET_UPPER && (band > 0)) if ((band > 0)) { int k = (fbucket + buckno) << 2; short[] b = blk.GetBlock(k >> 4); if (b != null) { k &= 0xf; if (b[k] != 0) { ctx++; } if (b[k + 1] != 0) { ctx++; } if (b[k + 2] != 0) { ctx++; } if ((ctx < 3) && (b[k + 3] != 0)) { ctx++; } } } //if (!DjVuOptions.NOCTX_BUCKET_ACTIVE && ((bbstate & 2) != 0)) if ((bbstate & 2) != 0) { ctx |= 4; } if (coder.Decoder(ref _CtxBucket[band][ctx]) != 0) { _BucketState[buckno] |= 4; } } } } if ((bbstate & 4) != 0) { cstate = _CoefficientState; cidx = 0; for (int buckno = 0; buckno < nbucket; buckno++, cidx += 16) { if ((_BucketState[buckno] & 4) != 0) { short[] pcoeff = blk.GetBlock(fbucket + buckno); if (pcoeff == null) { pcoeff = blk.GetInitializedBlock(fbucket + buckno); for (int i = 0; i < 16; i++) { if ((cstate[cidx + i] & 1) == 0) { cstate[cidx + i] = 8; } } } int gotcha = 0; int maxgotcha = 7; //if (!DjVuOptions.NOCTX_EXPECT) { for (int i = 0; i < 16; i++) { if ((cstate[cidx + i] & 8) != 0) { gotcha++; } } } for (int i = 0; i < 16; i++) { if ((cstate[cidx + i] & 8) != 0) { if (band == 0) { thres = _QuantLow[i]; } int ctx = 0; //if (!DjVuOptions.NOCTX_EXPECT) { if (gotcha >= maxgotcha) { ctx = maxgotcha; } else { ctx = gotcha; } } //if (!DjVuOptions.NOCTX_ACTIVE && ((bucketstate[buckno] & 2) != 0)) if (((_BucketState[buckno] & 2) != 0)) { ctx |= 8; } if (coder.Decoder(ref _CtxStart[ctx]) != 0) { cstate[cidx + i] |= 4; int halfthres = thres >> 1; int coeff = (thres + halfthres) - (halfthres >> 2); if (coder.IWDecoder() != 0) { pcoeff[i] = (short)(-coeff); } else { pcoeff[i] = (short)coeff; } } //if (!DjVuOptions.NOCTX_EXPECT) { if ((cstate[cidx + i] & 4) != 0) { gotcha = 0; } else if (gotcha > 0) { gotcha--; } } } } } } } if ((bbstate & 2) != 0) { cstate = _CoefficientState; cidx = 0; for (int buckno = 0; buckno < nbucket; buckno++, cidx += 16) { if ((_BucketState[buckno] & 2) != 0) { short[] pcoeff = blk.GetBlock(fbucket + buckno); for (int i = 0; i < 16; i++) { if ((cstate[cidx + i] & 2) != 0) { int coeff = pcoeff[i]; if (coeff < 0) { coeff = -coeff; } if (band == 0) { thres = _QuantLow[i]; } if (coeff <= (3 * thres)) { coeff += (thres >> 2); if (coder.Decoder(ref _CtxMant) != 0) { coeff += (thres >> 1); } else { coeff = (coeff - thres) + (thres >> 1); } } else { if (coder.IWDecoder() != 0) { coeff += (thres >> 1); } else { coeff = (coeff - thres) + (thres >> 1); } } if (pcoeff[i] > 0) { pcoeff[i] = (short)coeff; } else { pcoeff[i] = (short)(-coeff); } } } // end for (int i = 0 ... } } // end for (int buckno = 0 .... } }
/// <summary> /// Add docs /// </summary> /// <param name="subsample"></param> /// <param name="rect"></param> /// <param name="index"></param> /// <param name="img8"></param> /// <param name="rowsize"></param> /// <param name="pixsep"></param> /// <param name="fast"></param> public void Image(int subsample, Rectangle rect, int index, sbyte[] img8, int rowsize, int pixsep, bool fast) { int nlevel = 0; while ((nlevel < 5) && ((32 >> nlevel) > subsample)) { nlevel++; } int boxsize = 1 << nlevel; if (subsample != (32 >> nlevel)) { throw new DjvuArgumentOutOfRangeException("Unsupported subsampling factor"); } if (rect.Empty) { throw new DjvuArgumentException("Rectangle is empty", nameof(rect)); } Rectangle irect = new Rectangle( 0, 0, ((Width + subsample) - 1) / subsample, ((Height + subsample) - 1) / subsample); if ((rect.Right < 0) || (rect.Bottom < 0) || (rect.Left > irect.Left) || (rect.Top > irect.Top)) { throw new DjvuArgumentException( "Rectangle is out of bounds: " + rect.Right + "," + rect.Bottom + "," + rect.Left + "," + rect.Top + "," + irect.Left + "," + irect.Top, nameof(rect)); } Rectangle[] needed = new Rectangle[8]; Rectangle[] recomp = new Rectangle[8]; for (int i = 0; i < 8;) { needed[i] = new Rectangle(); recomp[i++] = new Rectangle(); } int r = 1; needed[nlevel] = (Rectangle)rect.Duplicate(); recomp[nlevel] = (Rectangle)rect.Duplicate(); for (int i = nlevel - 1; i >= 0; i--) { needed[i] = recomp[i + 1]; needed[i].Inflate(3 * r, 3 * r); needed[i].Intersect(needed[i], irect); r += r; recomp[i].Right = ((needed[i].Right + r) - 1) & ~(r - 1); recomp[i].Left = needed[i].Left & ~(r - 1); recomp[i].Bottom = ((needed[i].Bottom + r) - 1) & ~(r - 1); recomp[i].Top = needed[i].Top & ~(r - 1); } Rectangle work = new Rectangle(); work.Right = needed[0].Right & ~(boxsize - 1); work.Bottom = needed[0].Bottom & ~(boxsize - 1); work.Left = ((needed[0].Left - 1) & ~(boxsize - 1)) + boxsize; work.Top = ((needed[0].Top - 1) & ~(boxsize - 1)) + boxsize; int dataw = work.Width; short[] data = new short[dataw * work.Height]; int blkw = BlockWidth >> 5; int lblock = ((work.Bottom >> nlevel) * blkw) + (work.Right >> nlevel); short[] liftblock = new short[1024]; for (int by = work.Bottom, ldata = 0; by < work.Top; by += boxsize, ldata += (dataw << nlevel), lblock += blkw) { for (int bx = work.Right, bidx = lblock, rdata = ldata; bx < work.Left; bx += boxsize, bidx++, rdata += boxsize) { InterWaveBlock block = Blocks[bidx]; int mlevel = nlevel; if ((nlevel > 2) && (((bx + 31) < needed[2].Right) || (bx > needed[2].Left) || ((by + 31) < needed[2].Bottom) || (by > needed[2].Top))) { mlevel = 2; } int bmax = ((1 << (mlevel + mlevel)) + 15) >> 4; int ppinc = 1 << (nlevel - mlevel); int ppmod1 = dataw << (nlevel - mlevel); int ttmod0 = 32 >> mlevel; int ttmod1 = ttmod0 << 5; // liftblock should contain zeros only block.WriteLiftBlock(liftblock, 0, bmax); for (int ii = 0, tt = 0, pp = rdata; ii < boxsize; ii += ppinc, pp += ppmod1, tt += (ttmod1 - 32)) { for (int jj = 0; jj < boxsize; jj += ppinc, tt += ttmod0) { data[pp + jj] = liftblock[tt]; } } } } r = boxsize; for (int i = 0; i < nlevel; i++) { Rectangle comp = needed[i]; comp.Right = comp.Right & ~(r - 1); comp.Bottom = comp.Bottom & ~(r - 1); comp.Translate(-work.Right, -work.Bottom); if (fast && (i >= 4)) { for (int ii = comp.Bottom, pp = (comp.Bottom * dataw); ii < comp.Top; ii += 2, pp += (dataw + dataw)) { for (int jj = comp.Right; jj < comp.Left; jj += 2) { data[pp + jj + dataw] = data[pp + jj + dataw + 1] = data[pp + jj + 1] = data[pp + jj]; } } break; } Backward(data, (comp.Bottom * dataw) + comp.Right, comp.Width, comp.Height, dataw, r, r >> 1); r >>= 1; } Rectangle nrect = rect.Duplicate(); nrect.Translate(-work.Right, -work.Bottom); for (int i = nrect.Bottom, pidx = (nrect.Bottom * dataw), ridx = index; i++ < nrect.Top; ridx += rowsize, pidx += dataw) { for (int j = nrect.Right, pixidx = ridx; j < nrect.Left; j++, pixidx += pixsep) { int x = (data[pidx + j] + 32) >> 6; if (x < -128) { x = -128; } else if (x > 127) { x = 127; } img8[pixidx] = (sbyte)x; } } }