blob: 47730a9289ccfed7ffe192bb5cf9280a1e946181 [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% %
cristy7e41fe82010-12-04 23:12:08 +000021% Copyright 1999-2011 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*/
cristy4c08aed2011-07-01 19:47:50 +000043#include "MagickCore/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>
cristy4c08aed2011-07-01 19:47:50 +000048#include "MagickCore/cache.h"
49#include "MagickCore/colorspace.h"
cristy6a566122011-07-07 00:12:37 +000050#include "MagickCore/colorspace-private.h"
cristy4c08aed2011-07-01 19:47:50 +000051#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"
cristy9fae3312011-08-05 14:18:31 +000058#include "MagickCore/pixel-accessor.h"
cristy4c08aed2011-07-01 19:47:50 +000059#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"
cristy3ed852e2009-09-05 21:47:34 +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
cristy9d314ff2011-03-09 01:30:28 +0000102 BITMAP
103 bitmap;
104
105 HBITMAP
106 bitmapH;
107
108 HANDLE
109 bitmap_bitsH;
cristy3ed852e2009-09-05 21:47:34 +0000110
111 MagickBooleanType
112 proceed;
113
114 RectangleInfo
115 page;
116
cristy4c08aed2011-07-01 19:47:50 +0000117 register const Quantum
cristy3ed852e2009-09-05 21:47:34 +0000118 *p;
119
cristy3ed852e2009-09-05 21:47:34 +0000120 register RGBQUAD
121 *q;
122
123 RGBQUAD
124 *bitmap_bits;
125
cristy9d314ff2011-03-09 01:30:28 +0000126 ssize_t
127 y;
128
cristy3ed852e2009-09-05 21:47:34 +0000129 /*
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);
cristybb503372010-05-27 20:51:26 +0000139 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))
cristy3ed852e2009-09-05 21:47:34 +0000143 ThrowImageException(OptionError,"GeometryDoesNotContainImage");
144 page=(*geometry);
cristybb503372010-05-27 20:51:26 +0000145 if ((page.x+(ssize_t) page.width) > (ssize_t) image->columns)
cristy3ed852e2009-09-05 21:47:34 +0000146 page.width=image->columns-page.x;
cristybb503372010-05-27 20:51:26 +0000147 if ((page.y+(ssize_t) page.height) > (ssize_t) image->rows)
cristy3ed852e2009-09-05 21:47:34 +0000148 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;
cristyeaedf062010-05-29 22:36:02 +0000166 bitmap.bmWidth = (LONG) page.width;
167 bitmap.bmHeight = (LONG) page.height;
cristy3ed852e2009-09-05 21:47:34 +0000168 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;
cristy510d06a2011-07-06 23:43:54 +0000180 if (IsRGBColorspace(image->colorspace) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000181 TransformImageColorspace(image,RGBColorspace);
182 /*
183 Extract crop image.
184 */
185 q=bitmap_bits;
cristybb503372010-05-27 20:51:26 +0000186 for (y=0; y < (ssize_t) page.height; y++)
cristy3ed852e2009-09-05 21:47:34 +0000187 {
188 p=GetVirtualPixels(image,page.x,page.y+y,page.width,1,exception);
cristy4c08aed2011-07-01 19:47:50 +0000189 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000190 break;
191
192#if MAGICKCORE_QUANTUM_DEPTH == 8
193 /* Form of PixelPacket is identical to RGBQUAD when MAGICKCORE_QUANTUM_DEPTH==8 */
194 CopyMagickMemory((void*)q,(const void*)p,page.width*sizeof(PixelPacket));
195 q += page.width;
196
197#else /* 16 or 32 bit Quantum */
198 {
cristybb503372010-05-27 20:51:26 +0000199 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000200 x;
201
202 /* Transfer pixels, scaling to Quantum */
cristyeaedf062010-05-29 22:36:02 +0000203 for( x=(ssize_t) page.width ; x> 0 ; x-- )
cristy3ed852e2009-09-05 21:47:34 +0000204 {
cristy4c08aed2011-07-01 19:47:50 +0000205 q->rgbRed = ScaleQuantumToChar(GetPixelRed(image,p));
206 q->rgbGreen = ScaleQuantumToChar(GetPixelGreen(image,p));
207 q->rgbBlue = ScaleQuantumToChar(GetPixelBlue(image,p));
cristy3ed852e2009-09-05 21:47:34 +0000208 q->rgbReserved = 0;
209 ++q;
210 ++p;
211 }
212 }
213#endif
214 proceed=SetImageProgress(image,CropImageTag,y,page.height);
215 if (proceed == MagickFalse)
216 break;
217 }
cristybb503372010-05-27 20:51:26 +0000218 if (y < (ssize_t) page.height)
cristy3ed852e2009-09-05 21:47:34 +0000219 {
220 GlobalUnlock((HGLOBAL) bitmap_bitsH);
221 GlobalFree((HGLOBAL) bitmap_bitsH);
222 return((void *) NULL);
223 }
224 bitmap.bmBits=bitmap_bits;
225 bitmapH=CreateBitmapIndirect(&bitmap);
226 GlobalUnlock((HGLOBAL) bitmap_bitsH);
227 GlobalFree((HGLOBAL) bitmap_bitsH);
228 return((void *) bitmapH);
229}
230
231/*
232%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
233% %
234% %
235% %
236% I s M a g i c k C o n f l i c t %
237% %
238% %
239% %
240%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
241%
242% IsMagickConflict() returns true if the image format conflicts with a logical
243% drive (.e.g. X:).
244%
245% The format of the IsMagickConflict method is:
246%
247% MagickBooleanType IsMagickConflict(const char *magick)
248%
249% A description of each parameter follows:
250%
251% o magick: Specifies the image format.
252%
253*/
254MagickExport MagickBooleanType NTIsMagickConflict(const char *magick)
255{
256 MagickBooleanType
257 status;
258
259 assert(magick != (char *) NULL);
260 if (strlen(magick) > 1)
261 return(MagickFalse);
262 status=(GetLogicalDrives() & (1 << ((toupper((int) (*magick)))-'A'))) != 0 ?
263 MagickTrue : MagickFalse;
264 return(status);
265}
266
267/*
268%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
269% %
270% %
271% %
272+ N T G e t T y pe L i s t %
273% %
274% %
275% %
276%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
277%
278% NTLoadTypeLists() loads a Windows TrueType fonts.
279%
280% The format of the NTLoadTypeLists method is:
281%
282% MagickBooleanType NTLoadTypeLists(SplayTreeInfo *type_list)
283%
284% A description of each parameter follows:
285%
286% o type_list: A linked list of fonts.
287%
288*/
289MagickExport MagickBooleanType NTLoadTypeLists(SplayTreeInfo *type_list,
290 ExceptionInfo *exception)
291{
292 HKEY
293 reg_key = (HKEY) INVALID_HANDLE_VALUE;
294
295 LONG
296 res;
297
298
299 int
300 list_entries = 0;
301
302 char
303 buffer[MaxTextExtent],
304 system_root[MaxTextExtent],
305 font_root[MaxTextExtent];
306
307 DWORD
308 type,
309 system_root_length;
310
311 MagickBooleanType
312 status;
313
314 /*
315 Try to find the right Windows*\CurrentVersion key, the SystemRoot and
316 then the Fonts key
317 */
318 res = RegOpenKeyExA (HKEY_LOCAL_MACHINE,
319 "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", 0, KEY_READ, &reg_key);
320 if (res == ERROR_SUCCESS) {
321 system_root_length=sizeof(system_root)-1;
322 res = RegQueryValueExA(reg_key,"SystemRoot",NULL, &type,
323 (BYTE*) system_root, &system_root_length);
324 }
325 if (res != ERROR_SUCCESS) {
326 res = RegOpenKeyExA (HKEY_LOCAL_MACHINE,
327 "SOFTWARE\\Microsoft\\Windows\\CurrentVersion", 0, KEY_READ, &reg_key);
328 if (res == ERROR_SUCCESS) {
329 system_root_length=sizeof(system_root)-1;
330 res = RegQueryValueExA(reg_key,"SystemRoot",NULL, &type,
331 (BYTE*)system_root, &system_root_length);
332 }
333 }
334 if (res == ERROR_SUCCESS)
335 res = RegOpenKeyExA (reg_key, "Fonts",0, KEY_READ, &reg_key);
336 if (res != ERROR_SUCCESS)
337 return(MagickFalse);
338 *font_root='\0';
339 (void) CopyMagickString(buffer,system_root,MaxTextExtent);
340 (void) ConcatenateMagickString(buffer,"\\fonts\\arial.ttf",MaxTextExtent);
341 if (IsPathAccessible(buffer) != MagickFalse)
342 {
343 (void) CopyMagickString(font_root,system_root,MaxTextExtent);
344 (void) ConcatenateMagickString(font_root,"\\fonts\\",MaxTextExtent);
345 }
346 else
347 {
348 (void) CopyMagickString(font_root,system_root,MaxTextExtent);
349 (void) ConcatenateMagickString(font_root,"\\",MaxTextExtent);
350 }
351
352 {
353 TypeInfo
354 *type_info;
355
356 DWORD
357 registry_index = 0,
358 type,
359 value_data_size,
360 value_name_length;
361
362 char
363 value_data[MaxTextExtent],
364 value_name[MaxTextExtent];
365
366 res = ERROR_SUCCESS;
367
368 while (res != ERROR_NO_MORE_ITEMS)
369 {
370 char
371 *family_extent,
372 token[MaxTextExtent],
373 *pos,
374 *q;
375
376 value_name_length = sizeof(value_name) - 1;
377 value_data_size = sizeof(value_data) - 1;
378 res = RegEnumValueA ( reg_key, registry_index, value_name,
379 &value_name_length, 0, &type, (BYTE*)value_data, &value_data_size);
380 registry_index++;
381 if (res != ERROR_SUCCESS)
382 continue;
383 if ( (pos = strstr(value_name, " (TrueType)")) == (char*) NULL )
384 continue;
385 *pos='\0'; /* Remove (TrueType) from string */
386
cristy73bd4a52010-10-05 11:24:23 +0000387 type_info=(TypeInfo *) AcquireMagickMemory(sizeof(*type_info));
cristy3ed852e2009-09-05 21:47:34 +0000388 if (type_info == (TypeInfo *) NULL)
389 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
390 (void) ResetMagickMemory(type_info,0,sizeof(TypeInfo));
391
392 type_info->path=ConstantString("Windows Fonts");
393 type_info->signature=MagickSignature;
394
395 /* Name */
396 (void) CopyMagickString(buffer,value_name,MaxTextExtent);
397 for(pos = buffer; *pos != 0 ; pos++)
398 if (*pos == ' ')
399 *pos = '-';
400 type_info->name=ConstantString(buffer);
401
402 /* Fullname */
403 type_info->description=ConstantString(value_name);
404
405 /* Format */
406 type_info->format=ConstantString("truetype");
407
408 /* Glyphs */
409 if (strchr(value_data,'\\') != (char *) NULL)
410 (void) CopyMagickString(buffer,value_data,MaxTextExtent);
411 else
412 {
413 (void) CopyMagickString(buffer,font_root,MaxTextExtent);
414 (void) ConcatenateMagickString(buffer,value_data,MaxTextExtent);
415 }
416
417 LocaleLower(buffer);
418 type_info->glyphs=ConstantString(buffer);
419
420 type_info->stretch=NormalStretch;
421 type_info->style=NormalStyle;
422 type_info->weight=400;
423
424 /* Some fonts are known to require special encodings */
425 if ( (LocaleCompare(type_info->name, "Symbol") == 0 ) ||
426 (LocaleCompare(type_info->name, "Wingdings") == 0 ) ||
427 (LocaleCompare(type_info->name, "Wingdings-2") == 0 ) ||
428 (LocaleCompare(type_info->name, "Wingdings-3") == 0 ) )
429 type_info->encoding=ConstantString("AppleRoman");
430
431 family_extent=value_name;
432
433 for (q=value_name; *q != '\0'; )
434 {
435 GetMagickToken(q,(const char **) &q,token);
436 if (*token == '\0')
437 break;
438
439 if (LocaleCompare(token,"Italic") == 0)
440 {
441 type_info->style=ItalicStyle;
442 }
443
444 else if (LocaleCompare(token,"Oblique") == 0)
445 {
446 type_info->style=ObliqueStyle;
447 }
448
449 else if (LocaleCompare(token,"Bold") == 0)
450 {
451 type_info->weight=700;
452 }
453
454 else if (LocaleCompare(token,"Thin") == 0)
455 {
456 type_info->weight=100;
457 }
458
459 else if ( (LocaleCompare(token,"ExtraLight") == 0) ||
460 (LocaleCompare(token,"UltraLight") == 0) )
461 {
462 type_info->weight=200;
463 }
464
465 else if (LocaleCompare(token,"Light") == 0)
466 {
467 type_info->weight=300;
468 }
469
470 else if ( (LocaleCompare(token,"Normal") == 0) ||
471 (LocaleCompare(token,"Regular") == 0) )
472 {
473 type_info->weight=400;
474 }
475
476 else if (LocaleCompare(token,"Medium") == 0)
477 {
478 type_info->weight=500;
479 }
480
481 else if ( (LocaleCompare(token,"SemiBold") == 0) ||
482 (LocaleCompare(token,"DemiBold") == 0) )
483 {
484 type_info->weight=600;
485 }
486
487 else if ( (LocaleCompare(token,"ExtraBold") == 0) ||
488 (LocaleCompare(token,"UltraBold") == 0) )
489 {
490 type_info->weight=800;
491 }
492
493 else if ( (LocaleCompare(token,"Heavy") == 0) ||
494 (LocaleCompare(token,"Black") == 0) )
495 {
496 type_info->weight=900;
497 }
498
499 else if (LocaleCompare(token,"Condensed") == 0)
500 {
501 type_info->stretch = CondensedStretch;
502 }
503
504 else if (LocaleCompare(token,"Expanded") == 0)
505 {
506 type_info->stretch = ExpandedStretch;
507 }
508
509 else if (LocaleCompare(token,"ExtraCondensed") == 0)
510 {
511 type_info->stretch = ExtraCondensedStretch;
512 }
513
514 else if (LocaleCompare(token,"ExtraExpanded") == 0)
515 {
516 type_info->stretch = ExtraExpandedStretch;
517 }
518
519 else if (LocaleCompare(token,"SemiCondensed") == 0)
520 {
521 type_info->stretch = SemiCondensedStretch;
522 }
523
524 else if (LocaleCompare(token,"SemiExpanded") == 0)
525 {
526 type_info->stretch = SemiExpandedStretch;
527 }
528
529 else if (LocaleCompare(token,"UltraCondensed") == 0)
530 {
531 type_info->stretch = UltraCondensedStretch;
532 }
533
534 else if (LocaleCompare(token,"UltraExpanded") == 0)
535 {
536 type_info->stretch = UltraExpandedStretch;
537 }
538
539 else
540 {
541 family_extent=q;
542 }
543 }
544
545 (void) CopyMagickString(buffer,value_name,family_extent-value_name+1);
546 StripString(buffer);
547 type_info->family=ConstantString(buffer);
548
549 list_entries++;
550 status=AddValueToSplayTree(type_list,ConstantString(type_info->name),
551 type_info);
552 if (status == MagickFalse)
553 (void) ThrowMagickException(exception,GetMagickModule(),
554 ResourceLimitError,"MemoryAllocationFailed","`%s'",type_info->name);
555 }
556 }
557 RegCloseKey ( reg_key );
558 return(MagickTrue);
559}
560
561/*
562%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
563% %
564% %
565% %
566% I m a g e T o H B i t m a p %
567% %
568% %
569% %
570%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
571%
572% ImageToHBITMAP() creates a Windows HBITMAP from an image.
573%
574% The format of the ImageToHBITMAP method is:
575%
576% HBITMAP ImageToHBITMAP(Image *image)
577%
578% A description of each parameter follows:
579%
580% o image: the image to convert.
581%
582*/
583MagickExport void *ImageToHBITMAP(Image *image)
584{
585 BITMAP
586 bitmap;
587
588 ExceptionInfo
589 *exception;
590
591 HANDLE
592 bitmap_bitsH;
593
594 HBITMAP
595 bitmapH;
596
cristybb503372010-05-27 20:51:26 +0000597 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000598 x;
599
cristy4c08aed2011-07-01 19:47:50 +0000600 register const Quantum
cristy3ed852e2009-09-05 21:47:34 +0000601 *p;
602
603 register RGBQUAD
604 *q;
605
606 RGBQUAD
607 *bitmap_bits;
608
609 size_t
610 length;
611
cristy9d314ff2011-03-09 01:30:28 +0000612 ssize_t
613 y;
614
cristy3ed852e2009-09-05 21:47:34 +0000615 (void) ResetMagickMemory(&bitmap,0,sizeof(bitmap));
616 bitmap.bmType=0;
cristyeaedf062010-05-29 22:36:02 +0000617 bitmap.bmWidth=(LONG) image->columns;
618 bitmap.bmHeight=(LONG) image->rows;
cristy3ed852e2009-09-05 21:47:34 +0000619 bitmap.bmWidthBytes=4*bitmap.bmWidth;
620 bitmap.bmPlanes=1;
621 bitmap.bmBitsPixel=32;
622 bitmap.bmBits=NULL;
623 length=bitmap.bmWidthBytes*bitmap.bmHeight;
624 bitmap_bitsH=(HANDLE) GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE,length);
625 if (bitmap_bitsH == NULL)
626 {
627 char
628 *message;
629
630 message=GetExceptionMessage(errno);
631 (void) ThrowMagickException(&image->exception,GetMagickModule(),
632 ResourceLimitError,"MemoryAllocationFailed","`%s'",message);
633 message=DestroyString(message);
634 return(NULL);
635 }
636 bitmap_bits=(RGBQUAD *) GlobalLock((HGLOBAL) bitmap_bitsH);
637 q=bitmap_bits;
638 if (bitmap.bmBits == NULL)
639 bitmap.bmBits=bitmap_bits;
640 (void) TransformImageColorspace(image,RGBColorspace);
641 exception=(&image->exception);
cristybb503372010-05-27 20:51:26 +0000642 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000643 {
644 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +0000645 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000646 break;
cristybb503372010-05-27 20:51:26 +0000647 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000648 {
cristy4c08aed2011-07-01 19:47:50 +0000649 q->rgbRed=ScaleQuantumToChar(GetPixelRed(image,p));
650 q->rgbGreen=ScaleQuantumToChar(GetPixelGreen(image,p));
651 q->rgbBlue=ScaleQuantumToChar(GetPixelBlue(image,p));
cristy3ed852e2009-09-05 21:47:34 +0000652 q->rgbReserved=0;
cristyed231572011-07-14 02:18:59 +0000653 p+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000654 q++;
655 }
656 }
657 bitmap.bmBits=bitmap_bits;
658 bitmapH=CreateBitmapIndirect(&bitmap);
659 if (bitmapH == NULL)
660 {
661 char
662 *message;
663
664 message=GetExceptionMessage(errno);
665 (void) ThrowMagickException(&image->exception,GetMagickModule(),
666 ResourceLimitError,"MemoryAllocationFailed","`%s'",message);
667 message=DestroyString(message);
668 }
669 GlobalUnlock((HGLOBAL) bitmap_bitsH);
670 GlobalFree((HGLOBAL) bitmap_bitsH);
671 return((void *) bitmapH);
672}
673
674#endif