Ejemplo n.º 1
0
/*******************************************************************************************
 *  Fill out a true BITMAPINFOHEADER from a variable sized BITMAPINFOHEADER / BITMAPCOREHEADER.
 */
static BOOL bitmapinfoheader_from_user_bitmapinfo( BITMAPINFOHEADER *dst, const BITMAPINFOHEADER *info )
{
    if (!info) return FALSE;

    if (info->biSize == sizeof(BITMAPCOREHEADER))
    {
        const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER *)info;
        dst->biWidth         = core->bcWidth;
        dst->biHeight        = core->bcHeight;
        dst->biPlanes        = core->bcPlanes;
        dst->biBitCount      = core->bcBitCount;
        dst->biCompression   = BI_RGB;
        dst->biXPelsPerMeter = 0;
        dst->biYPelsPerMeter = 0;
        dst->biClrUsed       = 0;
        dst->biClrImportant  = 0;
    }
    else if (info->biSize >= sizeof(BITMAPINFOHEADER)) /* assume BITMAPINFOHEADER */
    {
        *dst = *info;
    }
    else
    {
        WARN( "(%u): unknown/wrong size for header\n", info->biSize );
        return FALSE;
    }

    dst->biSize = sizeof(*dst);
    if (dst->biCompression == BI_RGB || dst->biCompression == BI_BITFIELDS)
        dst->biSizeImage = get_dib_image_size( (BITMAPINFO *)dst );
    return TRUE;
}
Ejemplo n.º 2
0
static BOOL build_rle_bitmap( const BITMAPINFO *info, struct gdi_image_bits *bits, HRGN *clip )
{
    int i = 0;
    int left, right;
    int x, y, width = info->bmiHeader.biWidth, height = info->bmiHeader.biHeight;
    HRGN run = NULL;
    BYTE skip, num, data;
    BYTE *out_bits, *in_bits = bits->ptr;

    *clip = NULL;

    assert( info->bmiHeader.biBitCount == 4 || info->bmiHeader.biBitCount == 8 );

    out_bits = HeapAlloc( GetProcessHeap(), 0, get_dib_image_size( info ) );
    *clip = CreateRectRgn( 0, 0, 0, 0 );
    run   = CreateRectRgn( 0, 0, 0, 0 );
    if (!out_bits || !*clip || !run) goto fail;

    x = left = right = 0;
    y = height - 1;

    while (i < info->bmiHeader.biSizeImage - 1)
    {
        num = in_bits[i];
        data = in_bits[i + 1];
        i += 2;

        if (num)
        {
            if (x + num > width) num = width - x;
            if (num)
            {
                BYTE s = data, *out_ptr = get_pixel_ptr( info, out_bits, x, y );
                if (info->bmiHeader.biBitCount == 8)
                    memset( out_ptr, s, num );
                else
                {
                    if(x & 1)
                    {
                        s = ((s >> 4) & 0x0f) | ((s << 4) & 0xf0);
                        *out_ptr = (*out_ptr & 0xf0) | (s & 0x0f);
                        out_ptr++;
                        x++;
                        num--;
                    }
                    /* this will write one too many if num is odd, but that doesn't matter */
                    if (num) memset( out_ptr, s, (num + 1) / 2 );
                }
            }
            x += num;
            right = x;
        }
        else
        {
            if (data < 3)
Ejemplo n.º 3
0
DWORD stretch_bits( const BITMAPINFO *src_info, struct bitblt_coords *src,
                    BITMAPINFO *dst_info, struct bitblt_coords *dst,
                    struct gdi_image_bits *bits, int mode )
{
    void *ptr;
    DWORD err;

    dst_info->bmiHeader.biWidth = dst->visrect.right - dst->visrect.left;
    dst_info->bmiHeader.biHeight = dst->visrect.bottom - dst->visrect.top;
    dst_info->bmiHeader.biSizeImage = get_dib_image_size( dst_info );

    if (src_info->bmiHeader.biHeight < 0) dst_info->bmiHeader.biHeight = -dst_info->bmiHeader.biHeight;
    if (!(ptr = HeapAlloc( GetProcessHeap(), 0, dst_info->bmiHeader.biSizeImage )))
        return ERROR_OUTOFMEMORY;

    err = stretch_bitmapinfo( src_info, bits->ptr, src, dst_info, ptr, dst, mode );
    if (bits->free) bits->free( bits );
    bits->ptr = ptr;
    bits->is_copy = TRUE;
    bits->free = free_heap_bits;
    return err;
}
Ejemplo n.º 4
0
INT16 MFDRV_CreateBrushIndirect(PHYSDEV dev, HBRUSH hBrush )
{
    DWORD size;
    METARECORD *mr;
    LOGBRUSH logbrush;
    BOOL r;

    if (!GetObjectA( hBrush, sizeof(logbrush), &logbrush )) return -1;

    switch(logbrush.lbStyle)
    {
    case BS_SOLID:
    case BS_NULL:
    case BS_HATCHED:
        {
	    LOGBRUSH16 lb16;

	    lb16.lbStyle = logbrush.lbStyle;
	    lb16.lbColor = logbrush.lbColor;
	    lb16.lbHatch = logbrush.lbHatch;
	    size = sizeof(METARECORD) + sizeof(LOGBRUSH16) - 2;
	    mr = HeapAlloc( GetProcessHeap(), 0, size );
	    mr->rdSize = size / 2;
	    mr->rdFunction = META_CREATEBRUSHINDIRECT;
	    memcpy( mr->rdParm, &lb16, sizeof(LOGBRUSH16));
	    break;
	}
    case BS_PATTERN:
        {
            char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
            BITMAPINFO *dst_info, *src_info = (BITMAPINFO *)buffer;
            struct gdi_image_bits bits;
	    COLORREF cref;

            if (!get_bitmap_image( (HANDLE)logbrush.lbHatch, src_info, &bits )) goto done;
	    if (src_info->bmiHeader.biBitCount != 1)
            {
	        FIXME("Trying to store a colour pattern brush\n");
                if (bits.free) bits.free( &bits );
		goto done;
	    }

	    size = FIELD_OFFSET( METARECORD, rdParm[2] ) +
                FIELD_OFFSET( BITMAPINFO, bmiColors[2] ) + src_info->bmiHeader.biSizeImage;

            if (!(mr = HeapAlloc( GetProcessHeap(), 0, size )))
            {
                if (bits.free) bits.free( &bits );
                goto done;
            }
	    mr->rdFunction = META_DIBCREATEPATTERNBRUSH;
	    mr->rdSize = size / 2;
	    mr->rdParm[0] = BS_PATTERN;
	    mr->rdParm[1] = DIB_RGB_COLORS;
            dst_info = (BITMAPINFO *)(mr->rdParm + 2);
            dst_info->bmiHeader = src_info->bmiHeader;
            dst_info->bmiHeader.biClrUsed = 0;
	    cref = GetTextColor( dev->hdc );
            dst_info->bmiColors[0].rgbRed = GetRValue(cref);
            dst_info->bmiColors[0].rgbGreen = GetGValue(cref);
            dst_info->bmiColors[0].rgbBlue = GetBValue(cref);
            dst_info->bmiColors[0].rgbReserved = 0;
	    cref = GetBkColor( dev->hdc );
            dst_info->bmiColors[1].rgbRed = GetRValue(cref);
            dst_info->bmiColors[1].rgbGreen = GetGValue(cref);
            dst_info->bmiColors[1].rgbBlue = GetBValue(cref);
            dst_info->bmiColors[1].rgbReserved = 0;

            /* always return a bottom-up DIB */
            if (dst_info->bmiHeader.biHeight < 0)
            {
                int i, width_bytes = get_dib_stride( dst_info->bmiHeader.biWidth,
                                                     dst_info->bmiHeader.biBitCount );
                char *dst_ptr = (char *)&dst_info->bmiColors[2];
                dst_info->bmiHeader.biHeight = -dst_info->bmiHeader.biHeight;
                dst_ptr += (dst_info->bmiHeader.biHeight - 1) * width_bytes;
                for (i = 0; i < dst_info->bmiHeader.biHeight; i++, dst_ptr -= width_bytes)
                    memcpy( dst_ptr, (char *)bits.ptr + i * width_bytes, width_bytes );
            }
            else memcpy( &dst_info->bmiColors[2], bits.ptr, dst_info->bmiHeader.biSizeImage );
            if (bits.free) bits.free( &bits );
	    break;
	}

    case BS_DIBPATTERN:
        {
	      BITMAPINFO *info;
	      DWORD bmSize, biSize;

	      info = GlobalLock( (HGLOBAL)logbrush.lbHatch );
	      if (info->bmiHeader.biCompression)
		  bmSize = info->bmiHeader.biSizeImage;
	      else
		  bmSize = get_dib_image_size( info );
	      biSize = bitmap_info_size(info, LOWORD(logbrush.lbColor));
	      size = sizeof(METARECORD) + biSize + bmSize + 2;
	      mr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
              if (!mr)
              {
                  GlobalUnlock( (HGLOBAL)logbrush.lbHatch );
                  goto done;
              }
	      mr->rdFunction = META_DIBCREATEPATTERNBRUSH;
	      mr->rdSize = size / 2;
	      *(mr->rdParm) = logbrush.lbStyle;
	      *(mr->rdParm + 1) = LOWORD(logbrush.lbColor);
	      memcpy(mr->rdParm + 2, info, biSize + bmSize);
              GlobalUnlock( (HGLOBAL)logbrush.lbHatch );
	      break;
	}
	default:
	    FIXME("Unkonwn brush style %x\n", logbrush.lbStyle);
	    return 0;
    }
    r = MFDRV_WriteRecord( dev, mr, mr->rdSize * 2);
    HeapFree(GetProcessHeap(), 0, mr);
    if( !r )
        return -1;
done:
    return MFDRV_AddHandle( dev, hBrush );
}
Ejemplo n.º 5
0
/***********************************************************************
 *              create_surface
 */
struct window_surface *create_surface(macdrv_window window, const RECT *rect,
                                      struct window_surface *old_surface, BOOL use_alpha)
{
    struct macdrv_window_surface *surface;
    struct macdrv_window_surface *old_mac_surface = get_mac_surface(old_surface);
    int width = rect->right - rect->left, height = rect->bottom - rect->top;
    DWORD *colors;
    pthread_mutexattr_t attr;
    int err;
    DWORD window_background;

    surface = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
                        FIELD_OFFSET(struct macdrv_window_surface, info.bmiColors[3]));
    if (!surface) return NULL;

    err = pthread_mutexattr_init(&attr);
    if (!err)
    {
        err = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
        if (!err)
            err = pthread_mutex_init(&surface->mutex, &attr);
        pthread_mutexattr_destroy(&attr);
    }
    if (err)
    {
        HeapFree(GetProcessHeap(), 0, surface);
        return NULL;
    }

    surface->info.bmiHeader.biSize        = sizeof(surface->info.bmiHeader);
    surface->info.bmiHeader.biWidth       = width;
    surface->info.bmiHeader.biHeight      = height; /* bottom-up */
    surface->info.bmiHeader.biPlanes      = 1;
    surface->info.bmiHeader.biBitCount    = 32;
    surface->info.bmiHeader.biSizeImage   = get_dib_image_size(&surface->info);
    surface->info.bmiHeader.biCompression = BI_RGB;
    surface->info.bmiHeader.biClrUsed     = 0;

    colors = (DWORD *)((char *)&surface->info + surface->info.bmiHeader.biSize);
    colors[0] = 0x00ff0000;
    colors[1] = 0x0000ff00;
    colors[2] = 0x000000ff;

    surface->header.funcs = &macdrv_surface_funcs;
    surface->header.rect  = *rect;
    surface->header.ref   = 1;
    surface->window = window;
    reset_bounds(&surface->bounds);
    if (old_mac_surface && old_mac_surface->drawn)
    {
        surface->drawn = CreateRectRgnIndirect(rect);
        OffsetRgn(surface->drawn, -rect->left, -rect->top);
        if (CombineRgn(surface->drawn, surface->drawn, old_mac_surface->drawn, RGN_AND) <= NULLREGION)
        {
            DeleteObject(surface->drawn);
            surface->drawn = 0;
        }
    }
    update_blit_data(surface);
    surface->use_alpha = use_alpha;
    surface->bits = HeapAlloc(GetProcessHeap(), 0, surface->info.bmiHeader.biSizeImage);
    if (!surface->bits) goto failed;
    window_background = macdrv_window_background_color();
    memset_pattern4(surface->bits, &window_background, surface->info.bmiHeader.biSizeImage);

    TRACE("created %p for %p %s bits %p-%p\n", surface, window, wine_dbgstr_rect(rect),
          surface->bits, surface->bits + surface->info.bmiHeader.biSizeImage);

    return &surface->header;

failed:
    macdrv_surface_destroy(&surface->header);
    return NULL;
}
Ejemplo n.º 6
0
/***********************************************************************
 *           EMFDRV_CreateBrushIndirect
 */
DWORD EMFDRV_CreateBrushIndirect( PHYSDEV dev, HBRUSH hBrush )
{
    DWORD index = 0;
    LOGBRUSH logbrush;

    if (!GetObjectA( hBrush, sizeof(logbrush), &logbrush )) return 0;

    switch (logbrush.lbStyle) {
    case BS_SOLID:
    case BS_HATCHED:
    case BS_NULL:
      {
	EMRCREATEBRUSHINDIRECT emr;
	emr.emr.iType = EMR_CREATEBRUSHINDIRECT;
	emr.emr.nSize = sizeof(emr);
	emr.ihBrush = index = EMFDRV_AddHandle( dev, hBrush );
	emr.lb.lbStyle = logbrush.lbStyle;
	emr.lb.lbColor = logbrush.lbColor;
	emr.lb.lbHatch = logbrush.lbHatch;

	if(!EMFDRV_WriteRecord( dev, &emr.emr ))
	    index = 0;
      }
      break;
    case BS_DIBPATTERN:
      {
	EMRCREATEDIBPATTERNBRUSHPT *emr;
	DWORD bmSize, biSize, size;
	BITMAPINFO *info = GlobalLock( (HGLOBAL)logbrush.lbHatch );

	if (info->bmiHeader.biCompression)
            bmSize = info->bmiHeader.biSizeImage;
        else
	    bmSize = get_dib_image_size( info );
	biSize = bitmap_info_size(info, LOWORD(logbrush.lbColor));
	size = sizeof(EMRCREATEDIBPATTERNBRUSHPT) + biSize + bmSize;
	emr = HeapAlloc( GetProcessHeap(), 0, size );
	if(!emr) break;
	emr->emr.iType = EMR_CREATEDIBPATTERNBRUSHPT;
	emr->emr.nSize = size;
	emr->ihBrush = index = EMFDRV_AddHandle( dev, hBrush );
	emr->iUsage = LOWORD(logbrush.lbColor);
	emr->offBmi = sizeof(EMRCREATEDIBPATTERNBRUSHPT);
	emr->cbBmi = biSize;
	emr->offBits = sizeof(EMRCREATEDIBPATTERNBRUSHPT) + biSize;
	emr->cbBits = bmSize;
	memcpy((char *)emr + sizeof(EMRCREATEDIBPATTERNBRUSHPT), info,
	       biSize + bmSize );

	if(!EMFDRV_WriteRecord( dev, &emr->emr ))
	    index = 0;
	HeapFree( GetProcessHeap(), 0, emr );
	GlobalUnlock( (HGLOBAL)logbrush.lbHatch );
      }
      break;

    case BS_PATTERN:
      {
        EMRCREATEDIBPATTERNBRUSHPT *emr;
        char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
        BITMAPINFO *dst_info, *src_info = (BITMAPINFO *)buffer;
        struct gdi_image_bits bits;
        DWORD size;

        if (!get_bitmap_image( (HANDLE)logbrush.lbHatch, src_info, &bits )) break;
        if (src_info->bmiHeader.biBitCount != 1)
        {
            FIXME("Trying to create a color pattern brush\n");
            if (bits.free) bits.free( &bits );
            break;
        }

        /* FIXME: There is an extra DWORD written by native before the BMI.
         *        Not sure what its meant to contain.
         */
        size = sizeof(EMRCREATEDIBPATTERNBRUSHPT) + sizeof(DWORD) +
            sizeof(BITMAPINFOHEADER) + src_info->bmiHeader.biSizeImage;

        emr = HeapAlloc( GetProcessHeap(), 0, size );
        if(!emr)
        {
            if (bits.free) bits.free( &bits );
            break;
        }

        dst_info = (BITMAPINFO *)((LPBYTE)(emr + 1) + sizeof(DWORD));
        dst_info->bmiHeader = src_info->bmiHeader;
        memcpy( &dst_info->bmiHeader + 1, bits.ptr, dst_info->bmiHeader.biSizeImage );
        if (bits.free) bits.free( &bits );

        emr->emr.iType = EMR_CREATEMONOBRUSH;
        emr->emr.nSize = size;
        emr->ihBrush = index = EMFDRV_AddHandle( dev, hBrush );
        /* Presumably to reduce the size of the written EMF, MS supports an
         * undocumented iUsage value of 2, indicating a mono bitmap without the
         * 8 byte 2 entry black/white palette. Stupidly, they could have saved
         * over 20 bytes more by also ignoring the BITMAPINFO fields that are
         * irrelevant/constant for monochrome bitmaps.
         * FIXME: It may be that the DIB functions themselves accept this value.
         */
        emr->iUsage = DIB_PAL_MONO;
        emr->offBmi = (LPBYTE)dst_info - (LPBYTE)emr;
        emr->cbBmi = sizeof( BITMAPINFOHEADER );
        emr->offBits = emr->offBmi + emr->cbBmi;
        emr->cbBits = dst_info->bmiHeader.biSizeImage;

        if(!EMFDRV_WriteRecord( dev, &emr->emr ))
            index = 0;
        HeapFree( GetProcessHeap(), 0, emr );
      }
      break;

    default:
        FIXME("Unknown style %x\n", logbrush.lbStyle);
	break;
    }
    return index;
}
Ejemplo n.º 7
0
BOOL nulldrv_GradientFill( PHYSDEV dev, TRIVERTEX *vert_array, ULONG nvert,
                           void * grad_array, ULONG ngrad, ULONG mode )
{
    DC *dc = get_nulldrv_dc( dev );
    char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
    BITMAPINFO *info = (BITMAPINFO *)buffer;
    struct bitblt_coords src, dst;
    struct gdi_image_bits bits;
    unsigned int i;
    POINT *pts;
    BOOL ret = FALSE;
    DWORD err;
    HRGN rgn;

    if (!(pts = HeapAlloc( GetProcessHeap(), 0, nvert * sizeof(*pts) ))) return FALSE;
    for (i = 0; i < nvert; i++)
    {
        pts[i].x = vert_array[i].x;
        pts[i].y = vert_array[i].y;
    }
    LPtoDP( dev->hdc, pts, nvert );

    /* compute bounding rect of all the rectangles/triangles */
    reset_bounds( &dst.visrect );
    for (i = 0; i < ngrad * (mode == GRADIENT_FILL_TRIANGLE ? 3 : 2); i++)
    {
        ULONG v = ((ULONG *)grad_array)[i];
        dst.visrect.left   = min( dst.visrect.left,   pts[v].x );
        dst.visrect.top    = min( dst.visrect.top,    pts[v].y );
        dst.visrect.right  = max( dst.visrect.right,  pts[v].x );
        dst.visrect.bottom = max( dst.visrect.bottom, pts[v].y );
    }

    dst.x = dst.visrect.left;
    dst.y = dst.visrect.top;
    dst.width = dst.visrect.right - dst.visrect.left;
    dst.height = dst.visrect.bottom - dst.visrect.top;
    if (!clip_visrect( dc, &dst.visrect, &dst.visrect )) goto done;

    /* query the bitmap format */
    info->bmiHeader.biSize          = sizeof(info->bmiHeader);
    info->bmiHeader.biPlanes        = 1;
    info->bmiHeader.biBitCount      = 0;
    info->bmiHeader.biCompression   = BI_RGB;
    info->bmiHeader.biXPelsPerMeter = 0;
    info->bmiHeader.biYPelsPerMeter = 0;
    info->bmiHeader.biClrUsed       = 0;
    info->bmiHeader.biClrImportant  = 0;
    info->bmiHeader.biWidth         = dst.visrect.right - dst.visrect.left;
    info->bmiHeader.biHeight        = dst.visrect.bottom - dst.visrect.top;
    info->bmiHeader.biSizeImage     = 0;
    dev = GET_DC_PHYSDEV( dc, pPutImage );
    err = dev->funcs->pPutImage( dev, 0, info, NULL, NULL, NULL, 0 );
    if (err && err != ERROR_BAD_FORMAT) goto done;

    info->bmiHeader.biSizeImage = get_dib_image_size( info );
    if (!(bits.ptr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, info->bmiHeader.biSizeImage )))
        goto done;
    bits.is_copy = TRUE;
    bits.free = free_heap_bits;

    /* make src and points relative to the bitmap */
    src = dst;
    src.x -= dst.visrect.left;
    src.y -= dst.visrect.top;
    offset_rect( &src.visrect, -dst.visrect.left, -dst.visrect.top );
    for (i = 0; i < nvert; i++)
    {
        pts[i].x -= dst.visrect.left;
        pts[i].y -= dst.visrect.top;
    }

    rgn = CreateRectRgn( 0, 0, 0, 0 );
    gradient_bitmapinfo( info, bits.ptr, vert_array, nvert, grad_array, ngrad, mode, pts, rgn );
    OffsetRgn( rgn, dst.visrect.left, dst.visrect.top );
    ret = !dev->funcs->pPutImage( dev, rgn, info, &bits, &src, &dst, SRCCOPY );

    if (bits.free) bits.free( &bits );
    DeleteObject( rgn );

done:
    HeapFree( GetProcessHeap(), 0, pts );
    return ret;
}
Ejemplo n.º 8
0
/***********************************************************************
 *          create_icon_from_bmi
 *
 * Create an icon from its BITMAPINFO.
 */
static HICON create_icon_from_bmi( const BITMAPINFO *bmi, DWORD maxsize, HMODULE module, LPCWSTR resname,
                                   HRSRC rsrc, POINT hotspot, BOOL bIcon, INT width, INT height,
                                   UINT cFlag )
{
    DWORD size, color_size, mask_size;
    HBITMAP color = 0, mask = 0, alpha = 0;
    const void *color_bits, *mask_bits;
    BITMAPINFO *bmi_copy;
    BOOL ret = FALSE;
    BOOL do_stretch;
    HICON hObj = 0;
    HDC hdc = 0;

    /* Check bitmap header */

    if (maxsize < sizeof(BITMAPCOREHEADER))
    {
        return 0;
    }
    if (maxsize < bmi->bmiHeader.biSize)
    {
        WARN( "invalid header size %u\n", bmi->bmiHeader.biSize );
        return 0;
    }
    if ( (bmi->bmiHeader.biSize != sizeof(BITMAPCOREHEADER)) &&
         (bmi->bmiHeader.biSize != sizeof(BITMAPINFOHEADER)  ||
         (bmi->bmiHeader.biCompression != BI_RGB &&
          bmi->bmiHeader.biCompression != BI_BITFIELDS)) )
    {
        WARN( "invalid bitmap header %u\n", bmi->bmiHeader.biSize );
        return 0;
    }

    size = bitmap_info_size( bmi, DIB_RGB_COLORS );
    color_size = get_dib_image_size( bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight / 2,
                                     bmi->bmiHeader.biBitCount );
    mask_size = get_dib_image_size( bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight / 2, 1 );
    if (size > maxsize || color_size > maxsize - size)
    {
        WARN( "truncated file %u < %u+%u+%u\n", maxsize, size, color_size, mask_size );
        return 0;
    }
    if (mask_size > maxsize - size - color_size) mask_size = 0;  /* no mask */

    if (cFlag & LR_DEFAULTSIZE)
    {
        if (!width) width = GetSystemMetrics( bIcon ? SM_CXICON : SM_CXCURSOR );
        if (!height) height = GetSystemMetrics( bIcon ? SM_CYICON : SM_CYCURSOR );
    }
    else
    {
        if (!width) width = bmi->bmiHeader.biWidth;
        if (!height) height = bmi->bmiHeader.biHeight/2;
    }
    do_stretch = (bmi->bmiHeader.biHeight/2 != height) ||
                 (bmi->bmiHeader.biWidth != width);

    /* Scale the hotspot */
    if (bIcon)
    {
        hotspot.x = width / 2;
        hotspot.y = height / 2;
    }
    else if (do_stretch)
    {
        hotspot.x = (hotspot.x * width) / bmi->bmiHeader.biWidth;
        hotspot.y = (hotspot.y * height) / (bmi->bmiHeader.biHeight / 2);
    }

    if (!screen_dc) screen_dc = CreateDCW( DISPLAYW, NULL, NULL, NULL );
    if (!screen_dc) return 0;

    if (!(bmi_copy = (BITMAPINFO*)HeapAlloc( GetProcessHeap(), 0, max( size, FIELD_OFFSET( BITMAPINFO, bmiColors[2] )))))
        return 0;
    if (!(hdc = CreateCompatibleDC( 0 ))) goto done;

    memcpy( bmi_copy, bmi, size );
    bmi_copy->bmiHeader.biHeight /= 2;

    color_bits = (const char*)bmi + size;
    mask_bits = (const char*)color_bits + color_size;

    alpha = 0;
    if (is_dib_monochrome( bmi ))
    {
        if (!(mask = CreateBitmap( width, height * 2, 1, 1, NULL ))) goto done;
        color = 0;

        /* copy color data into second half of mask bitmap */
        SelectObject( hdc, mask );
        StretchDIBits( hdc, 0, height, width, height,
                       0, 0, bmi_copy->bmiHeader.biWidth, bmi_copy->bmiHeader.biHeight,
                       color_bits, bmi_copy, DIB_RGB_COLORS, SRCCOPY );
    }
    else
    {
        if (!(mask = CreateBitmap( width, height, 1, 1, NULL ))) goto done;
        if (!(color = CreateBitmap( width, height, GetDeviceCaps( screen_dc, PLANES ),
                                     GetDeviceCaps( screen_dc, BITSPIXEL ), NULL )))
        {
            DeleteObject( mask );
            goto done;
        }
        SelectObject( hdc, color );
        StretchDIBits( hdc, 0, 0, width, height,
                       0, 0, bmi_copy->bmiHeader.biWidth, bmi_copy->bmiHeader.biHeight,
                       color_bits, bmi_copy, DIB_RGB_COLORS, SRCCOPY );

        if (bmi_has_alpha( bmi_copy, color_bits ))
            alpha = create_alpha_bitmap(bmi_copy, color_bits ,width,height);

        /* convert info to monochrome to copy the mask */
        bmi_copy->bmiHeader.biBitCount = 1;
        if (bmi_copy->bmiHeader.biSize != sizeof(BITMAPCOREHEADER))
        {
            RGBQUAD *rgb = bmi_copy->bmiColors;

            bmi_copy->bmiHeader.biClrUsed = bmi_copy->bmiHeader.biClrImportant = 2;
            rgb[0].rgbBlue = rgb[0].rgbGreen = rgb[0].rgbRed = 0x00;
            rgb[1].rgbBlue = rgb[1].rgbGreen = rgb[1].rgbRed = 0xff;
            rgb[0].rgbReserved = rgb[1].rgbReserved = 0;
        }
        else
        {
            RGBTRIPLE *rgb = (RGBTRIPLE *)(((BITMAPCOREHEADER *)bmi_copy) + 1);

            rgb[0].rgbtBlue = rgb[0].rgbtGreen = rgb[0].rgbtRed = 0x00;
            rgb[1].rgbtBlue = rgb[1].rgbtGreen = rgb[1].rgbtRed = 0xff;
        }
    }

    if (mask_size)
    {
        SelectObject( hdc, mask );
        StretchDIBits( hdc, 0, 0, width, height,
                       0, 0, bmi_copy->bmiHeader.biWidth, bmi_copy->bmiHeader.biHeight,
                       mask_bits, bmi_copy, DIB_RGB_COLORS, SRCCOPY );
    }
    ret = TRUE;

done:
    DeleteDC( hdc );
    HeapFree( GetProcessHeap(), 0, bmi_copy );
	if(ret)
	{
		ICONINFO iconInfo={0};
		iconInfo.fIcon=bIcon;
		iconInfo.xHotspot=hotspot.x;
		iconInfo.yHotspot=hotspot.y;
		if(alpha)
		{
			iconInfo.hbmColor=alpha;
			iconInfo.hbmMask=mask;
		}
		else
		{
			iconInfo.hbmColor=color;
			iconInfo.hbmMask=mask;
		}

		hObj=CreateIconIndirect(&iconInfo);
		if(color) DeleteObject( color );
		if(alpha) DeleteObject( alpha );
		if(mask) DeleteObject( mask );
	}
	return hObj;
}