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