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)); }
public void Scale(Rectangle provided_input, PixelMap sourceMap, Rectangle targetRect, PixelMap output) { // Compute rectangles Rectangle required_red = new Rectangle(); Rectangle sourceRect = CreateRectangles(targetRect, required_red); // Parameter validation if ( (provided_input.Width != sourceMap.ImageWidth) || (provided_input.Height != sourceMap.ImageHeight)) { throw new Exception("invalid rectangle"); } if ( (provided_input.XMin > sourceRect.XMin) || (provided_input.YMin > sourceRect.YMin) || (provided_input.XMax < sourceRect.XMax) || (provided_input.YMax < sourceRect.YMax)) { throw new Exception("invalid rectangle"); } // Adjust output pixmap if ( (targetRect.Width != (int)output.ImageWidth) || (targetRect.Height != (int)output.ImageHeight)) { output.Init( targetRect.Height, targetRect.Width, null); } // Prepare temp stuff int bufw = required_red.Width; Pixel[] lbuffer = new Pixel[bufw + 2]; for (int i = 0; i < lbuffer.Length;) { lbuffer[i++] = new Pixel(); } try { if ((xshift > 0) || (yshift > 0)) { p1 = new PixelMap().Init(1, bufw, null); p2 = new PixelMap().Init(2, bufw, null); l1 = l2 = -1; } // Loop on output lines for (int y = targetRect.YMin; y < targetRect.YMax; y++) { // Perform vertical interpolation { int fy = vcoord[y]; int fy1 = fy >> FRACBITS; int fy2 = fy1 + 1; PixelReference upper; PixelReference lower; // Obtain upper and lower line in reduced image if ((xshift > 0) || (yshift > 0)) { lower = GetLine(fy1, required_red, provided_input, sourceMap); upper = GetLine(fy2, required_red, provided_input, sourceMap); } else { int dx = required_red.XMin - provided_input.XMin; if (required_red.YMin > fy1) { fy1 = required_red.YMin; } if (required_red.YMax <= fy2) { fy2 = required_red.YMax - 1; } lower = sourceMap.CreateGPixelReference(fy1 - provided_input.YMin, dx); upper = sourceMap.CreateGPixelReference(fy2 - provided_input.YMin, dx); } // Compute line int idest = 1; short[] deltas = interp[fy & FRACMASK]; for ( int edest = idest + bufw; idest < edest; upper.IncOffset(), lower.IncOffset()) { Pixel dest = lbuffer[idest++]; int lower_r = lower.Red; int delta_r = deltas[(256 + upper.Red) - lower_r]; int lower_g = lower.Green; int delta_g = deltas[(256 + upper.Green) - lower_g]; int lower_b = lower.Blue; int delta_b = deltas[(256 + upper.Blue) - lower_b]; dest.SetBGR(lower_b + delta_b, lower_g + delta_g, lower_r + delta_r); } } // Perform horizontal interpolation { // Prepare for side effects lbuffer[0] = lbuffer[1]; // lbuffer[bufw] = lbuffer[bufw]; int line = 1 - required_red.XMin; PixelReference dest = output.CreateGPixelReference(y - targetRect.YMin, 0); // Loop horizontally for (int x = targetRect.XMin; x < targetRect.XMax; x++) { int n = hcoord[x]; int lower = line + (n >> FRACBITS); Pixel lower0 = lbuffer[lower]; Pixel lower1 = lbuffer[lower + 1]; short[] deltas = interp[n & FRACMASK]; int lower_r = lower0.Red; int delta_r = deltas[(256 + lower1.Red) - lower_r]; int lower_g = lower0.Green; int delta_g = deltas[(256 + lower1.Green) - lower_g]; int lower_b = lower0.Blue; int delta_b = deltas[(256 + lower1.Blue) - lower_b]; dest.SetBGR(lower_b + delta_b, lower_g + delta_g, lower_r + delta_r); dest.IncOffset(); } } } } finally { p1 = null; p2 = null; } }
/// <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(); } } }
/// <summary> Fill this image from another source at reduced resolution. Pixel /// averaging will be used. /// /// </summary> /// <param name="src">image map to reduce /// </param> /// <param name="subsample">rate to subsample /// </param> /// <param name="pdr">target bounds /// </param> public virtual void Downsample(Map src, int subsample, Rectangle pdr) { Rectangle rect = new Rectangle(0, 0, ((src.ImageWidth + subsample) - 1) / subsample, ((src.ImageHeight + subsample) - 1) / subsample); if (pdr != null) { if ((pdr.Right < rect.Right) || (pdr.Bottom < rect.Bottom) || (pdr.Left > rect.Left) || (pdr.Top > rect.Top)) { throw new ArgumentException("Specified rectangle overflows destination PixelMap"); } rect = pdr; } Init(rect.Height, rect.Width, null); int sy = rect.Bottom * subsample; int sxz = rect.Right * subsample; int sidx = src.RowOffset(sy); int didx = 0; PixelReference sptr = src.CreateGPixelReference(0); PixelReference dptr = CreateGPixelReference(0); for (int y = 0; y < ImageHeight; y++) { int sx = sxz; for (int x = ImageWidth; x-- > 0; dptr.IncOffset()) { int r = 0; int g = 0; int b = 0; int s = 0; int kidx = sidx; int lsy = sy + subsample; if (lsy > src.ImageHeight) { lsy = src.ImageHeight; } int lsx = sx + subsample; if (lsx > src.ImageWidth) { lsx = src.ImageWidth; } for (int rsy = sy; rsy < lsy; rsy++) { sptr.SetOffset(kidx + sx); if (!IsRampNeeded) { for (int rsx = lsx - sx; rsx-- > 0; sptr.IncOffset()) { r += sptr.Red; g += sptr.Green; b += sptr.Blue; s++; } } else { for (int rsx = lsx - sx; rsx-- > 0; sptr.IncOffset()) { Pixel pix = src.PixelRamp(sptr); r += pix.Red; g += pix.Green; b += pix.Blue; s++; } } kidx += src.GetRowSize(); } if (s >= _invmap.Length) { dptr.SetBGR(b / s, g / s, r / s); } else { dptr.SetBGR(((b * _invmap[s]) + 32768) >> 16, ((g * _invmap[s]) + 32768) >> 16, ((r * _invmap[s]) + 32768) >> 16); } sx += subsample; } sy += subsample; sidx += src.RowOffset(subsample); dptr.SetOffset(didx += GetRowSize()); } }
/// <summary> Insert the specified bitmap with the specified color. /// /// </summary> /// <param name="bm">bitmap to insert /// </param> /// <param name="xpos">horizontal position /// </param> /// <param name="ypos">vertical position /// </param> /// <param name="color">color to insert bitmap with /// </param> public virtual void Blit(Bitmap bm, int xpos, int ypos, Pixel color) { // Check if (color == null) { return; } // Compute number of rows and columns int xrows = ypos + bm.ImageHeight; if (xrows > ImageHeight) { xrows = ImageHeight; } if (ypos > 0) { xrows -= ypos; } int xcolumns = xpos + bm.ImageWidth; if (xcolumns > ImageWidth) { xcolumns = ImageWidth; } if (xpos > 0) { xcolumns -= xpos; } if ((xrows <= 0) || (xcolumns <= 0)) { return; } // Precompute multiplier map int maxgray = bm.Grays - 1; int[] multiplier = new int[maxgray]; for (int i = 0; i < maxgray; i++) { multiplier[i] = 0x10000 - ((i << 16) / maxgray); } // Cache target color int gr = color.Red; int gg = color.Green; int gb = color.Blue; // Compute starting point int src = bm.RowOffset((ypos < 0) ? (-ypos) : 0) - ((xpos < 0) ? xpos : 0); int dst = ((ypos > 0) ? RowOffset(ypos) : 0) + ((xpos > 0) ? xpos : 0); PixelReference dstPixel = CreateGPixelReference(dst); // Loop over rows for (int y = 0; y < xrows; y++) { // Loop over columns dstPixel.SetOffset(dst); for (int x = 0; x < xcolumns; dstPixel.IncOffset()) { int srcpix = bm.GetByteAt(src + (x++)); // Perform pixel operation if (srcpix != 0) { if (srcpix >= maxgray) { dstPixel.SetBGR(gb, gg, gr); } else { int level0 = multiplier[srcpix]; int level1 = 0x10000 - level0; dstPixel.SetBGR(_clip[((dstPixel.Blue * level0) + (gb * level1)) >> 16], _clip[((dstPixel.Green * level0) + (gg * level1)) >> 16], _clip[((dstPixel.Red * level0) + (gr * level1)) >> 16]); } } } // Next line dst += GetRowSize(); src += bm.GetRowSize(); } }
/// <summary> Attenuate the specified bitmap. /// /// </summary> /// <param name="bm">Bitmap to attenuate /// </param> /// <param name="xpos">horizontal position /// </param> /// <param name="ypos">vertical position /// </param> public virtual void Attenuate(Bitmap bm, int xpos, int ypos) { // Check // Compute number of rows and columns int xrows = ypos + bm.ImageHeight; if (xrows > ImageHeight) { xrows = ImageHeight; } if (ypos > 0) { xrows -= ypos; } int xcolumns = xpos + bm.ImageWidth; if (xcolumns > ImageWidth) { xcolumns = ImageWidth; } if (xpos > 0) { xcolumns -= xpos; } if ((xrows <= 0) || (xcolumns <= 0)) { return; } // Precompute multiplier map int maxgray = bm.Grays - 1; int[] multiplier = GetMultiplier(maxgray); // Compute starting point int src = bm.RowOffset((ypos < 0) ? (-ypos) : 0) - ((xpos < 0) ? xpos : 0); int dst = RowOffset((ypos > 0) ? ypos : 0) + ((xpos > 0) ? xpos : 0); PixelReference dstPixel = CreateGPixelReference(0); // Loop over rows for (int y = 0; y < xrows; y++) { // Loop over columns dstPixel.SetOffset(dst); for (int x = 0; x < xcolumns; dstPixel.IncOffset()) { int srcpix = bm.GetByteAt(src + (x++)); // Perform pixel operation if (srcpix > 0) { if (srcpix >= maxgray) { dstPixel.SetGray(0); } else { int level = multiplier[srcpix]; dstPixel.SetBGR((dstPixel.Blue * level) >> 16, (dstPixel.Green * level) >> 16, (dstPixel.Red * level) >> 16); } } } // Next line dst += GetRowSize(); src += bm.GetRowSize(); } }