Write (image) to byte array

Help
GeorgeR
2011-01-02
2012-12-21
  •  GeorgeR
    GeorgeR
    2011-01-02

    If it's not too much trouble, i'd love to see an example of writing an openCL program to a byte array (which System.Drawing.Bitmap and so on can convert to a bitmap). The program would simply write a flat color (orange?) to the image so you know you're not getting a false positive!

     
  • nythrix
    nythrix
    2011-01-02

    I'm not sure I understood you correctly. You want to know how to generate an orange (or any color) Bitmap from a byte array using an OpenCL kernel?
    If yes here goes:

    using Cloo;
    using System;
    using System.Drawing;
    using System.Drawing.Imaging;
    namespace ClooTesting
    {
        public class BitmapExample
        {
            public static void Main()
            {
                int imgWidth = 320;
                int imgHeight = 240;
                int channels = 4; // you should beware of the pixel format of the final image. ARGB in our case so there are 4 bytes per pixel.
                int bufferSize = imgWidth * imgHeight * channels;
                ComputeContextPropertyList cpl = new ComputeContextPropertyList(ComputePlatform.Platforms[1]);
                ComputeContext context = new ComputeContext(ComputeDeviceTypes.Default, cpl, null, IntPtr.Zero);
                ComputeCommandQueue commands = new ComputeCommandQueue(context, context.Devices[0], ComputeCommandQueueFlags.None);
                ComputeBuffer<byte> clBuffer = new ComputeBuffer<byte>(context, ComputeMemoryFlags.WriteOnly, bufferSize);
                            
                string clKernel = @"
    kernel void BitmapKernel(global write_only uchar4* array)
    {
        int gid = get_global_id(0);
    // Even though the Bitmap format will be ARGB this array will be parsed as BGRA. So be careful with that. No, I don't know why it works like this. Ask Microsoft :)
        array[gid] = (uchar4)(0, 0, 255, 127); // This is full red/half transparent color.
    }";
                ComputeProgram program = new ComputeProgram(context, clKernel);
                program.Build(null, null, null, IntPtr.Zero);
                ComputeKernel kernel = program.CreateKernel("BitmapKernel");
                kernel.SetMemoryArgument(0, clBuffer);
                commands.Execute(kernel, null, new long[] { imgWidth*imgHeight }, null, null);
                byte[] array = null;
                commands.ReadFromBuffer(clBuffer, ref array, true, null);
                
                Bitmap bmp;
                unsafe
                {
                    fixed (byte* arrayPtr = array)
                        bmp = new Bitmap(imgWidth, imgHeight, channels * imgWidth, PixelFormat.Format32bppArgb, (IntPtr)arrayPtr);
                }
                bmp.Save("image.png");
                bmp.Dispose();
            }
        }
    }
    
     
  • nythrix
    nythrix
    2011-01-02

    However, there's a better way of getting the data directly into the Bitmap without using a temporary array.

    Bitmap bmp = new Bitmap(imgWidth, imgHeight, PixelFormat.Format32bppArgb); 
    BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, imgWidth, imgHeight), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); 
    commands.Read(clBuffer, true, 0, clBuffer.Size, bmpData.Scan0, null); bmp.UnlockBits(bmpData);