Home | History | Annotate | Download | only in MagickCore
      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, &reg_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, &reg_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, &reg_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