Club Delphi  
    FTP   CCD     Buscar   Trucos   Trabajo   Foros

Retroceder   Foros Club Delphi > Otros temas > Trucos
Registrarse FAQ Miembros Calendario Guía de estilo Buscar Temas de Hoy Marcar Foros Como Leídos

Los mejores trucos

Respuesta
 
Herramientas Buscar en Tema Desplegado
  #1  
Antiguo 29-12-2008
Avatar de escafandra
[escafandra] escafandra is offline
Miembro Premium
 
Registrado: nov 2007
Posts: 1.895
Poder: 13
escafandra Va camino a la famaescafandra Va camino a la fama
Pasar un HICON a un TIcon o a un archivo

Determinadas APIs como ExtractAssociatedIcon, devuelven un manejador HICON. Cuando queremos cargar la

imagen del Handle hIcon en un componente TIcon, la forma más directa es:
Código:
Icon->Handle = hIcon;
Pero, lamentablemente esto no funciona del todo bien en todas las versiones de Builder y Delphi. Si lo que pretendemos es conseguir un icono de 16 colores, entonces no tendremos problemas. Pero si queremos manejar mas colores nos los truncará a un máximo de 16 (4 bits). Esto ocurre con seguridad en versiones de Builder y Delphi inferiores a la 6, incluida ésta. En las versiones del 2009 está resuelto este problema.

Para solventar el inconveniente he escrito una función que consigue un bloque de memoria con una imagen de un archivo.ico a partir de un Handle HICON de Windows. Este Buffer puede usarse para salvar directamente el icono en un archivo.ico o para pasar la imagen a un TIcon mediante un TMemoryStream. El código permite elegir el número de bits de color (bitCount) con el que trabajaremos, este será de 1, 4, 8, 24, ó 32.

Pasamos al código.

En primer lugar publico un archivo cabecera con las definiciones y estructuras necesarias. Veréis que alinea al compilador a Word dato muy importante. Este archivo lo he denominado Iconos.h:
Código:
#ifndef iconosH
#define iconosH

#pragma pack( push )
#pragma pack( 2 )

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;


typedef struct
{
   BITMAPINFOHEADER   icHeader;      // DIB header
   RGBQUAD         icColors[1];   // Color table
   BYTE            icXOR[1];      // DIB bits for XOR mask
   BYTE            icAND[1];      // DIB bits for AND mask
} ICONIMAGE, *LPICONIMAGE;

#pragma pack( pop )


//---------------------------------------------------------------------------
#endif
A continuación coloco una versión de la función que localiza la memoria necesaria con la API VirtualAlloc, esto obliga a liberar el bloque después de usar la función. La función devuelve un puntero al mismo bloque:

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;
}

//---------------------------------------------------------------------------
// Devuelve una imagen de archivo.ico para poder guardar en disco....
// Reserva la memoria necesaria devolviendo en Size el Tamaño
// Requiere liberar luego la memoria con VirtualFree(Mem, 0, MEM_RELEASE);
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;
}
Para ilustrar el uso voy a colocar dos ejemplos prácticos. En el primero guardo un hIcon en un archivo y lo vuelvo a abrir para ver lo que sucede:

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);
Ahora vamos a pasar la Imagen de un hIcon a un TIcon. Para ello utilizamos un TMemoryStream como paso intermedio. Creo que su uso es bastante intuitivo:

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
El truco es un poco largo, pero seguro que a alguien le merece la pena usarlo.

Saludos.
Responder Con Cita
Respuesta


Herramientas Buscar en Tema
Buscar en Tema:

Búsqueda Avanzada
Desplegado

Normas de Publicación
no Puedes crear nuevos temas
no Puedes responder a temas
no Puedes adjuntar archivos
no Puedes editar tus mensajes

El código vB está habilitado
Las caritas están habilitado
Código [IMG] está habilitado
Código HTML está deshabilitado
Saltar a Foro


La franja horaria es GMT +2. Ahora son las 14:47:22.


Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2017, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi
Copyright 1996-2007 Club Delphi