예제 #1
0
void
SplashInitFrameShape(Splash * splash, int imageIndex)
{
    RGNDATA *pRgnData;
    RGNDATAHEADER *pRgnHdr;
    ImageRect maskRect;

    if (!splash->maskRequired)
        return;

    /* reserving memory for the worst case */
    if (!IS_SAFE_SIZE_MUL(splash->width / 2 + 1, splash->height)) {
        return;
    }
    pRgnData = (RGNDATA *) SAFE_SIZE_STRUCT_ALLOC(malloc, sizeof(RGNDATAHEADER),
            sizeof(RECT), (splash->width / 2 + 1) * splash->height);
    if (!pRgnData) {
        return;
    }
    pRgnHdr = (RGNDATAHEADER *) pRgnData;
    initRect(&maskRect, 0, 0, splash->width, splash->height, 1,
            splash->width * splash->imageFormat.depthBytes,
            splash->frames[imageIndex].bitmapBits, &splash->imageFormat);

    pRgnHdr->dwSize = sizeof(RGNDATAHEADER);
    pRgnHdr->iType = RDH_RECTANGLES;
    pRgnHdr->nRgnSize = 0;
    pRgnHdr->rcBound.top = 0;
    pRgnHdr->rcBound.left = 0;
    pRgnHdr->rcBound.bottom = splash->height;
    pRgnHdr->rcBound.right = splash->width;

    pRgnHdr->nCount = BitmapToYXBandedRectangles(&maskRect,
            (RECT *) (((BYTE *) pRgnData) + sizeof(RGNDATAHEADER)));

    splash->frames[imageIndex].hRgn = ExtCreateRegion(NULL,
            sizeof(RGNDATAHEADER) + sizeof(RECT) * pRgnHdr->nCount, pRgnData);

    free(pRgnData);
}
예제 #2
0
JNIEXPORT jlong JNICALL
Java_sun_font_FileFontStrike__1getGlyphImageFromWindows
(JNIEnv *env, jobject unused,
 jstring fontFamily, jint style, jint size, jint glyphCode, jboolean fm) {

    GLYPHMETRICS glyphMetrics;
    LOGFONTW lf;
    BITMAPINFO bmi;
    TEXTMETRIC textMetric;
    RECT rect;
    int bytesWidth, dibBytesWidth, extra, imageSize, dibImageSize;
    unsigned char* dibImage = NULL, *rowPtr, *pixelPtr, *dibPixPtr, *dibRowPtr;
    unsigned char r,g,b;
    unsigned char* igTable;
    GlyphInfo* glyphInfo = NULL;
    int nameLen;
    LPWSTR name;
    HFONT oldFont, hFont;
    MAT2 mat2;

    unsigned short width;
    unsigned short height;
    short advanceX;
    short advanceY;
    int topLeftX;
    int topLeftY;
    int err;
    int bmWidth, bmHeight;
    int x, y;
    HBITMAP hBitmap = NULL, hOrigBM;
    int gamma, orient;

    HWND hWnd = NULL;
    HDC hDesktopDC = NULL;
    HDC hMemoryDC = NULL;

    hWnd = GetDesktopWindow();
    hDesktopDC = GetWindowDC(hWnd);
    if (hDesktopDC == NULL) {
        return (jlong)0;
    }
    if (GetDeviceCaps(hDesktopDC, BITSPIXEL) < 15) {
        FREE_AND_RETURN;
    }

    hMemoryDC = CreateCompatibleDC(hDesktopDC);
    if (hMemoryDC == NULL || fontFamily == NULL) {
        FREE_AND_RETURN;
    }
    err = SetMapMode(hMemoryDC, MM_TEXT);
    if (err == 0) {
        FREE_AND_RETURN;
    }

    memset(&lf, 0, sizeof(LOGFONTW));
    lf.lfHeight = -size;
    lf.lfWeight = (style & 1) ? FW_BOLD : FW_NORMAL;
    lf.lfItalic = (style & 2) ? 0xff : 0;
    lf.lfCharSet = DEFAULT_CHARSET;
    lf.lfQuality = CLEARTYPE_QUALITY;
    lf.lfOutPrecision = OUT_TT_PRECIS;
    lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
    lf.lfPitchAndFamily = DEFAULT_PITCH;

    nameLen = (*env)->GetStringLength(env, fontFamily);
    name = (LPWSTR)alloca((nameLen+1)*2);
    if (name == NULL) {
       FREE_AND_RETURN;
    }
    (*env)->GetStringRegion(env, fontFamily, 0, nameLen, name);
    name[nameLen] = '\0';

    if (nameLen < (sizeof(lf.lfFaceName) / sizeof(lf.lfFaceName[0]))) {
        wcscpy(lf.lfFaceName, name);
    } else {
        FREE_AND_RETURN;
    }

    hFont = CreateFontIndirectW(&lf);
    if (hFont == NULL) {
        FREE_AND_RETURN;
    }
    oldFont = SelectObject(hMemoryDC, hFont);

    memset(&textMetric, 0, sizeof(TEXTMETRIC));
    err = GetTextMetrics(hMemoryDC, &textMetric);
    if (err == 0) {
        FREE_AND_RETURN;
    }
    memset(&glyphMetrics, 0, sizeof(GLYPHMETRICS));
    memset(&mat2, 0, sizeof(MAT2));
    mat2.eM11.value = 1; mat2.eM22.value = 1;
    err = GetGlyphOutline(hMemoryDC, glyphCode,
                          GGO_METRICS|GGO_GLYPH_INDEX,
                          &glyphMetrics,
                          0, NULL, &mat2);
    if (err == GDI_ERROR) {
        /* Probably no such glyph - ie the font wasn't the one we expected. */
        FREE_AND_RETURN;
    }

    width  = (unsigned short)glyphMetrics.gmBlackBoxX;
    height = (unsigned short)glyphMetrics.gmBlackBoxY;

    /* Don't handle "invisible" glyphs in this code */
    if (width <= 0 || height == 0) {
       FREE_AND_RETURN;
    }

    advanceX = glyphMetrics.gmCellIncX;
    advanceY = glyphMetrics.gmCellIncY;
    topLeftX = glyphMetrics.gmptGlyphOrigin.x;
    topLeftY = glyphMetrics.gmptGlyphOrigin.y;

    /* GetGlyphOutline pre-dates cleartype and I'm not sure that it will
     * account for all pixels touched by the rendering. Need to widen,
     * and also adjust by one the x position at which it is rendered.
     * The extra pixels of width are used as follows :
     * One extra pixel at the left and the right will be needed to absorb
     * the pixels that will be touched by filtering by GDI to compensate
     * for colour fringing.
     * However there seem to be some cases where GDI renders two extra
     * pixels to the right, so we add one additional pixel to the right,
     * and in the code that copies this to the image cache we test for
     * the (rare) cases when this is touched, and if its not reduce the
     * stated image width for the blitting loops.
     * For fractional metrics :
     * One extra pixel at each end to account for sub-pixel positioning used
     * when fractional metrics is on in LCD mode.
     * The pixel at the left is needed so the blitting loop can index into
     * that a byte at a time to more accurately position the glyph.
     * The pixel at the right is needed so that when such indexing happens,
     * the blitting still can use the same width.
     * Consequently the width that is specified for the glyph is one less
     * than that of the actual image.
     * Note that in the FM case as a consequence we need to adjust the
     * position at which GDI renders, and the declared width of the glyph
     * See the if (fm) {} cases in the code.
     * For the non-FM case, we not only save 3 bytes per row, but this
     * prevents apparent glyph overlapping which affects the rendering
     * performance of accelerated pipelines since it adds additional
     * read-back requirements.
     */
    width+=3;
    if (fm) {
        width+=1;
    }
    /* DIB scanline must end on a DWORD boundary. We specify 3 bytes per pixel,
     * so must round up as needed to a multiple of 4 bytes.
     */
    dibBytesWidth = bytesWidth = width*3;
    extra = dibBytesWidth % 4;
    if (extra != 0) {
        dibBytesWidth += (4-extra);
    }
    /* The glyph cache image must be a multiple of 3 bytes wide. */
    extra = bytesWidth % 3;
    if (extra != 0) {
        bytesWidth += (3-extra);
    }
    bmWidth = width;
    bmHeight = height;

    /* Must use desktop DC to create a bitmap of that depth */
    hBitmap = CreateCompatibleBitmap(hDesktopDC, bmWidth, bmHeight);
    if (hBitmap == NULL) {
        FREE_AND_RETURN;
    }
    hOrigBM = (HBITMAP)SelectObject(hMemoryDC, hBitmap);

    /* Fill in black */
    rect.left = 0;
    rect.top = 0;
    rect.right = bmWidth;
    rect.bottom = bmHeight;
    FillRect(hMemoryDC, (LPRECT)&rect, GetStockObject(BLACK_BRUSH));

    /* Set text color to white, background to black. */
    SetBkColor(hMemoryDC, RGB(0,0,0));
    SetTextColor(hMemoryDC, RGB(255,255,255));

    /* adjust rendering position */
    x = -topLeftX+1;
    if (fm) {
        x += 1;
    }
    y = topLeftY - textMetric.tmAscent;
    err = ExtTextOutW(hMemoryDC, x, y, ETO_GLYPH_INDEX|ETO_OPAQUE,
                (LPRECT)&rect, (LPCWSTR)&glyphCode, 1, NULL);
    if (err == 0) {
        FREE_AND_RETURN;
    }

    /* Now get the image into a DIB.
     * MS docs for GetDIBits says the compatible bitmap must not be
     * selected into a DC, so restore the original first.
     */
    SelectObject(hMemoryDC, hOrigBM);
    SelectObject(hMemoryDC, oldFont);
    DeleteObject(hFont);

    memset(&bmi, 0, sizeof(BITMAPINFO));
    bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
    bmi.bmiHeader.biWidth = width;
    bmi.bmiHeader.biHeight = -height;
    bmi.bmiHeader.biPlanes = 1;
    bmi.bmiHeader.biBitCount = 24;
    bmi.bmiHeader.biCompression = BI_RGB;

    dibImage = SAFE_SIZE_ARRAY_ALLOC(malloc, dibBytesWidth, height);
    if (dibImage == NULL) {
        FREE_AND_RETURN;
    }
    dibImageSize = dibBytesWidth*height;
    memset(dibImage, 0, dibImageSize);

    err = GetDIBits(hMemoryDC, hBitmap, 0, height, dibImage,
                    &bmi, DIB_RGB_COLORS);

    if (err == 0) {        /* GetDIBits failed. */
        FREE_AND_RETURN;
    }

    err = SystemParametersInfo(SPI_GETFONTSMOOTHINGORIENTATION, 0, &orient, 0);
    if (err == 0) {
        FREE_AND_RETURN;
    }
    err = SystemParametersInfo(SPI_GETFONTSMOOTHINGCONTRAST, 0, &gamma, 0);
    if (err == 0) {
        FREE_AND_RETURN;
    }
    igTable = getIGTable(gamma/10);
    if (igTable == NULL) {
        FREE_AND_RETURN;
    }

    /* Now copy glyph image into a GlyphInfo structure and return it.
     * NB the xadvance calculated here may be overwritten by the caller.
     * 1 is subtracted from the bitmap width to get the glyph width, since
     * that extra "1" was added as padding, so the sub-pixel positioning of
     * fractional metrics could index into it.
     */
    glyphInfo = (GlyphInfo*)SAFE_SIZE_STRUCT_ALLOC(malloc, sizeof(GlyphInfo),
            bytesWidth, height);
    if (glyphInfo == NULL) {
        FREE_AND_RETURN;
    }
    imageSize = bytesWidth*height;
    glyphInfo->cellInfo = NULL;
    glyphInfo->rowBytes = bytesWidth;
    glyphInfo->width = width;
    if (fm) {
        glyphInfo->width -= 1; // must subtract 1
    }
    glyphInfo->height = height;
    glyphInfo->advanceX = advanceX;
    glyphInfo->advanceY = advanceY;
    glyphInfo->topLeftX = (float)(topLeftX-1);
    if (fm) {
        glyphInfo->topLeftX -= 1;
    }
    glyphInfo->topLeftY = (float)-topLeftY;
    glyphInfo->image = (unsigned char*)glyphInfo+sizeof(GlyphInfo);
    memset(glyphInfo->image, 0, imageSize);

    /* DIB 24bpp data is always stored in BGR order, but we usually
     * need this in RGB, so we can't just memcpy and need to swap B and R.
     * Also need to apply inverse gamma adjustment here.
     * We re-use the variable "extra" to see if the last pixel is touched
     * at all. If its not we can reduce the glyph image width. This comes
     * into play in some cases where GDI touches more pixels than accounted
     * for by increasing width by two pixels over the B&W image. Whilst
     * the bytes are in the cache, it doesn't affect rendering performance
     * of the hardware pipelines.
     */
    extra = 0;
    if (fm) {
        extra = 1; // always need it.
    }
    dibRowPtr = dibImage;
    rowPtr = glyphInfo->image;
    for (y=0;y<height;y++) {
        pixelPtr = rowPtr;
        dibPixPtr = dibRowPtr;
        for (x=0;x<width;x++) {
            if (orient == FE_FONTSMOOTHINGORIENTATIONRGB) {
                b = *dibPixPtr++;
                g = *dibPixPtr++;
                r = *dibPixPtr++;
            } else {
                r = *dibPixPtr++;
                g = *dibPixPtr++;
                b = *dibPixPtr++;
            }
            *pixelPtr++ = igTable[r];
            *pixelPtr++ = igTable[g];
            *pixelPtr++ = igTable[b];
            if (!fm && (x==(width-1)) && (r|g|b)) {
                extra = 1;
            }
        }
        dibRowPtr += dibBytesWidth;
        rowPtr  += bytesWidth;
    }
    if (!extra) {
        glyphInfo->width -= 1;
    }

    free(dibImage);
    ReleaseDC(hWnd, hDesktopDC);
    DeleteObject(hMemoryDC);
    DeleteObject(hBitmap);

    return ptr_to_jlong(glyphInfo);
}
예제 #3
0
void
SplashPaint(Splash * splash, HDC hdc)
{
    unsigned numColors = splash->screenFormat.colorMap ?
        splash->screenFormat.numColors : 0;
    BITMAPV4HEADER *pBmi;
    HPALETTE hOldPal = NULL;

    if (!splash->frames)
        return;
    if (splash->currentFrame < 0 || splash->currentFrame >= splash->frameCount)
        return;
    pBmi = (BITMAPV4HEADER *) SAFE_SIZE_STRUCT_ALLOC(alloca, sizeof(BITMAPV4HEADER),
            sizeof(RGBQUAD), numColors);
    if (!pBmi) {
        return;
    }
    memset(pBmi, 0, sizeof(BITMAPV4HEADER));
    if (splash->screenFormat.colorMap)
        memcpy(((BYTE *) pBmi) + sizeof(BITMAPV4HEADER),
                splash->screenFormat.colorMap, sizeof(RGBQUAD) * numColors);

    pBmi->bV4Size = sizeof(BITMAPV4HEADER);
    pBmi->bV4Width = splash->width;
    pBmi->bV4Height = -splash->height;
    pBmi->bV4Planes = 1;
    pBmi->bV4BitCount = (WORD) (splash->screenFormat.depthBytes * 8);
    /* we're ALWAYS using BGRA in screenFormat */
    pBmi->bV4V4Compression = BI_RGB;
    pBmi->bV4ClrUsed = numColors;
    pBmi->bV4ClrImportant = numColors;
    pBmi->bV4AlphaMask = splash->screenFormat.mask[3];
    pBmi->bV4RedMask = splash->screenFormat.mask[2];
    pBmi->bV4GreenMask = splash->screenFormat.mask[1];
    pBmi->bV4BlueMask = splash->screenFormat.mask[0];

    /*  creating the palette in SplashInitPlatform does not work, so I'm creating it
       here on demand */
    if (!splash->hPalette) {
        unsigned i;
        LOGPALETTE *pLogPal = (LOGPALETTE *) SAFE_SIZE_STRUCT_ALLOC(malloc,
                sizeof(LOGPALETTE), sizeof(PALETTEENTRY), numColors);
        if (!pLogPal) {
            return;
        }

        pLogPal->palVersion = 0x300;
        pLogPal->palNumEntries = (WORD) numColors;
        for (i = 0; i < numColors; i++) {
            pLogPal->palPalEntry[i].peRed = (BYTE)
                QUAD_RED(splash->colorMap[i]);
            pLogPal->palPalEntry[i].peGreen = (BYTE)
                QUAD_GREEN(splash->colorMap[i]);
            pLogPal->palPalEntry[i].peBlue = (BYTE)
                QUAD_BLUE(splash->colorMap[i]);
            pLogPal->palPalEntry[i].peFlags = PC_NOCOLLAPSE;
        }
        splash->hPalette = CreatePalette(pLogPal);
        free(pLogPal);
    }
    if (splash->hPalette) {
        hOldPal = SelectPalette(hdc, splash->hPalette, FALSE);
        RealizePalette(hdc);
    }

    StretchDIBits(hdc, 0, 0, splash->width, splash->height, 0, 0,
            splash->width, splash->height, splash->screenData,
            (BITMAPINFO *) pBmi, DIB_RGB_COLORS, SRCCOPY);
    if (hOldPal)
        SelectPalette(hdc, hOldPal, FALSE);
}
/*
 * Class:     sun_awt_windows_WDataTransferer
 * Method:    imageDataToPlatformImageBytes
 * Signature: ([BIII)[B
 */
JNIEXPORT jbyteArray JNICALL
Java_sun_awt_windows_WDataTransferer_imageDataToPlatformImageBytes(JNIEnv *env,
                                               jobject self, jbyteArray imageData,
                                               jint width, jint height,
                                               jlong format) {

    TRY;

    if (JNU_IsNull(env, imageData)) {
        return NULL;
    }

    UINT size = env->GetArrayLength(imageData);
    if (size == 0) {
        return NULL;
    }

    // In the passed imageData array all lines are padded with zeroes except for
    // the last one, so we have to add one pad size here.
    int mod = (width * 3) % 4;
    int pad = mod > 0 ? 4 - mod : 0;
    int nBytes = sizeof(BITMAPINFO) + size + pad;
    BITMAPINFO* pinfo = (BITMAPINFO*)safe_Calloc(1, nBytes);

    static const int BITS_PER_PIXEL = 24;

    // prepare BITMAPINFO for a 24-bit BGR bitmap
    pinfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    pinfo->bmiHeader.biWidth = width;
    pinfo->bmiHeader.biHeight = height; // positive height means a bottom-up DIB
    pinfo->bmiHeader.biPlanes = 1;
    pinfo->bmiHeader.biBitCount = BITS_PER_PIXEL;
    pinfo->bmiHeader.biCompression = BI_RGB;
    // NOTE: MSDN says that biSizeImage may be set to 0 for BI_RGB bitmaps,
    // but some programs (e.g. Imaging for Windows NT by Wang Laboratories)
    // don't handle such DIBs correctly, so we specify the size explicitly.
    pinfo->bmiHeader.biSizeImage = size + pad;

    jbyte *array = (jbyte*)((LPSTR)pinfo + sizeof(BITMAPINFOHEADER));
    env->GetByteArrayRegion(imageData, 0, size, array);
    HRESULT hr = S_OK;

    jbyteArray bytes = NULL;
    switch (format) {
    case CF_DIB:
        bytes = env->NewByteArray(nBytes);
        if( NULL == bytes ) {
            hr = E_OUTOFMEMORY;
        } else {
            env->SetByteArrayRegion(bytes, 0, nBytes, (jbyte*)pinfo);
        }
        break;
    case CF_ENHMETAFILE:
    {
        HDC hdc = ::GetDC(NULL);
        if( NULL == hdc) {
            hr = HRESULT_FROM_WIN32(::GetLastError());
        } else {
            POINT p = { width, height };
            //We are trying to support context-independent metafile.
            //To implement it we have to select correct MM_HIMETRIC map mode.
            VERIFY(::SetMapMode(hdc, MM_HIMETRIC));
            VERIFY(::DPtoLP(hdc, &p, 1));
            //In accordance with CreateEnhMetaFile documentation the rectangle have to
            //be normal (left <= right, top <= bottom)
            RECT r = { min(0, p.x), min(0, p.y), max(0, p.x), max(0, p.y) };
            //Due to inversed row order in source bitmap the destination
            //height have to be negative.
            HDC hemfdc = ::CreateEnhMetaFile(NULL, NULL, &r, NULL);
            if( NULL == hemfdc) {
                hr = HRESULT_FROM_WIN32(::GetLastError());
            } else {
                int iMFHeight = r.bottom - r.top;
                int iMFWidth = r.right - r.left;
                VERIFY(::SetMapMode(hemfdc, MM_HIMETRIC));
                if( GDI_ERROR == ::StretchDIBits(hemfdc,
                    0, iMFHeight, iMFWidth, -iMFHeight,
                    0, 0, width, height,
                    (LPVOID)array, pinfo,
                    DIB_RGB_COLORS, SRCCOPY))
                {
                    hr = HRESULT_FROM_WIN32(::GetLastError());
                }
                HENHMETAFILE hemf = ::CloseEnhMetaFile(hemfdc);
                if( NULL == hemf) {
                    hr = HRESULT_FROM_WIN32(::GetLastError());
                } else {
                    if(SUCCEEDED(hr)){
                        UINT uEmfSize = ::GetEnhMetaFileBits(hemf, 0, NULL);
                        if( 0 == uEmfSize) {
                            hr = HRESULT_FROM_WIN32(::GetLastError());
                        } else {
                            LPBYTE lpbEmfBuffer = NULL;
                            try {
                                lpbEmfBuffer = (LPBYTE)safe_Malloc(uEmfSize);
                                VERIFY(::GetEnhMetaFileBits(hemf, uEmfSize,
                                                            lpbEmfBuffer) == uEmfSize);
                                bytes = env->NewByteArray(uEmfSize);
                                if(NULL == bytes) {
                                    hr = E_OUTOFMEMORY;
                                } else {
                                    env->SetByteArrayRegion(bytes, 0, uEmfSize, (jbyte*)lpbEmfBuffer);
                                }
                            } catch (std::bad_alloc &) {
                                hr = E_OUTOFMEMORY;
                            }
                            free(lpbEmfBuffer);
                        }
                    }
                    VERIFY(::DeleteEnhMetaFile(hemf));
                }
            }
            VERIFY(::ReleaseDC(NULL, hdc));
        }
        break;
    }
    case CF_METAFILEPICT:
    {
        HDC hdc = ::GetDC(NULL);
        if( NULL == hdc) {
            hr = HRESULT_FROM_WIN32(::GetLastError());
        } else {
            POINT p = { width, height };
            VERIFY(::SetMapMode(hdc, MM_HIMETRIC));
            VERIFY(::DPtoLP(hdc, &p, 1));
            RECT r = { min(0, p.x), min(0, p.y), max(0, p.x), max(0, p.y) };
            HDC hmfdc = ::CreateMetaFile(NULL);
            if( NULL == hmfdc) {
                hr = HRESULT_FROM_WIN32(::GetLastError());
            } else {
                VERIFY(::SetMapMode(hmfdc, MM_HIMETRIC));
                int iMFHeight = r.bottom - r.top;
                int iMFWidth = r.right - r.left;
                //The destination Y coordinate (3d parameter in StretchDIBits call) is different for
                //CF_ENHMETAFILE and CF_METAFILEPICT formats due to applying MM_ANISOTROPIC map mode
                //at very last moment. MM_ANISOTROPIC map mode changes the Y-axis direction and can be
                //selected just for metafile header.
                if( GDI_ERROR == ::StretchDIBits(hmfdc,
                    0, 0, iMFWidth, -iMFHeight,
                    0, 0, width, height,
                    (LPVOID)array, pinfo,
                    DIB_RGB_COLORS, SRCCOPY))
                {
                    hr = HRESULT_FROM_WIN32(::GetLastError());
                }
                HMETAFILE hmf = ::CloseMetaFile(hmfdc);
                if( NULL == hmf) {
                    hr = HRESULT_FROM_WIN32(::GetLastError());
                } else {
                    if(SUCCEEDED(hr)){
                        UINT uMfSize = ::GetMetaFileBitsEx(hmf, 0, NULL);
                        if( 0 == uMfSize) {
                            hr = HRESULT_FROM_WIN32(::GetLastError());
                        } else {
                            LPBYTE lpbMfBuffer = NULL;
                            try {
                                lpbMfBuffer = (LPBYTE)SAFE_SIZE_STRUCT_ALLOC(safe_Malloc,
                                        sizeof(METAFILEPICT), uMfSize, 1);
                                const UINT uMfSizeWithHead = uMfSize + sizeof(METAFILEPICT);
                                VERIFY(::GetMetaFileBitsEx(hmf, uMfSize,
                                                            lpbMfBuffer + sizeof(METAFILEPICT)) == uMfSize);
                                bytes = env->NewByteArray(uMfSizeWithHead);
                                if(NULL == bytes) {
                                    hr = E_OUTOFMEMORY;
                                } else {
                                    LPMETAFILEPICT lpMfp = (LPMETAFILEPICT)lpbMfBuffer;
                                    lpMfp->mm = MM_ANISOTROPIC; // should use MM_ANISOTROPIC exactly (MSDN)
                                    lpMfp->xExt = iMFWidth;
                                    lpMfp->yExt = iMFHeight;
                                    env->SetByteArrayRegion(bytes, 0, uMfSizeWithHead, (jbyte*)lpbMfBuffer);
                                }
                            } catch (std::bad_alloc &) {
                                hr = E_OUTOFMEMORY;
                            }
                            free(lpbMfBuffer);
                        }
                    }
                    VERIFY(::DeleteMetaFile(hmf));
                }
            }
            VERIFY(::ReleaseDC(NULL, hdc));
        }
        break;
    }
    default:
        DASSERT(FALSE); // Other formats are not supported yet.
        hr = E_NOTIMPL;
        break;
    }
    free(pinfo);
    if(FAILED(hr)){
        if(E_OUTOFMEMORY == hr)
            throw std::bad_alloc();
        return NULL;
    }
    return bytes;
    CATCH_BAD_ALLOC_RET(NULL);
}