private YCbCrImage ycbcrImage; // YCrCb #endregion Fields #region Constructors public JpegDecoderCore() { huff = new Huffman[maxTc + 1, maxTh + 1]; quant = new Block[maxTq + 1]; tmp = new byte[2*Block.blockSize]; comp = new Component[maxComponents]; progCoeffs = new Block[maxComponents][]; bits = new BitsClass(); bytes = new BytesClass(); for (int i = 0; i < maxTc + 1; i++){ for (int j = 0; j < maxTh + 1; j++){ huff[i, j] = new Huffman(); } } for (int i = 0; i < quant.Length; i++){ quant[i] = new Block(); } for (int i = 0; i < comp.Length; i++){ comp[i] = new Component(); } }
private void ProcessSos(int n) { if (nComp == 0){ throw new Exception("missing SOF marker"); } if (n < 6 || 4 + (2*nComp) < n || n%2 != 0){ throw new Exception("SOS has wrong length"); } ReadFull(tmp, 0, n); byte lnComp = tmp[0]; if (n != 4 + (2*lnComp)){ throw new Exception("SOS length inconsistent with number of components"); } Scan[] scan = new Scan[maxComponents]; int totalHv = 0; for (int i = 0; i < lnComp; i++){ int cs = tmp[1 + (2*i)]; int compIndex = -1; for (int j = 0; j < nComp; j++){ Component compv = comp[j]; if (cs == compv.c){ compIndex = j; } } if (compIndex < 0){ throw new Exception("Unknown component selector"); } scan[i].compIndex = (byte) compIndex; for (int j = 0; j < i; j++){ if (scan[i].compIndex == scan[j].compIndex){ throw new Exception("Repeated component selector"); } } totalHv += comp[compIndex].h*comp[compIndex].v; scan[i].td = (byte) (tmp[2 + (2*i)] >> 4); if (scan[i].td > maxTh){ throw new Exception("bad Td value"); } scan[i].ta = (byte) (tmp[2 + (2*i)] & 0x0f); if (scan[i].ta > maxTh){ throw new Exception("bad Ta value"); } } if (nComp > 1 && totalHv > 10){ throw new Exception("Total sampling factors too large."); } int zigStart = 0; int zigEnd = Block.blockSize - 1; int ah = 0; int al = 0; if (progressive){ zigStart = tmp[1 + (2*lnComp)]; zigEnd = tmp[2 + (2*lnComp)]; ah = tmp[3 + (2*lnComp)] >> 4; al = tmp[3 + (2*lnComp)] & 0x0f; if ((zigStart == 0 && zigEnd != 0) || zigStart > zigEnd || Block.blockSize <= zigEnd){ throw new Exception("Bad spectral selection bounds"); } if (zigStart != 0 && lnComp != 1){ throw new Exception("Progressive AC coefficients for more than one component"); } if (ah != 0 && ah != al + 1){ throw new Exception("Bad successive approximation values"); } } int h0 = comp[0].h; int v0 = comp[0].v; int mxx = (width + (8*h0) - 1)/(8*h0); int myy = (height + (8*v0) - 1)/(8*v0); if (grayImage == null && ycbcrImage == null){ MakeImg(mxx, myy); } if (progressive){ for (int i = 0; i < lnComp; i++){ int compIndex = scan[i].compIndex; if (progCoeffs[compIndex] == null){ progCoeffs[compIndex] = new Block[mxx*myy*comp[compIndex].h*comp[compIndex].v]; for (int j = 0; j < progCoeffs[compIndex].Length; j++){ progCoeffs[compIndex][j] = new Block(); } } } } bits = new BitsClass(); int mcu = 0; byte expectedRst = JpegConstants.Markers.RST0; Block b = new Block(); int[] dc = new int[maxComponents]; int blockCount = 0; for (int my = 0; my < myy; my++){ for (int mx = 0; mx < mxx; mx++){ for (int i = 0; i < lnComp; i++){ int compIndex = scan[i].compIndex; int hi = comp[compIndex].h; int vi = comp[compIndex].v; Block qt = quant[comp[compIndex].tq]; for (int j = 0; j < hi*vi; j++){ int bx; int by; if (lnComp != 1){ bx = hi*mx + j%hi; by = vi*my + j/hi; } else{ int q = mxx*hi; bx = blockCount%q; by = blockCount/q; blockCount++; if (bx*8 >= width || by*8 >= height){ continue; } } b = progressive ? progCoeffs[compIndex][@by*mxx*hi + bx] : new Block(); if (ah != 0){ Refine(b, huff[acTable, scan[i].ta], zigStart, zigEnd, 1 << al); } else{ int zig = zigStart; if (zig == 0){ zig++; byte value = DecodeHuffman(huff[dcTable, scan[i].td]); if (value > 16){ throw new Exception("Excessive DC component"); } int dcDelta = ReceiveExtend(value); dc[compIndex] += dcDelta; b[0] = dc[compIndex] << al; } if (zig <= zigEnd && eobRun > 0){ eobRun--; } else{ var huffv = huff[acTable, scan[i].ta]; for (; zig <= zigEnd; zig++){ byte value = DecodeHuffman(huffv); byte val0 = (byte) (value >> 4); byte val1 = (byte) (value & 0x0f); if (val1 != 0){ zig += val0; if (zig > zigEnd){ break; } int ac = ReceiveExtend(val1); b[unzig[zig]] = ac << al; } else{ if (val0 != 0x0f){ eobRun = (ushort) (1 << val0); if (val0 != 0){ eobRun |= (ushort) DecodeBits(val0); } eobRun--; break; } zig += 0x0f; } } } } if (progressive){ if (zigEnd != Block.blockSize - 1 || al != 0){ progCoeffs[compIndex][by*mxx*hi + bx] = b; continue; } } for (int zig = 0; zig < Block.blockSize; zig++){ b[unzig[zig]] *= qt[zig]; } IDCT.Transform(b); byte[] dst; int offset; int stride; if (nComp == 1){ dst = grayImage.pixels; stride = grayImage.stride; offset = grayImage.offset + 8*(by*grayImage.stride + bx); } else{ switch (compIndex){ case 0: dst = ycbcrImage.pix_y; stride = ycbcrImage.y_stride; offset = ycbcrImage.y_offset + 8*(by*ycbcrImage.y_stride + bx); break; case 1: dst = ycbcrImage.pix_cb; stride = ycbcrImage.c_stride; offset = ycbcrImage.c_offset + 8*(by*ycbcrImage.c_stride + bx); break; case 2: dst = ycbcrImage.pix_cr; stride = ycbcrImage.c_stride; offset = ycbcrImage.c_offset + 8*(by*ycbcrImage.c_stride + bx); break; case 3: throw new Exception("Too many components"); default: throw new Exception("Too many components"); } } for (int y = 0; y < 8; y++){ int y8 = y*8; int yStride = y*stride; for (int x = 0; x < 8; x++){ int c = b[y8 + x]; if (c < -128){ c = 0; } else if (c > 127){ c = 255; } else{ c += 128; } dst[yStride + x + offset] = (byte) c; } } } // for j } // for i mcu++; if (ri > 0 && mcu%ri == 0 && mcu < mxx*myy){ ReadFull(tmp, 0, 2); if (tmp[0] != 0xff || tmp[1] != expectedRst){ throw new Exception("Bad RST marker"); } expectedRst++; if (expectedRst == JpegConstants.Markers.RST7 + 1){ expectedRst = JpegConstants.Markers.RST0; } bits = new BitsClass(); dc = new int[maxComponents]; eobRun = 0; } } // for mx } // for my }