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