Пример #1
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;
            }
        }
Пример #2
0
        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);
        }
Пример #3
0
        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));
        }
Пример #4
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;
            }
        }
Пример #5
0
        private bool Stencil(PixelMap pm, Graphics.Rectangle rect, int subsample, double gamma)
        {
            if (Info == null)
            {
                return false;
            }

            int width = Info.Width;
            int height = Info.Height;

            if ((width <= 0) || (height <= 0))
            {
                return false;
            }

            double gamma_correction = 1.0D;

            if (gamma > 0.0D)
            {
                gamma_correction = gamma / Info.Gamma;
            }

            if (gamma_correction < 0.10000000000000001D)
            {
                gamma_correction = 0.10000000000000001D;
            }
            else if (gamma_correction > 10D)
            {
                gamma_correction = 10D;
            }

            JB2Image fgJb2 = ForegroundJB2Image;

            if (fgJb2 != null)
            {
                ColorPalette fgPalette = ForegroundPalette;

                if (fgPalette != null)
                {
                    List<int> components = new List<int>();
                    GBitmap bm = GetBitmapList(rect, subsample, 1, components);

                    if (fgJb2.Blits.Count != fgPalette.BlitColors.Length)
                    {
                        pm.Attenuate(bm, 0, 0);

                        return false;
                    }

                    GPixmap colors =
                      new GPixmap().Init(
                        1,
                        fgPalette.PaletteColors.Length,
                        null);
                    GPixelReference color = colors.CreateGPixelReference(0);

                    for (int i = 0; i < colors.ImageWidth; color.IncOffset())
                    {
                        fgPalette.index_to_color(i++, color);
                    }

                    colors.ApplyGammaCorrection(gamma_correction);

                    List<int> compset = new List<int>();

                    while (components.Count > 0)
                    {
                        int lastx = 0;
                        int colorindex = fgPalette.BlitColors[((int)components[0])];
                        GRect comprect = new GRect();
                        compset = new List<int>();

                        for (int pos = 0; pos < components.Count; )
                        {
                            int blitno = ((int)components[pos]);
                            JB2Blit pblit = fgJb2.Blits[blitno];

                            if (pblit.Left < lastx)
                            {
                                break;
                            }

                            lastx = pblit.Left;

                            if (fgPalette.BlitColors[blitno] == colorindex)
                            {
                                JB2Shape pshape = fgJb2.GetShape(pblit.ShapeNumber);
                                GRect xrect =
                                  new GRect(
                                    pblit.Left,
                                    pblit.Bottom,
                                    pshape.Bitmap.ImageWidth,
                                    pshape.Bitmap.ImageHeight);
                                comprect.Recthull(comprect, xrect);
                                compset.Add(components[pos]);
                                components.Remove(pos);
                            }
                            else
                            {
                                pos++;
                            }
                        }

                        comprect.XMin /= subsample;
                        comprect.YMin /= subsample;
                        comprect.XMax = ((comprect.XMax + subsample) - 1) / subsample;
                        comprect.YMax = ((comprect.YMax + subsample) - 1) / subsample;
                        comprect.Intersect(comprect, rect);

                        if (comprect.Empty)
                        {
                            continue;
                        }

                        //        bm   = getBitmap(comprect, subsample, 1);
                        bm = new GBitmap();
                        bm.Init(
                          comprect.Height,
                          comprect.Width,
                          0);
                        bm.Grays = 1 + (subsample * subsample);

                        int rxmin = comprect.XMin * subsample;
                        int rymin = comprect.YMin * subsample;

                        for (int pos = 0; pos < compset.Count; ++pos)
                        {
                            int blitno = ((int)compset[pos]);
                            JB2Blit pblit = fgJb2.Blits[blitno];
                            JB2Shape pshape = fgJb2.GetShape(pblit.ShapeNumber);
                            bm.Blit(
                              pshape.Bitmap,
                              pblit.Left - rxmin,
                              pblit.Bottom - rymin,
                              subsample);
                        }

                        color.SetOffset(colorindex);
                        pm.Blit(
                          bm,
                          comprect.XMin - rect.XMin,
                          comprect.YMin - rect.YMin,
                          color);
                    }

                    return true;
                }

                // Three layer model.
                IWPixelMap fgIWPixmap = ForegroundIWPixelMap;

                if (fgIWPixmap != null)
                {
                    GBitmap bm = GetBitmap(rect, subsample, 1, null);

                    if ((bm != null) && (pm != null))
                    {
                        GPixmap fgPixmap = ForegroundPixelMap;
                        int w = fgPixmap.ImageWidth;
                        int h = fgPixmap.ImageHeight;
                        int red = ComputeRed(width, height, w, h);

                        //          if((red < 1) || (red > 12))
                        if ((red < 1) || (red > 16))
                        {
                            return false;
                        }
                        //
                        //          int supersample = (red <= subsample)
                        //            ? 1
                        //            : (red / subsample);
                        //          int wantedred = supersample * subsample;
                        //
                        //          if(red == wantedred)
                        //          {
                        //            pm.stencil(bm, fgPixmap, supersample, rect, gamma_correction);
                        //
                        //            return 1;
                        //          }
                        pm.Stencil(bm, fgPixmap, red, subsample, rect, gamma_correction);
                        return true;
                    }
                }
            }

            return false;
        }
Пример #6
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();
                }
            }
        }
Пример #7
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();
                }
            }
        }