locked
How to merge images in backgroundtask without Writeablebitmap.

    Question

  • Hi there,

    since writeablebitmap inherits UI-Stuff, it is failing in a backgroundtask. How could I merge to Images together (on top of antother) with BitmapImages?

    I have two or more byteArrays coming each from a pixelDataProvider (Decoder -> BitmapTransform -> PixelDataProvider -> DetachPixelData) . How could I merge those byteArrays into one BitmapImage?

    For example:

    StorageFile image1= await localFolder.GetFileAsync("filepath into here");
    StorageFile image2= await localFolder.GetFileAsync("filepath into here");
    byte[] sourcePixelsImage1;
    byte[] sourcePixelsImage2;
    
    using (IRandomAccessStream fileStream = await image1.OpenAsync(FileAccessMode.Read))
                {
    BitmapDecoder decoder = await BitmapDecoder.CreateAsync(fileStream);
                    int imgW = Convert.ToUInt16(decoder.OrientedPixelWidth);
                    int imgH = Convert.ToUInt16(decoder.OrientedPixelHeight);
                    double ratio = (double)imgW / imgH;
    
                    imgW = Convert.ToInt16(1920);
                    imgH = Convert.ToInt16((double)imgW / ratio);
    
                    BitmapTransform transformPrimary = new BitmapTransform()
                    {
                        ScaledWidth = Convert.ToUInt32(imgW),
                        ScaledHeight = Convert.ToUInt32(imgH),
                        InterpolationMode = BitmapInterpolationMode.Cubic
                    };
    
                    PixelDataProvider pixelData = await decoder.GetPixelDataAsync(
                        BitmapPixelFormat.Bgra8,
                        BitmapAlphaMode.Straight,
                        transformPrimary,
                        ExifOrientationMode.IgnoreExifOrientation,
                        ColorManagementMode.DoNotColorManage);
    
                    sourcePixelsImage1 = pixelData.DetachPixelData();
    }
    
    
    

    and fairly the same code for image2 with a different scale Setting resulting in sourcePixelsImage2.

    Finally somehow combining these two and write to file (below example writes only sourcePixelsImage1):

     StorageFile file = await localFolder.CreateFileAsync("finaleImage.jpg", CreationCollisionOption.ReplaceExisting);
    
    using (IRandomAccessStream stream = await file.OpenAsync(FileAccessMode.ReadWrite))
                    {
                        BitmapEncoder encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.JpegEncoderId, stream);
                        encoder.SetPixelData(BitmapPixelFormat.Bgra8,
                                             BitmapAlphaMode.Ignore,
                                             (uint)imgW, (uint)imgH,
                                             96, 96, sourcePixelsImage1);
                        await encoder.FlushAsync();
                    }

    Sunday, June 15, 2014 12:04 PM

Answers

  • WriteableBitmap wouldn't help for this. You already have the PixelBuffers from the BitmapDecoder and can manipulate them however you'd like. The only thing the WritableBitmap would add would be the ability to display the buffer, but that isn't relevant from the background.

    How to combine them will depend on what you want that combination to look like. Ultimately you'll loop over the two bitmaps and choose which bitmap you want each pixel to originate from, or which combination of the two pixels. Depending on the goal this may take the pixel's alpha into account or not.

    --Rob

    Monday, June 16, 2014 12:50 AM
    Owner
  • After thinking again of merging bytearrays and strictly searching for that term I found a Little snippet I just modified and giving my the results I wanted... so I'm on the right way now ;)

    Here's the snippet I modified a Little bit:
    private byte[] LoadPixelBytesAt(byte[] dest, byte[] src, int destX, int destY, int destW, int srcW, int srcH)
            {
                for (int i = 0; i < srcH; i++)
                {
                    for (int j = 0; j < srcW; j++)
                    {
                        if (src.Length < ((i * srcW + j + 1) * 4)) return dest;
                        for (int p = 0; p < 4; p++)
                            dest[((destY + i) * destW + destX + j) * 4 + p] = src[(i * srcW + j) * 4 + p];
                    }
                }
    
                return dest;
            }

    So basically that would answer my question. I'm not sure if I am allowed and/or supposed to mark it as an answer by myself.
    Monday, June 23, 2014 4:00 PM

All replies

  • WriteableBitmap wouldn't help for this. You already have the PixelBuffers from the BitmapDecoder and can manipulate them however you'd like. The only thing the WritableBitmap would add would be the ability to display the buffer, but that isn't relevant from the background.

    How to combine them will depend on what you want that combination to look like. Ultimately you'll loop over the two bitmaps and choose which bitmap you want each pixel to originate from, or which combination of the two pixels. Depending on the goal this may take the pixel's alpha into account or not.

    --Rob

    Monday, June 16, 2014 12:50 AM
    Owner
  • Hey Rob,

    thanks for the heads-up... but do you have some Kind of (basic) example how to achieve this?
    Right now I'm kinda lost and did a fallback solution in php with gd (merging Images online, download result). But I really want to keep it in C# on the Client machine if possible.

    I already searched for examples with the technique you mentioned... but all I can find is either undocumented or for wpf or other .NET Frameworks.


    • Edited by SW_Andy Monday, June 16, 2014 6:42 AM
    Monday, June 16, 2014 6:41 AM
  • What "this" are you trying to achieve? What do you want the merge to look like?

    The results from the BitmapDecoder are essentially just arrays of pixels. You can create a new array of the target bitmap size and then loop through its pixels and choose a colour based on the pixels in your original two arrays. How you choose that colour depends on how you want to merge them.

    --Rob

    Monday, June 16, 2014 6:17 PM
    Owner
  • Hi Rob,

    sorry for the late reply. I "just" want to merge one Image on top of another in a scaled Version. Like the good old "Picture in Picture" Mode of TVs.

    I suspected to go through the Byte Arrays but I frankly do not know how (how to know wheres the x,y width/height etc).

    Example how the result could look like. Image1 is the Background landscape, Image2 is a different Image, scaled down and merged on top (overlayed) of the backgroundimage:





    • Edited by SW_Andy Monday, June 23, 2014 3:01 PM
    Monday, June 23, 2014 2:59 PM
  • After thinking again of merging bytearrays and strictly searching for that term I found a Little snippet I just modified and giving my the results I wanted... so I'm on the right way now ;)

    Here's the snippet I modified a Little bit:
    private byte[] LoadPixelBytesAt(byte[] dest, byte[] src, int destX, int destY, int destW, int srcW, int srcH)
            {
                for (int i = 0; i < srcH; i++)
                {
                    for (int j = 0; j < srcW; j++)
                    {
                        if (src.Length < ((i * srcW + j + 1) * 4)) return dest;
                        for (int p = 0; p < 4; p++)
                            dest[((destY + i) * destW + destX + j) * 4 + p] = src[(i * srcW + j) * 4 + p];
                    }
                }
    
                return dest;
            }

    So basically that would answer my question. I'm not sure if I am allowed and/or supposed to mark it as an answer by myself.
    Monday, June 23, 2014 4:00 PM