なんとなく、ふわっと・・

写真と画像処理関係とひとりごとをなんとなく書き溜めていきたい

SetGradientAlpha32

2008-03-27 00:12:10 | C#(Graphics)

PixelFormat.Format32bppArgb の画像に8方向からアルファ値の傾斜をかける
SetGradientAlpha32 をつくった。

ここでやった AlphaGradient と同じように、LinerGradientBrush をつかって
マスクをつくり、すでに設定されているアルファ値に対して任意の傾斜を
設定できる。



using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

using System.Drawing.Imaging;
using System.Drawing.Drawing2D;
using ImageUtils;

namespace LuminanceToAlpha
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        public static bool LuminanceToAlpha(Bitmap bmp, bool bStretch,
            Color baseColor, out Bitmap result32)
        {
            result32 = null;

            if (bmp.PixelFormat != PixelFormat.Format24bppRgb)
                return false;

            int w = bmp.Width;
            int h = bmp.Height;

            Bitmap bw = bmp.Clone() as Bitmap;
            ImgUtils.GrayScale(ref bw);
            if (bStretch) ImgUtils.HistoStretch(ref bw);

            result32 = new Bitmap(w, h, PixelFormat.Format32bppArgb);

            Graphics g = Graphics.FromImage(result32);
            g.Clear(baseColor);
            g.Dispose();

            BmpProc8 src = new BmpProc8(bw);
            BmpProc32 dst = new BmpProc32(result32);

            for (int y = 0; y <h; y++)<br>
                for (int x = 0; x <w; x++)<br>
                {
                    dst[x, y, eRGB.a] = (byte)(255 - src[x, y]);
                }
            ImgUtils.CallDispose(dst, src, bw);

            return true;
        }

        public static bool SetAlpha32(ref Bitmap bmp, int percent)
        {
            if (bmp.PixelFormat != PixelFormat.Format32bppArgb)
                return false;

            int w = bmp.Width;
            int h = bmp.Height;

            double p = percent / 100d;

            BmpProc32 dst = new BmpProc32(bmp);

            for (int y = 0; y <h; y++)<br>
                for (int x = 0; x <w; x++)<br>
                {
                    if (dst[x, y, eRGB.a] == 0) continue;
                    dst[x, y, eRGB.a] = ImgUtils.AdjustByte(dst[x, y, eRGB.a] * p);
                }
            dst.Dispose();

            return true;
        }

        public static void DrawImageCenterAt(Graphics g, Bitmap bmp, int x, int y)
        {
            int xx = x - bmp.Width / 2;
            int yy = y - bmp.Height / 2;

            g.DrawImage(bmp, xx, yy, bmp.Width, bmp.Height);

        }

        public static Bitmap GetGradientMask(int width, int height, float[] factor,
                                                        float[] position, GradientSide gs)
        {
            Bitmap bmp = new Bitmap(width, height, PixelFormat.Format24bppRgb);

            Color endColor = Color.White;
            Color startColor = Color.Black;

            Point start = new Point(-1, 0);
            Point end = new Point(0, 0);

            switch (gs)
            {
                case GradientSide.Left:
                    end.X = width;
                    break;

                case GradientSide.Right:
                    start.X = width;
                    break;

                case GradientSide.Upper:
                    end.Y = height;
                    break;

                case GradientSide.Lower:
                    start.Y = height;
                    break;

                case GradientSide.UpperLeft:
                    end.X = width;
                    end.Y = height;
                    break;

                case GradientSide.UpperRight:
                    start.X = width;
                    end.Y = height;
                    break;

                case GradientSide.LowerLeft:
                    start.Y = height;
                    end.X = width;
                    break;

                case GradientSide.LowerRight:
                    start.X = width;
                    start.Y = height;
                    break;
            }

            Blend bl = new Blend();
            bl.Factors = factor;
            bl.Positions = position;

            LinearGradientBrush br = new LinearGradientBrush(
                                        start, end, startColor, endColor);
            br.Blend = bl;
            //br.GammaCorrection = true;

            Rectangle rct = new Rectangle(0, 0, width, height);

            Graphics g = Graphics.FromImage(bmp);
            g.FillRectangle(br, rct);
            g.Dispose();

            return bmp;
        }

        public static bool SetGradientAlpha32(ref Bitmap bmp32, float[] factor,
                                                 float[] position, GradientSide gs)
        {

            if (bmp32.PixelFormat != PixelFormat.Format32bppArgb)
                return false;

            int w = bmp32.Width;
            int h = bmp32.Height;

            Bitmap mask = GetGradientMask(w, h, factor, position, gs);

            byte a;

            BmpProc24 src = new BmpProc24(mask);
            BmpProc32 dst = new BmpProc32(bmp32);

            for (int y = 0; y <h; y++)<br>
                for (int x = 0; x <w; x++)<br>
                {
                    a = dst[x, y, eRGB.a];
                    if (a == 0) continue;
                    dst[x, y, eRGB.a] = ImgUtils.AdjustByte(a * src[x, y, eRGB.r] / 255);
                }

            ImgUtils.CallDispose(dst, src, mask);            

            return true;

        }

        private void button1_Click(object sender, EventArgs e)
        {
            Bitmap bmp = new Bitmap(@"c:HomeImgWorkSGASample2.png");

            int w = bmp.Width;
            int h = bmp.Height;

            Bitmap tmp1, tmp2;

            LuminanceToAlpha(bmp, true, Color.FromArgb(120, 0, 0), out tmp1);

            tmp2 = tmp1.Clone() as Bitmap;

            float[] position = { 0.0f, 0.2f, 0.4f, 0.6f, 0.8f, 1.0f };
            float[] factor = { 1.0f, 0.9f, 0.6f, 0.15f, 0.03f, 0.0f };

            SetGradientAlpha32(ref tmp2, factor, position, GradientSide.Left);

            Graphics g = this.CreateGraphics();

            for (int i = 0; i <4; i++)<br>
            {
                g.DrawImage(tmp2, 20 + 90 * i, 50 + 45 * i, w, h);
            }

            g.DrawImage(tmp1, 20 + 90 * 4, 50 + 45 * 4, w, h);

            g.Dispose();

            tmp2.Dispose();
            tmp1.Dispose();
            bmp.Dispose();
        }

    }
}


SGASample2



Comment

DrawImageCenterAt

2008-03-26 20:01:01 | C#(Graphics)

画像の中心を設定座標になるように描く DrawImageCenterAt をつくった。
非常に簡単な関数だが、こういうのが意外と便利だったりする。




全コードをしめす。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

using System.Drawing.Imaging;
using System.Drawing.Drawing2D;
using ImageUtils;

namespace LuminanceToAlpha
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        public static bool LuminanceToAlpha(Bitmap bmp, bool bStretch,
            Color baseColor, out Bitmap result32)
        {
            result32 = null;

            if (bmp.PixelFormat != PixelFormat.Format24bppRgb)
                return false;

            int w = bmp.Width;
            int h = bmp.Height;

            Bitmap bw = bmp.Clone() as Bitmap;
            ImgUtils.GrayScale(ref bw);
            if (bStretch) ImgUtils.HistoStretch(ref bw);

            result32 = new Bitmap(w, h, PixelFormat.Format32bppArgb);

            Graphics g = Graphics.FromImage(result32);
            g.Clear(baseColor);
            g.Dispose();

            BmpProc8 src = new BmpProc8(bw);
            BmpProc32 dst = new BmpProc32(result32);

            for (int y = 0; y < h; y++)
                for (int x = 0; x < w; x++)
                {
                    dst[x, y, eRGB.a] = (byte)(255 - src[x, y]);
                }
            ImgUtils.CallDispose(dst, src, bw);

            return true;
        }

        public static bool SetAlpha32(ref Bitmap bmp, int percent)
        {
            if (bmp.PixelFormat != PixelFormat.Format32bppArgb)
                return false;

            int w = bmp.Width;
            int h = bmp.Height;

            double p = percent / 100d;

            BmpProc32 dst = new BmpProc32(bmp);

            for (int y = 0; y < h; y++)
                for (int x = 0; x < w; x++)
                {
                    if (dst[x, y, eRGB.a] == 0) continue;
                    dst[x, y, eRGB.a] = ImgUtils.AdjustByte(dst[x, y, eRGB.a] * p);
                }
            dst.Dispose();

            return true;
        }

        public static void DrawImageCenterAt(Graphics g, Bitmap bmp, int x, int y)
        {
            int xx = x - bmp.Width / 2;
            int yy = y - bmp.Height / 2;

            g.DrawImage(bmp, xx, yy, bmp.Width, bmp.Height);

        }

        private void button1_Click(object sender, EventArgs e)
        {
            Bitmap bmp = new Bitmap(@"c:\Home\ImgWork\CenterAtSample3.png");

            int centerX = 450;
            int centerY = 450;

            double radius = 250d;

            int hh;
            int ss = 250;
            int ll = 50;
            byte rr, gg, bb;

            int xx, yy;

            Bitmap tmp1, tmp2;
            Color baseColor;         


            Graphics g = this.CreateGraphics();

            for (int i = 0; i < 10; i++)
            {
                hh = 36 * i;
                ImgUtils.HSLToRGB(hh, ss, ll, out rr, out gg, out bb);
                baseColor = Color.FromArgb(rr, gg, bb);

                LuminanceToAlpha(bmp, true, baseColor, out tmp1);

                tmp2 = ImgUtils.BitmapRotate(tmp1, (float)(hh+90), Color.Transparent);
                SetAlpha32(ref tmp2, 85);

                xx = (int)(Math.Cos((double)hh / 180d * Math.PI) * radius) + centerX;
                yy = (int)(Math.Sin((double)hh / 180d * Math.PI) * radius) + centerY;

                DrawImageCenterAt(g, tmp2, xx, yy);

                tmp2.Dispose();
                tmp1.Dispose();
            }

            g.Dispose();

            bmp.Dispose();
        }
    }
}



CenterAtSample3





Comment

Crop と SmoothEdge

2008-03-24 19:02:31 | C#(Graphics)

旧ブログからのコード移植、その3。

Crop は、Mask をつかって、指定色領域を指定の色許容度で透明にする。
SmoothEdge は、Crop された画像のエッジのアルファ値を傾斜をかけて滑らかにする。



全コードをしめす。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

using System.Drawing.Imaging;
using System.Drawing.Drawing2D;
using ImageUtils;

namespace CropSmoothEdge
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        public static bool Crop(ref Bitmap bmp, Bitmap mask, Color maskColor,
                                                      int tolerance)
        {
            if (bmp.PixelFormat != PixelFormat.Format24bppRgb)
                return false;

            if (mask.PixelFormat != PixelFormat.Format24bppRgb)
                return false;

            if ((tolerance < 0) | (tolerance > 100))
                return false;

            int w = bmp.Width;
            int h = bmp.Height;

            if ((w != mask.Width) | (h != mask.Height)) return false;

            byte redSmall = ImgUtils.AdjustByte(maskColor.R - tolerance);
            byte redLarge = ImgUtils.AdjustByte(maskColor.R + tolerance);
            byte greenSmall = ImgUtils.AdjustByte(maskColor.G - tolerance);
            byte greenLarge = ImgUtils.AdjustByte(maskColor.G + tolerance);
            byte blueSmall = ImgUtils.AdjustByte(maskColor.B - tolerance);
            byte blueLarge = ImgUtils.AdjustByte(maskColor.B + tolerance);

            Bitmap tmp = new Bitmap(w, h, PixelFormat.Format32bppArgb);

            Graphics g = Graphics.FromImage(tmp);
            g.DrawImageUnscaled(bmp, 0, 0);
            g.Dispose();

            BmpProc24 src = new BmpProc24(mask);
            BmpProc32 dst = new BmpProc32(tmp);

            for (int y = 0; y < h; y++)
                for (int x = 0; x < w; x++)
                {
                    src.SetXY(x, y);
                    if ((src.R < redSmall) | (src.R > redLarge) |
                        (src.G < greenSmall) | (src.G > greenLarge) |
                        (src.B < blueSmall) | (src.B > blueLarge)) continue;

                    dst[x, y, eRGB.a] = 0;
                }

            ImgUtils.CallDispose(dst, src, bmp);

            bmp = tmp;

            return true;
        }

        public static bool SmoothEdge(ref Bitmap bmp, int zone)
        {
            if (bmp.PixelFormat != PixelFormat.Format32bppArgb)
                return false;

            int w = bmp.Width;
            int h = bmp.Height;

            Bitmap tmp = bmp.Clone() as Bitmap;

            ImgUtils.Blur32(ref bmp, zone);

            BmpProc32 src = new BmpProc32(tmp);
            BmpProc32 dst = new BmpProc32(bmp);

            for (int y = 0; y < h; y++)
                for (int x = 0; x < w; x++)
                {
                    src.SetXY(x, y);
                    dst.SetXY(x, y);

                    if (dst.A == 0) continue;

                    if (src.A == dst.A)
                    {
                        dst.R = src.R;
                        dst.G = src.G;
                        dst.B = src.B;
                    }
                }

            ImgUtils.CallDispose(dst, src, tmp);

            return true;
        }

        private void button1_Click(object sender, EventArgs e)
        {
            Bitmap bmp = new Bitmap(@"c:\Home\ImgWork\CropSample.png");

            Bitmap mask = new Bitmap(@"c:\Home\ImgWork\CropMask.png");

            Bitmap haikei = new Bitmap(@"c:\Home\ImgWork\CropBack.png");

            Color maskColor = mask.GetPixel(50, 50);

            Crop(ref bmp, mask, maskColor, 40);            

            Graphics g = Graphics.FromImage(haikei);
            g.DrawImage(bmp, -160, 0, bmp.Width, bmp.Height);
            SmoothEdge(ref bmp, 2);
            g.DrawImage(bmp, 230, 0, bmp.Width, bmp.Height);
            g.Dispose();

            g = this.CreateGraphics();
            g.DrawImageUnscaled(haikei, 5, 35);
            Clipboard.SetImage(haikei);
            g.Dispose();

            haikei.Dispose();
            mask.Dispose();
            bmp.Dispose();
        }
    }
}


CropSample



CropMask



CropBack



Comments (4)

SetAlpha32

2008-03-23 00:06:11 | C#(Graphics)

旧ブログからのコード移植、その2。

SetAlpha32 は PixelFormat.Format32bppArgb の元画像のアルファ値を
均一に設定した値に減少させる。




using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

using System.Drawing.Imaging;
using System.Drawing.Drawing2D;
using ImageUtils;

namespace LuminanceToAlpha
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        public static bool LuminanceToAlpha(Bitmap bmp, bool bStretch,
            Color baseColor, out Bitmap result32)
        {
            result32 = null;

            if (bmp.PixelFormat != PixelFormat.Format24bppRgb)
                return false;

            int w = bmp.Width;
            int h = bmp.Height;

            Bitmap bw = bmp.Clone() as Bitmap;
            ImgUtils.GrayScale(ref bw);
            if (bStretch) ImgUtils.HistoStretch(ref bw);

            result32 = new Bitmap(w, h, PixelFormat.Format32bppArgb);

            Graphics g = Graphics.FromImage(result32);
            g.Clear(baseColor);
            g.Dispose();

            BmpProc8 src = new BmpProc8(bw);
            BmpProc32 dst = new BmpProc32(result32);

            for (int y = 0; y < h; y++)
                for (int x = 0; x < w; x++)
                {
                    dst[x, y, eRGB.a] = (byte)(255 - src[x, y]);
                }
            ImgUtils.CallDispose(dst, src, bw);

            return true;
        }

        public static bool SetAlpha32(ref Bitmap bmp, int percent)
        {
            if (bmp.PixelFormat != PixelFormat.Format32bppArgb)
                return false;

            int w = bmp.Width;
            int h = bmp.Height;

            double p = percent / 100d;

            BmpProc32 dst = new BmpProc32(bmp);

            for (int y = 0; y < h; y++)
                for (int x = 0; x < w; x++)
                {
                    if (dst[x, y, eRGB.a] == 0) continue;
                    dst[x, y, eRGB.a] = ImgUtils.AdjustByte(dst[x, y, eRGB.a] * p);
                }
            dst.Dispose();

            return true;
        }

        private void button1_Click(object sender, EventArgs e)
        {
            Bitmap bmp = new Bitmap(@"c:\Home\ImgWork\SASample2.png");

            int w = bmp.Width;
            int h = bmp.Height;

            Bitmap tmp1, tmp2;
            Color baseColor = Color.FromArgb(10, 00, 70);

            LuminanceToAlpha(bmp, true, baseColor, out tmp1);


            Graphics g = this.CreateGraphics();

            for (int i = 0; i < 5; i++)
            {
                tmp2 = tmp1.Clone() as Bitmap;
                SetAlpha32(ref tmp2, 15 + 20 * i);
                g.DrawImage(tmp2, 20 + 150 * i, 50 + 30 * i, w, h);
                tmp2.Dispose();
            }

            g.Dispose();

            tmp1.Dispose();
            bmp.Dispose();
        }
    }
}
Comment

LuminanceToAlpha

2008-03-21 23:11:44 | C#(Graphics)

旧ブログからのコード移植、その1。

LuminanceToAlpha は元画像の輝度の反転(255から引いたもの)した値に
比例して任意の色シートのアルファ値を設定する。

色つきのカーボンコピーをつくる感じ。





全コードをしめす。


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

using System.Drawing.Imaging;
using System.Drawing.Drawing2D;
using ImageUtils;

namespace LuminanceToAlpha
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        public static bool LuminanceToAlpha(Bitmap bmp, bool bStretch,
            Color baseColor, out Bitmap result32)
        {
            result32 = null;

            if (bmp.PixelFormat != PixelFormat.Format24bppRgb)
                return false;

            int w = bmp.Width;
            int h = bmp.Height;

            Bitmap bw = bmp.Clone() as Bitmap;
            ImgUtils.GrayScale(ref bw);
            if (bStretch) ImgUtils.HistoStretch(ref bw);

            result32 = new Bitmap(w, h, PixelFormat.Format32bppArgb);

            Graphics g = Graphics.FromImage(result32);
            g.Clear(baseColor);
            g.Dispose();

            BmpProc8 src = new BmpProc8(bw);
            BmpProc32 dst = new BmpProc32(result32);

            for (int y = 0; y < h; y++)
                for (int x = 0; x < w; x++)
                {
                    dst[x, y, eRGB.a] = (byte)(255 - src[x, y]);
                }
            ImgUtils.CallDispose(dst, src, bw);

            return true;
        }

        private void button1_Click(object sender, EventArgs e)
        {
            Bitmap bmp = new Bitmap(@"c:\Home\ImgWork\LASample.png");

            int w = bmp.Width;
            int h = bmp.Height;

            Bitmap tmp;
            Color baseColor;

            Graphics g = this.CreateGraphics();

                baseColor = Color.FromArgb(100, 0, 0);

                LuminanceToAlpha(bmp, true, baseColor, out tmp);            
                g.DrawImage(tmp, 20, 50, w, h);
                tmp.Dispose();


                baseColor = Color.FromArgb(0, 100, 0);

                LuminanceToAlpha(bmp, true, baseColor, out tmp);
                g.DrawImage(tmp, 20 + (w - 50), 50, w, h);
                tmp.Dispose();


                baseColor = Color.FromArgb(0, 0, 100);

                LuminanceToAlpha(bmp, true, baseColor, out tmp);
                g.DrawImage(tmp, 20 + (w - 50) * 2, 50, w, h);
                tmp.Dispose();

            g.Dispose();

            
            bmp.Dispose();
        }
    }
}

Comment

アルファ値とクリップボード 2

2008-02-09 15:14:08 | C#(Graphics)

前回では、カスタムフォーマットをつかってアルファ値を保ったままクリップボードを
介してやり取りすることができた。しかし、これでは従来のグラフィックアプリには
貼り付けられない。 アルファ値を犠牲にしても従来どおり貼り付けられ、かつ、
カスタムフォーマットを知っているアプリにはアルファ値を保ったまま、貼り付ける
ことができるようにしたい。

ここを参考にして、複数のフォーマットをつかってクリップボードにコピーしてみよう。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

using System.Drawing.Imaging;
using System.Drawing.Drawing2D;

namespace Clipboard32_2
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private Bitmap MakeTestBitmap32(Color color)
        {
            Bitmap bmp = new Bitmap(200, 200, PixelFormat.Format32bppArgb);

            SolidBrush br = new SolidBrush(color);

            String st = "ふわっと";
            Font ft = new Font("・ュ・ウ 譏取悃", 30, FontStyle.Bold);
            //ft.Style = FontStyle.Bold;


            Graphics g = Graphics.FromImage(bmp);
            g.SmoothingMode = SmoothingMode.AntiAlias;
            g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
            g.FillEllipse(br, 10, 10, 180, 180);
            g.DrawString(st, ft, Brushes.White, 12f, 75f);

            g.Dispose();

            ft.Dispose();
            br.Dispose();

            return bmp;
        }

        private void button1_Click(object sender, EventArgs e)
        {
            Bitmap bmp = MakeTestBitmap32(Color.Crimson);

            Graphics g = this.CreateGraphics();
            g.DrawImage(bmp, 10, 10);
            g.Dispose();

            DataObject data = new DataObject();
            data.SetData(DataFormats.Bitmap, bmp);
            data.SetData("Bitmap32Format3", bmp);

            Clipboard.SetDataObject(data, true);

            bmp.Dispose();
        }

        private void button2_Click(object sender, EventArgs e)
        {
            if (Clipboard.ContainsImage())
            {
                Bitmap bmp = (Bitmap)Clipboard.GetImage();

                Graphics g = this.CreateGraphics();
                g.DrawImage(bmp, 10, 220);
                g.Dispose();

                bmp.Dispose();
            }

            if (Clipboard.ContainsData("Bitmap32Format3"))
            {
                Bitmap bmp = Clipboard.GetData("Bitmap32Format3") as Bitmap;

                Graphics g = this.CreateGraphics();
                g.DrawImage(bmp, 220, 220);
                g.Dispose();

                bmp.Dispose();
            }
        }
    }
}


このように、DataObject のインスタンスに複数のフォーマットを設定してセットしてから
クリップボードに SetDataObject() する。

結果は、



となり、ふつうに GetImage() では従来どおり、 カスタムフォーマットで GetData() ではアルファ値を
保ったままペーストできる。

PSPaint にも従来どおり貼り付けられる。




Comments (4)

アルファ値とクリップボード

2008-01-31 00:02:51 | C#(Graphics)

アルファチャネルを持つ画像をクリップボードを経由してやり取りしたい。

普通に SetImage() と GetImage() を使うとうまくいかない。 ちょっとやってみよう。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

using System.Drawing.Imaging;
using System.Drawing.Drawing2D;

namespace Clipboard32
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            Bitmap bmp = new Bitmap(200, 200, PixelFormat.Format32bppArgb);

            Graphics g = Graphics.FromImage(bmp);
            g.SmoothingMode = SmoothingMode.AntiAlias;
            g.FillEllipse(Brushes.Crimson, 10, 10, 180, 180);
            g.Dispose();

            g = this.CreateGraphics();
            g.DrawImage(bmp, 10, 10);
            g.Dispose();

            Clipboard.SetImage(bmp);

            bmp.Dispose();
        }

        private void button2_Click(object sender, EventArgs e)
        {
            if (Clipboard.ContainsImage())
            {
                Bitmap bmp = (Bitmap)Clipboard.GetImage();

                Graphics g = this.CreateGraphics();
                g.DrawImage(bmp, 10, 220);
                g.Dispose();

                bmp.Dispose();
            }
            else
                MessageBox.Show("There is no Image in the Clipboard!");
        }
    }
}


button1 を押してから、button2 を押すと



のようになり、GetImage() でクリップボードからえられるビットマップは、本来、透過している
部分が青になってしまいアルファ値が無視される。 MSPaint に貼り付けると



となり、同じくアルファ値が無視されている。 また、Windows のユーティリティー Clipbrd.exe を
つかって、クリップボードを内容を見てみると



となっており、クリップボードが勝手にレンダリングしてアルファ値を失っている。

WEB を検索してみると、この問題は FAQ であることが分かるが、回避策のコードを探し出せなかった。

そこで、ここを参考にして、内部に Bitmap を抱えたクラスをつくり、そのインスタンスをカスタムフォーマット
としてクリップボードを介してやり取りすることを試してみた。

        private void button3_Click(object sender, EventArgs e)
        {
            Bitmap bmp = new Bitmap(200, 200, PixelFormat.Format32bppArgb);

            Graphics g = Graphics.FromImage(bmp);
            g.SmoothingMode = SmoothingMode.AntiAlias;
            g.FillEllipse(Brushes.Crimson, 10, 10, 180, 180);
            g.Dispose();

            g = this.CreateGraphics();
            g.DrawImage(bmp, 10, 10);
            g.Dispose();

            Bitmap32 bmp32 = new Bitmap32(bmp);
            Clipboard.SetData("Bitmap32Format", bmp32);

            bmp.Dispose();
        }

        private void button4_Click(object sender, EventArgs e)
        {
            if (Clipboard.ContainsData("Bitmap32Format"))
            {
                Bitmap32 bmp32 = Clipboard.GetData("Bitmap32Format") as Bitmap32;
                Bitmap bmp = bmp32.Bmp32;

                Graphics g = this.CreateGraphics();
                g.DrawImage(bmp, 10, 220);
                g.Dispose();

                bmp.Dispose();
            }
        }
    }

    [Serializable]
    public class Bitmap32
    {
        private Bitmap bmp = null;

        public Bitmap32(Bitmap bmp32)
        {
            bmp = bmp32;
        }

        ~Bitmap32()
        {
            if (bmp != null) { bmp.Dispose(); }
        }

        public Bitmap Bmp32
        {
            get
            {
                return bmp.Clone() as Bitmap;
            }

            set
            {
                if (bmp != null) { bmp.Dispose(); }
                bmp = value.Clone() as Bitmap;
            }
        }
    }


この結果は



となり、うまくいく。 当然、カスタムフォーマットなので、他のアプリケーションには貼り付けられない。



このようにして、すくなくとも自作の C# アプリケーション間では、アルファ値を保ったままクリップボードを
介したやり取りができるようになった。

さらに進んで、Bitmap オブジェクトそのものをカスタムフォーマットとしてやり取りすることを試した。

        private void button5_Click(object sender, EventArgs e)
        {
            Bitmap bmp = new Bitmap(200, 200, PixelFormat.Format32bppArgb);

            Graphics g = Graphics.FromImage(bmp);
            g.SmoothingMode = SmoothingMode.AntiAlias;
            g.FillEllipse(Brushes.Crimson, 10, 10, 180, 180);
            g.Dispose();

            g = this.CreateGraphics();
            g.DrawImage(bmp, 10, 10);
            g.Dispose();

            Clipboard.SetData("Bitmap32Format2", bmp);

            bmp.Dispose();
        }

        private void button6_Click(object sender, EventArgs e)
        {
            if (Clipboard.ContainsData("Bitmap32Format2"))
            {
                Bitmap bmp = Clipboard.GetData("Bitmap32Format2") as Bitmap;

                Graphics g = this.CreateGraphics();
                g.DrawImage(bmp, 10, 220);
                g.Dispose();

                bmp.Dispose();
            }
        }


結果は、



となり、うまくいく。

この方法では、パレットをもったビットマップの場合でも、その情報を失わずにやり取りできるだろう。


Comment

Non-Linear InsideOut

2007-12-27 22:07:30 | C#(Graphics)

これまでの普通の InsideOut は、境界の半径Rより内側のピクセルについては

r = R - r'

という変形を行ってきた。 これは、外縁と中心を線形に反転させることと等価である。
上の式は

(r / R) = 1 - (r'/R)

と変形できる。 これを線形ではなく指数関数をつかって非線形変形に拡張してみる。

(r / R) = 1 - (r'/R)**n

ここで、n は累乗の指数である。実際に関数を実装するときに使用する逆変換では、

r' = R * Math.Pow( (1 - r/R), 1/n)

となる。実際にやってみよう。


元画像は既存のものを使用した。




n = 0.5




n = 1.0 (これは今までの InsideOut と同じ)




n = 1.5




n = 2.0




n = 3.0



このように、n が1より小さいときは、従来の InsideOut に比べて変換前の中心部分が重視される。
逆に1より大きい場合は、変換前の外縁部分が相対的に拡大される。


今回つくった関数部分を示す。


        public static bool NLInsideOut(ref Bitmap bmp, double cx, double cy,
                                        double radius, double index, Color bkColor)
        {
            if (bmp.PixelFormat != PixelFormat.Format24bppRgb)
                return false;

            int w = bmp.Width;
            int h = bmp.Height;

            int mg = 2; // margin for interpolations

            if ((cx == 0) & (cy == 0)) { cx = (double)w / 2; cy = (double)h / 2; }

            Bitmap tmp = new Bitmap(w + mg * 2, h + mg * 2, bmp.PixelFormat);

            Graphics g = Graphics.FromImage(tmp);
            g.Clear(bkColor);
            g.DrawImageUnscaled(bmp, mg, mg);
            g.Dispose();

            g = Graphics.FromImage(bmp);
            if (bkColor != Color.Transparent) g.Clear(bkColor);
            g.Dispose();

            RectangleF rct = new RectangleF(-1, -1, w + 1, h + 1);

            double r, a, xx, yy;
            double rindex = 1d / index;

            BmpProc24 src = new BmpProc24(tmp);
            BmpProc24 dst = new BmpProc24(bmp);

            for (int y = 0; y < h; y++)
                for (int x = 0; x < w; x++)
                {
                    r = Math.Sqrt((x - cx) * (x - cx) + (y - cy) * (y - cy));

                    if (r > radius) continue;

                    r = radius * Math.Pow((1d - r / radius), rindex);
                    a = Math.Atan2(y - cy, x - cx);                // radian

                    xx = r * Math.Cos(a) + cx;
                    yy = r * Math.Sin(a) + cy;

                    if (rct.Contains(new PointF((float)xx, (float)yy)))
                    {
                        xx = xx + mg;
                        yy = yy + mg;

                        ImgUtils.intBicubic(dst, src, x, y, xx, yy);
                    }
                }

            ImgUtils.CallDispose(dst, src, tmp);

            return true;
        }


Comment

色をかぞえる

2007-09-26 19:46:57 | C#(Graphics)
24ビットカラーの画像の中の色の数をかぞえるために、これまでに
ArrayList を使った関数をライブラリでつくってきた。ところで、
最近、申し訳ないがどこか探せないのだが Delphi で TBits クラスを
つかった実装を見かけた。論理的には、ArrayList で全色を保持して
ソートすることにより、色数をかぞえるよりスマートで、画像のサイズ
が大きくなるほど、速いと思われる。

C# で Delphi の TBits に相当するクラスは BitArray クラスである。
これは項目ごとに Boolean 値を保持できる。これをつかって、色を
かぞえるのは簡単かつソートがいらないので高速であるはずである。

さっそく試してみた。今回試した色をかぞえる画像はこれである。


ラ・フランドル、二ノ宮2、つくば市

結果は、以下に示すように、これまでの関数より2倍くらい速い。
ライブラリも変更することにしよう。






using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

using System.Drawing.Imaging;
using System.Drawing.Drawing2D;
using ImageUtils;

using System.Collections;

namespace CountColors
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        public static int CountColors(Bitmap bmp)
        {
            if (bmp.PixelFormat != PixelFormat.Format24bppRgb)
                return -1;

            int w = bmp.Width;
            int h = bmp.Height;

            BitArray ba = new BitArray(0x1000000, false);

            int count = 0;
            int indx;
            int ir;

            BmpProc24 src = new BmpProc24(bmp);

            for (int y = 0; y < h; y++)
                for (int x = 0; x < w; x++)
                {
                    ir = src.IndexR(x, y);
                    indx = (int)((((src[ir] << 8) | src[ir - 1]) << 8) | src[ir - 2]);
                    if (!ba[indx])
                    {
                        ba[indx] = true;
                        count++;
                    }
                }

            src.Dispose();

            return count;
        }

        private void button1_Click(object sender, EventArgs e)
        {
            Bitmap bmp = new Bitmap(@"c:\Home\ImgWork\LaFlandre.png");

            StopWatch.Start();

            int cn = CountColors(bmp);

            StopWatch.Stop();            

            label1.Text = cn.ToString() + " colors";
            label2.Text = StopWatch.time.ToString() + " ms";


            StopWatch.Start();

            cn = ImgUtils.CountColors(bmp);

            StopWatch.Stop();

            label3.Text = cn.ToString() + " colors";
            label4.Text = StopWatch.time.ToString() + " ms";


            bmp.Dispose();

        }
    }
}

Comments (2)