/// <summary> /// Writes a block of pixel data using the given quantization table, /// returning the post-quantized DC value of the DCT-transformed block. /// The block is in natural (not zig-zag) order. /// </summary> /// <param name="index">The quantization table index.</param> /// <param name="prevDC">The previous DC value.</param> /// <param name="src">Source block</param> /// <param name="tempDest1">Temporal block to be used as FDCT Destination</param> /// <param name="tempDest2">Temporal block 2</param> /// <param name="quant">Quantization table</param> /// <param name="unzigPtr">The 8x8 Unzig block pointer</param> /// <returns> /// The <see cref="int"/> /// </returns> private int WriteBlock( QuantIndex index, int prevDC, Block8x8F *src, Block8x8F *tempDest1, Block8x8F *tempDest2, Block8x8F *quant, int *unzigPtr) { DCT.TransformFDCT(ref *src, ref *tempDest1, ref *tempDest2); Block8x8F.UnzigDivRound(tempDest1, tempDest2, quant, unzigPtr); float *unziggedDestPtr = (float *)tempDest2; int dc = (int)unziggedDestPtr[0]; // Emit the DC delta. this.EmitHuffRLE((HuffIndex)((2 * (int)index) + 0), 0, dc - prevDC); // Emit the AC components. HuffIndex h = (HuffIndex)((2 * (int)index) + 1); int runLength = 0; for (int zig = 1; zig < Block8x8F.ScalarCount; zig++) { int ac = (int)unziggedDestPtr[zig]; if (ac == 0) { runLength++; } else { while (runLength > 15) { this.EmitHuff(h, 0xf0); runLength -= 16; } this.EmitHuffRLE(h, runLength, ac); runLength = 0; } } if (runLength > 0) { this.EmitHuff(h, 0x00); } return(dc); }
/// <summary> /// Initializes quantization table. /// </summary> /// <param name="i">The quantization index.</param> /// <param name="scale">The scaling factor.</param> /// <param name="quant">The quantization table.</param> private static void InitQuantizationTable(int i, int scale, ref Block8x8F quant) { for (int j = 0; j < Block8x8F.ScalarCount; j++) { int x = UnscaledQuant[i, j]; x = ((x * scale) + 50) / 100; if (x < 1) { x = 1; } if (x > 255) { x = 255; } quant[j] = x; } }
internal void Clear() { // The cheapest way to do this in C#: this = new Block8x8F(); }
/// <summary> /// Encodes the image with subsampling. The Cb and Cr components are each subsampled /// at a factor of 2 both horizontally and vertically. /// </summary> /// <typeparam name="TColor">The pixel format.</typeparam> /// <param name="pixels">The pixel accessor providing access to the image pixels.</param> private void Encode420 <TColor>(PixelAccessor <TColor> pixels) where TColor : struct, IPackedPixel, IEquatable <TColor> { // TODO: Need a JpegScanEncoder<TColor> class or struct that encapsulates the scan-encoding implementation. (Similar to JpegScanDecoder.) Block8x8F b = default(Block8x8F); BlockQuad cb = default(BlockQuad); BlockQuad cr = default(BlockQuad); Block8x8F *cbPtr = (Block8x8F *)cb.Data; Block8x8F *crPtr = (Block8x8F *)cr.Data; Block8x8F temp1 = default(Block8x8F); Block8x8F temp2 = default(Block8x8F); Block8x8F onStackLuminanceQuantTable = this.luminanceQuantTable; Block8x8F onStackChrominanceQuantTable = this.chrominanceQuantTable; UnzigData unzig = UnzigData.Create(); // ReSharper disable once InconsistentNaming int prevDCY = 0, prevDCCb = 0, prevDCCr = 0; using (PixelArea <TColor> rgbBytes = new PixelArea <TColor>(8, 8, ComponentOrder.Xyz)) { for (int y = 0; y < pixels.Height; y += 16) { for (int x = 0; x < pixels.Width; x += 16) { for (int i = 0; i < 4; i++) { int xOff = (i & 1) * 8; int yOff = (i & 2) * 4; ToYCbCr(pixels, x + xOff, y + yOff, &b, cbPtr + i, crPtr + i, rgbBytes); prevDCY = this.WriteBlock( QuantIndex.Luminance, prevDCY, &b, &temp1, &temp2, &onStackLuminanceQuantTable, unzig.Data); } Block8x8F.Scale16X16To8X8(&b, cbPtr); prevDCCb = this.WriteBlock( QuantIndex.Chrominance, prevDCCb, &b, &temp1, &temp2, &onStackChrominanceQuantTable, unzig.Data); Block8x8F.Scale16X16To8X8(&b, crPtr); prevDCCr = this.WriteBlock( QuantIndex.Chrominance, prevDCCr, &b, &temp1, &temp2, &onStackChrominanceQuantTable, unzig.Data); } } } }