2009-11-30 7 views
2

J'utilise IShellItemImageFactory pour extraire l'icône d'un fichier. J'ai réussi à l'extraire et à l'afficher dans un dialogue en utilisant SendDlgItemMessage (hDlg, IDC_STATIC2, STM_SETIMAGE, IMAGE_ICON, (LPARAM) hicon);Enregistrer HICON en tant que png

voir la sortie: click here

Le problème est quand je fais des économies en tant que fichier (format PNG) en utilisant GDI + les gradients ne sont pas corriger la préservation. Trouvez le code ci-dessous que j'utilise.

 
GdiplusStartupInput gdiplusStartupInput; 
ULONG_PTR gdiplusToken; 
GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL); 
Bitmap *h = new Bitmap(256, 256, PixelFormat32bppARGB); 
Graphics* g = Graphics::FromImage(copy); 
HDC copyHdc = g->GetHDC(); 
DrawIconEx(copyHdc, 0, 0, hicon, 256, 256, 0, NULL, DI_NORMAL); 
g->ReleaseHDC(copyHdc);; 
CLSID encoderClsid; 
GetEncoderClsid(L"image/png", &encoderClsid); 
h->Save(L"D:\\mynew.png", &encoderClsid, NULL); 
GdiplusShutdown(gdiplusToken); 

La sortie que je suis arrivé après l'extraction d'un fichier texte: click here

Quelqu'un peut-il me aider à résoudre ce?

Cordialement, Manoj

+0

ne vois aucune différence dans les images liées. –

+0

regarde le dégradé des deux images, le second a une couleur noire. – Manoj

Répondre

2

Il me manque la « copie » de votre code:

Graphics* g = Graphics::FromImage(copy); 

En regardant les images, il semble que le contexte de l'appareil que vous dessinez l'icône pour n » t avoir des couleurs de 32 bits (le canal alpha est manquant).

essayer de créer un courant continu de ce type:

HDC hDC = CreateCompatibleDC(NULL); 

puis sélectionner un bitmap de couleur (vide) 32 bits dans ce courant continu. Après cela, vous pouvez dessiner l'icône et l'enregistrer.

+0

oui, il devrait être Graphics * g = Graphics :: FromImage (h); – Manoj

+0

ok, merci. J'ai implémenté un exemple de programme comme celui-ci. – Manoj

6

Ce sujet est plutôt ancien mais j'ai juste eu le même problème et j'ai passé beaucoup d'heures à trouver une solution qui préserve la transparence dans le fichier PNG.

Étant donné que le problème peut être facilement résolu en Java ...

sun.awt.shell.ShellFolder sf = sun.awt.shell.ShellFolder.getShellFolder(file); 
    ImageIcon icon = new ImageIcon(sf.getIcon(true)); 
    FileOutputStream bos = new FileOutputStream("d:\\icons\\icon.png"); 
    ImageIO.write((BufferedImage)icon.getImage(), "PNG", bos); 

... J'ai regardé un code source JDK. Dans le fichier "\ jdk \ src \ windows \ natif \ sun \ windows \ ShellFolder2.cpp" de la fonction "Java_sun_awt_shell_Win32ShellFolder2_getIconBits", j'ai trouvé le bon conseil dont j'avais besoin. Cette fonction récupère le bitmap de couleur à partir de HICON et appelle GetDIBits pour obtenir les données d'image. Il n'est pas nessaire de dessiner l'icone - par quoi la transpacence serait perdue de toute facon.

Merci beaucoup, développeurs JDK.

Ce code je me retrouve avec:

static CLSID g_pngClsid = GUID_NULL; 

// http://msdn.microsoft.com/en-us/library/windows/desktop/ms533843(v=vs.85).aspx 
extern int GetEncoderClsid(const WCHAR* format, CLSID* pClsid); 

static HICON getShellIconByIndex(int shilsize, int iImage) 
{ 
    IImageListPtr spiml; 
    SHGetImageList(shilsize, IID_PPV_ARGS(&spiml)); 

    HICON hico; 
    spiml->GetIcon(iImage, ILD_TRANSPARENT, &hico); 
    return hico; 
} 

static HICON getShellIcon(int shilsize, const std::wstring& fname) { 
    UINT flags = SHGFI_SYSICONINDEX; 
    SHFILEINFO fi = {0}; 
    HICON hIcon = NULL; 

    if (SHGetFileInfo(fname.c_str(), 0, &fi, sizeof(fi), flags) != 0) { 
     hIcon = getShellIconByIndex(shilsize, fi.iIcon); 
    } 

    return hIcon; 
} 

struct BITMAP_AND_BYTES { 
    Gdiplus::Bitmap* bmp; 
    int32_t* bytes; 
}; 

static BITMAP_AND_BYTES createAlphaChannelBitmapFromIcon(HICON hIcon) { 

    // Get the icon info 
    ICONINFO iconInfo = {0}; 
    GetIconInfo(hIcon, &iconInfo); 

    // Get the screen DC 
    HDC dc = GetDC(NULL); 

    // Get icon size info 
    BITMAP bm = {0}; 
    GetObject(iconInfo.hbmColor, sizeof(BITMAP), &bm); 

    // Set up BITMAPINFO 
    BITMAPINFO bmi = {0}; 
    bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); 
    bmi.bmiHeader.biWidth = bm.bmWidth; 
    bmi.bmiHeader.biHeight = -bm.bmHeight; 
    bmi.bmiHeader.biPlanes = 1; 
    bmi.bmiHeader.biBitCount = 32; 
    bmi.bmiHeader.biCompression = BI_RGB; 

    // Extract the color bitmap 
    int nBits = bm.bmWidth * bm.bmHeight; 
    int32_t* colorBits = new int32_t[nBits]; 
    GetDIBits(dc, iconInfo.hbmColor, 0, bm.bmHeight, colorBits, &bmi, DIB_RGB_COLORS); 

    // Check whether the color bitmap has an alpha channel. 
     // (On my Windows 7, all file icons I tried have an alpha channel.) 
    BOOL hasAlpha = FALSE; 
    for (int i = 0; i < nBits; i++) { 
     if ((colorBits[i] & 0xff000000) != 0) { 
      hasAlpha = TRUE; 
      break; 
     } 
    } 

    // If no alpha values available, apply the mask bitmap 
    if (!hasAlpha) { 
     // Extract the mask bitmap 
     int32_t* maskBits = new int32_t[nBits]; 
     GetDIBits(dc, iconInfo.hbmMask, 0, bm.bmHeight, maskBits, &bmi, DIB_RGB_COLORS); 
     // Copy the mask alphas into the color bits 
     for (int i = 0; i < nBits; i++) { 
      if (maskBits[i] == 0) { 
       colorBits[i] |= 0xff000000; 
      } 
     } 
     delete[] maskBits; 
    } 

    // Release DC and GDI bitmaps 
    ReleaseDC(NULL, dc); 
    ::DeleteObject(iconInfo.hbmColor); 
    ::DeleteObject(iconInfo.hbmMask); 

    // Create GDI+ Bitmap 
    Gdiplus::Bitmap* bmp = new Gdiplus::Bitmap(bm.bmWidth, bm.bmHeight, bm.bmWidth*4, PixelFormat32bppARGB, (BYTE*)colorBits); 
    BITMAP_AND_BYTES ret = {bmp, colorBits}; 

    return ret; 
} 

static void saveFileIconAsPng(int shilsize, const std::wstring& fname, const std::wstring& pngFile) { 
    HICON hIcon = getShellIcon(shilsize, fname); 
    BITMAP_AND_BYTES bbs = createAlphaChannelBitmapFromIcon(hIcon); 

    IStream* fstrm = NULL; 
    SHCreateStreamOnFile(pngFile.c_str(), STGM_WRITE|STGM_CREATE, &fstrm); 
    bbs.bmp->Save(fstrm, &g_pngClsid, NULL); 
    fstrm->Release(); 

    delete bbs.bmp; 
    delete[] bbs.bytes; 
    DestroyIcon(hIcon); 
} 

Exemple invokation:

GdiplusStartup(...); 
GetEncoderClsid(L"image/png", &g_pngClsid); 

wstring fname = L"d:\\index.html"; 
wstring pngFile = L"d:\\icons\\index.html.png"; 
saveFileIconAsPng(SHIL_JUMBO, fname, pngFile); 

GdiplusShutdown(...); 
+0

Beau travail, merci. – noober

Questions connexes