Club Builder - Foros de discusión Club Builder
Foro de C++Builder en español
 
 FAQFAQ   BuscarBuscar   MiembrosMiembros   Grupos de UsuariosGrupos de Usuarios   RegistrarseRegistrarse 
 PerfilPerfil   Entra para ver tus mensajes privadosEntra para ver tus mensajes privados   EntrarEntrar 

Pasar HICON a TIcon o File.ico

 
Publicar nuevo tema   Responder al tema    Foros de discusión -> Tips & Tricks
Ver tema anterior :: Ver tema siguiente  
Autor Mensaje
Mensaje    Asunto: Pasar HICON a TIcon o File.ico Responder citando

En las versiones de Builder 5 y 6, y posiblemente alguna mas moderna, cuando creamos un TIcon a partir de un HICON, lo crea de 4 bits, es decir, de 16 colores. Si queremos conseguir el icono con todos los colores debemos hacerlo nosotros mismos.

Con ese motivo, y a raíz de un hilo del foro , he escrito una función que lo realiza. Simplemente crea una imagen en memoria de un archivo.ico que puede salvarse directamente o rescatarse con un TMemoryStream para luego pasarlo a un TIcon con TIcon::LoadFromStream.

Usa el siguiente archivo cabecera: Iconons.h
Código:
#ifndef iconosH
#define iconosH
//---------------------------------------------------------------------------
// Tomado de http://msdn.microsoft.com/en-us/library/ms997538.aspx
// Modificado del original.

// Necesario para alinear a Word el compilador
#pragma pack( push )
#pragma pack( 2 )

// These first two structs represent how the icon information is stored
// when it is bound into a EXE or DLL file. Structure members are WORD
// aligned and the last member of the structure is the ID instead of
// the imageoffset.

typedef struct
{
    BYTE    bWidth;               // Width of the image
    BYTE    bHeight;              // Height of the image (times 2)
    BYTE    bColorCount;          // Number of colors in image (0 if >=8bpp)
    BYTE    bReserved;            // Reserved
    WORD    wPlanes;              // Color Planes
    WORD    wBitCount;            // Bits per pixel
    DWORD    dwBytesInRes;         // how many bytes in this resource?
    WORD    nID;                  // the ID
} MEMICONDIRENTRY, *LPMEMICONDIRENTRY, GRPICONDIRENTRY, *LPGRPICONDIRENTRY;

typedef struct
{
    WORD            idReserved;   // Reserved
    WORD            idType;       // resource type (1 for icons)
    WORD            idCount;      // how many images?
    MEMICONDIRENTRY    idEntries[1]; // the entries for each image
} MEMICONDIR, *LPMEMICONDIR, GRPICONDIR, *LPGRPICONDIR;


// These next two structs represent how the icon information is stored
// in an ICO file.
typedef struct
{
    BYTE    bWidth;               // Width of the image
    BYTE    bHeight;              // Height of the image (times 2)
    BYTE    bColorCount;          // Number of colors in image (0 if >=8bpp)
    BYTE    bReserved;            // Reserved
    WORD    wPlanes;              // Color Planes
    WORD    wBitCount;            // Bits per pixel
    DWORD    dwBytesInRes;         // how many bytes in this resource?
    DWORD    dwImageOffset;        // where in the file is this image
} ICONDIRENTRY, *LPICONDIRENTRY;

typedef struct
{
    WORD             idReserved;   // Reserved
    WORD             idType;       // resource type (1 for icons)
    WORD             idCount;      // how many images?
    ICONDIRENTRY idEntries[1]; // the entries for each image
} ICONDIR, *LPICONDIR;

#pragma pack( pop )

//---------------------------------------------------------------------------
#endif


Y la función hIconToMem:

Código:
# include "Iconos.h"

//---------------------------------------------------------------------------
long
NColors(WORD bitCount)
{
  if (bitCount == 1 || bitCount == 4 || bitCount == 8)
    return 1 << bitCount;
  else if (bitCount >= 24)
    return 0;
  return -1;
}

//---------------------------------------------------------------------------
void* hIconToMem(HICON hIcon, int BitCountPerPixel, int* Size)
{
    // Localizo la información del icono y su tamaño en un fichero.ico
    HDC hDC = ::GetDC(NULL);    // ScreenDC
    ICONINFO IconInfo;
    BITMAP bmpAND={0};
    BITMAP bmpXOR={0};
    bool I = GetIconInfo(hIcon, &IconInfo);
    GetObject(IconInfo.hbmMask, sizeof(BITMAP), &bmpAND);
    GetObject(IconInfo.hbmColor, sizeof(BITMAP), &bmpXOR);
    if(BitCountPerPixel==0) BitCountPerPixel=bmpXOR.bmPlanes*bmpXOR.bmBitsPixel;
   
    int RawDataSizeAND=((((bmpAND.bmWidth*bmpAND.bmBitsPixel)+31) & ~31) >> 3)*bmpAND.bmHeight;
    int RawDataSizeXOR=((((bmpXOR.bmWidth*BitCountPerPixel)+31) & ~31) >> 3)*bmpXOR.bmHeight;
    int RawDataSize = RawDataSizeAND + RawDataSizeXOR;
    int PalSize=(BitCountPerPixel>8 ? 0 :1 << BitCountPerPixel)<<2; // RGBQUAD 4
    int AllSize= sizeof(ICONDIR)+sizeof(BITMAPINFOHEADER)+PalSize+RawDataSizeAND+RawDataSizeXOR;
    int Width  = bmpAND.bmWidth;
    int Height = bmpAND.bmHeight;

    // Reservo memoria para el fichero
    BYTE* FileIconMem = (BYTE*)VirtualAlloc(0, AllSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    ICONDIR* IconDir  = (ICONDIR*)FileIconMem;
   
    // Obtengo los Bits de cada parte Mask y Color
    BITMAPINFO bmiAND;
    BITMAPINFO *bmiICON = (BITMAPINFO*)(FileIconMem + sizeof(ICONDIR));
    LPVOID lpBitsXOR =    (BITMAPINFO*)(FileIconMem + sizeof(ICONDIR) + sizeof(BITMAPINFOHEADER) + PalSize);
    LPVOID lpBitsAND =    (BITMAPINFO*)((BYTE*)lpBitsXOR + RawDataSizeXOR);

    // Preparo la cabecera del Icon
    IconDir->idReserved = 0;
    IconDir->idType = 1;
    IconDir->idCount = 1;
    IconDir->idEntries[0].bWidth = Width;
    IconDir->idEntries[0].bHeight = Height;
    IconDir->idEntries[0].bColorCount = NColors(BitCountPerPixel);
    IconDir->idEntries[0].bReserved = 0;
    IconDir->idEntries[0].wPlanes = 0;         // Color Planes
    IconDir->idEntries[0].wBitCount = 0;//BitCountPerPixel;       // Bits per pixel
    IconDir->idEntries[0].dwBytesInRes = AllSize-sizeof(ICONDIR);    // How many bytes in this resource?
    IconDir->idEntries[0].dwImageOffset = sizeof(ICONDIR);   // Where in the file is this image?
    LPICONIMAGE IconImage = (LPICONIMAGE)(bmiICON);
    memset(IconImage, 0, sizeof(BITMAPINFOHEADER));
    IconImage->icHeader.biSize = sizeof(BITMAPINFOHEADER);
    IconImage->icHeader.biWidth = Width;
    IconImage->icHeader.biHeight = Height;
    IconImage->icHeader.biPlanes = 1;
    IconImage->icHeader.biBitCount = BitCountPerPixel;
    IconImage->icHeader.biSizeImage = RawDataSize;

    // Preparo BITMAPINFOHEADER para la Mascara (bmiAND)
    memcpy(&bmiAND, bmiICON, sizeof(BITMAPINFOHEADER));
    bmiAND.bmiHeader.biSizeImage = RawDataSizeAND;
    bmiAND.bmiHeader.biBitCount = 1;
    bmiAND.bmiHeader.biClrUsed = 1;
    bmiAND.bmiHeader.biClrImportant = 1;

    // Recupero los bits de cada hBitmap del icono
    GetDIBits(hDC, IconInfo.hbmColor, 0, Height, lpBitsXOR, bmiICON, DIB_RGB_COLORS);
    GetDIBits(hDC, IconInfo.hbmMask, 0, Height, lpBitsAND, &bmiAND, DIB_RGB_COLORS);

    // Sumo las dos alturas de ambos bitmaps del icono
    IconImage->icHeader.biHeight = Height*2;

    ReleaseDC(0, hDC);

    // Salida
    *Size = AllSize;
    return FileIconMem;
}


Un ejemplo de uso y para ver como funciona:
Código:

   TIcon *Icon = new TIcon;
   Icon->LoadFromFile("MI_ICONO.ICO");
   
   // Convertimos el HICON a imagen en memoria del .ico
   int Size;
   void* FileIconMem = hIconToMem(Icon->Handle, 32, &Size);

   HANDLE hFile=CreateFile("FilePath.ico", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
   DWORD dwWritten;
   WriteFile(hFile, FileIconMem, Size, &dwWritten, 0);
   CloseHandle(hFile);
   VirtualFree(FileIconMem, 0, MEM_RELEASE);

   // Lo recuperamos para ver que ha pasado
   Icon->LoadFromFile("FilePath.ico");
   Image1->Picture->Icon->Assign(Icon);




Saludos.


Ultima edición por escafandra el Jue 08 Ene, 2009 1:04 am, editado 1 vez
Volver arriba
Ver perfil de usuario Enviar mensaje privado
Mensaje    Asunto: Truco para Crear TIcon desde hIcon Responder citando

Basado en el truco anterior, en la función hIconToMem, Propongo un sencillo e intuitivo ejemplo para conseguir asignar la imagen de un hIcon a un TIcon.

La forma directa sería:
Código:
Icon->Handle = hIcon

Pero sólo funciona bien con iconos de 16 colores (4 bits). Para mas colores tendremos problemas en las versiones de Builder 5 y 6, y posiblemente alguna mas moderna.

Propongo mi función hIconToMem para los casos de más de 16 colores. Veamos como se hace con 32bit, por ejemplo:
Código:

// Creo un MemoryStream
TMemoryStream* Stream = new TMemoryStream;
// Leo el mapa del hIcon deseado
int Size;
void* FileIconMem = hIconToMem(hIcon, 32, &Size);
// lo paso al MemoryStream
Stream->Write(FileIconMem, Size);
Stream->Position = 0;
// Libero el mapa
VirtualFree(FileIconMem, 0, MEM_RELEASE);
// Creo el icono con la imagen del hIcon
TIcon *Icon = new TIcon;
Stream->Position = 0;  // Para situar le puntero de lectura al principio del Stream
Icon->LoadFromStream(Stream); // Cargo la imagen del Stream


Si alguien está interesado en la función hIconToMem y no le gusta el tratamiento de la memoria con la API VirtualAlloc, prefiriendo utilizar el operador new, tengo otra versión similar que trabaja de esta forma.

Saludos.
Volver arriba
Ver perfil de usuario Enviar mensaje privado
Mostrar mensajes de anteriores:   
Cambiar a:  
No puedes publicar temas nuevos en este foro
No puedes responder a temas en este foro
No puedes editar tus mensajes en este foro
No puedes borrar tus mensajes en este foro
No puedes votar en las encuestas de este foro


Hosting WordPress Indedmedia desde 3,99 €
© 2002–2026 Club Builder · Funciona con phpBB.