1/* 2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3% % 4% % 5% % 6% % 7% N N TTTTT % 8% NN N T % 9% N N N T % 10% N NN T % 11% N N T % 12% % 13% % 14% Windows NT Feature Methods for MagickCore % 15% % 16% Software Design % 17% Cristy % 18% December 1996 % 19% % 20% % 21% Copyright 1999-2016 ImageMagick Studio LLC, a non-profit organization % 22% dedicated to making software imaging solutions freely available. % 23% % 24% You may not use this file except in compliance with the License. You may % 25% obtain a copy of the License at % 26% % 27% http://www.imagemagick.org/script/license.php % 28% % 29% Unless required by applicable law or agreed to in writing, software % 30% distributed under the License is distributed on an "AS IS" BASIS, % 31% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. % 32% See the License for the specific language governing permissions and % 33% limitations under the License. % 34% % 35%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 36% 37% 38*/ 39 40/* 41 Include declarations. 42*/ 43#include "MagickCore/studio.h" 44#if defined(MAGICKCORE_WINDOWS_SUPPORT) || defined(__CYGWIN__) 45#define WIN32_LEAN_AND_MEAN 46#define VC_EXTRALEAN 47#include <windows.h> 48#include "MagickCore/cache.h" 49#include "MagickCore/colorspace.h" 50#include "MagickCore/colorspace-private.h" 51#include "MagickCore/draw.h" 52#include "MagickCore/exception.h" 53#include "MagickCore/exception-private.h" 54#include "MagickCore/image-private.h" 55#include "MagickCore/memory_.h" 56#include "MagickCore/monitor.h" 57#include "MagickCore/monitor-private.h" 58#include "MagickCore/nt-base.h" 59#include "MagickCore/nt-base-private.h" 60#include "MagickCore/pixel-accessor.h" 61#include "MagickCore/quantum.h" 62#include "MagickCore/string_.h" 63#include "MagickCore/token.h" 64#include "MagickCore/splay-tree.h" 65#include "MagickCore/utility.h" 66 67/* 68%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 69% % 70% % 71% % 72% C r o p I m a g e T o H B i t m a p % 73% % 74% % 75% % 76%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 77% 78% CropImageToHBITMAP() extracts a specified region of the image and returns 79% it as a Windows HBITMAP. While the same functionality can be accomplished by 80% invoking CropImage() followed by ImageToHBITMAP(), this method is more 81% efficient since it copies pixels directly to the HBITMAP. 82% 83% The format of the CropImageToHBITMAP method is: 84% 85% HBITMAP CropImageToHBITMAP(Image* image,const RectangleInfo *geometry, 86% ExceptionInfo *exception) 87% 88% A description of each parameter follows: 89% 90% o image: the image. 91% 92% o geometry: Define the region of the image to crop with members 93% x, y, width, and height. 94% 95% o exception: return any errors or warnings in this structure. 96% 97*/ 98MagickExport void *CropImageToHBITMAP(Image *image, 99 const RectangleInfo *geometry,ExceptionInfo *exception) 100{ 101#define CropImageTag "Crop/Image" 102 103 BITMAP 104 bitmap; 105 106 HBITMAP 107 bitmapH; 108 109 HANDLE 110 bitmap_bitsH; 111 112 MagickBooleanType 113 proceed; 114 115 RectangleInfo 116 page; 117 118 register const Quantum 119 *p; 120 121 register RGBQUAD 122 *q; 123 124 RGBQUAD 125 *bitmap_bits; 126 127 ssize_t 128 y; 129 130 /* 131 Check crop geometry. 132 */ 133 assert(image != (const Image *) NULL); 134 assert(image->signature == MagickCoreSignature); 135 if (image->debug != MagickFalse) 136 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 137 assert(geometry != (const RectangleInfo *) NULL); 138 assert(exception != (ExceptionInfo *) NULL); 139 assert(exception->signature == MagickCoreSignature); 140 if (((geometry->x+(ssize_t) geometry->width) < 0) || 141 ((geometry->y+(ssize_t) geometry->height) < 0) || 142 (geometry->x >= (ssize_t) image->columns) || 143 (geometry->y >= (ssize_t) image->rows)) 144 ThrowImageException(OptionError,"GeometryDoesNotContainImage"); 145 page=(*geometry); 146 if ((page.x+(ssize_t) page.width) > (ssize_t) image->columns) 147 page.width=image->columns-page.x; 148 if ((page.y+(ssize_t) page.height) > (ssize_t) image->rows) 149 page.height=image->rows-page.y; 150 if (page.x < 0) 151 { 152 page.width+=page.x; 153 page.x=0; 154 } 155 if (page.y < 0) 156 { 157 page.height+=page.y; 158 page.y=0; 159 } 160 161 if ((page.width == 0) || (page.height == 0)) 162 ThrowImageException(OptionError,"GeometryDimensionsAreZero"); 163 /* 164 Initialize crop image attributes. 165 */ 166 bitmap.bmType = 0; 167 bitmap.bmWidth = (LONG) page.width; 168 bitmap.bmHeight = (LONG) page.height; 169 bitmap.bmWidthBytes = bitmap.bmWidth * 4; 170 bitmap.bmPlanes = 1; 171 bitmap.bmBitsPixel = 32; 172 bitmap.bmBits = NULL; 173 174 bitmap_bitsH=(HANDLE) GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE,page.width* 175 page.height*bitmap.bmBitsPixel); 176 if (bitmap_bitsH == NULL) 177 return(NULL); 178 bitmap_bits=(RGBQUAD *) GlobalLock((HGLOBAL) bitmap_bitsH); 179 if ( bitmap.bmBits == NULL ) 180 bitmap.bmBits = bitmap_bits; 181 if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse) 182 SetImageColorspace(image,sRGBColorspace,exception); 183 /* 184 Extract crop image. 185 */ 186 q=bitmap_bits; 187 for (y=0; y < (ssize_t) page.height; y++) 188 { 189 register ssize_t 190 x; 191 192 p=GetVirtualPixels(image,page.x,page.y+y,page.width,1,exception); 193 if (p == (const Quantum *) NULL) 194 break; 195 196 /* Transfer pixels, scaling to Quantum */ 197 for( x=(ssize_t) page.width ; x> 0 ; x-- ) 198 { 199 q->rgbRed = ScaleQuantumToChar(GetPixelRed(image,p)); 200 q->rgbGreen = ScaleQuantumToChar(GetPixelGreen(image,p)); 201 q->rgbBlue = ScaleQuantumToChar(GetPixelBlue(image,p)); 202 q->rgbReserved = 0; 203 p+=GetPixelChannels(image); 204 q++; 205 } 206 proceed=SetImageProgress(image,CropImageTag,y,page.height); 207 if (proceed == MagickFalse) 208 break; 209 } 210 if (y < (ssize_t) page.height) 211 { 212 GlobalUnlock((HGLOBAL) bitmap_bitsH); 213 GlobalFree((HGLOBAL) bitmap_bitsH); 214 return((void *) NULL); 215 } 216 bitmap.bmBits=bitmap_bits; 217 bitmapH=CreateBitmapIndirect(&bitmap); 218 GlobalUnlock((HGLOBAL) bitmap_bitsH); 219 GlobalFree((HGLOBAL) bitmap_bitsH); 220 return((void *) bitmapH); 221} 222 223/* 224%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 225% % 226% % 227% % 228% I s M a g i c k C o n f l i c t % 229% % 230% % 231% % 232%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 233% 234% IsMagickConflict() returns true if the image format conflicts with a logical 235% drive (.e.g. X:). 236% 237% The format of the IsMagickConflict method is: 238% 239% MagickBooleanType IsMagickConflict(const char *magick) 240% 241% A description of each parameter follows: 242% 243% o magick: Specifies the image format. 244% 245*/ 246MagickExport MagickBooleanType NTIsMagickConflict(const char *magick) 247{ 248 MagickBooleanType 249 status; 250 251 assert(magick != (char *) NULL); 252 if (strlen(magick) > 1) 253 return(MagickFalse); 254 status=(GetLogicalDrives() & (1 << ((toupper((int) (*magick)))-'A'))) != 0 ? 255 MagickTrue : MagickFalse; 256 return(status); 257} 258 259/* 260%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 261% % 262% % 263% % 264% N T A c q u i r e T y p e C a c h e % 265% % 266% % 267% % 268%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 269% 270% NTAcquireTypeCache() loads a Windows TrueType fonts. 271% 272% The format of the NTAcquireTypeCache method is: 273% 274% MagickBooleanType NTAcquireTypeCache(SplayTreeInfo *type_cache) 275% 276% A description of each parameter follows: 277% 278% o type_cache: A linked list of fonts. 279% 280*/ 281MagickExport MagickBooleanType NTAcquireTypeCache(SplayTreeInfo *type_cache, 282 ExceptionInfo *exception) 283{ 284 HKEY 285 reg_key = (HKEY) INVALID_HANDLE_VALUE; 286 287 LONG 288 res; 289 290 int 291 list_entries = 0; 292 293 char 294 buffer[MagickPathExtent], 295 system_root[MagickPathExtent], 296 font_root[MagickPathExtent]; 297 298 DWORD 299 type, 300 system_root_length; 301 302 MagickBooleanType 303 status; 304 305 /* 306 Try to find the right Windows*\CurrentVersion key, the SystemRoot and 307 then the Fonts key 308 */ 309 res = RegOpenKeyExA (HKEY_LOCAL_MACHINE, 310 "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", 0, KEY_READ, ®_key); 311 if (res == ERROR_SUCCESS) { 312 system_root_length=sizeof(system_root)-1; 313 res = RegQueryValueExA(reg_key,"SystemRoot",NULL, &type, 314 (BYTE*) system_root, &system_root_length); 315 } 316 if (res != ERROR_SUCCESS) { 317 res = RegOpenKeyExA (HKEY_LOCAL_MACHINE, 318 "SOFTWARE\\Microsoft\\Windows\\CurrentVersion", 0, KEY_READ, ®_key); 319 if (res == ERROR_SUCCESS) { 320 system_root_length=sizeof(system_root)-1; 321 res = RegQueryValueExA(reg_key,"SystemRoot",NULL, &type, 322 (BYTE*)system_root, &system_root_length); 323 } 324 } 325 if (res == ERROR_SUCCESS) 326 res = RegOpenKeyExA (reg_key, "Fonts",0, KEY_READ, ®_key); 327 if (res != ERROR_SUCCESS) 328 return(MagickFalse); 329 *font_root='\0'; 330 (void) CopyMagickString(buffer,system_root,MagickPathExtent); 331 (void) ConcatenateMagickString(buffer,"\\fonts\\arial.ttf",MagickPathExtent); 332 if (IsPathAccessible(buffer) != MagickFalse) 333 { 334 (void) CopyMagickString(font_root,system_root,MagickPathExtent); 335 (void) ConcatenateMagickString(font_root,"\\fonts\\",MagickPathExtent); 336 } 337 else 338 { 339 (void) CopyMagickString(font_root,system_root,MagickPathExtent); 340 (void) ConcatenateMagickString(font_root,"\\",MagickPathExtent); 341 } 342 343 { 344 TypeInfo 345 *type_info; 346 347 DWORD 348 registry_index = 0, 349 type, 350 value_data_size, 351 value_name_length; 352 353 char 354 value_data[MagickPathExtent], 355 value_name[MagickPathExtent]; 356 357 res = ERROR_SUCCESS; 358 359 while (res != ERROR_NO_MORE_ITEMS) 360 { 361 char 362 *family_extent, 363 token[MagickPathExtent], 364 *pos, 365 *q; 366 367 value_name_length = sizeof(value_name) - 1; 368 value_data_size = sizeof(value_data) - 1; 369 res = RegEnumValueA ( reg_key, registry_index, value_name, 370 &value_name_length, 0, &type, (BYTE*)value_data, &value_data_size); 371 registry_index++; 372 if (res != ERROR_SUCCESS) 373 continue; 374 if ( (pos = strstr(value_name, " (TrueType)")) == (char*) NULL ) 375 continue; 376 *pos='\0'; /* Remove (TrueType) from string */ 377 378 type_info=(TypeInfo *) AcquireMagickMemory(sizeof(*type_info)); 379 if (type_info == (TypeInfo *) NULL) 380 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed"); 381 (void) ResetMagickMemory(type_info,0,sizeof(TypeInfo)); 382 383 type_info->path=ConstantString("Windows Fonts"); 384 type_info->signature=MagickCoreSignature; 385 386 /* Name */ 387 (void) CopyMagickString(buffer,value_name,MagickPathExtent); 388 for(pos = buffer; *pos != 0 ; pos++) 389 if (*pos == ' ') 390 *pos = '-'; 391 type_info->name=ConstantString(buffer); 392 393 /* Fullname */ 394 type_info->description=ConstantString(value_name); 395 396 /* Format */ 397 type_info->format=ConstantString("truetype"); 398 399 /* Glyphs */ 400 if (strchr(value_data,'\\') != (char *) NULL) 401 (void) CopyMagickString(buffer,value_data,MagickPathExtent); 402 else 403 { 404 (void) CopyMagickString(buffer,font_root,MagickPathExtent); 405 (void) ConcatenateMagickString(buffer,value_data,MagickPathExtent); 406 } 407 408 LocaleLower(buffer); 409 type_info->glyphs=ConstantString(buffer); 410 411 type_info->stretch=NormalStretch; 412 type_info->style=NormalStyle; 413 type_info->weight=400; 414 415 /* Some fonts are known to require special encodings */ 416 if ( (LocaleCompare(type_info->name, "Symbol") == 0 ) || 417 (LocaleCompare(type_info->name, "Wingdings") == 0 ) || 418 (LocaleCompare(type_info->name, "Wingdings-2") == 0 ) || 419 (LocaleCompare(type_info->name, "Wingdings-3") == 0 ) ) 420 type_info->encoding=ConstantString("AppleRoman"); 421 422 family_extent=value_name; 423 424 for (q=value_name; *q != '\0'; ) 425 { 426 GetNextToken(q,(const char **) &q,MagickPathExtent,token); 427 if (*token == '\0') 428 break; 429 430 if (LocaleCompare(token,"Italic") == 0) 431 { 432 type_info->style=ItalicStyle; 433 } 434 435 else if (LocaleCompare(token,"Oblique") == 0) 436 { 437 type_info->style=ObliqueStyle; 438 } 439 440 else if (LocaleCompare(token,"Bold") == 0) 441 { 442 type_info->weight=700; 443 } 444 445 else if (LocaleCompare(token,"Thin") == 0) 446 { 447 type_info->weight=100; 448 } 449 450 else if ( (LocaleCompare(token,"ExtraLight") == 0) || 451 (LocaleCompare(token,"UltraLight") == 0) ) 452 { 453 type_info->weight=200; 454 } 455 456 else if (LocaleCompare(token,"Light") == 0) 457 { 458 type_info->weight=300; 459 } 460 461 else if ( (LocaleCompare(token,"Normal") == 0) || 462 (LocaleCompare(token,"Regular") == 0) ) 463 { 464 type_info->weight=400; 465 } 466 467 else if (LocaleCompare(token,"Medium") == 0) 468 { 469 type_info->weight=500; 470 } 471 472 else if ( (LocaleCompare(token,"SemiBold") == 0) || 473 (LocaleCompare(token,"DemiBold") == 0) ) 474 { 475 type_info->weight=600; 476 } 477 478 else if ( (LocaleCompare(token,"ExtraBold") == 0) || 479 (LocaleCompare(token,"UltraBold") == 0) ) 480 { 481 type_info->weight=800; 482 } 483 484 else if ( (LocaleCompare(token,"Heavy") == 0) || 485 (LocaleCompare(token,"Black") == 0) ) 486 { 487 type_info->weight=900; 488 } 489 490 else if (LocaleCompare(token,"Condensed") == 0) 491 { 492 type_info->stretch = CondensedStretch; 493 } 494 495 else if (LocaleCompare(token,"Expanded") == 0) 496 { 497 type_info->stretch = ExpandedStretch; 498 } 499 500 else if (LocaleCompare(token,"ExtraCondensed") == 0) 501 { 502 type_info->stretch = ExtraCondensedStretch; 503 } 504 505 else if (LocaleCompare(token,"ExtraExpanded") == 0) 506 { 507 type_info->stretch = ExtraExpandedStretch; 508 } 509 510 else if (LocaleCompare(token,"SemiCondensed") == 0) 511 { 512 type_info->stretch = SemiCondensedStretch; 513 } 514 515 else if (LocaleCompare(token,"SemiExpanded") == 0) 516 { 517 type_info->stretch = SemiExpandedStretch; 518 } 519 520 else if (LocaleCompare(token,"UltraCondensed") == 0) 521 { 522 type_info->stretch = UltraCondensedStretch; 523 } 524 525 else if (LocaleCompare(token,"UltraExpanded") == 0) 526 { 527 type_info->stretch = UltraExpandedStretch; 528 } 529 530 else 531 { 532 family_extent=q; 533 } 534 } 535 536 (void) CopyMagickString(buffer,value_name,family_extent-value_name+1); 537 StripString(buffer); 538 type_info->family=ConstantString(buffer); 539 540 list_entries++; 541 status=AddValueToSplayTree(type_cache,type_info->name,type_info); 542 if (status == MagickFalse) 543 (void) ThrowMagickException(exception,GetMagickModule(), 544 ResourceLimitError,"MemoryAllocationFailed","`%s'",type_info->name); 545 } 546 } 547 RegCloseKey ( reg_key ); 548 return(MagickTrue); 549} 550 551/* 552%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 553% % 554% % 555% % 556% I m a g e T o H B i t m a p % 557% % 558% % 559% % 560%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 561% 562% ImageToHBITMAP() creates a Windows HBITMAP from an image. 563% 564% The format of the ImageToHBITMAP method is: 565% 566% HBITMAP ImageToHBITMAP(Image *image,Exceptioninfo *exception) 567% 568% A description of each parameter follows: 569% 570% o image: the image to convert. 571% 572*/ 573MagickExport void *ImageToHBITMAP(Image *image,ExceptionInfo *exception) 574{ 575 BITMAP 576 bitmap; 577 578 HANDLE 579 bitmap_bitsH; 580 581 HBITMAP 582 bitmapH; 583 584 register ssize_t 585 x; 586 587 register const Quantum 588 *p; 589 590 register RGBQUAD 591 *q; 592 593 RGBQUAD 594 *bitmap_bits; 595 596 size_t 597 length; 598 599 ssize_t 600 y; 601 602 (void) ResetMagickMemory(&bitmap,0,sizeof(bitmap)); 603 bitmap.bmType=0; 604 bitmap.bmWidth=(LONG) image->columns; 605 bitmap.bmHeight=(LONG) image->rows; 606 bitmap.bmWidthBytes=4*bitmap.bmWidth; 607 bitmap.bmPlanes=1; 608 bitmap.bmBitsPixel=32; 609 bitmap.bmBits=NULL; 610 length=bitmap.bmWidthBytes*bitmap.bmHeight; 611 bitmap_bitsH=(HANDLE) GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE,length); 612 if (bitmap_bitsH == NULL) 613 { 614 char 615 *message; 616 617 message=GetExceptionMessage(errno); 618 (void) ThrowMagickException(exception,GetMagickModule(), 619 ResourceLimitError,"MemoryAllocationFailed","`%s'",message); 620 message=DestroyString(message); 621 return(NULL); 622 } 623 bitmap_bits=(RGBQUAD *) GlobalLock((HGLOBAL) bitmap_bitsH); 624 q=bitmap_bits; 625 if (bitmap.bmBits == NULL) 626 bitmap.bmBits=bitmap_bits; 627 (void) SetImageColorspace(image,sRGBColorspace,exception); 628 for (y=0; y < (ssize_t) image->rows; y++) 629 { 630 p=GetVirtualPixels(image,0,y,image->columns,1,exception); 631 if (p == (const Quantum *) NULL) 632 break; 633 for (x=0; x < (ssize_t) image->columns; x++) 634 { 635 q->rgbRed=ScaleQuantumToChar(GetPixelRed(image,p)); 636 q->rgbGreen=ScaleQuantumToChar(GetPixelGreen(image,p)); 637 q->rgbBlue=ScaleQuantumToChar(GetPixelBlue(image,p)); 638 q->rgbReserved=0; 639 p+=GetPixelChannels(image); 640 q++; 641 } 642 } 643 bitmap.bmBits=bitmap_bits; 644 bitmapH=CreateBitmapIndirect(&bitmap); 645 if (bitmapH == NULL) 646 { 647 char 648 *message; 649 650 message=GetExceptionMessage(errno); 651 (void) ThrowMagickException(exception,GetMagickModule(), 652 ResourceLimitError,"MemoryAllocationFailed","`%s'",message); 653 message=DestroyString(message); 654 } 655 GlobalUnlock((HGLOBAL) bitmap_bitsH); 656 GlobalFree((HGLOBAL) bitmap_bitsH); 657 return((void *) bitmapH); 658} 659 660#endif 661