0

I'm trying to draw InkCanvas to an 8bpp image but when I try to do so the image convert itself to 32bpp, the lower I got was 24bpp but not 8bpp. Anyone can help me out? The image I am giving as input is an 8bpp BMP image created with paint.

        Image imgToEdit;
        InkCanvas inkCanvas;
        file = await Windows.ApplicationModel.Package.Current.InstalledLocation.GetFileAsync(Ambiente.imgBlankFirma);
        
        await file.CopyAsync(photoFolder, NomeFile, NameCollisionOption.ReplaceExisting);
        file = await photoFolder.GetFileAsync(NomeFile);

        imgToEdit = imgFirma;
        inkCanvas = inkCanvasFirma;
        
        if (inkCanvas.InkPresenter.StrokeContainer.GetStrokes().Count <= 0)
        {
            errore = true;
            return;
        }

        var randomAccessStream = await file.OpenReadAsync();
        

        CanvasDevice device = CanvasDevice.GetSharedDevice();
        
        CanvasRenderTarget renderTarget = new CanvasRenderTarget(device, (int)inkCanvas.ActualWidth, (int)inkCanvas.ActualHeight, 96); //inkCanvas.ActualWidth inkCanvas.ActualHeight
        
        using (var ds = renderTarget.CreateDrawingSession())
        {
            var image = await CanvasBitmap.LoadAsync(device, randomAccessStream);
            // draw your image first
            ds.DrawImage(image);
            // then draw contents of your ink canvas over it
            ds.DrawInk(inkCanvas.InkPresenter.StrokeContainer.GetStrokes());
        }

        randomAccessStream.Dispose();

        // save results
        using (var fileStream = await file.OpenAsync(FileAccessMode.ReadWrite))
        {
            await renderTarget.SaveAsync(fileStream, CanvasBitmapFileFormat.Tiff, 1f);
        }
  • 1
    I would assume the rendering is always done in 32bpp, so you might need to do the color conversion in a later step. See [32bpp to 8bpp](https://stackoverflow.com/questions/6355135/c-sharp-converting-32bpp-image-to-8bpp) and [render target to bitmapImage](https://stackoverflow.com/questions/52226884/converting-a-win2d-canvasrendertarget-to-a-bitmapimage) – JonasH Oct 28 '21 at 09:31
  • Hi, I already tried this solution but the problem is that with gif I can create an 8bpp image but can't upload it to the server where the image is needed in BMP format with 8bpp. – SonicMast3r Oct 29 '21 at 08:18

1 Answers1

0

This shows how to do the conversion by hand. It requires direct pointer access to the image data. So just create a new 8bpp (i.e. Format8bppIndexed) bitmap with the correct size for the conversion target. So converting the data should look something like this:

public static unsafe void Bgr24ToMono8(byte* source, byte* target, int sourceStride, int targetStride, int width, int height)
{

        for(var y = 0; y < height; y++)
        {
            var sourceRow = source + y * sourceStride;
            var targetRow = y * targetStride;
            for (int x = 0; x < width; x++)
            {
                var sourceIndex = (sourceRow + x * 3);
                var value = (byte)(sourceIndex[0] * 0.11f + sourceIndex[1] * 0.59f + sourceIndex[2] * 0.3f);
                target[targetRow + x] = value;
            }
        }
}

if you have 32bpp data it should just be a issue of changing x * 3 to x * 4. Note that there is some confusion regarding Bgr vs Rbg, different contexts uses different terms for the same thing.

Note that this converts the bitmap to 8bpp grayscale. If you need 8bpp color indexed this will be much more work since you would ideally need to find a optimal color-map, find the closest colors in said map, and apply dithering to avoid banding. For this I would recommend some image processing library. I do not think there is any built in functions for this, and it is way to much work to demonstrate here.

JonasH
  • 28,608
  • 2
  • 10
  • 23
  • sorry for the late reply JonasH but I don't know how to use that Parallel, and I don't know what is sourceStride and how to get it. – SonicMast3r Nov 03 '21 at 15:02
  • @SonicMast3r you can use regular for-loop instead of a parallel one. The stride is the number of bytes in a row, this should be available in some property, in for example [BitmapData.Stride](https://learn.microsoft.com/en-us/dotnet/api/system.drawing.imaging.bitmapdata.stride?view=windowsdesktop-5.0), check the link. – JonasH Nov 03 '21 at 15:30
  • thanks a lot I will try this code maybe tomorrow. – SonicMast3r Nov 04 '21 at 20:22
  • Hi @JonasH I tried the code above but I can't use the library System.Drawing since I am on UWP. – SonicMast3r Nov 05 '21 at 09:14
  • @sonicMast3r For Wpf you can use [BitmapSource.CopyPixels](https://learn.microsoft.com/en-us/dotnet/api/system.windows.media.imaging.bitmapsource.copypixels?view=windowsdesktop-5.0) and/or writableBitmap to get access to the pixelData. – JonasH Nov 05 '21 at 09:18
  • Hi @JonasH sorry for the late reply again, are you able to provide a complete code? since I never used pointers and I don't know how to use them. I was able to get the Stride by using this code [link](https://learn.microsoft.com/en-us/windows/uwp/audio-video-camera/imaging#create-or-edit-a-softwarebitmap-programmatically). – SonicMast3r Nov 12 '21 at 08:15