1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef UI_GFX_ICON_UTIL_H_ 6 #define UI_GFX_ICON_UTIL_H_ 7 8 #include <windows.h> 9 #include <stddef.h> 10 #include <stdint.h> 11 #include <memory> 12 #include <string> 13 #include <vector> 14 15 #include "base/macros.h" 16 #include "base/win/scoped_gdi_object.h" 17 #include "ui/gfx/geometry/point.h" 18 #include "ui/gfx/geometry/size.h" 19 #include "ui/gfx/gfx_export.h" 20 21 namespace base { 22 class FilePath; 23 } 24 25 namespace gfx { 26 class ImageFamily; 27 class Size; 28 } 29 class SkBitmap; 30 31 /////////////////////////////////////////////////////////////////////////////// 32 // 33 // The IconUtil class contains helper functions for manipulating Windows icons. 34 // The class interface contains methods for converting an HICON handle into an 35 // SkBitmap object and vice versa. The class can also create a .ico file given 36 // a PNG image contained in an SkBitmap object. The following code snippet 37 // shows an example usage of IconUtil::CreateHICONFromSkBitmap(): 38 // 39 // SkBitmap bitmap; 40 // 41 // // Fill |bitmap| with valid data 42 // bitmap.setConfig(...); 43 // bitmap.allocPixels(); 44 // 45 // ... 46 // 47 // // Convert the bitmap into a Windows HICON 48 // base::win::ScopedHICON icon(IconUtil::CreateHICONFromSkBitmap(bitmap)); 49 // if (!icon.is_valid()) { 50 // // Handle error 51 // ... 52 // } 53 // 54 // // Use the icon with a WM_SETICON message 55 // ::SendMessage(hwnd, WM_SETICON, static_cast<WPARAM>(ICON_BIG), 56 // reinterpret_cast<LPARAM>(icon.get())); 57 // 58 /////////////////////////////////////////////////////////////////////////////// 59 class GFX_EXPORT IconUtil { 60 public: 61 // ATOMIC_WRITE ensures that a partially written icon won't be created even if 62 // Chrome crashes part way through, but ATOMIC_WRITE is more expensive than 63 // NORMAL_WRITE. See CreateIconFileFromImageFamily. ATOMIC_WRITE is the 64 // default for historical reasons. 65 enum WriteType { ATOMIC_WRITE, NORMAL_WRITE }; 66 // The size of the large icon entries in .ico files on Windows Vista+. 67 enum { kLargeIconSize = 256 }; 68 // The size of icons in the medium icons view on Windows Vista+. This is the 69 // maximum size Windows will display an icon that does not have a 256x256 70 // image, even at the large or extra large icons views. 71 enum { kMediumIconSize = 48 }; 72 73 // The dimensions for icon images in Windows icon files. All sizes are square; 74 // that is, the value 48 means a 48x48 pixel image. Sizes are listed in 75 // ascending order. 76 static const int kIconDimensions[]; 77 78 // The number of elements in kIconDimensions. 79 static const size_t kNumIconDimensions; 80 // The number of elements in kIconDimensions <= kMediumIconSize. 81 static const size_t kNumIconDimensionsUpToMediumSize; 82 83 // Given an SkBitmap object, the function converts the bitmap to a Windows 84 // icon and returns the corresponding HICON handle. If the function cannot 85 // convert the bitmap, NULL is returned. 86 // 87 // The client is responsible for destroying the icon when it is no longer 88 // needed by calling ::DestroyIcon(). 89 static base::win::ScopedHICON CreateHICONFromSkBitmap(const SkBitmap& bitmap); 90 91 // Given a valid HICON handle representing an icon, this function converts 92 // the icon into an SkBitmap object containing an ARGB bitmap using the 93 // dimensions specified in |s|. |s| must specify valid dimensions (both 94 // width() an height() must be greater than zero). If the function cannot 95 // convert the icon to a bitmap (most probably due to an invalid parameter), 96 // the returned SkBitmap's isNull() method will return true. 97 static SkBitmap CreateSkBitmapFromHICON(HICON icon, const gfx::Size& s); 98 99 // Loads an icon resource as a SkBitmap for the specified |size| from a 100 // loaded .dll or .exe |module|. Supports loading smaller icon sizes as well 101 // as the Vista+ 256x256 PNG icon size. If the icon could not be loaded or 102 // found, returns a NULL scoped_ptr. 103 static std::unique_ptr<gfx::ImageFamily> CreateImageFamilyFromIconResource( 104 HMODULE module, 105 int resource_id); 106 107 // Given a valid HICON handle representing an icon, this function converts 108 // the icon into an SkBitmap object containing an ARGB bitmap using the 109 // dimensions of HICON. If the function cannot convert the icon to a bitmap 110 // (most probably due to an invalid parameter), the returned SkBitmap's 111 // isNull() method will return true. 112 static SkBitmap CreateSkBitmapFromHICON(HICON icon); 113 114 // Creates Windows .ico file at |icon_path|. The icon file is created with 115 // multiple BMP representations at varying predefined dimensions (by resizing 116 // an appropriately sized image from |image_family|) because Windows uses 117 // different image sizes when loading icons, depending on where the icon is 118 // drawn (ALT+TAB window, desktop shortcut, Quick Launch, etc.). 119 // 120 // If |image_family| contains an image larger than 48x48, the resulting icon 121 // will contain all sizes up to 256x256. The 256x256 image will be stored in 122 // PNG format inside the .ico file. If not, the resulting icon will contain 123 // all sizes up to 48x48. 124 // 125 // The function returns true on success and false otherwise. Returns false if 126 // |image_family| is empty. 127 static bool CreateIconFileFromImageFamily( 128 const gfx::ImageFamily& image_family, 129 const base::FilePath& icon_path, 130 WriteType write_type = ATOMIC_WRITE); 131 132 // Creates a cursor of the specified size from the SkBitmap passed in. 133 // Returns the cursor on success or NULL on failure. 134 static base::win::ScopedHICON CreateCursorFromSkBitmap( 135 const SkBitmap& bitmap, 136 const gfx::Point& hotspot); 137 138 // Given a valid HICON handle representing an icon, this function retrieves 139 // the hot spot of the icon. 140 static gfx::Point GetHotSpotFromHICON(HICON icon); 141 142 private: 143 // The icon format is published in the MSDN but there is no definition of 144 // the icon file structures in any of the Windows header files so we need to 145 // define these structure within the class. We must make sure we use 2 byte 146 // packing so that the structures are laid out properly within the file. 147 // See: http://msdn.microsoft.com/en-us/library/ms997538.aspx 148 #pragma pack(push) 149 #pragma pack(2) 150 151 // ICONDIRENTRY contains meta data for an individual icon image within a 152 // .ico file. 153 struct ICONDIRENTRY { 154 BYTE bWidth; 155 BYTE bHeight; 156 BYTE bColorCount; 157 BYTE bReserved; 158 WORD wPlanes; 159 WORD wBitCount; 160 DWORD dwBytesInRes; 161 DWORD dwImageOffset; 162 }; 163 164 // ICONDIR Contains information about all the icon images contained within a 165 // single .ico file. 166 struct ICONDIR { 167 WORD idReserved; 168 WORD idType; 169 WORD idCount; 170 ICONDIRENTRY idEntries[1]; 171 }; 172 173 // GRPICONDIRENTRY contains meta data for an individual icon image within a 174 // RT_GROUP_ICON resource in an .exe or .dll. 175 struct GRPICONDIRENTRY { 176 BYTE bWidth; 177 BYTE bHeight; 178 BYTE bColorCount; 179 BYTE bReserved; 180 WORD wPlanes; 181 WORD wBitCount; 182 DWORD dwBytesInRes; 183 WORD nID; 184 }; 185 186 // GRPICONDIR Contains information about all the icon images contained within 187 // a RT_GROUP_ICON resource in an .exe or .dll. 188 struct GRPICONDIR { 189 WORD idReserved; 190 WORD idType; 191 WORD idCount; 192 GRPICONDIRENTRY idEntries[1]; 193 }; 194 195 // Contains the actual icon image. 196 struct ICONIMAGE { 197 BITMAPINFOHEADER icHeader; 198 RGBQUAD icColors[1]; 199 BYTE icXOR[1]; 200 BYTE icAND[1]; 201 }; 202 #pragma pack(pop) 203 204 friend class IconUtilTest; 205 206 // Returns true if any pixel in the given pixels buffer has an non-zero alpha. 207 static bool PixelsHaveAlpha(const uint32_t* pixels, size_t num_pixels); 208 209 // A helper function that initializes a BITMAPV5HEADER structure with a set 210 // of values. 211 static void InitializeBitmapHeader(BITMAPV5HEADER* header, int width, 212 int height); 213 214 // Given a single SkBitmap object and pointers to the corresponding icon 215 // structures within the icon data buffer, this function sets the image 216 // information (dimensions, color depth, etc.) in the icon structures and 217 // also copies the underlying icon image into the appropriate location. 218 // The width and height of |bitmap| must be < 256. 219 // (Note that the 256x256 icon is treated specially, as a PNG, and should not 220 // use this method.) 221 // 222 // The function will set the data pointed to by |image_byte_count| with the 223 // number of image bytes written to the buffer. Note that the number of bytes 224 // includes only the image data written into the memory pointed to by 225 // |icon_image|. 226 static void SetSingleIconImageInformation(const SkBitmap& bitmap, 227 size_t index, 228 ICONDIR* icon_dir, 229 ICONIMAGE* icon_image, 230 DWORD image_offset, 231 size_t* image_byte_count); 232 233 // Copies the bits of an SkBitmap object into a buffer holding the bits of 234 // the corresponding image for an icon within the .ico file. 235 static void CopySkBitmapBitsIntoIconBuffer(const SkBitmap& bitmap, 236 unsigned char* buffer, 237 size_t buffer_size); 238 239 // Given a set of bitmaps with varying dimensions, this function computes 240 // the amount of memory needed in order to store the bitmaps as image icons 241 // in a .ico file. 242 static size_t ComputeIconFileBufferSize(const std::vector<SkBitmap>& set); 243 244 // A helper function for computing various size components of a given bitmap. 245 // The different sizes can be used within the various .ico file structures. 246 // 247 // |xor_mask_size| - the size, in bytes, of the XOR mask in the ICONIMAGE 248 // structure. 249 // |and_mask_size| - the size, in bytes, of the AND mask in the ICONIMAGE 250 // structure. 251 // |bytes_in_resource| - the total number of bytes set in the ICONIMAGE 252 // structure. This value is equal to the sum of the 253 // bytes in the AND mask and the XOR mask plus the size 254 // of the BITMAPINFOHEADER structure. Note that since 255 // only 32bpp are handled by the IconUtil class, the 256 // icColors field in the ICONIMAGE structure is ignored 257 // and is not accounted for when computing the 258 // different size components. 259 static void ComputeBitmapSizeComponents(const SkBitmap& bitmap, 260 size_t* xor_mask_size, 261 DWORD* bytes_in_resource); 262 263 // A helper function of CreateSkBitmapFromHICON. 264 static SkBitmap CreateSkBitmapFromHICONHelper(HICON icon, 265 const gfx::Size& s); 266 267 // Prevent clients from instantiating objects of that class by declaring the 268 // ctor/dtor as private. 269 DISALLOW_IMPLICIT_CONSTRUCTORS(IconUtil); 270 }; 271 272 #endif // UI_GFX_ICON_UTIL_H_ 273