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