Example #1
0
        public unsafe override BitmapBase Apply(RenderTask renderTask, BitmapBase layer)
        {
            Tank tank   = renderTask.Tank;
            var  bounds =
                Mode == ClipMode.ByPixels
                    ? layer.PreciseSize(PixelAlphaThreshold)
                : Mode == ClipMode.ByLayerBounds
                    ? PixelRect.FromMixed(0, 0, layer.Width, layer.Height)
                    : PixelRect.FromMixed(0, 0, Layer.ParentStyle.IconWidth, Layer.ParentStyle.IconHeight);

            using (layer.UseWrite())
            {
                int   count;
                byte *ptr;
                // Clip Top
                for (int y = 0; y < bounds.Top + ClipTop && y < layer.Height; y++)
                {
                    Ut.MemSet(layer.Data + y * layer.Stride, 0, layer.Width * 4);
                }
                // Clip Bottom
                for (int y = layer.Height - 1; y > bounds.Bottom - ClipBottom && y >= 0; y--)
                {
                    Ut.MemSet(layer.Data + y * layer.Stride, 0, layer.Width * 4);
                }
                // Clip Left
                count = Math.Min(bounds.Left + ClipLeft, layer.Width) * 4;
                ptr   = layer.Data;
                if (count > 0)
                {
                    for (int y = 0; y < layer.Height; y++, ptr += layer.Stride)
                    {
                        Ut.MemSet(ptr, 0, count);
                    }
                }
                // Clip Right
                count = Math.Min(layer.Width - 1 - bounds.Right + ClipRight, layer.Width) * 4;
                ptr   = layer.Data + layer.Width * 4 - count;
                if (count > 0)
                {
                    for (int y = 0; y < layer.Height; y++, ptr += layer.Stride)
                    {
                        Ut.MemSet(ptr, 0, count);
                    }
                }
            }
            return(layer);
        }
        public unsafe override BitmapBase Apply(Tank tank, BitmapBase layer)
        {
            using (layer.UseWrite())
            {
                // Just scale the brightness and alpha channels so as to normalize the maximum value.
                // This is crude but gives good results; a better algorithm would try to fit the histogram
                // to a predefined standard by scaling non-linearly.
                double maxBrightness = -1;
                double maxAlpha = -1;
                for (int y = 0; y < layer.Height; y++)
                {
                    byte* ptr = layer.Data + y * layer.Stride;
                    byte* end = ptr + layer.Width * 4;
                    while (ptr < end)
                    {
                        byte alpha = *(ptr + 3);
                        if (alpha > 0) // there are a lot of non-black pixels in the fully-transparent regions
                        {
                            if (NormalizeBrightness)
                            {
                                double brightness = *(ptr + 0) * 0.0722 + *(ptr + 1) * 0.7152 + *(ptr + 2) * 0.2126;
                                if (brightness > maxBrightness)
                                    maxBrightness = brightness;
                            }
                            if (NormalizeAlpha)
                            {
                                if (alpha > maxAlpha)
                                    maxAlpha = alpha;
                            }
                        }
                        ptr += 4;
                    }
                }

                double scaleBrightness = (double) MaxBrightness / maxBrightness;
                double scaleAlpha = (double) MaxAlpha / maxAlpha;
                for (int y = 0; y < layer.Height; y++)
                {
                    byte* ptr = layer.Data + y * layer.Stride;
                    byte* end = ptr + layer.Width * 4;
                    while (ptr < end)
                    {
                        byte alpha = *(ptr + 3);
                        if (alpha > 0)
                        {
                            if (NormalizeBrightness)
                            {
                                if (Grayscale)
                                {
                                    double brightness = *(ptr + 0) * 0.0722 + *(ptr + 1) * 0.7152 + *(ptr + 2) * 0.2126;
                                    *(ptr + 0) = *(ptr + 1) = *(ptr + 2) = (byte) (brightness * scaleBrightness).ClipMax(255);
                                }
                                else
                                {
                                    // TODO: the clipping here alters the hue. Ideally the color should be clipped without altering hue, by increasing brightness until white.
                                    *(ptr + 0) = (byte) (*(ptr + 0) * scaleBrightness).ClipMax(255);
                                    *(ptr + 1) = (byte) (*(ptr + 1) * scaleBrightness).ClipMax(255);
                                    *(ptr + 2) = (byte) (*(ptr + 2) * scaleBrightness).ClipMax(255);
                                }
                            }
                            else if (Grayscale)
                            {
                                double brightness = *(ptr + 0) * 0.0722 + *(ptr + 1) * 0.7152 + *(ptr + 2) * 0.2126;
                                *(ptr + 0) = *(ptr + 1) = *(ptr + 2) = (byte) brightness;
                            }
                            if (NormalizeAlpha)
                            {
                                *(ptr + 3) = (byte) (alpha * scaleAlpha);
                            }
                        }
                        ptr += 4;
                    }
                }
            }
            return layer;
        }
        public unsafe override BitmapBase Apply(RenderTask renderTask, BitmapBase layer)
        {
            Tank tank = renderTask.Tank;

            using (layer.UseWrite())
            {
                // Just scale the brightness and alpha channels so as to normalize the maximum value.
                // This is crude but gives good results; a better algorithm would try to fit the histogram
                // to a predefined standard by scaling non-linearly.
                double maxBrightness = -1;
                double maxAlpha      = -1;
                for (int y = 0; y < layer.Height; y++)
                {
                    byte *ptr = layer.Data + y * layer.Stride;
                    byte *end = ptr + layer.Width * 4;
                    while (ptr < end)
                    {
                        byte alpha = *(ptr + 3);
                        if (alpha > 0) // there are a lot of non-black pixels in the fully-transparent regions
                        {
                            if (NormalizeBrightness)
                            {
                                double brightness = *(ptr + 0) * 0.0722 + *(ptr + 1) * 0.7152 + *(ptr + 2) * 0.2126;
                                if (brightness > maxBrightness)
                                {
                                    maxBrightness = brightness;
                                }
                            }
                            if (NormalizeAlpha)
                            {
                                if (alpha > maxAlpha)
                                {
                                    maxAlpha = alpha;
                                }
                            }
                        }
                        ptr += 4;
                    }
                }

                double scaleBrightness = (double)MaxBrightness / maxBrightness;
                double scaleAlpha      = (double)MaxAlpha / maxAlpha;
                for (int y = 0; y < layer.Height; y++)
                {
                    byte *ptr = layer.Data + y * layer.Stride;
                    byte *end = ptr + layer.Width * 4;
                    while (ptr < end)
                    {
                        byte alpha = *(ptr + 3);
                        if (alpha > 0)
                        {
                            if (NormalizeBrightness)
                            {
                                if (Grayscale)
                                {
                                    double brightness = *(ptr + 0) * 0.0722 + *(ptr + 1) * 0.7152 + *(ptr + 2) * 0.2126;
                                    *(ptr + 0) = *(ptr + 1) = *(ptr + 2) = (byte)(brightness * scaleBrightness).ClipMax(255);
                                }
                                else
                                {
                                    // TODO: the clipping here alters the hue. Ideally the color should be clipped without altering hue, by increasing brightness until white.
                                    *(ptr + 0) = (byte)(*(ptr + 0) * scaleBrightness).ClipMax(255);
                                    *(ptr + 1) = (byte)(*(ptr + 1) * scaleBrightness).ClipMax(255);
                                    *(ptr + 2) = (byte)(*(ptr + 2) * scaleBrightness).ClipMax(255);
                                }
                            }
                            else if (Grayscale)
                            {
                                double brightness = *(ptr + 0) * 0.0722 + *(ptr + 1) * 0.7152 + *(ptr + 2) * 0.2126;
                                *(ptr + 0) = *(ptr + 1) = *(ptr + 2) = (byte)brightness;
                            }
                            if (NormalizeAlpha)
                            {
                                *(ptr + 3) = (byte)(alpha * scaleAlpha);
                            }
                        }
                        ptr += 4;
                    }
                }
            }
            return(layer);
        }
Example #4
0
        public unsafe override BitmapBase Apply(RenderTask renderTask, BitmapBase layer)
        {
            Tank      tank = renderTask.Tank;
            LayerBase maskLayer;

            if (string.IsNullOrEmpty(MaskLayerId))
            {
                return(layer);
            }
            maskLayer = renderTask.Style.Layers.FirstOrDefault(x => x.Id == MaskLayerId);
            if (maskLayer == null)
            {
                throw new StyleUserError(App.Translation.EffectMaskLayer.ErrorInvalidId.Fmt(MaskLayerId));
            }
            if (renderTask.IsLayerAlreadyReferenced(maskLayer))
            {
                throw new StyleUserError(App.Translation.EffectMaskLayer.ErrorRecursiveLayerReference.Fmt(MaskLayerId));
            }
            var maskImg = renderTask.RenderLayer(maskLayer);

            using (layer.UseWrite())
            {
                using (maskImg.UseRead())
                {
                    for (int i = 0; i < layer.Width; ++i)
                    {
                        for (int j = 0; j < layer.Height; ++j)
                        {
                            decimal alpha = 0;
                            if (i < maskImg.Width && j < maskImg.Height)
                            {
                                switch (MaskMode)
                                {
                                case Effects.MaskMode.Opacity:
                                    alpha = maskImg.Data[i * 4 + maskImg.Stride * j + 3];
                                    break;

                                case Effects.MaskMode.Grayscale:
                                    alpha = (maskImg.Data[i * 4 + maskImg.Stride * j]
                                             + maskImg.Data[i * 4 + maskImg.Stride * j + 1]
                                             + maskImg.Data[i * 4 + maskImg.Stride * j + 2]
                                             ) / 3;
                                    break;

                                case Effects.MaskMode.Combined:
                                    alpha = (maskImg.Data[i * 4 + maskImg.Stride * j]
                                             + maskImg.Data[i * 4 + maskImg.Stride * j + 1]
                                             + maskImg.Data[i * 4 + maskImg.Stride * j + 2]
                                             ) / 3 * maskImg.Data[i * 4 + maskImg.Stride * j + 3] / 255m;
                                    break;
                                }
                            }
                            if (Invert)
                            {
                                alpha = 255m - alpha;
                            }
                            var opacity = layer.Data[i * 4 + layer.Stride * j + 3] * (alpha / 255m);
                            layer.Data[i * 4 + layer.Stride * j + 3] = (byte)opacity;
                        }
                    }
                }
            }
            return(layer);
        }
Example #5
0
        public unsafe override BitmapBase Apply(Tank tank, BitmapBase layer)
        {
            var bounds =
                Mode == ClipMode.ByPixels
                    ? layer.PreciseSize(PixelAlphaThreshold)
                : Mode == ClipMode.ByLayerBounds
                    ? PixelRect.FromMixed(0, 0, layer.Width, layer.Height)
                    : PixelRect.FromMixed(0, 0, Layer.ParentStyle.IconWidth, Layer.ParentStyle.IconHeight);

            using (layer.UseWrite())
            {
                int count;
                byte* ptr;
                // Clip Top
                for (int y = 0; y < bounds.Top + ClipTop && y < layer.Height; y++)
                    Ut.MemSet(layer.Data + y * layer.Stride, 0, layer.Width * 4);
                // Clip Bottom
                for (int y = layer.Height - 1; y > bounds.Bottom - ClipBottom && y >= 0; y--)
                    Ut.MemSet(layer.Data + y * layer.Stride, 0, layer.Width * 4);
                // Clip Left
                count = Math.Min(bounds.Left + ClipLeft, layer.Width) * 4;
                ptr = layer.Data;
                if (count > 0)
                    for (int y = 0; y < layer.Height; y++, ptr += layer.Stride)
                        Ut.MemSet(ptr, 0, count);
                // Clip Right
                count = Math.Min(layer.Width - 1 - bounds.Right + ClipRight, layer.Width) * 4;
                ptr = layer.Data + layer.Width * 4 - count;
                if (count > 0)
                    for (int y = 0; y < layer.Height; y++, ptr += layer.Stride)
                        Ut.MemSet(ptr, 0, count);
            }
            return layer;
        }