コード例 #1
0
        internal unsafe void Vertical(BitmapBase src, BitmapBase dest, BlurEdgeMode edgeMode)
        {
            for (int x = 0; x < src.Width; x++)
            {
                byte *colSource = src.Data + x * 4;
                byte *colResult = dest.Data + x * 4;
                for (int y = 0; y < src.Height; y++)
                {
                    int rSum = 0, gSum = 0, bSum = 0, aSum = 0;
                    for (int k = 0, ySrc = y - _kernel.Length / 2; k < _kernel.Length; k++, ySrc++)
                    {
                        int yRead = ySrc;
                        if (yRead < 0 || yRead >= src.Height)
                        {
                            switch (edgeMode)
                            {
                            case BlurEdgeMode.Transparent:
                                continue;

                            case BlurEdgeMode.Same:
                                yRead = yRead < 0 ? 0 : src.Height - 1;
                                break;

                            case BlurEdgeMode.Wrap:
                                yRead = Ut.ModPositive(yRead, src.Height);
                                break;

                            case BlurEdgeMode.Mirror:
                                if (yRead < 0)
                                {
                                    yRead = -yRead - 1;
                                }
                                yRead = yRead % (2 * src.Height);
                                if (yRead >= src.Height)
                                {
                                    yRead = 2 * src.Height - yRead - 1;
                                }
                                break;
                            }
                        }
                        yRead *= src.Stride;
                        bSum  += _kernel[k] * colSource[yRead + 0];
                        gSum  += _kernel[k] * colSource[yRead + 1];
                        rSum  += _kernel[k] * colSource[yRead + 2];
                        aSum  += _kernel[k] * colSource[yRead + 3];
                    }

                    int yWrite = y * dest.Stride;
                    colResult[yWrite + 0] = (byte)(bSum / _kernelSum);
                    colResult[yWrite + 1] = (byte)(gSum / _kernelSum);
                    colResult[yWrite + 2] = (byte)(rSum / _kernelSum);
                    colResult[yWrite + 3] = (byte)(aSum / _kernelSum);
                }
            }
        }
コード例 #2
0
        internal unsafe void Horizontal(BitmapBase src, BitmapBase dest, BlurEdgeMode edgeMode)
        {
            for (int y = 0; y < src.Height; y++)
            {
                byte *rowSource = src.Data + y * src.Stride;
                byte *rowResult = dest.Data + y * dest.Stride;
                for (int x = 0; x < src.Width; x++)
                {
                    int rSum = 0, gSum = 0, bSum = 0, aSum = 0;
                    for (int k = 0, xSrc = x - _kernel.Length / 2; k < _kernel.Length; k++, xSrc++)
                    {
                        int xRead = xSrc;
                        if (xRead < 0 || xRead >= src.Width)
                        {
                            switch (edgeMode)
                            {
                            case BlurEdgeMode.Transparent:
                                continue;

                            case BlurEdgeMode.Same:
                                xRead = xRead < 0 ? 0 : src.Width - 1;
                                break;

                            case BlurEdgeMode.Wrap:
                                xRead = Ut.ModPositive(xRead, src.Width);
                                break;

                            case BlurEdgeMode.Mirror:
                                if (xRead < 0)
                                {
                                    xRead = -xRead - 1;
                                }
                                xRead = xRead % (2 * src.Width);
                                if (xRead >= src.Width)
                                {
                                    xRead = 2 * src.Width - xRead - 1;
                                }
                                break;
                            }
                        }
                        xRead <<= 2; // * 4
                        bSum   += _kernel[k] * rowSource[xRead + 0];
                        gSum   += _kernel[k] * rowSource[xRead + 1];
                        rSum   += _kernel[k] * rowSource[xRead + 2];
                        aSum   += _kernel[k] * rowSource[xRead + 3];
                    }

                    int xWrite = x << 2; // * 4
                    rowResult[xWrite + 0] = (byte)(bSum / _kernelSum);
                    rowResult[xWrite + 1] = (byte)(gSum / _kernelSum);
                    rowResult[xWrite + 2] = (byte)(rSum / _kernelSum);
                    rowResult[xWrite + 3] = (byte)(aSum / _kernelSum);
                }
            }
        }
コード例 #3
0
        unsafe private static void Resample1D(BitmapBase bmpDest, BitmapBase bmpSrc, int transparentOffset, ContributorEntry[] contrib, int alongSize, int crossSize, bool horz)
        {
            using (bmpSrc.UseRead())
                using (bmpDest.UseWrite())
                {
                    byte *srcBytes = bmpSrc.Data + transparentOffset;
                    for (int crossCoord = 0; crossCoord < crossSize; ++crossCoord)
                    {
                        for (int alongCoord = 0; alongCoord < alongSize; ++alongCoord)
                        {
                            for (int channel = 0; channel < 4; ++channel)
                            {
                                double intensity = 0;
                                double wsum      = 0;

                                for (int j = 0; j < contrib[alongCoord].SrcPixelCount; j++)
                                {
                                    int    contribCoord  = contrib[alongCoord].SrcPixel[j].Coord;
                                    int    contribOffset = (horz ? contribCoord : crossCoord) * 4 + (horz ? crossCoord : contribCoord) * bmpSrc.Stride;
                                    double weight        = contrib[alongCoord].SrcPixel[j].Weight;

                                    if (channel != 3)
                                    {
                                        weight *= srcBytes[contribOffset + 3] / 255d;
                                    }

                                    if (weight == 0)
                                    {
                                        continue;
                                    }

                                    wsum      += weight;
                                    intensity += srcBytes[contribOffset + channel] * weight;
                                }

                                bmpDest.Data[(horz ? alongCoord : crossCoord) * 4 + (horz ? crossCoord : alongCoord) * bmpDest.Stride + channel] =
                                    (byte)Math.Min(Math.Max(intensity / wsum, byte.MinValue), byte.MaxValue);
                            }
                        }
                    }
                }
        }
コード例 #4
0
        /// <summary>
        /// Returns a new image which contains a 1 pixel wide black outline of the specified image.
        /// </summary>
        public void GetOutline(BitmapBase result, Color color, int threshold, bool inside)
        {
            const byte outside = 0;

            using (UseRead())
                using (result.UseWrite())
                {
                    var  src = Data;
                    var  tgt = result.Data;
                    byte cr = color.R, cg = color.G, cb = color.B, ca = color.A;
                    for (int y = 0; y < Height; y++)
                    {
                        int b    = y * Stride;
                        int left = outside;
                        int cur  = src[b + 0 + 3];
                        int right;
                        for (int x = 0; x < Width; x++, b += 4)
                        {
                            right = x == Width - 1 ? outside : src[b + 4 + 3];
                            if ((src[b + 3] <= threshold) ^ inside)
                            {
                                if (
                                    ((left > threshold) ^ inside) ||
                                    ((right > threshold) ^ inside) ||
                                    (((y == 0 ? outside : src[b - Stride + 3]) > threshold) ^ inside) ||
                                    (((y == Height - 1 ? outside : src[b + Stride + 3]) > threshold) ^ inside)
                                    )
                                {
                                    tgt[b]     = cb;
                                    tgt[b + 1] = cg;
                                    tgt[b + 2] = cr;
                                    tgt[b + 3] = ca;
                                }
                            }
                            left = cur;
                            cur  = right;
                        }
                    }
                }
        }
コード例 #5
0
ファイル: Targa.cs プロジェクト: rstarkov/TankIconMaker
        /// <summary>A convenience method to save a GDI image directly to a .tga file.</summary>
        public static unsafe void Save(BitmapBase image, string filename)
        {
            using (image.UseRead())
            using (var file = File.Open(filename, FileMode.Create, FileAccess.Write, FileShare.Read))
            {
                var header = new byte[18];
                header[2] = 2;
                header[12] = (byte) (image.Width);
                header[13] = (byte) (image.Width >> 8);
                header[14] = (byte) (image.Height);
                header[15] = (byte) (image.Height >> 8);
                header[16] = 32;
                header[17] = 32;
                file.Write(header);

                byte[] dummy = new byte[image.Width * 4];
                for (int y = 0; y < image.Height; y++)
                {
                    Ut.MemCpy(dummy, image.Data + y * image.Stride, image.Width * 4);
                    file.Write(dummy);
                }
            }
        }
コード例 #6
0
        /// <summary>A convenience method to save a GDI image directly to a .tga file.</summary>
        public static unsafe void Save(BitmapBase image, string filename)
        {
            using (image.UseRead())
                using (var file = File.Open(filename, FileMode.Create, FileAccess.Write, FileShare.Read))
                {
                    var header = new byte[18];
                    header[2]  = 2;
                    header[12] = (byte)(image.Width);
                    header[13] = (byte)(image.Width >> 8);
                    header[14] = (byte)(image.Height);
                    header[15] = (byte)(image.Height >> 8);
                    header[16] = 32;
                    header[17] = 32;
                    file.Write(header);

                    byte[] dummy = new byte[image.Width * 4];
                    for (int y = 0; y < image.Height; y++)
                    {
                        Ut.MemCpy(dummy, image.Data + y * image.Stride, image.Width * 4);
                        file.Write(dummy);
                    }
                }
        }
コード例 #7
0
        public void DrawImage(BitmapBase image, int destX, int destY, int srcX, int srcY, int width, int height, bool below)
        {
            using (UseWrite())
                using (image.UseRead())
                {
                    if (width <= 0 || height <= 0)
                    {
                        return;
                    }
                    if (destX < 0)
                    {
                        srcX  -= destX;
                        width += destX;
                        destX  = 0;
                    }
                    if (destY < 0)
                    {
                        srcY   -= destY;
                        height += destY;
                        destY   = 0;
                    }
                    if (srcX >= image.Width || srcY >= image.Height)
                    {
                        return;
                    }
                    if (srcX < 0)
                    {
                        destX -= srcX;
                        width += srcX;
                        srcX   = 0;
                    }
                    if (srcY < 0)
                    {
                        destY  -= srcY;
                        height += srcY;
                        srcY    = 0;
                    }
                    if (destX >= Width || destY >= Height)
                    {
                        return;
                    }
                    if (destX + width > Width)
                    {
                        width = Width - destX;
                    }
                    if (destY + height > Height)
                    {
                        height = Height - destY;
                    }
                    if (srcX + width > image.Width)
                    {
                        width = image.Width - srcX;
                    }
                    if (srcY + height > image.Height)
                    {
                        height = image.Height - srcY;
                    }
                    if (width <= 0 || height <= 0) // cannot be negative at this stage, but just in case...
                    {
                        return;
                    }

                    byte *dest = Data + destY * Stride + destX * 4;
                    byte *src  = image.Data + srcY * image.Stride + srcX * 4;

                    for (int y = 0; y < height; y++, dest += Stride, src += image.Stride)
                    {
                        byte *tgt = dest;
                        byte *btm = below ? src : dest;
                        byte *top = below ? dest : src;
                        byte *end = tgt + width * 4;
                        do
                        {
                            byte topA = *(top + 3);
                            byte btmA = *(btm + 3);
                            if (topA == 255 || btmA == 0)
                            {
                                *(int *)tgt = *(int *)top;
                            }
                            else if (topA == 0)
                            {
                                *(int *)tgt = *(int *)btm;
                            }
                            else if (btmA == 255)
                            {
                                // green
                                *(tgt + 1) = (byte)((*(top + 1) * topA + *(btm + 1) * (255 - topA)) >> 8);
                                // red and blue
                                *(uint *)tgt = (*(uint *)tgt & 0xFF00FF00u) | (((((*(uint *)top) & 0x00FF00FFu) * topA + ((*(uint *)btm) & 0x00FF00FFu) * (uint)(255 - topA)) >> 8) & 0x00FF00FFu);
                                // alpha (only needed when "below" is true)
                                *(tgt + 3) = 255;
                            }
                            else // topA and btmA both >0 and <255
                            {
                                byte tgtAA = *(tgt + 3) = (byte)(topA + (btmA * (255 - topA) >> 8));
                                int  btmAA = (btmA * (255 - topA)) / 255;
                                tgtAA     += 1; // ensures the division below never results in a value greater than 255
                                *(tgt + 0) = (byte)((*(top + 0) * topA + *(btm + 0) * btmAA) / tgtAA);
                                *(tgt + 1) = (byte)((*(top + 1) * topA + *(btm + 1) * btmAA) / tgtAA);
                                *(tgt + 2) = (byte)((*(top + 2) * topA + *(btm + 2) * btmAA) / tgtAA);
                            }
                            tgt += 4;
                            btm += 4;
                            top += 4;
                        }while (tgt < end);
                    }
                }
        }
コード例 #8
0
 public void DrawImage(BitmapBase image, int destX = 0, int destY = 0, bool below = false)
 {
     DrawImage(image, destX, destY, 0, 0, image.Width, image.Height, below);
 }
コード例 #9
0
 public void CopyPixelsFrom(BitmapBase source)
 {
     using (source.UseRead())
         CopyPixelsFrom(source.Data, source.Width, source.Height, source.Stride);
 }
コード例 #10
0
 public BitmapWriteReleaser(BitmapBase bitmap)
 {
     _bmp = bitmap; lock (_bmp) _bmp.acquire(write: true);
 }
コード例 #11
0
 public BitmapReadReleaser(BitmapBase bitmap)
 {
     _bmp = bitmap; lock (_bmp) _bmp.acquire(write: false);
 }
コード例 #12
0
ファイル: Bitmap.cs プロジェクト: rstarkov/TankIconMaker
 public BitmapWriteReleaser(BitmapBase bitmap)
 {
     _bmp = bitmap; lock (_bmp) _bmp.acquire(write: true);
 }
コード例 #13
0
ファイル: Bitmap.cs プロジェクト: rstarkov/TankIconMaker
 /// <summary>
 /// Returns a new image which contains a 1 pixel wide black outline of the specified image.
 /// </summary>
 public void GetOutline(BitmapBase result, Color color, int threshold, bool inside)
 {
     const byte outside = 0;
     using (UseRead())
     using (result.UseWrite())
     {
         var src = Data;
         var tgt = result.Data;
         byte cr = color.R, cg = color.G, cb = color.B, ca = color.A;
         for (int y = 0; y < Height; y++)
         {
             int b = y * Stride;
             int left = outside;
             int cur = src[b + 0 + 3];
             int right;
             for (int x = 0; x < Width; x++, b += 4)
             {
                 right = x == Width - 1 ? outside : src[b + 4 + 3];
                 if ((src[b + 3] <= threshold) ^ inside)
                 {
                     if (
                         ((left > threshold) ^ inside) ||
                         ((right > threshold) ^ inside) ||
                         (((y == 0 ? outside : src[b - Stride + 3]) > threshold) ^ inside) ||
                         (((y == Height - 1 ? outside : src[b + Stride + 3]) > threshold) ^ inside)
                     )
                     {
                         tgt[b] = cb;
                         tgt[b + 1] = cg;
                         tgt[b + 2] = cr;
                         tgt[b + 3] = ca;
                     }
                 }
                 left = cur;
                 cur = right;
             }
         }
     }
 }
コード例 #14
0
ファイル: Bitmap.cs プロジェクト: rstarkov/TankIconMaker
 public void DrawImage(BitmapBase image, int destX = 0, int destY = 0, bool below = false)
 {
     DrawImage(image, destX, destY, 0, 0, image.Width, image.Height, below);
 }
コード例 #15
0
        public static unsafe BitmapBase SizePos(BitmapBase source, double scaleWidth, double scaleHeight, int inX, int inY, int outX, int outY, int maxWidth = 0, int maxHeight = 0, Filter filter = null)
        {
            if (source.Width <= 0 || source.Height <= 0)
            {
                return(source.ToBitmapSame());
            }

            PixelRect pureImg = source.PreciseSize(0);

            if (pureImg.Width <= 0 || pureImg.Height <= 0)
            {
                return(source.ToBitmapSame());
            }

            int outWidth  = (int)Math.Round(pureImg.Width * scaleWidth);
            int outHeight = (int)Math.Round(pureImg.Height * scaleHeight);

            if (scaleWidth == 1 && scaleHeight == 1)
            {
                //no resize needed
                if (inX != outX || inY != outY)
                {
                    BitmapBase result;
                    if (maxWidth == 0 && maxHeight == 0)
                    {
                        result = new BitmapRam(outX - inX + source.Width, outY - inY + source.Height);
                    }
                    else
                    {
                        result = new BitmapRam(Math.Min(outX - inX + source.Width, maxWidth), Math.Min(outY - inY + source.Height, maxHeight));
                    }

                    result.DrawImage(source, outX - inX, outY - inY);
                    return(result);
                }
                else
                {
                    return(source.ToBitmapSame());
                }
            }

            if (filter == null)
            {
                if (scaleWidth < 1)
                {
                    filter = new LanczosFilter();
                }
                else
                {
                    filter = new MitchellFilter();
                }
            }

            int transparentOffset;

            if (pureImg.Left != 0 || pureImg.Top != 0)
            {
                transparentOffset = pureImg.Left * 4 + pureImg.Top * source.Stride;
                // Resample looks better if transprent pixels is cropped. Especially if the image is square
                // Data+DataOffset, pureImg.Width, pureImg.Height instead of Data, Width, Height works like left-top cropping
            }
            else
            {
                transparentOffset = 0;
            }

            BitmapBase afterHorzResample, afterVertResample;

            // Horizontal resampling
            if (scaleWidth == 1)
            {
                afterHorzResample = source;
            }
            else
            {
                afterHorzResample = new BitmapRam(outWidth, pureImg.Height);
                ContributorEntry[] contrib = filter.PrecomputeResample(scaleWidth, pureImg.Width, outWidth);
                Resample1D(afterHorzResample, source, transparentOffset, contrib, outWidth, pureImg.Height, true);
                transparentOffset = 0;
            }

            // Vertical resampling
            if (scaleHeight == 1)
            {
                afterVertResample = afterHorzResample;
            }
            else
            {
                afterVertResample = new BitmapRam(outWidth, outHeight);
                ContributorEntry[] contrib = filter.PrecomputeResample(scaleHeight, pureImg.Height, outHeight);
                Resample1D(afterVertResample, afterHorzResample, transparentOffset, contrib, outHeight, outWidth, false);
            }

            BitmapBase final;
            //At this point image will be resized and moved to another BitmapBase anyway
            int drawX = outX - (int)Math.Round((inX - pureImg.Left) * scaleWidth);
            int drawY = outY - (int)Math.Round((inY - pureImg.Top) * scaleHeight);

            if (maxWidth == 0 && maxHeight == 0)
            {
                final = new BitmapRam(Math.Max(drawX + outWidth, maxWidth), Math.Max(drawY + outHeight, maxHeight));
            }
            else
            {
                final = new BitmapRam(Math.Max(drawX + outWidth, maxWidth), Math.Max(drawY + outHeight, maxHeight));
            }
            final.DrawImage(afterVertResample, drawX, drawY);
            return(final);
        }
コード例 #16
0
ファイル: Bitmap.cs プロジェクト: rstarkov/TankIconMaker
 public void CopyPixelsFrom(BitmapBase source)
 {
     using (source.UseRead())
         CopyPixelsFrom(source.Data, source.Width, source.Height, source.Stride);
 }
コード例 #17
0
ファイル: UtGraphics.cs プロジェクト: rstarkov/TankIconMaker
        internal unsafe void Vertical(BitmapBase src, BitmapBase dest, BlurEdgeMode edgeMode)
        {
            for (int x = 0; x < src.Width; x++)
            {
                byte* colSource = src.Data + x * 4;
                byte* colResult = dest.Data + x * 4;
                for (int y = 0; y < src.Height; y++)
                {
                    int rSum = 0, gSum = 0, bSum = 0, aSum = 0;
                    for (int k = 0, ySrc = y - _kernel.Length / 2; k < _kernel.Length; k++, ySrc++)
                    {
                        int yRead = ySrc;
                        if (yRead < 0 || yRead >= src.Height)
                            switch (edgeMode)
                            {
                                case BlurEdgeMode.Transparent:
                                    continue;
                                case BlurEdgeMode.Same:
                                    yRead = yRead < 0 ? 0 : src.Height - 1;
                                    break;
                                case BlurEdgeMode.Wrap:
                                    yRead = Ut.ModPositive(yRead, src.Height);
                                    break;
                                case BlurEdgeMode.Mirror:
                                    if (yRead < 0)
                                        yRead = -yRead - 1;
                                    yRead = yRead % (2 * src.Height);
                                    if (yRead >= src.Height)
                                        yRead = 2 * src.Height - yRead - 1;
                                    break;
                            }
                        yRead *= src.Stride;
                        bSum += _kernel[k] * colSource[yRead + 0];
                        gSum += _kernel[k] * colSource[yRead + 1];
                        rSum += _kernel[k] * colSource[yRead + 2];
                        aSum += _kernel[k] * colSource[yRead + 3];
                    }

                    int yWrite = y * dest.Stride;
                    colResult[yWrite + 0] = (byte) (bSum / _kernelSum);
                    colResult[yWrite + 1] = (byte) (gSum / _kernelSum);
                    colResult[yWrite + 2] = (byte) (rSum / _kernelSum);
                    colResult[yWrite + 3] = (byte) (aSum / _kernelSum);
                }
            }
        }
コード例 #18
0
ファイル: Effect.cs プロジェクト: rstarkov/TankIconMaker
 /// <summary>
 /// Applies the effect to the specified layer. Returns the resulting image. If the layer is writable, may modify it
 /// directly and return the same instance, instead of creating a new one.
 /// </summary>
 public abstract BitmapBase Apply(Tank tank, BitmapBase layer);
コード例 #19
0
ファイル: UtGraphics.cs プロジェクト: rstarkov/TankIconMaker
        internal unsafe void Horizontal(BitmapBase src, BitmapBase dest, BlurEdgeMode edgeMode)
        {
            for (int y = 0; y < src.Height; y++)
            {
                byte* rowSource = src.Data + y * src.Stride;
                byte* rowResult = dest.Data + y * dest.Stride;
                for (int x = 0; x < src.Width; x++)
                {
                    int rSum = 0, gSum = 0, bSum = 0, aSum = 0;
                    for (int k = 0, xSrc = x - _kernel.Length / 2; k < _kernel.Length; k++, xSrc++)
                    {
                        int xRead = xSrc;
                        if (xRead < 0 || xRead >= src.Width)
                            switch (edgeMode)
                            {
                                case BlurEdgeMode.Transparent:
                                    continue;
                                case BlurEdgeMode.Same:
                                    xRead = xRead < 0 ? 0 : src.Width - 1;
                                    break;
                                case BlurEdgeMode.Wrap:
                                    xRead = Ut.ModPositive(xRead, src.Width);
                                    break;
                                case BlurEdgeMode.Mirror:
                                    if (xRead < 0)
                                        xRead = -xRead - 1;
                                    xRead = xRead % (2 * src.Width);
                                    if (xRead >= src.Width)
                                        xRead = 2 * src.Width - xRead - 1;
                                    break;
                            }
                        xRead <<= 2; // * 4
                        bSum += _kernel[k] * rowSource[xRead + 0];
                        gSum += _kernel[k] * rowSource[xRead + 1];
                        rSum += _kernel[k] * rowSource[xRead + 2];
                        aSum += _kernel[k] * rowSource[xRead + 3];
                    }

                    int xWrite = x << 2; // * 4
                    rowResult[xWrite + 0] = (byte) (bSum / _kernelSum);
                    rowResult[xWrite + 1] = (byte) (gSum / _kernelSum);
                    rowResult[xWrite + 2] = (byte) (rSum / _kernelSum);
                    rowResult[xWrite + 3] = (byte) (aSum / _kernelSum);
                }
            }
        }
コード例 #20
0
ファイル: Bitmap.cs プロジェクト: rstarkov/TankIconMaker
 public BitmapReadReleaser(BitmapBase bitmap)
 {
     _bmp = bitmap; lock (_bmp) _bmp.acquire(write: false);
 }
コード例 #21
0
ファイル: Bitmap.cs プロジェクト: rstarkov/TankIconMaker
        public void DrawImage(BitmapBase image, int destX, int destY, int srcX, int srcY, int width, int height, bool below)
        {
            using (UseWrite())
            using (image.UseRead())
            {
                if (width <= 0 || height <= 0)
                    return;
                if (destX < 0)
                {
                    srcX -= destX;
                    width += destX;
                    destX = 0;
                }
                if (destY < 0)
                {
                    srcY -= destY;
                    height += destY;
                    destY = 0;
                }
                if (srcX >= image.Width || srcY >= image.Height)
                    return;
                if (srcX < 0)
                {
                    destX -= srcX;
                    width += srcX;
                    srcX = 0;
                }
                if (srcY < 0)
                {
                    destY -= srcY;
                    height += srcY;
                    srcY = 0;
                }
                if (destX >= Width || destY >= Height)
                    return;
                if (destX + width > Width)
                    width = Width - destX;
                if (destY + height > Height)
                    height = Height - destY;
                if (srcX + width > image.Width)
                    width = image.Width - srcX;
                if (srcY + height > image.Height)
                    height = image.Height - srcY;
                if (width <= 0 || height <= 0) // cannot be negative at this stage, but just in case...
                    return;

                byte* dest = Data + destY * Stride + destX * 4;
                byte* src = image.Data + srcY * image.Stride + srcX * 4;

                for (int y = 0; y < height; y++, dest += Stride, src += image.Stride)
                {
                    byte* tgt = dest;
                    byte* btm = below ? src : dest;
                    byte* top = below ? dest : src;
                    byte* end = tgt + width * 4;
                    do
                    {
                        byte topA = *(top + 3);
                        byte btmA = *(btm + 3);
                        if (topA == 255 || btmA == 0)
                            *(int*) tgt = *(int*) top;
                        else if (topA == 0)
                            *(int*) tgt = *(int*) btm;
                        else if (btmA == 255)
                        {
                            // green
                            *(tgt + 1) = (byte) ((*(top + 1) * topA + *(btm + 1) * (255 - topA)) >> 8);
                            // red and blue
                            *(uint*) tgt = (*(uint*) tgt & 0xFF00FF00u) | (((((*(uint*) top) & 0x00FF00FFu) * topA + ((*(uint*) btm) & 0x00FF00FFu) * (uint) (255 - topA)) >> 8) & 0x00FF00FFu);
                            // alpha (only needed when "below" is true)
                            *(tgt + 3) = 255;
                        }
                        else // topA and btmA both >0 and <255
                        {
                            byte tgtAA = *(tgt + 3) = (byte) (topA + (btmA * (255 - topA) >> 8));
                            int btmAA = (btmA * (255 - topA)) / 255;
                            tgtAA += 1; // ensures the division below never results in a value greater than 255
                            *(tgt + 0) = (byte) ((*(top + 0) * topA + *(btm + 0) * btmAA) / tgtAA);
                            *(tgt + 1) = (byte) ((*(top + 1) * topA + *(btm + 1) * btmAA) / tgtAA);
                            *(tgt + 2) = (byte) ((*(top + 2) * topA + *(btm + 2) * btmAA) / tgtAA);
                        }
                        tgt += 4;
                        btm += 4;
                        top += 4;
                    }
                    while (tgt < end);
                }
            }
        }
コード例 #22
0
 /// <summary>
 /// Applies the effect to the specified layer. Returns the resulting image. The caller must make sure that the layer
 /// is writable, because all Apply methods expect to be able to modify the layer if necessary and return it, instead of
 /// creating a new instance.
 /// </summary>
 public abstract BitmapBase Apply(RenderTask renderTask, BitmapBase layer);