private PixelReference GetLine(int fy, Rectangle required_red, Rectangle provided_input, PixelMap input) { if (fy < required_red.YMin) { fy = required_red.YMin; } else if (fy >= required_red.YMax) { fy = required_red.YMax - 1; } // Cached line if (fy == l2) { return p2.CreateGPixelReference(0); } if (fy == l1) { return p1.CreateGPixelReference(0); } // Shift PixelMap p = p1; p1 = p2; l1 = l2; p2 = p; l2 = fy; // Compute location of line Rectangle line = new Rectangle(); line.XMin = required_red.XMin << xshift; line.XMax = required_red.XMax << xshift; line.YMin = fy << yshift; line.YMax = (fy + 1) << yshift; line.Intersect(line, provided_input); line.Translate(-provided_input.XMin, -provided_input.YMin); // Prepare variables int botline = input.RowOffset(line.YMin); int rowsize = input.GetRowSize(); int sw = 1 << xshift; int div = xshift + yshift; int rnd = 1 << (div - 1); int rnd2 = rnd + rnd; PixelReference inp1 = input.CreateGPixelReference(0); PixelReference ip = p.CreateGPixelReference(0); // Compute averages for (int x = line.XMin; x < line.XMax; x += sw, ip.IncOffset()) { int r = 0; int g = 0; int b = 0; int s = 0; int inp0 = botline + x; int sy2 = line.Height; int sy1 = (1 << yshift); if (sy1 > sy2) { sy1 = sy2; } for (int sy = 0; sy < sy1; sy++, inp0 += rowsize) { int sx1 = x + sw; inp1.SetOffset(inp0); if (sx1 > line.XMax) { sx1 = line.XMax; } for (int sx = sx1 - x; sx-- > 0; s++, inp1.IncOffset()) { r += inp1.Red; g += inp1.Green; b += inp1.Blue; } } if (s == rnd2) { ip.SetBGR((b + rnd) >> div, (g + r) >> div, (r + rnd) >> div); } else { ip.SetBGR((b + (s / 2)) / 2, (g + (s / 2)) / s, (r + (s / 2)) / s); } } // Return return p2.CreateGPixelReference(0); }
/// <summary> Draw the foreground layer onto this background image. /// /// </summary> /// <param name="mask">the mask layer /// </param> /// <param name="foregroundMap">the foreground colors /// </param> /// <param name="supersample">rate to upsample the foreground colors /// </param> /// <param name="subsample">rate to subsample the foreground colors /// </param> /// <param name="bounds">the target rectangle /// </param> /// <param name="gamma">color correction factor /// /// </param> /// <throws> IllegalArgumentException if the specified bounds are not contained in the page </throws> public virtual void Stencil(Bitmap mask, PixelMap foregroundMap, int supersample, int subsample, Rectangle bounds, double gamma) { // Check arguments Rectangle rect = new Rectangle(0, 0, (foregroundMap.ImageWidth * supersample + subsample - 1) / subsample, (foregroundMap.ImageHeight * supersample + subsample - 1) / subsample); if (bounds != null) { if ((bounds.Right < rect.Right) || (bounds.Bottom < rect.Bottom) || (bounds.Left > rect.Left) || (bounds.Top > rect.Top)) { throw new ArgumentException("rectangle out of bounds" + "bounds=(" + bounds.Right + "," + bounds.Bottom + "," + bounds.Left + "," + bounds.Top + "),rect=(" + rect.Right + "," + rect.Bottom + "," + rect.Left + "," + rect.Top + ")"); } rect = bounds; } // Compute number of rows int xrows = ImageHeight; if (mask.ImageHeight < xrows) { xrows = mask.ImageHeight; } if (rect.Height < xrows) { xrows = rect.Height; } // Compute number of columns int xcolumns = ImageWidth; if (mask.ImageWidth < xcolumns) { xcolumns = mask.ImageWidth; } if (rect.Width < xcolumns) { xcolumns = rect.Width; } // Precompute multiplier map int maxgray = mask.Grays - 1; int[] multiplier = new int[maxgray]; for (int i = 1; i < maxgray; i++) { multiplier[i] = (0x10000 * i) / maxgray; } // Prepare color correction table int[] gtable = GetColorCorrection(gamma); double ratioFg = supersample / (double)subsample; // Compute starting point in blown up foreground PixelMap int fgy = (rect.Bottom * subsample) / supersample; double fgy1 = rect.Bottom - ratioFg * fgy; if (fgy1 < 0) { fgy--; fgy1 += ratioFg; } int fgxz = (rect.Right * subsample) / supersample; double fgx1z = rect.Right - ratioFg * fgxz; if (fgx1z < 0) { fgxz--; fgx1z += ratioFg; } int fg = foregroundMap.RowOffset(fgy); PixelReference fgx = foregroundMap.CreateGPixelReference(0); PixelReference dst = CreateGPixelReference(0); // Loop over rows for (int y = 0; y < xrows; y++) { // Loop over columns fgx.SetOffset(fg + fgxz); double fgx1 = fgx1z; dst.SetOffset(y, 0); int src = mask.RowOffset(y); for (int x = 0; x < xcolumns; x++, dst.IncOffset()) { int srcpix = mask.GetByteAt(src + x); // Perform pixel operation if (srcpix > 0) { //fixed (int* gTableLocation = gtable) { if (srcpix >= maxgray) { dst.SetBGR(gtable[fgx.Blue], gtable[fgx.Green], gtable[fgx.Red]); } else { int level = multiplier[srcpix]; dst.SetBGR(((dst.Blue * (0x10000 - level)) + (level * gtable[fgx.Blue])) >> 16, ((dst.Green * (0x10000 - level)) + (level * gtable[fgx.Green])) >> 16, ((dst.Red * (0x10000 - level)) + (level * gtable[fgx.Red])) >> 16); } } } // Next column if (++fgx1 >= ratioFg) { fgx1 -= ratioFg; fgx.IncOffset(); } } // Next line if (++fgy1 >= ratioFg) { fgy1 -= ratioFg; fg += foregroundMap.GetRowSize(); } } }
private PixelReference GetLine(int fy, Rectangle required_red, Rectangle provided_input, PixelMap input) { if (fy < required_red.YMin) { fy = required_red.YMin; } else if (fy >= required_red.YMax) { fy = required_red.YMax - 1; } // Cached line if (fy == l2) { return(p2.CreateGPixelReference(0)); } if (fy == l1) { return(p1.CreateGPixelReference(0)); } // Shift PixelMap p = p1; p1 = p2; l1 = l2; p2 = p; l2 = fy; // Compute location of line Rectangle line = new Rectangle(); line.XMin = required_red.XMin << xshift; line.XMax = required_red.XMax << xshift; line.YMin = fy << yshift; line.YMax = (fy + 1) << yshift; line.Intersect(line, provided_input); line.Translate(-provided_input.XMin, -provided_input.YMin); // Prepare variables int botline = input.RowOffset(line.YMin); int rowsize = input.GetRowSize(); int sw = 1 << xshift; int div = xshift + yshift; int rnd = 1 << (div - 1); int rnd2 = rnd + rnd; PixelReference inp1 = input.CreateGPixelReference(0); PixelReference ip = p.CreateGPixelReference(0); // Compute averages for (int x = line.XMin; x < line.XMax; x += sw, ip.IncOffset()) { int r = 0; int g = 0; int b = 0; int s = 0; int inp0 = botline + x; int sy2 = line.Height; int sy1 = (1 << yshift); if (sy1 > sy2) { sy1 = sy2; } for (int sy = 0; sy < sy1; sy++, inp0 += rowsize) { int sx1 = x + sw; inp1.SetOffset(inp0); if (sx1 > line.XMax) { sx1 = line.XMax; } for (int sx = sx1 - x; sx-- > 0; s++, inp1.IncOffset()) { r += inp1.Red; g += inp1.Green; b += inp1.Blue; } } if (s == rnd2) { ip.SetBGR((b + rnd) >> div, (g + r) >> div, (r + rnd) >> div); } else { ip.SetBGR((b + (s / 2)) / 2, (g + (s / 2)) / s, (r + (s / 2)) / s); } } // Return return(p2.CreateGPixelReference(0)); }
/// <summary> Draw the foreground layer onto this background image. /// /// </summary> /// <param name="mask">the mask layer /// </param> /// <param name="foregroundMap">the foreground colors /// </param> /// <param name="supersample">rate to upsample the foreground colors /// </param> /// <param name="subsample">rate to subsample the foreground colors /// </param> /// <param name="bounds">the target rectangle /// </param> /// <param name="gamma">color correction factor /// /// </param> /// <throws> IllegalArgumentException if the specified bounds are not contained in the page </throws> public unsafe virtual void Stencil(Bitmap mask, PixelMap foregroundMap, int supersample, int subsample, Rectangle bounds, double gamma) { // Check arguments Rectangle rect = new Rectangle(0, 0, (foregroundMap.ImageWidth * supersample + subsample - 1) / subsample, (foregroundMap.ImageHeight * supersample + subsample - 1) / subsample); if (bounds != null) { if ((bounds.Right < rect.Right) || (bounds.Bottom < rect.Bottom) || (bounds.Left > rect.Left) || (bounds.Top > rect.Top)) { throw new ArgumentException("rectangle out of bounds" + "bounds=(" + bounds.Right + "," + bounds.Bottom + "," + bounds.Left + "," + bounds.Top + "),rect=(" + rect.Right + "," + rect.Bottom + "," + rect.Left + "," + rect.Top + ")"); } rect = bounds; } // Compute number of rows int xrows = ImageHeight; if (mask.ImageHeight < xrows) { xrows = mask.ImageHeight; } if (rect.Height < xrows) { xrows = rect.Height; } // Compute number of columns int xcolumns = ImageWidth; if (mask.ImageWidth < xcolumns) { xcolumns = mask.ImageWidth; } if (rect.Width < xcolumns) { xcolumns = rect.Width; } // Precompute multiplier map int maxgray = mask.Grays - 1; int[] multiplier = new int[maxgray]; for (int i = 1; i < maxgray; i++) { multiplier[i] = (0x10000 * i) / maxgray; } // Prepare color correction table int[] gtable = GetColorCorrection(gamma); double ratioFg = supersample / (double)subsample; // Compute starting point in blown up foreground PixelMap int fgy = (rect.Bottom * subsample) / supersample; double fgy1 = rect.Bottom - ratioFg * fgy; if (fgy1 < 0) { fgy--; fgy1 += ratioFg; } int fgxz = (rect.Right * subsample) / supersample; double fgx1z = rect.Right - ratioFg * fgxz; if (fgx1z < 0) { fgxz--; fgx1z += ratioFg; } int fg = foregroundMap.RowOffset(fgy); PixelReference fgx = foregroundMap.CreateGPixelReference(0); PixelReference dst = CreateGPixelReference(0); // Loop over rows for (int y = 0; y < xrows; y++) { // Loop over columns fgx.SetOffset(fg + fgxz); double fgx1 = fgx1z; dst.SetOffset(y, 0); int src = mask.RowOffset(y); for (int x = 0; x < xcolumns; x++, dst.IncOffset()) { int srcpix = mask.GetByteAt(src + x); // Perform pixel operation if (srcpix > 0) { fixed (int* gTableLocation = gtable) { if (srcpix >= maxgray) { dst.SetBGR(gTableLocation[fgx.Blue], gTableLocation[fgx.Green], gTableLocation[fgx.Red]); } else { int level = multiplier[srcpix]; dst.SetBGR(((dst.Blue * (0x10000 - level)) + (level * gTableLocation[fgx.Blue])) >> 16, ((dst.Green * (0x10000 - level)) + (level * gTableLocation[fgx.Green])) >> 16, ((dst.Red * (0x10000 - level)) + (level * gTableLocation[fgx.Red])) >> 16); } } } // Next column if (++fgx1 >= ratioFg) { fgx1 -= ratioFg; fgx.IncOffset(); } } // Next line if (++fgy1 >= ratioFg) { fgy1 -= ratioFg; fg += foregroundMap.GetRowSize(); } } }