/// <summary> /// Encodes a bitonal bitmap using 1D CCITT fax encoding. /// </summary> /// <param name="imageData">Space reserved for the fax encoded bitmap. An exception will be thrown if this buffer is too small.</param> /// <param name="imageBits">The bitmap to be encoded.</param> /// <param name="bytesFileOffset">Offset of image data in bitmap file.</param> /// <param name="width">The width of the image.</param> /// <param name="height">The height of the image.</param> /// <returns>The size of the fax encoded image (0 on failure).</returns> private static int DoFaxEncoding(ref byte[] imageData, byte[] imageBits, uint bytesFileOffset, uint width, uint height) { try { uint bytesPerLineBmp = ((width + 31) / 32) * 4; BitWriter writer = new BitWriter(ref imageData); for (uint y = 0; y < height; ++y) { uint bytesOffsetRead = bytesFileOffset + (height - 1 - y) * bytesPerLineBmp; BitReader reader = new BitReader(imageBits, bytesOffsetRead, width); for (uint bitsRead = 0; bitsRead < width;) { uint white = CountOneBits(reader, width - bitsRead); WriteSample(writer, white, true); bitsRead += white; if (bitsRead < width) { uint black = CountZeroBits(reader, width - bitsRead); WriteSample(writer, black, false); bitsRead += black; } } } writer.FlushBuffer(); return writer.BytesWritten(); } catch (Exception /*ex*/) { //ex.GetType(); return 0; } }
/// <summary> /// Returns the offset of the next bit in the range /// [bitStart..bitEnd] that is different from the /// specified color. The end, bitEnd, is returned /// if no such bit exists. /// Like FindDifference, but also check the /// starting bit against the end in case start > end. /// </summary> /// <param name="reader">The reader.</param> /// <param name="bitStart">The offset of the start bit.</param> /// <param name="bitEnd">The offset of the end bit.</param> /// <param name="searchOne">If set to <c>true</c> searches "one" (i. e. white), otherwise searches black.</param> /// <returns>The offset of the first non-matching bit.</returns> private static uint FindDifferenceWithCheck(BitReader reader, uint bitStart, uint bitEnd, bool searchOne) { // Translated from LibTiff return ((bitStart < bitEnd) ? FindDifference(reader, bitStart, bitEnd, searchOne) : bitEnd); }
/// <summary> /// 2d-encode a row of pixels. Consult the CCITT documentation for the algorithm. /// </summary> /// <param name="writer">The writer.</param> /// <param name="bytesFileOffset">Offset of image data in bitmap file.</param> /// <param name="imageBits">The bitmap file.</param> /// <param name="currentRow">Index of the current row.</param> /// <param name="referenceRow">Index of the reference row (0xffffffff if there is none).</param> /// <param name="width">The width of the image.</param> /// <param name="height">The height of the image.</param> /// <param name="bytesPerLineBmp">The bytes per line in the bitmap file.</param> static void FaxEncode2DRow(BitWriter writer, uint bytesFileOffset, byte[] imageBits, uint currentRow, uint referenceRow, uint width, uint height, uint bytesPerLineBmp) { // Translated from LibTiff uint bytesOffsetRead = bytesFileOffset + (height - 1 - currentRow) * bytesPerLineBmp; BitReader reader = new BitReader(imageBits, bytesOffsetRead, width); BitReader readerReference; if (referenceRow != 0xffffffff) { uint bytesOffsetReadReference = bytesFileOffset + (height - 1 - referenceRow) * bytesPerLineBmp; readerReference = new BitReader(imageBits, bytesOffsetReadReference, width); } else { byte[] tmpImageBits = new byte[bytesPerLineBmp]; for (int i = 0; i < bytesPerLineBmp; ++i) tmpImageBits[i] = 255; readerReference = new BitReader(tmpImageBits, 0, width); } uint a0 = 0; uint a1 = !reader.GetBit(0) ? 0 : FindDifference(reader, 0, width, true); uint b1 = !readerReference.GetBit(0) ? 0 : FindDifference(readerReference, 0, width, true); // ReSharper disable TooWideLocalVariableScope uint a2, b2; // ReSharper restore TooWideLocalVariableScope for (;;) { b2 = FindDifferenceWithCheck(readerReference, b1, width, readerReference.GetBit(b1)); if (b2 >= a1) { int d = (int)b1 - (int)a1; if (!(-3 <= d && d <= 3)) { /* horizontal mode */ a2 = FindDifferenceWithCheck(reader, a1, width, reader.GetBit(a1)); writer.WriteTableLine(HorizontalCodes, 0); if (a0 + a1 == 0 || reader.GetBit(a0)) { WriteSample(writer, a1 - a0, true); WriteSample(writer, a2 - a1, false); } else { WriteSample(writer, a1 - a0, false); WriteSample(writer, a2 - a1, true); } a0 = a2; } else { /* vertical mode */ writer.WriteTableLine(VerticalCodes, (uint)(d + 3)); a0 = a1; } } else { /* pass mode */ writer.WriteTableLine(PassCodes, 0); a0 = b2; } if (a0 >= width) break; bool bitA0 = reader.GetBit(a0); a1 = FindDifference(reader, a0, width, bitA0/*reader.GetBit(a0)*/); b1 = FindDifference(readerReference, a0, width, !bitA0/*reader.GetBit(a0)*/); b1 = FindDifferenceWithCheck(readerReference, b1, width, bitA0/*reader.GetBit(a0)*/); } }
/// <summary> /// Returns the offset of the next bit in the range /// [bitStart..bitEnd] that is different from the /// specified color. The end, bitEnd, is returned /// if no such bit exists. /// </summary> /// <param name="reader">The reader.</param> /// <param name="bitStart">The offset of the start bit.</param> /// <param name="bitEnd">The offset of the end bit.</param> /// <param name="searchOne">If set to <c>true</c> searches "one" (i. e. white), otherwise searches black.</param> /// <returns>The offset of the first non-matching bit.</returns> private static uint FindDifference(BitReader reader, uint bitStart, uint bitEnd, bool searchOne) { // Translated from LibTiff reader.SetPosition(bitStart); return (bitStart + (searchOne ? CountOneBits(reader, bitEnd - bitStart) : CountZeroBits(reader, bitEnd - bitStart))); }
/// <summary> /// Counts the consecutive zero bits in an image line. /// </summary> /// <param name="reader">The reader.</param> /// <param name="bitsLeft">The bits left.</param> private static uint CountZeroBits(BitReader reader, uint bitsLeft) { uint found = 0; for (;;) { uint bits; int @byte = reader.PeekByte(out bits); uint hits = _zeroRuns[@byte]; if (hits < bits) { if (hits > 0) reader.SkipBits(hits); found += hits; return found >= bitsLeft ? bitsLeft : found; } found += bits; if (found >= bitsLeft) return bitsLeft; reader.NextByte(); } }
/// <summary> /// 2d-encode a row of pixels. Consult the CCITT documentation for the algorithm. /// </summary> /// <param name="writer">The writer.</param> /// <param name="bytesFileOffset">Offset of image data in bitmap file.</param> /// <param name="imageBits">The bitmap file.</param> /// <param name="currentRow">Index of the current row.</param> /// <param name="referenceRow">Index of the reference row (0xffffffff if there is none).</param> /// <param name="width">The width of the image.</param> /// <param name="height">The height of the image.</param> /// <param name="bytesPerLineBmp">The bytes per line in the bitmap file.</param> static void FaxEncode2DRow(BitWriter writer, uint bytesFileOffset, byte[] imageBits, uint currentRow, uint referenceRow, uint width, uint height, uint bytesPerLineBmp) { // Translated from LibTiff uint bytesOffsetRead = bytesFileOffset + (height - 1 - currentRow) * bytesPerLineBmp; BitReader reader = new BitReader(imageBits, bytesOffsetRead, width); BitReader readerReference; if (referenceRow != 0xffffffff) { uint bytesOffsetReadReference = bytesFileOffset + (height - 1 - referenceRow) * bytesPerLineBmp; readerReference = new BitReader(imageBits, bytesOffsetReadReference, width); } else { byte[] tmpImageBits = new byte[bytesPerLineBmp]; for (int i = 0; i < bytesPerLineBmp; ++i) { tmpImageBits[i] = 255; } readerReference = new BitReader(tmpImageBits, 0, width); } uint a0 = 0; uint a1 = !reader.GetBit(0) ? 0 : FindDifference(reader, 0, width, true); uint b1 = !readerReference.GetBit(0) ? 0 : FindDifference(readerReference, 0, width, true); // ReSharper disable TooWideLocalVariableScope uint a2, b2; // ReSharper restore TooWideLocalVariableScope for (;;) { b2 = FindDifferenceWithCheck(readerReference, b1, width, readerReference.GetBit(b1)); if (b2 >= a1) { int d = (int)b1 - (int)a1; if (!(-3 <= d && d <= 3)) { /* horizontal mode */ a2 = FindDifferenceWithCheck(reader, a1, width, reader.GetBit(a1)); writer.WriteTableLine(HorizontalCodes, 0); if (a0 + a1 == 0 || reader.GetBit(a0)) { WriteSample(writer, a1 - a0, true); WriteSample(writer, a2 - a1, false); } else { WriteSample(writer, a1 - a0, false); WriteSample(writer, a2 - a1, true); } a0 = a2; } else { /* vertical mode */ writer.WriteTableLine(VerticalCodes, (uint)(d + 3)); a0 = a1; } } else { /* pass mode */ writer.WriteTableLine(PassCodes, 0); a0 = b2; } if (a0 >= width) { break; } bool bitA0 = reader.GetBit(a0); a1 = FindDifference(reader, a0, width, bitA0 /*reader.GetBit(a0)*/); b1 = FindDifference(readerReference, a0, width, !bitA0 /*reader.GetBit(a0)*/); b1 = FindDifferenceWithCheck(readerReference, b1, width, bitA0 /*reader.GetBit(a0)*/); } }
/// <summary> /// Returns the offset of the next bit in the range /// [bitStart..bitEnd] that is different from the /// specified color. The end, bitEnd, is returned /// if no such bit exists. /// Like FindDifference, but also check the /// starting bit against the end in case start > end. /// </summary> /// <param name="reader">The reader.</param> /// <param name="bitStart">The offset of the start bit.</param> /// <param name="bitEnd">The offset of the end bit.</param> /// <param name="searchOne">If set to <c>true</c> searches "one" (i. e. white), otherwise searches black.</param> /// <returns>The offset of the first non-matching bit.</returns> private static uint FindDifferenceWithCheck(BitReader reader, uint bitStart, uint bitEnd, bool searchOne) { // Translated from LibTiff return((bitStart < bitEnd) ? FindDifference(reader, bitStart, bitEnd, searchOne) : bitEnd); }
/// <summary> /// Returns the offset of the next bit in the range /// [bitStart..bitEnd] that is different from the /// specified color. The end, bitEnd, is returned /// if no such bit exists. /// </summary> /// <param name="reader">The reader.</param> /// <param name="bitStart">The offset of the start bit.</param> /// <param name="bitEnd">The offset of the end bit.</param> /// <param name="searchOne">If set to <c>true</c> searches "one" (i. e. white), otherwise searches black.</param> /// <returns>The offset of the first non-matching bit.</returns> private static uint FindDifference(BitReader reader, uint bitStart, uint bitEnd, bool searchOne) { // Translated from LibTiff reader.SetPosition(bitStart); return(bitStart + (searchOne ? CountOneBits(reader, bitEnd - bitStart) : CountZeroBits(reader, bitEnd - bitStart))); }