0

I have written a function which changes the alpha coefficient of an image. I use setpixel and getpixel,which is very slow. I found out that Lockbits method is faster.How can I do it with Lockbits? Here is my current code:

 using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WindowsFormsApplication2
{
    public partial class Form1 : Form
    {
        private static Image Tran(Image s,int alpha)
        {
            int x = 0, y = 0;
            Bitmap tImage = new Bitmap(s);
            for (x = 0; x < tImage.Width; x++)
            {
                for (y = 0; y < tImage.Height; y++)
                {

                    tImage.SetPixel(x, y, Color.FromArgb(alpha, tImage.GetPixel(x, y).R, tImage.GetPixel(x, y).G, tImage.GetPixel(x, y).B));
                }
            }
            return tImage;

        }
        public Form1()
        {
            InitializeComponent();
            trackBar1.TickStyle = TickStyle.Both;
            trackBar1.Orientation = Orientation.Vertical;
            trackBar1.Minimum = 0;
            trackBar1.Maximum = 255;
            trackBar1.Height = 101;
            trackBar1.Value = 255;
            pictureBox1.Image = Image.FromFile("C:\\Users\\rati\\Desktop\\water.jpg");
            pictureBox1.SizeMode = PictureBoxSizeMode.StretchImage;
        }
        private void trackBar1_Scroll(object sender, EventArgs e)
        {
            pictureBox1.Image = ChangeAlpha(pictureBox1.Image, trackBar1.Value);

            textBox1.Text = trackBar1.Value.ToString();

        }


    }
}
Rati Sharabidze
  • 69
  • 1
  • 12
  • The first routine in [this post](http://stackoverflow.com/questions/26386527/c-sharp-image-filter-parallel-for-takes-longer-time/26388451?s=3|0.1023#26388451) may be of interest as a Lockbits example.. – TaW Nov 18 '15 at 16:27
  • The main problem in your code is when you change the opacity, you set the result as image of your picturebox again and apply opacity again on the rsult. In other word you apply opacity on an image that you applied opacity to it before. – Reza Aghaei Nov 18 '15 at 16:42
  • Reza,do you have any other suggestions? – Rati Sharabidze Nov 18 '15 at 16:46
  • See the the edit part of my answer to find your problem in using the method :) – Reza Aghaei Nov 18 '15 at 16:50

2 Answers2

2

You can change the opacity of your image by drawing it in a new bitmap using a new ColorMatrix and assigning a float value between 0 and 1 to its Matrix33 as its new alpha value:

public Image ChangeAlpha(Image img, int value)
{
    if (value < 0 || value > 255)
        throw new Exception("value must be between 0 and 255");

    Bitmap bmp = new Bitmap(img.Width, img.Height); // Determining Width and Height of Source Image
    Graphics graphics = Graphics.FromImage(bmp);
    ColorMatrix colormatrix = new ColorMatrix();
    colormatrix.Matrix33 = value / 255f;
    ImageAttributes imgAttribute = new ImageAttributes();
    imgAttribute.SetColorMatrix(colormatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);
    graphics.DrawImage(img, new Rectangle(0, 0, bmp.Width, bmp.Height), 0, 0, img.Width, img.Height, GraphicsUnit.Pixel, imgAttribute);
    graphics.Dispose();   // Releasing all resource used by graphics 
    return bmp;
}

And here is a sample usage:

private void button1_Click(object sender, EventArgs e)
{
    int opacityvalue = 127;
    var img = ChangeAlpha(Image.FromFile(@"d:\1.png"), opacityvalue);
    img.Save(@"d:\2.png");
}

Don't forget to add using System.Drawing; and using System.Drawing.Imaging;.

You can see before and after calling the function with value=127 below:

enter image description hereenter image description here

EDIT

If you want to see the result in a PictureBox you should pay attention to using 2 different picture boxes, one for original image, and one for changed image:

private void trackBar1_Scroll(object sender, EventArgs e)
{
    this.pictureBox2.Image = ChangeAlpha(this.pictureBox1.Image, this.trackBar1.Value);
}

As I see in your code when you change the opacity, you set the result as image of your PictureBox1 again and apply opacity again on the result. In other word you apply opacity on an image that you applied opacity to it before over and over again.

Reza Aghaei
  • 120,393
  • 18
  • 203
  • 398
  • It is working but not properly,I have a track bar which has minvalue 0 and maxvalue 255, when Idecrease it,it does not change in this distance,on 200 it is invisible already, when I increase it it is getting invisible anyway – Rati Sharabidze Nov 18 '15 at 16:31
  • The images that I attached are result of using this method. when your value decrease, your image will be more transparent, when the value increase your image will be less transparent. – Reza Aghaei Nov 18 '15 at 16:38
  • when I ncrease the value,it is getting more transparent,which is very strange – Rati Sharabidze Nov 18 '15 at 16:45
  • actually it worked :) your changealpha now works perfectly,taking another picturebox solved this, my old function is slow anyway,I googled and setpixel and getpixel methods are very slow. thanx for your help – Rati Sharabidze Nov 18 '15 at 17:10
1
public Form1()
{
    ...
    originalImage = new Bitmap("C:\\Users\\rati\\Desktop\\water.jpg");
    pictureBox1.Image = originalImage;
    ...
}

// Add an extra field to the Form class.
Bitmap originalImage;

void trackBar1_Scroll(object sender, EventArgs e)
{
    pictureBox1.Image = ChangeAlpha((byte)trackBar1.Value);
    textBox1.Text = trackBar1.Value.ToString();
}

Image ChangeAlpha(byte alpha)
{
    Bitmap bmp = new Bitmap(originalImage);

    Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
    BitmapData bmpData = bmp.LockBits(rect, ImageLockMode.ReadWrite, bmp.PixelFormat);

    IntPtr ptr = bmpData.Scan0;

    int bytes = Math.Abs(bmpData.Stride) * bmp.Height;
    byte[] rgbValues = new byte[bytes];

    Marshal.Copy(ptr, rgbValues, 0, bytes);

    // Set every fourth value to alpha. A 32bpp bitmap will change transparency.
    for (int counter = 3; counter < rgbValues.Length; counter += 4)
        rgbValues[counter] = alpha;

    // Also you can try parallelize loop.
    //int length = rgbValues.Length / 4;
    //Parallel.For(3, length, counter => rgbValues[counter * 4 - 1] = alpha);

    Marshal.Copy(rgbValues, 0, ptr, bytes);
    bmp.UnlockBits(bmpData);

    return bmp;
}
Alexander Petrov
  • 13,457
  • 2
  • 20
  • 49