alternetsoft / AlternetUI

MIT License
24 stars 2 forks source link

Problem with "bitmap.ToGrayScale()" #66

Closed neoxeo closed 9 months ago

neoxeo commented 9 months ago

@generalloki

Version : 5ba2cc387830dbd3c53d59b3f8982202f00b3f8c

My test code :

private void btnLoad_Click(object sender, System.EventArgs e)
{
    OpenFileDialog dialog = new OpenFileDialog
    {
        Filter = "Images | *.bmp; *.png; *.jpg; *.JPEG"
    };

    if (dialog.ShowModal(this) != ModalResult.Accepted || dialog.FileName == null)
        return;

    Stream bm = File.OpenRead(dialog.FileName);        
    var bitmap = new Bitmap(bm);
    bitmap = ResizeBitmap(bitmap);
    bitmap.ToGrayScale();
    var resGray = dialog.FileName.Replace(".", "_Gray.");
    bitmap.Save(resGray);
}

Error 👍 image

generalloki commented 9 months ago

@neoxeo , What is in your ResizeBitmap() method? Could you please post the code?

neoxeo commented 9 months ago

@generalloki

Here is the code but it doesn't work :

private const int MAX_WIDTH = 400;
private const double WIDTH_OFFSET = 1.5;

private Bitmap ResizeBitmap(Bitmap bitmap)
{
    var newHeight = bitmap.Size.Height / WIDTH_OFFSET * MAX_WIDTH / bitmap.Size.Width;
    if (bitmap.Size.Width > MAX_WIDTH || bitmap.Size.Height > newHeight)
    {               
        bitmap = new Bitmap(new Size(MAX_WIDTH,newHeight));
        bitmap = new Bitmap(bitmap);
    }
    return bitmap;
}

The problem come from of "ToGrayScale()", not from this method. If you comment this line bitmap = ResizeBitmap(bitmap);" error is always present when execute "bitmap.ToGrayScale();"

It would be usefull to have this : bitmap = new Bitmap(bitmap, width, height); and bitmap.GetPixel(x, y); bitmap.SetPixel (x, y, color);

generalloki commented 9 months ago

What is bitmap type you are opening? It worked on png images when I last time checked this ToGrayScale function

neoxeo commented 9 months ago

I have new tests with AlternetUI\Source\Samples\ControlsSample\Resources\logo-128x128.png and it works.

But if you save logo-128x128.png to bmp or jpg image, error is present.

generalloki commented 9 months ago

@neoxeo , Thanks! I digged Image and now understand what is going bad. I will post a fix on these days and let you know here. Also there will be more methods and properties to handle images, with new constructors, per pixel access, etc.

neoxeo commented 9 months ago

Thanks !

Need to be confirmed, but I can't now. When I have tried to convert PNG to gray, result is not gray but same thing as source. I will try to test this again tomorrow.

generalloki commented 9 months ago

@neoxeo , ToGrayScale will be rewritten. There will be also GenericImage class for the image manipulations. An import from https://docs.wxwidgets.org/3.2/classwx_image.html It has many different methods to work with images.

neoxeo commented 9 months ago

@generalloki

Ok. Indeed, I confirm after new tests that "tograyscale" doesn't work : no change between source and target after used ToGrayScale function.

Yes, there is a lot of interesting different methods to work with images ! :-)

generalloki commented 9 months ago

@neoxeo,

This is still not in master, but I beleive will be there tomorrow, after I do some tests. I will post an update here.

Whatsnew:

New class GenericImage with almost all features of wxImage https://docs.wxwidgets.org/3.2/classwx_image.html This class has different methods for pixels manipulation, etc.

Bitmap new features: DefaultDisabledBrightness, AsGeneric (comverts to GenericImage), HasAlpha, PixelWidth, PixelHeight, DefaultBitmapType, Depth, Load(string, BitmapType), Save(string, BitmapType), Save(Stream, BitmapType), Load(Stream, BitmapType), GetSubBitmap(Int32Rect), ConvertToDisabled(brightness), Rescale(Int32Size), ResetAlpha()

GreyScale now works fine (tested). As you see there are new save/load methods which are capable to work with different formats.

neoxeo commented 9 months ago

@generalloki

You never sleep ? When I see what you can produce in one day, I'm very impressed.

Thanks again for all of your job and the speed of corrections when I create an issue.

generalloki commented 9 months ago

@neoxeo , :smile:

I uploaded to master changes related to GenericImage and Bitmap. Tomorrow will test it.

neoxeo commented 9 months ago

@generalloki

Juste make very quick tests with b2737ad version :

I will continue tests with Windows and Linux this weekend.

neoxeo commented 9 months ago

@generalloki

Is there equivalent of : bitmap.GetPixel(x, y); bitmap.SetPixel (x, y, color);

In genericimage or in bitmap ?

Thanks

generalloki commented 9 months ago

Currently in GenericBitmap: SetRGB(int x, int y, RGBValue rgb) SetRGBRect(RGBValue rgb, Int32Rect? rect = null) GetAlpha(int x, int y), GetGreen, GetBlue, GetRed

Color is auto converted to/from RGBValue which is used in GenericImage And also there is GetData/SetData to get/set full data with pixels but I haven't checked whether it works fine.

And I am going to add GetRGB, GetPixel, SetPixel

generalloki commented 9 months ago

Added GetRGB, GetPixel, SetPixel and ForEachPixel(ActionRef<RGBValue, T> action, T param) fast way to change all pixels

Also there is an example of raw pixel data manipulation in PaintSample. Updated master with these changes. I beleive it's ok now with image/pixel situation...

neoxeo commented 9 months ago

@generalloki

You are the best !

generalloki commented 9 months ago

For now I am closing this issue as it's seems to be solved.

neoxeo commented 9 months ago

@generalloki

Problem with "bitmap.ToGrayScale() seems not to be fixed. I use this code to make tests (with png and jpg file) :

OpenFileDialog dialog = new OpenFileDialog
{
    Filter = "Images | *.bmp; *.png; *.jpg; *.JPEG"
};

if (dialog.ShowModal(this) != ModalResult.Accepted || dialog.FileName == null)
    return;

string ext = Path.GetExtension(dialog.FileName);
var bm = new Bitmap();
bm.Load(dialog.FileName,BitmapType.Any);
bm.ToGrayScale();
bm.Save(dialog.FileName.Replace(ext, "_Gray" + ext));
generalloki commented 9 months ago

Creates grayscaled version of the image. Returns new grayscaled image from this image. public Image ToGrayScale()

You need to write like this:

var grayBitmap = bm.ToGrayScale(); grayBitmap.Save(dialog.FileName.Replace(ext, "_Gray" + ext));

neoxeo commented 9 months ago

@generalloki

Thanks, sorry for my error.

But I have a doubt : ToGrayScale convert color image to gray image ? Like this : Mario Mario_Gray_3

If yes, I havn't this result with "bitmap.ToGrayScale" but this : Mario_Gray

This code give the good result (for me) :

private GenericImage ToGrayScale_ANUI(Bitmap bmap)
   {
       Color c;
       var gi = (GenericImage)bmap;

       for (int i = 0; i < bmap.PixelWidth; i++)
       {
           for (int j = 0; j < bmap.PixelHeight; j++)
           {
               c = gi.GetPixel(i, j);
               byte gray = (byte)(.299 * c.R + .587 * c.G + .114 * c.B);
               gi.SetPixel(i, j, Color.FromArgb(gray, gray, gray));
           }
       }
       return gi;
   }
generalloki commented 9 months ago

I will check this. I see you use GetPixel/SetPixel. In general it is faster to use GetRGB/SetRGB and much more faster to use native buffer access with GetData/SetData. An example of such pixel access is in PaintSample. Anyway I will study and post an update here.

generalloki commented 9 months ago

@neoxeo, The approach you have proposed looks better image So I changed ToGrayScale to use it. Thanks!