blob: 69b87ad68729d62143d549a7ef3a92f96354f817 [file] [log] [blame]
cristyf7836bf2012-02-20 16:32:47 +00001/*
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% John Cristy %
18% December 1996 %
19% %
20% %
21% Copyright 1999-2012 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*/
cristy309042f2012-02-20 18:59:35 +000043#include "MagickCore/studio.h"
cristyf7836bf2012-02-20 16:32:47 +000044#if defined(MAGICKCORE_WINDOWS_SUPPORT) || defined(__CYGWIN__)
45#define WIN32_LEAN_AND_MEAN
46#define VC_EXTRALEAN
47#include <windows.h>
cristy309042f2012-02-20 18:59:35 +000048#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/pixel-accessor.h"
59#include "MagickCore/quantum.h"
60#include "MagickCore/string_.h"
61#include "MagickCore/token.h"
62#include "MagickCore/splay-tree.h"
63#include "MagickCore/utility.h"
64#include "MagickCore/nt-feature.h"
cristyf7836bf2012-02-20 16:32:47 +000065
66/*
67%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
68% %
69% %
70% %
71% C r o p I m a g e T o H B i t m a p %
72% %
73% %
74% %
75%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
76%
77% CropImageToHBITMAP() extracts a specified region of the image and returns
78% it as a Windows HBITMAP. While the same functionality can be accomplished by
79% invoking CropImage() followed by ImageToHBITMAP(), this method is more
80% efficient since it copies pixels directly to the HBITMAP.
81%
82% The format of the CropImageToHBITMAP method is:
83%
84% HBITMAP CropImageToHBITMAP(Image* image,const RectangleInfo *geometry,
85% ExceptionInfo *exception)
86%
87% A description of each parameter follows:
88%
89% o image: the image.
90%
91% o geometry: Define the region of the image to crop with members
92% x, y, width, and height.
93%
94% o exception: return any errors or warnings in this structure.
95%
96*/
97MagickExport void *CropImageToHBITMAP(Image *image,
98 const RectangleInfo *geometry,ExceptionInfo *exception)
99{
100#define CropImageTag "Crop/Image"
101
102 BITMAP
103 bitmap;
104
105 HBITMAP
106 bitmapH;
107
108 HANDLE
109 bitmap_bitsH;
110
111 MagickBooleanType
112 proceed;
113
114 RectangleInfo
115 page;
116
cristy309042f2012-02-20 18:59:35 +0000117 register const Quantum
cristyf7836bf2012-02-20 16:32:47 +0000118 *p;
119
120 register RGBQUAD
121 *q;
122
123 RGBQUAD
124 *bitmap_bits;
125
126 ssize_t
127 y;
128
129 /*
130 Check crop geometry.
131 */
132 assert(image != (const Image *) NULL);
133 assert(image->signature == MagickSignature);
134 if (image->debug != MagickFalse)
135 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
136 assert(geometry != (const RectangleInfo *) NULL);
137 assert(exception != (ExceptionInfo *) NULL);
138 assert(exception->signature == MagickSignature);
139 if (((geometry->x+(ssize_t) geometry->width) < 0) ||
140 ((geometry->y+(ssize_t) geometry->height) < 0) ||
141 (geometry->x >= (ssize_t) image->columns) ||
142 (geometry->y >= (ssize_t) image->rows))
143 ThrowImageException(OptionError,"GeometryDoesNotContainImage");
144 page=(*geometry);
145 if ((page.x+(ssize_t) page.width) > (ssize_t) image->columns)
146 page.width=image->columns-page.x;
147 if ((page.y+(ssize_t) page.height) > (ssize_t) image->rows)
148 page.height=image->rows-page.y;
149 if (page.x < 0)
150 {
151 page.width+=page.x;
152 page.x=0;
153 }
154 if (page.y < 0)
155 {
156 page.height+=page.y;
157 page.y=0;
158 }
159
160 if ((page.width == 0) || (page.height == 0))
161 ThrowImageException(OptionError,"GeometryDimensionsAreZero");
162 /*
163 Initialize crop image attributes.
164 */
165 bitmap.bmType = 0;
166 bitmap.bmWidth = (LONG) page.width;
167 bitmap.bmHeight = (LONG) page.height;
168 bitmap.bmWidthBytes = bitmap.bmWidth * 4;
169 bitmap.bmPlanes = 1;
170 bitmap.bmBitsPixel = 32;
171 bitmap.bmBits = NULL;
172
173 bitmap_bitsH=(HANDLE) GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE,page.width*
174 page.height*bitmap.bmBitsPixel);
175 if (bitmap_bitsH == NULL)
176 return(NULL);
177 bitmap_bits=(RGBQUAD *) GlobalLock((HGLOBAL) bitmap_bitsH);
178 if ( bitmap.bmBits == NULL )
179 bitmap.bmBits = bitmap_bits;
180 if (IsRGBColorspace(image->colorspace) == MagickFalse)
cristy309042f2012-02-20 18:59:35 +0000181 TransformImageColorspace(image,sRGBColorspace,exception);
cristyf7836bf2012-02-20 16:32:47 +0000182 /*
183 Extract crop image.
184 */
185 q=bitmap_bits;
186 for (y=0; y < (ssize_t) page.height; y++)
187 {
cristy309042f2012-02-20 18:59:35 +0000188 register ssize_t
189 x;
190
cristyf7836bf2012-02-20 16:32:47 +0000191 p=GetVirtualPixels(image,page.x,page.y+y,page.width,1,exception);
cristy309042f2012-02-20 18:59:35 +0000192 if (p == (const Quantum *) NULL)
cristyf7836bf2012-02-20 16:32:47 +0000193 break;
194
cristy309042f2012-02-20 18:59:35 +0000195 /* Transfer pixels, scaling to Quantum */
196 for( x=(ssize_t) page.width ; x> 0 ; x-- )
197 {
198 q->rgbRed = ScaleQuantumToChar(GetPixelRed(image,p));
199 q->rgbGreen = ScaleQuantumToChar(GetPixelGreen(image,p));
200 q->rgbBlue = ScaleQuantumToChar(GetPixelBlue(image,p));
201 q->rgbReserved = 0;
202 p+=GetPixelChannels(image);
203 q++;
204 }
cristyf7836bf2012-02-20 16:32:47 +0000205 proceed=SetImageProgress(image,CropImageTag,y,page.height);
206 if (proceed == MagickFalse)
207 break;
208 }
209 if (y < (ssize_t) page.height)
210 {
211 GlobalUnlock((HGLOBAL) bitmap_bitsH);
212 GlobalFree((HGLOBAL) bitmap_bitsH);
213 return((void *) NULL);
214 }
215 bitmap.bmBits=bitmap_bits;
216 bitmapH=CreateBitmapIndirect(&bitmap);
217 GlobalUnlock((HGLOBAL) bitmap_bitsH);
218 GlobalFree((HGLOBAL) bitmap_bitsH);
219 return((void *) bitmapH);
220}
221
222/*
223%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
224% %
225% %
226% %
227% I s M a g i c k C o n f l i c t %
228% %
229% %
230% %
231%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
232%
233% IsMagickConflict() returns true if the image format conflicts with a logical
234% drive (.e.g. X:).
235%
236% The format of the IsMagickConflict method is:
237%
238% MagickBooleanType IsMagickConflict(const char *magick)
239%
240% A description of each parameter follows:
241%
242% o magick: Specifies the image format.
243%
244*/
245MagickExport MagickBooleanType NTIsMagickConflict(const char *magick)
246{
247 MagickBooleanType
248 status;
249
250 assert(magick != (char *) NULL);
251 if (strlen(magick) > 1)
252 return(MagickFalse);
253 status=(GetLogicalDrives() & (1 << ((toupper((int) (*magick)))-'A'))) != 0 ?
254 MagickTrue : MagickFalse;
255 return(status);
256}
257
258/*
259%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
260% %
261% %
262% %
263+ N T G e t T y pe L i s t %
264% %
265% %
266% %
267%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
268%
269% NTLoadTypeLists() loads a Windows TrueType fonts.
270%
271% The format of the NTLoadTypeLists method is:
272%
273% MagickBooleanType NTLoadTypeLists(SplayTreeInfo *type_list)
274%
275% A description of each parameter follows:
276%
277% o type_list: A linked list of fonts.
278%
279*/
280MagickExport MagickBooleanType NTLoadTypeLists(SplayTreeInfo *type_list,
281 ExceptionInfo *exception)
282{
283 HKEY
284 reg_key = (HKEY) INVALID_HANDLE_VALUE;
285
286 LONG
287 res;
288
289
290 int
291 list_entries = 0;
292
293 char
294 buffer[MaxTextExtent],
295 system_root[MaxTextExtent],
296 font_root[MaxTextExtent];
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, &reg_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, &reg_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, &reg_key);
327 if (res != ERROR_SUCCESS)
328 return(MagickFalse);
329 *font_root='\0';
330 (void) CopyMagickString(buffer,system_root,MaxTextExtent);
331 (void) ConcatenateMagickString(buffer,"\\fonts\\arial.ttf",MaxTextExtent);
332 if (IsPathAccessible(buffer) != MagickFalse)
333 {
334 (void) CopyMagickString(font_root,system_root,MaxTextExtent);
335 (void) ConcatenateMagickString(font_root,"\\fonts\\",MaxTextExtent);
336 }
337 else
338 {
339 (void) CopyMagickString(font_root,system_root,MaxTextExtent);
340 (void) ConcatenateMagickString(font_root,"\\",MaxTextExtent);
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[MaxTextExtent],
355 value_name[MaxTextExtent];
356
357 res = ERROR_SUCCESS;
358
359 while (res != ERROR_NO_MORE_ITEMS)
360 {
361 char
362 *family_extent,
363 token[MaxTextExtent],
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=MagickSignature;
385
386 /* Name */
387 (void) CopyMagickString(buffer,value_name,MaxTextExtent);
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,MaxTextExtent);
402 else
403 {
404 (void) CopyMagickString(buffer,font_root,MaxTextExtent);
405 (void) ConcatenateMagickString(buffer,value_data,MaxTextExtent);
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 GetMagickToken(q,(const char **) &q,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_list,ConstantString(type_info->name),
542 type_info);
543 if (status == MagickFalse)
544 (void) ThrowMagickException(exception,GetMagickModule(),
545 ResourceLimitError,"MemoryAllocationFailed","`%s'",type_info->name);
546 }
547 }
548 RegCloseKey ( reg_key );
549 return(MagickTrue);
550}
551
552/*
553%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
554% %
555% %
556% %
557% I m a g e T o H B i t m a p %
558% %
559% %
560% %
561%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
562%
563% ImageToHBITMAP() creates a Windows HBITMAP from an image.
564%
565% The format of the ImageToHBITMAP method is:
566%
567% HBITMAP ImageToHBITMAP(Image *image,Exceptioninfo *exception)
568%
569% A description of each parameter follows:
570%
571% o image: the image to convert.
572%
573*/
574MagickExport void *ImageToHBITMAP(Image *image,ExceptionInfo *exception)
575{
576 BITMAP
577 bitmap;
578
579 HANDLE
580 bitmap_bitsH;
581
582 HBITMAP
583 bitmapH;
584
585 register ssize_t
586 x;
587
cristy309042f2012-02-20 18:59:35 +0000588 register const Quantum
cristyf7836bf2012-02-20 16:32:47 +0000589 *p;
590
591 register RGBQUAD
592 *q;
593
594 RGBQUAD
595 *bitmap_bits;
596
597 size_t
598 length;
599
600 ssize_t
601 y;
602
603 (void) ResetMagickMemory(&bitmap,0,sizeof(bitmap));
604 bitmap.bmType=0;
605 bitmap.bmWidth=(LONG) image->columns;
606 bitmap.bmHeight=(LONG) image->rows;
607 bitmap.bmWidthBytes=4*bitmap.bmWidth;
608 bitmap.bmPlanes=1;
609 bitmap.bmBitsPixel=32;
610 bitmap.bmBits=NULL;
611 length=bitmap.bmWidthBytes*bitmap.bmHeight;
612 bitmap_bitsH=(HANDLE) GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE,length);
613 if (bitmap_bitsH == NULL)
614 {
615 char
616 *message;
617
618 message=GetExceptionMessage(errno);
619 (void) ThrowMagickException(exception,GetMagickModule(),
620 ResourceLimitError,"MemoryAllocationFailed","`%s'",message);
621 message=DestroyString(message);
622 return(NULL);
623 }
624 bitmap_bits=(RGBQUAD *) GlobalLock((HGLOBAL) bitmap_bitsH);
625 q=bitmap_bits;
626 if (bitmap.bmBits == NULL)
627 bitmap.bmBits=bitmap_bits;
cristy309042f2012-02-20 18:59:35 +0000628 (void) TransformImageColorspace(image,sRGBColorspace,exception);
cristyf7836bf2012-02-20 16:32:47 +0000629 for (y=0; y < (ssize_t) image->rows; y++)
630 {
631 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
cristy309042f2012-02-20 18:59:35 +0000632 if (p == (const Quantum *) NULL)
cristyf7836bf2012-02-20 16:32:47 +0000633 break;
634 for (x=0; x < (ssize_t) image->columns; x++)
635 {
cristy309042f2012-02-20 18:59:35 +0000636 q->rgbRed=ScaleQuantumToChar(GetPixelRed(image,p));
637 q->rgbGreen=ScaleQuantumToChar(GetPixelGreen(image,p));
638 q->rgbBlue=ScaleQuantumToChar(GetPixelBlue(image,p));
cristyf7836bf2012-02-20 16:32:47 +0000639 q->rgbReserved=0;
cristy309042f2012-02-20 18:59:35 +0000640 p+=GetPixelChannels(image);
cristyf7836bf2012-02-20 16:32:47 +0000641 q++;
642 }
643 }
644 bitmap.bmBits=bitmap_bits;
645 bitmapH=CreateBitmapIndirect(&bitmap);
646 if (bitmapH == NULL)
647 {
648 char
649 *message;
650
651 message=GetExceptionMessage(errno);
652 (void) ThrowMagickException(exception,GetMagickModule(),
653 ResourceLimitError,"MemoryAllocationFailed","`%s'",message);
654 message=DestroyString(message);
655 }
656 GlobalUnlock((HGLOBAL) bitmap_bitsH);
657 GlobalFree((HGLOBAL) bitmap_bitsH);
658 return((void *) bitmapH);
659}
660
661#endif