/// <summary> /// Creates a new Bitmap with the resolution reduced by half in the vertical direction using /// the indicated method. Source must be 1bppIndexed. Source must be a standard Fax size. /// </summary> /// <param name="bmp">Source Bitmap.</param> /// <param name="scaleMethod">The scaling method.</param> /// <returns>The new bitmap in 1bppIndexed format.</returns> internal static Bitmap ConvertTiffHiToTiffLow(Bitmap bmp, HighToLowScaleMethod scaleMethod) { PaperSize paperSize = BitmapHelper.GetStandardPaperSize(bmp); //If the paper size is not standard then throw error if (paperSize == PaperSize.Undefined) { throw new Exception("Source bitmap returned an incorrect paper size."); } //If its not in 32bppArgb format then throw error if (bmp.PixelFormat != PixelFormat.Format1bppIndexed) { throw new Exception("Source format must be Format1bppIndexed."); } //If its already a low resolution, then copy and return. if (bmp.VerticalResolution == ImageUtility.FAX_TIF_VER_RES_LOW) { return(BitmapHelper.CreateCopyExact(bmp)); } //No Scale requested. if (scaleMethod == HighToLowScaleMethod.NoScale) { return(BitmapHelper.CreateCopyExact(bmp)); } //If its in tiff high resolution, then throw error if (bmp.VerticalResolution != ImageUtility.FAX_TIF_VER_RES_HI) { throw new Exception("Source resolution is not FAX_TIF_VER_RES_HI."); } Bitmap ret = BitmapHelper.CreateBitMap(paperSize, FaxQuality.Normal, PixelFormat.Format1bppIndexed); // Lock source bitmap in memory BitmapData sourceData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, PixelFormat.Format1bppIndexed); // Copy image data to binary array int imageSize = sourceData.Stride * sourceData.Height; byte[] sourceBuffer = new byte[imageSize]; Marshal.Copy(sourceData.Scan0, sourceBuffer, 0, imageSize); // Unlock source bitmap bmp.UnlockBits(sourceData); // Lock destination bitmap in memory BitmapData destinationData = ret.LockBits(new Rectangle(0, 0, ret.Width, ret.Height), ImageLockMode.WriteOnly, PixelFormat.Format1bppIndexed); // Create destination buffer imageSize = destinationData.Stride * destinationData.Height; byte[] destinationBuffer = new byte[imageSize]; int nnx_ratio = (int)((sourceData.Stride << 16) / destinationData.Stride) + 1; int nny_ratio = (int)((sourceData.Height << 16) / destinationData.Height) + 1; int A, B, C, D, x, y, index, gray; float x_ratio = ((float)(sourceData.Stride - 1)) / destinationData.Stride; float y_ratio = ((float)(sourceData.Height - 1)) / destinationData.Height; float x_diff, y_diff; int offset = 0; for (int j = 0; j < destinationData.Height; j++) //For every row { for (int i = 0; i < destinationData.Stride; i++) //For each byte in row { byte s1 = sourceBuffer[(j * 2) * destinationData.Stride + i]; byte s2 = sourceBuffer[((j * 2) + 1) * destinationData.Stride + i]; byte d1 = 0; switch (scaleMethod) { case HighToLowScaleMethod.ORing: { d1 = (byte)(s1 | s2); destinationBuffer[j * destinationData.Stride + i] = d1; break; } case HighToLowScaleMethod.ANDing: { d1 = (byte)(s1 & s2); destinationBuffer[j * destinationData.Stride + i] = d1; break; } case HighToLowScaleMethod.Elimination: { d1 = s1; destinationBuffer[j * destinationData.Stride + i] = d1; break; } case HighToLowScaleMethod.Averaging: { //d1 = (byte)(s1 | s2); //d1 = (byte)(s1 ^ s2); d1 = (byte)((s1 + s2) / 2); //int a1s1 = s1 >> 6 & 3; //int a1s2 = s2 >> 6 & 3; //int a2s1 = s1 >> 4 & 3; //int a2s2 = s2 >> 4 & 3; //int a3s1 = s1 >> 2 & 3; //int a3s2 = s2 >> 2 & 3; //int a4s1 = s1 & 3; //int a4s2 = s2 & 3; //d1 = (byte)(((a1s1 + a1s2) / 2 << 6) + ((a2s1 + a2s2) / 2 << 4) + ((a3s1 + a3s2) / 2 << 2) + ((a4s1 + a4s2) / 2)); destinationBuffer[j * destinationData.Stride + i] = d1; break; } case HighToLowScaleMethod.NearestNeighbor: { int x2 = ((i * nnx_ratio) >> 16); int y2 = ((j * nny_ratio) >> 16); destinationBuffer[j * destinationData.Stride + i] = sourceBuffer[(y2 * sourceData.Stride) + x2]; break; } case HighToLowScaleMethod.Bilinear: { x = (int)(x_ratio * i); y = (int)(y_ratio * j); x_diff = (x_ratio * i) - x; y_diff = (y_ratio * j) - y; index = y * sourceData.Stride + x; A = sourceBuffer[index] & 0xff; B = sourceBuffer[index + 1] & 0xff; C = sourceBuffer[index + sourceData.Stride] & 0xff; D = sourceBuffer[index + sourceData.Stride + 1] & 0xff; gray = (int)( A * (1 - x_diff) * (1 - y_diff) + B * (x_diff) * (1 - y_diff) + C * (y_diff) * (1 - x_diff) + D * (x_diff * y_diff) ); destinationBuffer[offset++] = (byte)gray; break; } } } } // Copy binary image data to destination bitmap Marshal.Copy(destinationBuffer, 0, destinationData.Scan0, imageSize); // Unlock destination bitmap ret.UnlockBits(destinationData); return(ret); }