Skip to content

LoadPNG c-style #7

@Rinat84

Description

@Rinat84
//
//  LoadPNG.c
//
//  www.catch22.net
//
//  Copyright (C) 2012 James Brown
//  Please refer to the file LICENCE.TXT for copying permission
//

#include "WinSpy.h"
#include <wincodec.h>

// #import "wincodec.idl" no_namespace

// Creates a stream object initialized with the data from an executable resource.
IStream *CreateStreamOnResource(WCHAR *lpName, WCHAR *lpType) {

  // find the resource
  HRSRC hRes;
  DWORD dwResourceSize;
  HGLOBAL hglbImage;
  PVOID pvSourceResourceData;
  HGLOBAL hgblResourceData;
  PVOID pvResourceData;
  IStream *ipStream;

  hRes = FindResource(NULL, lpName, lpType);

  // load the resource
  hglbImage = LoadResource(NULL, hRes);

  // allocate memory to hold the resource data
  dwResourceSize = SizeofResource(NULL, hRes);
  hgblResourceData = GlobalAlloc(GMEM_MOVEABLE, dwResourceSize);

  // get a pointer to the allocated memory
  pvResourceData = GlobalLock(hgblResourceData);

  // copy the data from the resource to the new memory block
  pvSourceResourceData = LockResource(hglbImage);
  memcpy(pvResourceData, pvSourceResourceData, dwResourceSize);

  GlobalUnlock(hgblResourceData);

  // create a stream on the HGLOBAL containing the data
  // Specify that the HGLOBAL will be automatically free'd on the last Release()

  CreateStreamOnHGlobal(hgblResourceData, TRUE, &ipStream);

  // couldn't create stream; free the memory
  //GlobalFree(hgblResourceData);

  // no need to unlock or free the resource
  return ipStream;
}

// Now that we have an IStream pointer to the data of the image,
// we can use WIC to load that image. An important step in this
// process is to use WICConvertBitmapSource to ensure that the image
// is in a 32bpp format suitable for direct conversion into a DIB.
// This method assumes that the input image is in the PNG format;
// for a splash screen, this is an excellent choice because it allows
// an alpha channel as well as lossless compression of the source image.
// (To make the splash screen image as small as possible,
// I highly recommend the PNGOUT compression utility.)

// Loads a PNG image from the specified stream (using Windows Imaging Component).
IWICBitmapSource *LoadBitmapFromStream(IStream *ipImageStream) {
  // initialize return value
  IWICBitmapSource *ipBitmap;
  // load WIC's PNG decoder
  IWICBitmapDecoder *ipDecoder;
  UINT nFrameCount;
  IWICBitmapFrameDecode *ipFrame;

  if (FAILED(CoCreateInstance(&CLSID_WICPngDecoder, NULL, CLSCTX_INPROC_SERVER,
    &IID_IWICBitmapDecoder, (VOID **) &ipDecoder)))
    goto Return;

  // load the PNG
  if (FAILED(ipDecoder->lpVtbl->Initialize(ipDecoder, ipImageStream, WICDecodeMetadataCacheOnLoad)))
    goto ReleaseDecoder;

  // check for the presence of the first frame in the bitmap

  if (FAILED(ipDecoder->lpVtbl->GetFrameCount(ipDecoder, &nFrameCount)) || nFrameCount != 1)
    goto ReleaseDecoder;

  // load the first frame (i.e., the image)

  if (FAILED(ipDecoder->lpVtbl->GetFrame(ipDecoder, 0, &ipFrame)))
    goto ReleaseDecoder;

  // convert the image to 32bpp BGRA format with pre-multiplied alpha
  //   (it may not be stored in that format natively in the PNG resource,
  //   but we need this format to create the DIB to use on-screen)
  WICConvertBitmapSource(&GUID_WICPixelFormat32bppPBGRA, (IWICBitmapSource *) ipFrame, &ipBitmap);
  ipFrame->lpVtbl->Release(ipFrame);

ReleaseDecoder:
  ipDecoder->lpVtbl->Release(ipDecoder);

Return:
  return ipBitmap;
}

// Creates a 32-bit DIB from the specified WIC bitmap.
HBITMAP CreateHBITMAP(IWICBitmapSource *ipBitmap, PVOID *bits) {
  // initialize return value
  HBITMAP hbmp;
  BITMAPINFO bminfo;

  // get image attributes and check for valid image
  UINT width, height;
  UINT cbStride, cbImage;

  VOID *pvImageBits;
  HDC hdcScreen;

  if (FAILED(ipBitmap->lpVtbl->GetSize(ipBitmap, &width, &height)) || width == 0 || height == 0)
    goto Return;

  // prepare structure giving bitmap information (negative height indicates a top-down DIB)

  memset(&bminfo, 0, sizeof(bminfo));

  bminfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  bminfo.bmiHeader.biWidth = width;
  bminfo.bmiHeader.biHeight = -((LONG) height);
  bminfo.bmiHeader.biPlanes = 1;
  bminfo.bmiHeader.biBitCount = 32;
  bminfo.bmiHeader.biCompression = BI_RGB;

  // create a DIB section that can hold the image

  hdcScreen = GetDC(NULL);
  hbmp = CreateDIBSection(hdcScreen, &bminfo, DIB_RGB_COLORS, &pvImageBits, NULL, 0);
  ReleaseDC(NULL, hdcScreen);

  if (bits)
    *bits = pvImageBits;

  if (hbmp == NULL)
    goto Return;

  // extract the image into the HBITMAP
  cbStride = width * 4;
  cbImage = cbStride * height;
  if (FAILED(ipBitmap->lpVtbl->CopyPixels(ipBitmap, NULL, cbStride, cbImage, (BYTE *) pvImageBits))) {
    // couldn't extract image; delete HBITMAP
    DeleteObject(hbmp);

    hbmp = NULL;
  }

Return:
  return hbmp;
}

// Loads the PNG bitmap into a 32bit HBITMAP.
HBITMAP LoadPNGImage(UINT id, OUT VOID **bits) {
  HBITMAP hbmpSplash;

  // load the PNG image data into a stream
  IStream *ipImageStream;
  IWICBitmapSource *ipBitmap;

  ipImageStream = CreateStreamOnResource(MAKEINTRESOURCE(id), L"PNG");
  if (ipImageStream == NULL)
    goto Return;

  // load the bitmap with WIC

  ipBitmap = LoadBitmapFromStream(ipImageStream);
  if (ipBitmap == NULL)
    goto ReleaseStream;

  // create a HBITMAP containing the image
  hbmpSplash = CreateHBITMAP(ipBitmap, bits);

  ipBitmap->lpVtbl->Release(ipBitmap);

ReleaseStream:

  ipImageStream->lpVtbl->Release(ipImageStream);

Return:
  return hbmpSplash;
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions