none
CreateBitmapSourceFromHBitmap DPI RRS feed

  • Question

  •  

    Hi,

     

    I am trying to convert a System.Drawing.Bitmap instance into System.Windows.Media.Imaging.BitmapSource instance.

    I am using Imaging.CreateBitmapSourceFromHBitmap to acomplish that.

    The problem is that the source (Drawing.Bitmap) is 200 px width and height and  200 dpi width and height, and the resulted BitmapSource is 200 px width and height but 96 dpi width and height!

     

    How can I create the same size and dpi BitmapSource from a Drawing.Bitmap instance?

     

    Thank you,

    Ido.

    Tuesday, January 1, 2008 9:13 AM

Answers

  • This should do the trick:

     

     

    // Create a new bitmap.

    System.Drawing.Bitmap bmp = new System.Drawing.Bitmap("c:\\images\\foo.jpg");

    // Lock the bitmap's bits.

    System.Drawing.Rectangle rect = new System.Drawing.Rectangle(0, 0, bmp.Width, bmp.Height);

    System.Drawing.Imaging.BitmapData bmpData =

    bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite,

    System.Drawing.Imaging.PixelFormat.Format32bppRgb);

    // Declare an array to hold the bytes of the bitmap.

    int bufferSize = bmpData.Stride * bmp.Height;

    WriteableBitmap wb = new WriteableBitmap(bmp.Width, bmp.Height, bmp.HorizontalResolution, bmp.VerticalResolution, PixelFormats.Bgr32, null);

    wb.WritePixels(new Int32Rect(0, 0, bmp.Width, bmp.Height), bmpData.Scan0, bufferSize, bmpData.Stride);

    // Unlock the bits.

    bmp.UnlockBits(bmpData);

    ShowMe.Source = wb;

     

    Note that I chose a pixel format that worked for my image. You might need to write a little bit of code to handle arbitrary incoming images depending on the pixel formats you want to support.

    Hopefully this sample unblocks you. I am also forwarding this thread to our imaging team in case there is a bug with the transfer of the DPI data.

     

    Thursday, January 3, 2008 6:47 AM

All replies

  • I don't think you can preserve the DPI information if you are targeting a different display with different DPI settings, one thing you can do is to scale the bitmap accordingly if the source DPI and the target DPI are different, you can caculate the final pixel size using the following formula:
    targetPixel = sourcePixel / targetDPI * sourceDPI

    When you are done calculating the targetPixel values(targetPixelWidth, targetPixelHeight), you can pass them as BitmapSizeOptions parameters as follows:
    Imaging.CreateBitmapSourceFromHBitmap(
    hBitmap,
    IntPtr.Zero,
    Int32Rect.Empty,
    BitmapSizeOptions.FromWidthAndHeight(targetPixelWidth, targetPixelHeight));

    Hope this helps

    Thursday, January 3, 2008 3:03 AM
  • This should do the trick:

     

     

    // Create a new bitmap.

    System.Drawing.Bitmap bmp = new System.Drawing.Bitmap("c:\\images\\foo.jpg");

    // Lock the bitmap's bits.

    System.Drawing.Rectangle rect = new System.Drawing.Rectangle(0, 0, bmp.Width, bmp.Height);

    System.Drawing.Imaging.BitmapData bmpData =

    bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite,

    System.Drawing.Imaging.PixelFormat.Format32bppRgb);

    // Declare an array to hold the bytes of the bitmap.

    int bufferSize = bmpData.Stride * bmp.Height;

    WriteableBitmap wb = new WriteableBitmap(bmp.Width, bmp.Height, bmp.HorizontalResolution, bmp.VerticalResolution, PixelFormats.Bgr32, null);

    wb.WritePixels(new Int32Rect(0, 0, bmp.Width, bmp.Height), bmpData.Scan0, bufferSize, bmpData.Stride);

    // Unlock the bits.

    bmp.UnlockBits(bmpData);

    ShowMe.Source = wb;

     

    Note that I chose a pixel format that worked for my image. You might need to write a little bit of code to handle arbitrary incoming images depending on the pixel formats you want to support.

    Hopefully this sample unblocks you. I am also forwarding this thread to our imaging team in case there is a bug with the transfer of the DPI data.

     

    Thursday, January 3, 2008 6:47 AM
  • Hi,

     

    Marco - I'm sorry to say that you are wrong in what you are saing. What you are suggesting will only affect the size of the image, and not its resolution. If I will scale my image I will loss important information which I do not want to loss.

     

    Gerhard is write. You solution will work, only I did it little different as follows:

    System.Drawing.Imaging.BitmapData data = gdiBitmap.LockBits( new System.Drawing.Rectangle( 0, 0, gdiBitmap.Width, gdiBitmap.Height ), System.Drawing.Imaging.ImageLockMode.ReadOnly, gdiBitmap.PixelFormat );

    BitmapSource bs = BitmapSource.Create( gdiBitmap.Width, gdiBitmap.Height, Settings.Default.Dpi, Settings.Default.Dpi, PixelFormats.Bgr24, null,

    data.Scan0, data.Stride * gdiBitmap.Height, data.Stride );

    gdiBitmap.UnlockBits( data );

     

    I think it is the only was I can transfer the pixel information without scaling them and still preserve the dpi information.

     

    I think that WPF imaging classes lack interop abilities and the interop functionality should be extended.

     

    Ido.

    Thursday, January 3, 2008 3:03 PM
  •  Ido wrote:

    Marco - I'm sorry to say that you are wrong in what you are saing. What you are suggesting will only affect the size of the image, and not its resolution. If I will scale my image I will loss important information which I do not want to loss.


    Yes, I was totally wrong in this respect.
    Actually your original question is about how to preserve resolution when converting bitmap from GDI+ representation to WIC representation, not about how to properly display it.

    Friday, January 4, 2008 1:49 AM