rmagick 1.10.1 → 1.11.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of rmagick might be problematic. Click here for more details.

@@ -1,4 +1,4 @@
1
- /* $Id: rminfo.c,v 1.36 2006/01/18 00:23:03 rmagick Exp $ */
1
+ /* $Id: rminfo.c,v 1.37 2006/05/07 21:41:12 rmagick Exp $ */
2
2
  /*============================================================================\
3
3
  | Copyright (C) 2006 by Timothy P. Hunter
4
4
  | Name: rminfo.c
@@ -140,7 +140,7 @@ Info_aset(VALUE self, VALUE format, VALUE key, VALUE value)
140
140
 
141
141
  GetExceptionInfo(&exception);
142
142
  okay = AddDefinitions(info, definitions, &exception);
143
- HANDLE_ERROR
143
+ CHECK_EXCEPTION()
144
144
  if (!okay)
145
145
  {
146
146
  rb_warn("%.60s:%.1024s not defined - AddDefinitions failed.", format_p, key_p);
@@ -408,7 +408,7 @@ Info_define(int argc, VALUE *argv, VALUE self)
408
408
 
409
409
  GetExceptionInfo(&exception);
410
410
  okay = AddDefinitions(info, definitions, &exception);
411
- HANDLE_ERROR
411
+ CHECK_EXCEPTION()
412
412
  if (!okay)
413
413
  {
414
414
  rb_warn("%.*s not defined - AddDefinitions failed.", sizeof(definitions), definitions);
@@ -938,7 +938,7 @@ Info_format_eq(VALUE self, VALUE magick)
938
938
 
939
939
  mgk = STRING_PTR(magick);
940
940
  m = GetMagickInfo(mgk, &exception);
941
- HANDLE_ERROR
941
+ CHECK_EXCEPTION()
942
942
 
943
943
  if (!m)
944
944
  {
@@ -1,4 +1,4 @@
1
- /* $Id: rmmain.c,v 1.111 2006/02/19 17:12:20 rmagick Exp $ */
1
+ /* $Id: rmmain.c,v 1.118 2006/05/07 21:41:12 rmagick Exp $ */
2
2
  /*============================================================================\
3
3
  | Copyright (C) 2006 by Timothy P. Hunter
4
4
  | Name: rmmain.c
@@ -43,7 +43,7 @@ Magick_colors(VALUE class)
43
43
  GetExceptionInfo(&exception);
44
44
 
45
45
  color_ary = GetColorInfoArray(&exception);
46
- HANDLE_ERROR
46
+ CHECK_EXCEPTION()
47
47
 
48
48
  if (rb_block_given_p())
49
49
  {
@@ -86,7 +86,8 @@ Magick_colors(VALUE class)
86
86
  GetExceptionInfo(&exception);
87
87
 
88
88
  color_info_list = GetColorInfoList("*", &number_colors, &exception);
89
- HANDLE_ERROR
89
+ CHECK_EXCEPTION()
90
+
90
91
  #endif
91
92
 
92
93
 
@@ -174,7 +175,8 @@ Magick_fonts(VALUE class)
174
175
 
175
176
  GetExceptionInfo(&exception);
176
177
  type_info = GetTypeInfoList("*", &number_types, &exception);
177
- HANDLE_ERROR
178
+ CHECK_EXCEPTION()
179
+
178
180
  #endif
179
181
 
180
182
  if (rb_block_given_p())
@@ -207,7 +209,7 @@ Magick_fonts(VALUE class)
207
209
  GetExceptionInfo(&exception);
208
210
 
209
211
  type_list = GetTypeInfo("*", &exception);
210
- HANDLE_ERROR
212
+ CHECK_EXCEPTION()
211
213
 
212
214
  // If block, iterate over fonts
213
215
  if (rb_block_given_p())
@@ -307,7 +309,7 @@ Magick_init_formats(VALUE class)
307
309
  // IM 6.1.3 added an exception argument to GetMagickInfoList
308
310
  GetExceptionInfo(&exception);
309
311
  magick_info = GetMagickInfoList("*", &number_formats, &exception);
310
- HANDLE_ERROR
312
+ CHECK_EXCEPTION()
311
313
  #endif
312
314
 
313
315
  for(x = 0; x < number_formats; x++)
@@ -330,7 +332,7 @@ Magick_init_formats(VALUE class)
330
332
 
331
333
  GetExceptionInfo(&exception);
332
334
  m = (MagickInfo *)GetMagickInfo("*", &exception);
333
- HANDLE_ERROR
335
+ CHECK_EXCEPTION()
334
336
 
335
337
  for ( ; m != NULL; m = m->next)
336
338
  {
@@ -342,6 +344,98 @@ Magick_init_formats(VALUE class)
342
344
  #endif
343
345
  }
344
346
 
347
+
348
+ /*
349
+ Method: Magick.limit_resource(resource[, limit])
350
+ Purpose: Get/set resource limits. If a limit is specified the old limit
351
+ is set to the new value. Either way the current/new limit is returned.
352
+ Notes: Don't support "AreaLimit" because GraphicsMagick doesn't support it.
353
+ */
354
+ static VALUE
355
+ Magick_limit_resource(int argc, VALUE *argv, VALUE class)
356
+ {
357
+ #if defined(HAVE_GETMAGICKRESOURCELIMIT)
358
+ volatile VALUE resource, limit;
359
+ ResourceType res = UndefinedResource;
360
+ char *str;
361
+ ID id;
362
+ unsigned long cur_limit;
363
+
364
+ rb_scan_args(argc, argv, "11", &resource, &limit);
365
+
366
+ switch (TYPE(resource))
367
+ {
368
+ case T_NIL:
369
+ return class;
370
+
371
+ case T_SYMBOL:
372
+ id = SYM2ID(resource);
373
+ if (id == rb_intern("memory"))
374
+ {
375
+ res = MemoryResource;
376
+ }
377
+ else if (id == rb_intern("map"))
378
+ {
379
+ res = MapResource;
380
+ }
381
+ else if (id == rb_intern("disk"))
382
+ {
383
+ res = DiskResource;
384
+ }
385
+ else if (id == rb_intern("file"))
386
+ {
387
+ res = FileResource;
388
+ }
389
+ else
390
+ {
391
+ rb_raise(rb_eArgError, "unknown resource: `:%s'", rb_id2name(id));
392
+ }
393
+ break;
394
+
395
+ default:
396
+ str = STRING_PTR(resource);
397
+ if (*str == '\0')
398
+ {
399
+ return class;
400
+ }
401
+ else if (rm_strcasecmp("memory", str) == 0)
402
+ {
403
+ res = MemoryResource;
404
+ }
405
+ else if (rm_strcasecmp("map", str) == 0)
406
+ {
407
+ res = MapResource;
408
+ }
409
+ else if (rm_strcasecmp("disk", str) == 0)
410
+ {
411
+ res = DiskResource;
412
+ }
413
+ else if (rm_strcasecmp("file", str) == 0)
414
+ {
415
+ res = FileResource;
416
+ }
417
+ else
418
+ {
419
+ rb_raise(rb_eArgError, "unknown resource: `%s'", str);
420
+ }
421
+ break;
422
+ }
423
+
424
+ cur_limit = GetMagickResourceLimit(res);
425
+
426
+ if (argc > 1)
427
+ {
428
+ SetMagickResourceLimit(res, NUM2ULONG(limit));
429
+ }
430
+
431
+ return ULONG2NUM(cur_limit);
432
+ #else
433
+ rm_not_implemented();
434
+ return (VALUE)0;
435
+ #endif
436
+ }
437
+
438
+
345
439
  /*
346
440
  This is the exit known to ImageMagick. Retrieve the monitor
347
441
  proc and call it, passing the 3 exit arguments.
@@ -530,6 +624,7 @@ Init_RMagick(void)
530
624
  rb_define_module_function(Module_Magick, "colors", Magick_colors, 0);
531
625
  rb_define_module_function(Module_Magick, "fonts", Magick_fonts, 0);
532
626
  rb_define_module_function(Module_Magick, "init_formats", Magick_init_formats, 0);
627
+ rb_define_module_function(Module_Magick, "limit_resource", Magick_limit_resource, -1);
533
628
  rb_define_module_function(Module_Magick, "set_monitor", Magick_set_monitor, 1);
534
629
  rb_define_module_function(Module_Magick, "set_cache_threshold", Magick_set_cache_threshold, 1);
535
630
  rb_define_module_function(Module_Magick, "set_log_event_mask", Magick_set_log_event_mask, -1);
@@ -659,6 +754,7 @@ Init_RMagick(void)
659
754
  rb_define_method(Class_Image, "composite_affine", Image_composite_affine, 2);
660
755
  rb_define_method(Class_Image, "compress_colormap!", Image_compress_colormap_bang, 0);
661
756
  rb_define_method(Class_Image, "contrast", Image_contrast, -1);
757
+ rb_define_method(Class_Image, "contrast_stretch_channel", Image_contrast_stretch_channel, -1);
662
758
  rb_define_method(Class_Image, "convolve", Image_convolve, 2);
663
759
  rb_define_method(Class_Image, "convolve_channel", Image_convolve_channel, -1);
664
760
  rb_define_method(Class_Image, "copy", Image_copy, 0);
@@ -801,6 +897,7 @@ Init_RMagick(void)
801
897
  rb_define_method(Class_ImageList, "montage", ImageList_montage, 0);
802
898
  rb_define_method(Class_ImageList, "morph", ImageList_morph, 1);
803
899
  rb_define_method(Class_ImageList, "mosaic", ImageList_mosaic, 0);
900
+ rb_define_method(Class_ImageList, "optimize_layers", ImageList_optimize_layers, 1);
804
901
  rb_define_method(Class_ImageList, "quantize", ImageList_quantize, -1);
805
902
  rb_define_method(Class_ImageList, "to_blob", ImageList_to_blob, 0);
806
903
  rb_define_method(Class_ImageList, "write", ImageList_write, 1);
@@ -818,7 +915,7 @@ Init_RMagick(void)
818
915
 
819
916
  DCL_ATTR_WRITER(Draw, affine)
820
917
  DCL_ATTR_WRITER(Draw, align)
821
- DCL_ATTR_WRITER(Draw, border_color)
918
+ DCL_ATTR_WRITER(Draw, border_color)
822
919
  DCL_ATTR_WRITER(Draw, decorate)
823
920
  DCL_ATTR_WRITER(Draw, density)
824
921
  DCL_ATTR_WRITER(Draw, encoding)
@@ -1340,6 +1437,22 @@ Init_RMagick(void)
1340
1437
  ENUMERATOR(PartitionInterlace)
1341
1438
  END_ENUM
1342
1439
 
1440
+ #if defined(HAVE_COMPAREIMAGELAYERS)
1441
+ DEF_ENUM(MagickLayerMethod)
1442
+ ENUMERATOR(UndefinedLayer)
1443
+ ENUMERATOR(CompareAnyLayer)
1444
+ ENUMERATOR(CompareClearLayer)
1445
+ ENUMERATOR(CompareOverlayLayer)
1446
+ ENUMERATOR(OptimizeLayer)
1447
+ ENUMERATOR(OptimizePlusLayer)
1448
+ #if defined(HAVE_COALESCELAYER)
1449
+ // Introduced in IM 6.2.7-0
1450
+ ENUMERATOR(CoalesceLayer)
1451
+ ENUMERATOR(DisposeLayer)
1452
+ #endif
1453
+ END_ENUM
1454
+ #endif
1455
+
1343
1456
  #if defined(HAVE_COMPAREIMAGECHANNELS)
1344
1457
  DEF_ENUM(MetricType)
1345
1458
  ENUMERATOR(UndefinedMetric)
@@ -1662,7 +1775,7 @@ static void version_constants(void)
1662
1775
  rb_define_const(Module_Magick, "Version", str);
1663
1776
 
1664
1777
  sprintf(long_version,
1665
- "This is %s ($Date: 2006/02/19 17:12:20 $) Copyright (C) 2006 by Timothy P. Hunter\n"
1778
+ "This is %s ($Date: 2006/05/07 21:41:12 $) Copyright (C) 2006 by Timothy P. Hunter\n"
1666
1779
  "Built with %s\n"
1667
1780
  "Built for %s\n"
1668
1781
  "Web page: http://rmagick.rubyforge.org\n"
@@ -1,4 +1,4 @@
1
- /* $Id: rmutil.c,v 1.66 2006/01/20 23:59:46 rmagick Exp $ */
1
+ /* $Id: rmutil.c,v 1.75 2006/05/07 23:40:14 rmagick Exp $ */
2
2
  /*============================================================================\
3
3
  | Copyright (C) 2006 by Timothy P. Hunter
4
4
  | Name: rmutil.c
@@ -9,12 +9,13 @@
9
9
  #include "rmagick.h"
10
10
  #include <errno.h>
11
11
 
12
- static const char *Compliance_name(ComplianceType *);
12
+ static const char *ComplianceType_name(ComplianceType *);
13
13
  static const char *StyleType_name(StyleType);
14
14
  static const char *StretchType_name(StretchType);
15
15
  static void Color_Name_to_PixelPacket(PixelPacket *, VALUE);
16
16
  static VALUE Enum_type_values(VALUE);
17
17
  static VALUE Enum_type_inspect(VALUE);
18
+ static void handle_exception(ExceptionInfo *, Image *, ErrorRetention);
18
19
 
19
20
  /*
20
21
  Extern: magick_malloc, magick_free, magick_realloc
@@ -276,6 +277,71 @@ rm_percentage(VALUE arg)
276
277
  }
277
278
 
278
279
 
280
+ /*
281
+ Static: check_num2dbl
282
+ Purpose: return 0 if rb_num2dbl doesn't raise an exception
283
+ */
284
+ static VALUE
285
+ check_num2dbl(VALUE obj)
286
+ {
287
+ rb_num2dbl(obj);
288
+ return INT2FIX(1);
289
+ }
290
+
291
+
292
+ /*
293
+ Static: rescue_not_dbl
294
+ Purpose: called if rb_num2dbl raises an exception
295
+ */
296
+ static VALUE
297
+ rescue_not_dbl(VALUE ignored)
298
+ {
299
+ return INT2FIX(0);
300
+ }
301
+
302
+
303
+ /*
304
+ Extern: rm_check_num2dbl
305
+ Purpose: Return 1 if the object can be converted to a double, 0 otherwise.
306
+ */
307
+ int rm_check_num2dbl(VALUE obj)
308
+ {
309
+ return FIX2INT(rb_rescue(check_num2dbl, obj, rescue_not_dbl, (VALUE)0));
310
+ }
311
+
312
+
313
+ /*
314
+ * Extern: rm_str_to_pct
315
+ * Purpose: Given a string in the form NN% return the corresponding double.
316
+ *
317
+ */
318
+ double rm_str_to_pct(VALUE str)
319
+ {
320
+ long pct;
321
+ char *pct_str, *end;
322
+
323
+ str = rb_rescue(rb_str_to_str, str, rescue_not_str, str);
324
+ pct_str = STRING_PTR(str);
325
+ errno = 0;
326
+ pct = strtol(pct_str, &end, 10);
327
+
328
+ if (errno == ERANGE)
329
+ {
330
+ rb_raise(rb_eRangeError, "`%s' out of range", pct_str);
331
+ }
332
+ if (*end != '%')
333
+ {
334
+ rb_raise(rb_eArgError, "expected percentage, got `%s'", pct_str);
335
+ }
336
+ if (pct < 0L)
337
+ {
338
+ rb_raise(rb_eArgError, "percentages may not be negative (got `%s')", pct_str);
339
+ }
340
+
341
+ return pct / 100.0;
342
+ }
343
+
344
+
279
345
  /*
280
346
  * Extern: rm_fuzz_to_dbl(obj)
281
347
  * Purpose: If the argument is a number, convert it to a double.
@@ -417,7 +483,7 @@ Pixel_from_color(VALUE class, VALUE name)
417
483
 
418
484
  GetExceptionInfo(&exception);
419
485
  okay = QueryColorDatabase(STRING_PTR(name), &pp, &exception);
420
- HANDLE_ERROR
486
+ CHECK_EXCEPTION()
421
487
  if (!okay)
422
488
  {
423
489
  rb_raise(rb_eArgError, "invalid color name: %s", STRING_PTR(name));
@@ -486,7 +552,7 @@ Pixel_to_color(int argc, VALUE *argv, VALUE self)
486
552
  GetExceptionInfo(&exception);
487
553
  (void) QueryColorname(image, pixel, compliance, name, &exception);
488
554
  DestroyImage(image);
489
- HANDLE_ERROR
555
+ CHECK_EXCEPTION()
490
556
 
491
557
  // Always return a string, even if it's ""
492
558
  return rb_str_new2(name);
@@ -912,7 +978,7 @@ PixelPacket_to_Color_Name(Image *image, PixelPacket *color)
912
978
  GetExceptionInfo(&exception);
913
979
 
914
980
  (void) QueryColorname(image, color, X11Compliance, name, &exception);
915
- HANDLE_ERROR_IMG(image)
981
+ CHECK_EXCEPTION()
916
982
 
917
983
  return rb_str_new2(name);
918
984
  }
@@ -1152,7 +1218,7 @@ ComplianceType_new(ComplianceType compliance)
1152
1218
 
1153
1219
  // Turn off undefined bits
1154
1220
  compliance &= (SVGCompliance|X11Compliance|XPMCompliance);
1155
- name = Compliance_name(&compliance);
1221
+ name = ComplianceType_name(&compliance);
1156
1222
  return rm_enum_new(Class_ComplianceType, ID2SYM(rb_intern(name)), INT2FIX(compliance));
1157
1223
  }
1158
1224
 
@@ -1290,7 +1356,7 @@ CompressionType_new(CompressionType ct)
1290
1356
  Purpose: Return the name of a DisposeType enum as a string
1291
1357
  */
1292
1358
  static const char *
1293
- DisposeType_name(type)
1359
+ DisposeType_name(DisposeType type)
1294
1360
  {
1295
1361
  switch(type)
1296
1362
  {
@@ -1367,7 +1433,7 @@ FilterTypes_new(FilterTypes type)
1367
1433
  Purpose: Return the name of a EndianType enum as a string
1368
1434
  */
1369
1435
  static const char *
1370
- EndianType_name(type)
1436
+ EndianType_name(EndianType type)
1371
1437
  {
1372
1438
  switch(type)
1373
1439
  {
@@ -1398,7 +1464,7 @@ EndianType_new(EndianType type)
1398
1464
  Purpose: Return the name of a ImageType enum as a string
1399
1465
  */
1400
1466
  static char *
1401
- ImageType_name(type)
1467
+ ImageType_name(ImageType type)
1402
1468
  { switch(type)
1403
1469
  {
1404
1470
  default:
@@ -1437,7 +1503,7 @@ ImageType_new(ImageType type)
1437
1503
  Purpose: Return the name of a InterlaceType enum as a string
1438
1504
  */
1439
1505
  static const char *
1440
- InterlaceType_name(interlace)
1506
+ InterlaceType_name(InterlaceType interlace)
1441
1507
  {
1442
1508
  switch(interlace)
1443
1509
  {
@@ -1465,13 +1531,47 @@ InterlaceType_new(InterlaceType interlace)
1465
1531
  }
1466
1532
 
1467
1533
 
1534
+ /*
1535
+ External: MagickLayerMethod_new
1536
+ Purpose: Construct an MagickLayerMethod enum object for the specified value.
1537
+ */
1538
+ #if defined(HAVE_COMPAREIMAGELAYERS)
1539
+ static const char *
1540
+ MagickLayerMethod_name(MagickLayerMethod method)
1541
+ {
1542
+ switch(method)
1543
+ {
1544
+ default:
1545
+ ENUM_TO_NAME(UndefinedLayer)
1546
+ ENUM_TO_NAME(CompareAnyLayer)
1547
+ ENUM_TO_NAME(CompareClearLayer)
1548
+ ENUM_TO_NAME(CompareOverlayLayer)
1549
+ ENUM_TO_NAME(OptimizeLayer)
1550
+ ENUM_TO_NAME(OptimizePlusLayer)
1551
+ #if defined(HAVE_COALESCELAYER)
1552
+ ENUM_TO_NAME(CoalesceLayer)
1553
+ ENUM_TO_NAME(DisposeLayer)
1554
+ #endif
1555
+ }
1556
+ }
1557
+
1558
+ VALUE
1559
+ MagickLayerMethod_new(MagickLayerMethod method)
1560
+ {
1561
+ const char *name;
1562
+
1563
+ name = MagickLayerMethod_name(method);
1564
+ return rm_enum_new(Class_MagickLayerMethod, ID2SYM(rb_intern(name)), INT2FIX(method));
1565
+ }
1566
+ #endif
1567
+
1468
1568
 
1469
1569
  /*
1470
1570
  Static: RenderingIntent_name
1471
1571
  Purpose: Return the name of a RenderingIntent enum as a string
1472
1572
  */
1473
1573
  static const char *
1474
- RenderingIntent_name(intent)
1574
+ RenderingIntent_name(RenderingIntent intent)
1475
1575
  {
1476
1576
  switch(intent)
1477
1577
  {
@@ -1506,7 +1606,7 @@ RenderingIntent_new(RenderingIntent intent)
1506
1606
  Purpose: Return the name of a ResolutionType enum as a string
1507
1607
  */
1508
1608
  static const char *
1509
- ResolutionType_name(type)
1609
+ ResolutionType_name(ResolutionType type)
1510
1610
  {
1511
1611
  switch(type)
1512
1612
  {
@@ -1540,7 +1640,7 @@ ResolutionType_new(ResolutionType type)
1540
1640
  Purpose: Return the name of a OrientationType enum as a string
1541
1641
  */
1542
1642
  static const char *
1543
- OrientationType_name(type)
1643
+ OrientationType_name(OrientationType type)
1544
1644
  {
1545
1645
  switch(type)
1546
1646
  {
@@ -1659,7 +1759,7 @@ Color_to_s(VALUE self)
1659
1759
  sprintf(buff, "name=%s, compliance=%s, "
1660
1760
  "color.red=%d, color.green=%d, color.blue=%d, color.opacity=%d ",
1661
1761
  ci.name,
1662
- Compliance_name(&ci.compliance),
1762
+ ComplianceType_name(&ci.compliance),
1663
1763
  ci.color.red, ci.color.green, ci.color.blue, ci.color.opacity);
1664
1764
 
1665
1765
  destroy_ColorInfo(&ci);
@@ -1993,14 +2093,14 @@ Font_from_TypeInfo(TypeInfo *ti)
1993
2093
  volatile VALUE encoding, foundry, format;
1994
2094
 
1995
2095
  name = rb_str_new2(ti->name);
1996
- description = rb_str_new2(ti->description);
1997
2096
  family = rb_str_new2(ti->family);
1998
2097
  style = StyleType_new(ti->style);
1999
2098
  stretch = StretchType_new(ti->stretch);
2000
2099
  weight = INT2NUM(ti->weight);
2001
- encoding = ti->encoding ? rb_str_new2(ti->encoding) : Qnil;
2002
- foundry = ti->foundry ? rb_str_new2(ti->foundry) : Qnil;
2003
- format = ti->format ? rb_str_new2(ti->format) : Qnil;
2100
+ description = ti->description ? rb_str_new2(ti->description) : Qnil;
2101
+ encoding = ti->encoding ? rb_str_new2(ti->encoding) : Qnil;
2102
+ foundry = ti->foundry ? rb_str_new2(ti->foundry) : Qnil;
2103
+ format = ti->format ? rb_str_new2(ti->format) : Qnil;
2004
2104
 
2005
2105
  return rb_funcall(Class_Font, ID_new, 9
2006
2106
  , name, description, family, style
@@ -2288,8 +2388,11 @@ VALUE rm_enum_new(VALUE class, VALUE sym, VALUE val)
2288
2388
  VALUE Enum_alloc(VALUE class)
2289
2389
  {
2290
2390
  MagickEnum *magick_enum;
2391
+ volatile VALUE enumr;
2291
2392
 
2292
- return Data_Make_Struct(class, MagickEnum, NULL, NULL, magick_enum);
2393
+ enumr = Data_Make_Struct(class, MagickEnum, NULL, NULL, magick_enum);
2394
+ OBJ_FREEZE(enumr);
2395
+ return enumr;
2293
2396
  }
2294
2397
 
2295
2398
 
@@ -2311,7 +2414,7 @@ VALUE rm_enum_new(VALUE class, VALUE sym, VALUE val)
2311
2414
  VALUE Enum_new(VALUE class, VALUE sym, VALUE val)
2312
2415
  {
2313
2416
  volatile VALUE new_enum;
2314
- VALUE argv[2];
2417
+ volatile VALUE argv[2];
2315
2418
  MagickEnum *magick_enum;
2316
2419
 
2317
2420
  new_enum = Data_Make_Struct(class, MagickEnum, NULL, NULL, magick_enum);
@@ -2319,6 +2422,7 @@ VALUE Enum_new(VALUE class, VALUE sym, VALUE val)
2319
2422
  argv[1] = val;
2320
2423
 
2321
2424
  rb_obj_call_init(new_enum, 2, argv);
2425
+ OBJ_FREEZE(new_enum);
2322
2426
  return new_enum;
2323
2427
  }
2324
2428
 
@@ -2458,35 +2562,50 @@ static VALUE Enum_type_inspect(VALUE self)
2458
2562
 
2459
2563
 
2460
2564
  /*
2461
- * Method: xxx.each
2462
- * Purpose: singleton iterator over enumerators list
2565
+ * Method: xxx.values
2566
+ * Purpose: Behaves like #each if a block is present, otherwise like #to_a.
2463
2567
  * Notes: defined for each Enum subclass
2464
2568
  */
2465
2569
  static VALUE Enum_type_values(VALUE class)
2466
2570
  {
2467
- volatile VALUE enumerators;
2571
+ volatile VALUE enumerators, copy;
2572
+ volatile VALUE rv;
2468
2573
  int x;
2469
2574
 
2470
2575
  enumerators = rb_cvar_get(class, ID_enumerators);
2471
2576
 
2472
- for (x = 0; x < RARRAY(enumerators)->len; x++)
2577
+ if (rb_block_given_p())
2578
+ {
2579
+ for (x = 0; x < RARRAY(enumerators)->len; x++)
2580
+ {
2581
+ rb_yield(rb_ary_entry(enumerators, x));
2582
+ }
2583
+ rv = class;
2584
+ }
2585
+ else
2473
2586
  {
2474
- rb_yield(rb_ary_entry(enumerators, x));
2587
+ copy = rb_ary_new2(RARRAY(enumerators)->len);
2588
+ for (x = 0; x < RARRAY(enumerators)->len; x++)
2589
+ {
2590
+ rb_ary_push(copy, rb_ary_entry(enumerators, x));
2591
+ }
2592
+ OBJ_FREEZE(copy);
2593
+ rv = copy;
2475
2594
  }
2476
2595
 
2477
- return class;
2596
+ return rv;
2478
2597
  }
2479
2598
 
2480
2599
 
2481
2600
  /*
2482
- Static: Compliance_name
2601
+ Static: ComplianceType_name
2483
2602
  Purpose: Return the string representation of a ComplianceType value
2484
2603
  Notes: xMagick will OR multiple compliance types so we have to
2485
2604
  arbitrarily pick one name. Set the compliance argument
2486
2605
  to the selected value.
2487
2606
  */
2488
2607
  static const char *
2489
- Compliance_name(ComplianceType *c)
2608
+ ComplianceType_name(ComplianceType *c)
2490
2609
  {
2491
2610
  if ((*c & (SVGCompliance|X11Compliance|XPMCompliance))
2492
2611
  == (SVGCompliance|X11Compliance|XPMCompliance))
@@ -2662,7 +2781,7 @@ rm_write_temp_image(Image *image, char *tmpnam)
2662
2781
  {
2663
2782
  rb_raise(rb_eRuntimeError, "SetMagickRegistry failed.");
2664
2783
  }
2665
- HANDLE_ERROR_IMG(image)
2784
+ rm_check_image_exception(image, RetainOnError);
2666
2785
 
2667
2786
  sprintf(tmpnam, "mpri:%ld", registry_id);
2668
2787
  }
@@ -2806,229 +2925,379 @@ rm_get_geometry(
2806
2925
 
2807
2926
 
2808
2927
  /*
2809
- Static: magick_error_handler
2810
- Purpose: Build error or warning message string. If the error
2811
- is severe, raise the ImageMagickError exception,
2812
- otherwise print an optional warning.
2813
- */
2814
- static void
2815
- magick_error_handler(
2816
- ExceptionType severity,
2817
- const char *reason,
2818
- const char *description
2819
- #if defined(HAVE_EXCEPTIONINFO_MODULE)
2820
- ,
2821
- const char *module,
2822
- const char *function,
2823
- unsigned long line
2824
- #endif
2825
- )
2928
+ * Extern: rm_clone_image
2929
+ * Purpose: clone an image, handle errors
2930
+ */
2931
+ Image *rm_clone_image(Image *image)
2826
2932
  {
2827
- char msg[1024];
2933
+ Image *clone;
2934
+ ExceptionInfo exception;
2828
2935
 
2829
- if (severity >= ErrorException)
2936
+ GetExceptionInfo(&exception);
2937
+ clone = CloneImage(image, 0, 0, True, &exception);
2938
+ if (!clone)
2830
2939
  {
2831
- #if defined(HAVE_SNPRINTF)
2832
- snprintf(msg, sizeof(msg)-1,
2833
- #else
2834
- sprintf(msg,
2835
- #endif
2836
- "%s%s%s",
2837
- GetLocaleExceptionMessage(severity, reason),
2838
- description ? ": " : "",
2839
- description ? GetLocaleExceptionMessage(severity, description) : "");
2940
+ rb_raise(rb_eNoMemError, "not enough memory to continue");
2941
+ }
2942
+ rm_check_exception(&exception, clone, DestroyOnError);
2840
2943
 
2841
- #if defined(HAVE_EXCEPTIONINFO_MODULE)
2842
- {
2843
- char extra[100];
2944
+ return clone;
2945
+ }
2844
2946
 
2845
- #if defined(HAVE_SNPRINTF)
2846
- snprintf(extra, sizeof(extra)-1, "%s at %s:%lu", function, module, line);
2847
- #else
2848
- sprintf(extra, "%s at %s:%lu", function, module, line);
2849
- #endif
2850
- raise_error(msg, extra);
2851
- }
2852
- #else
2853
- raise_error(msg, NULL);
2854
- #endif
2855
- }
2856
- else if (severity != UndefinedException)
2857
- {
2858
- #if defined(HAVE_SNPRINTF)
2859
- snprintf(msg, sizeof(msg)-1,
2947
+
2948
+ /*
2949
+ Extern: rm_progress_monitor
2950
+ Purpose: SetImage(Info)ProgressMonitor exit
2951
+ Notes: ImageMagick's "tag" argument is unused. We pass along the method name instead.
2952
+ */
2953
+ #if defined(HAVE_SETIMAGEPROGRESSMONITOR)
2954
+ MagickBooleanType rm_progress_monitor(
2955
+ const char *tag,
2956
+ const MagickOffsetType of,
2957
+ const MagickSizeType sp,
2958
+ void *client_data)
2959
+ {
2960
+ volatile VALUE rval;
2961
+ volatile VALUE method, offset, span;
2962
+
2963
+ #if defined(HAVE_LONG_LONG) // defined in Ruby's defines.h
2964
+ offset = rb_ll2inum(of);
2965
+ span = rb_ull2inum(sp);
2860
2966
  #else
2861
- sprintf(msg,
2967
+ offset = rb_int2big((long)of);
2968
+ span = rb_uint2big((unsigned long)sp);
2862
2969
  #endif
2863
- "RMagick: %s%s%s",
2864
- GetLocaleExceptionMessage(severity, reason),
2865
- description ? ": " : "",
2866
- description ? GetLocaleExceptionMessage(severity, description) : "");
2867
- rb_warning(msg);
2868
- }
2970
+
2971
+ method = rb_str_new2(rb_id2name(rb_frame_last_func()));
2972
+
2973
+ rval = rb_funcall((VALUE)client_data, ID_call, 3, method, offset, span);
2974
+
2975
+ return RTEST(rval) ? MagickTrue : MagickFalse;
2869
2976
  }
2977
+ #endif
2870
2978
 
2871
2979
 
2872
2980
  /*
2873
- Extern: handle_error
2874
- Purpose: Called from RMagick routines to issue warning messages
2875
- and raise the ImageMagickError exception.
2876
- Notes: In order to free up memory before calling raise, this
2877
- routine copies the ExceptionInfo data to local storage
2878
- and then calls DestroyExceptionInfo before raising
2879
- the error.
2880
-
2881
- If the exception is an error, DOES NOT RETURN!
2981
+ Extern: rm_split
2982
+ Purpose: Remove the ImageMagick links between images in an scene
2983
+ sequence.
2984
+ Notes: The images remain grouped via the ImageList
2882
2985
  */
2883
2986
  void
2884
- rm_handle_error(ExceptionInfo *ex)
2987
+ rm_split(Image *image)
2885
2988
  {
2886
- #define RM_MAX_ERROR_CLAUSE 250
2887
- ExceptionType sev = ex->severity;
2888
- char reason[RM_MAX_ERROR_CLAUSE+1];
2889
- char desc[RM_MAX_ERROR_CLAUSE+1];
2890
-
2891
- #if defined(HAVE_EXCEPTIONINFO_MODULE)
2892
- char module[RM_MAX_ERROR_CLAUSE+1], function[RM_MAX_ERROR_CLAUSE+1];
2893
- unsigned long line;
2894
- #endif
2895
-
2896
- reason[0] = '\0';
2897
- desc[0] = '\0';
2898
2989
 
2899
- if (sev == UndefinedException)
2990
+ if (!image)
2900
2991
  {
2901
- return;
2992
+ rb_bug("RMagick FATAL: unseq called with NULL argument.");
2902
2993
  }
2903
- if (ex->reason)
2994
+ while (image)
2904
2995
  {
2905
- strncpy(reason, ex->reason, RM_MAX_ERROR_CLAUSE);
2906
- reason[RM_MAX_ERROR_CLAUSE] = '\0';
2996
+ (void) RemoveFirstImageFromList(&image);
2907
2997
  }
2908
- if (ex->description)
2998
+ }
2999
+
3000
+
3001
+
3002
+ /*
3003
+ * Static: copy_exception
3004
+ * clear_exception
3005
+ * Purpose: Define alternative implementations of ImageMagick's
3006
+ * InheritException and ClearMagickException.
3007
+ * Notes: InheritException is ALWAYS defined in ImageMagick and
3008
+ * NEVER defined in GraphicsMagick. ClearMagickException
3009
+ * is defined in ImageMagick 6.2.6 and later and NEVER
3010
+ * defined in GraphicsMagick.
3011
+ *
3012
+ * The purpose of InheritException is to copy the exception
3013
+ * information from a "related" exception to a destination
3014
+ * exception if the related exception is more severe than the
3015
+ * destination exception.
3016
+ *
3017
+ * The purpose of ClearException is to reset the ExceptionInfo
3018
+ * structure to its initial format.
3019
+ */
3020
+
3021
+ #if defined(HAVE_INHERITEXCEPTION)
3022
+
3023
+ // This is ImageMagick - InheritException is always defined
3024
+ static void copy_exception(ExceptionInfo *exception, ExceptionInfo *relative)
2909
3025
  {
2910
- strncpy(desc, ex->description, RM_MAX_ERROR_CLAUSE);
2911
- desc[RM_MAX_ERROR_CLAUSE] = '\0';
3026
+ InheritException(exception, relative);
2912
3027
  }
2913
3028
 
2914
- #if defined(HAVE_EXCEPTIONINFO_MODULE)
2915
- module[0] = '\0';
2916
- function[0] = '\0';
3029
+ // ImageMagick < 6.2.6 had a different kind of ExceptionInfo struct
3030
+ // and doesn't define ClearMagickException.
3031
+ #if defined(HAVE_CLEARMAGICKEXCEPTION)
3032
+ static void clear_exception(ExceptionInfo *exception)
3033
+ {
3034
+ ClearMagickException(exception);
3035
+ }
3036
+ #else
3037
+
3038
+ static void clear_exception(ExceptionInfo *exception)
3039
+ {
3040
+ DestroyExceptionInfo(exception);
3041
+ GetExceptionInfo(exception);
3042
+ }
2917
3043
 
2918
- if (ex->module)
3044
+ #endif
3045
+
3046
+
3047
+ #else // !defined(HAVE_INHERITEXCEPTION)
3048
+
3049
+ // This is GraphicsMagick. Very old versions don't support the
3050
+ // module, function, and line fields in the ExceptionInfo struct.
3051
+
3052
+ static void copy_exception(ExceptionInfo *exception, ExceptionInfo *relative)
2919
3053
  {
2920
- strncpy(module, ex->module, RM_MAX_ERROR_CLAUSE);
2921
- module[RM_MAX_ERROR_CLAUSE] = '\0';
3054
+ assert(exception != NULL);
3055
+ assert(exception->signature == MagickSignature);
3056
+ assert(relative != NULL);
3057
+
3058
+ if (relative->severity < exception->severity)
3059
+ {
3060
+ return;
3061
+ }
3062
+
3063
+ DestroyExceptionInfo(exception);
3064
+ GetExceptionInfo(exception);
3065
+
3066
+ exception->severity = relative->severity;
3067
+ if (relative->reason)
3068
+ {
3069
+ magick_clone_string(&exception->reason, relative->reason);
3070
+ }
3071
+
3072
+ if (relative->description)
3073
+ {
3074
+ magick_clone_string(&exception->description, relative->description);
3075
+ }
3076
+
3077
+
3078
+ #if defined(HAVE_EXCEPTIONINFO_MODULE)
3079
+ if (relative->module)
3080
+ {
3081
+ magick_clone_string(&exception->module, relative->module);
3082
+ }
3083
+ if (relative->function)
3084
+ {
3085
+ magick_clone_string(&exception->function, relative->function);
3086
+ }
3087
+
3088
+ exception->line = relative->line;
3089
+ #endif
2922
3090
  }
2923
- if (ex->function)
3091
+
3092
+
3093
+ static void clear_exception(ExceptionInfo *exception)
2924
3094
  {
2925
- strncpy(function, ex->function, RM_MAX_ERROR_CLAUSE);
2926
- function[RM_MAX_ERROR_CLAUSE] = '\0';
3095
+ DestroyExceptionInfo(exception);
3096
+ GetExceptionInfo(exception);
2927
3097
  }
2928
- line = ex->line;
2929
- #endif
2930
-
2931
- // Let ImageMagick reclaim its storage
2932
- DestroyExceptionInfo(ex);
2933
- // Reset the severity. If the exception structure is in an
2934
- // Image and this exception is rescued and the Image reused,
2935
- // we need the Image to be pristine!
2936
- GetExceptionInfo(ex);
2937
3098
 
2938
- #if !defined(HAVE_EXCEPTIONINFO_MODULE)
2939
- magick_error_handler(sev, reason, desc);
2940
- #else
2941
- magick_error_handler(sev, reason, desc, module, function, line);
2942
3099
  #endif
2943
- }
3100
+
2944
3101
 
2945
3102
  /*
2946
- Extern: handle_all_errors
2947
- Purpose: Examine all the images in a sequence. If any
2948
- image has an error, raise an exception. Otherwise
2949
- if any image has a warning, issue a warning message.
2950
- */
2951
- void rm_handle_all_errors(Image *seq)
3103
+ Extern: rm_check_image_exception
3104
+ Purpose: If an ExceptionInfo struct in a list of images indicates a warning,
3105
+ issue a warning message. If an ExceptionInfo struct indicates an
3106
+ error, raise an exception and optionally destroy the images.
3107
+ */
3108
+ void
3109
+ rm_check_image_exception(Image *imglist, ErrorRetention retention)
2952
3110
  {
3111
+ ExceptionInfo exception;
2953
3112
  Image *badboy = NULL;
2954
- Image *image = seq;
3113
+ Image *image;
3114
+
3115
+ if (imglist == NULL)
3116
+ {
3117
+ return;
3118
+ }
2955
3119
 
3120
+ GetExceptionInfo(&exception);
3121
+
3122
+ // Find the image with the highest severity
3123
+ image = GetFirstImageInList(imglist);
2956
3124
  while (image)
2957
3125
  {
2958
3126
  if (image->exception.severity != UndefinedException)
2959
3127
  {
2960
- // Stop at the 1st image with an error
2961
- if (image->exception.severity > WarningException)
2962
- {
2963
- badboy = image;
2964
- break;
2965
- }
2966
- else if (!badboy)
3128
+ if (!badboy || image->exception.severity > badboy->exception.severity)
2967
3129
  {
2968
3130
  badboy = image;
3131
+ copy_exception(&exception, &badboy->exception);
2969
3132
  }
3133
+
3134
+ clear_exception(&image->exception);
2970
3135
  }
2971
3136
  image = GetNextImageInList(image);
2972
3137
  }
2973
3138
 
2974
3139
  if (badboy)
2975
3140
  {
2976
- if (badboy->exception.severity > WarningException)
2977
- {
2978
- rm_split(seq);
2979
- }
2980
- rm_handle_error(&badboy->exception);
3141
+ rm_check_exception(&exception, imglist, retention);
2981
3142
  }
2982
3143
  }
2983
3144
 
3145
+
2984
3146
  /*
2985
- Extern: rm_progress_monitor
2986
- Purpose: SetImage(Info)ProgressMonitor exit
2987
- Notes: ImageMagick's "tag" argument is unused. We pass along the method name instead.
3147
+ * Extern: rm_check_exception
3148
+ * Purpose: Call handle_exception if there is an exception to handle.
3149
+ */
3150
+ void
3151
+ rm_check_exception(ExceptionInfo *exception, Image *imglist, ErrorRetention retention)
3152
+ {
3153
+ if (exception->severity == UndefinedException)
3154
+ {
3155
+ return;
3156
+ }
3157
+
3158
+ handle_exception(exception, imglist, retention);
3159
+ }
3160
+
3161
+
3162
+ /*
3163
+ * Static: handle_exception
3164
+ * Purpose: called when rm_check_exception determines that we need
3165
+ * to either issue a warning message or raise an exception.
3166
+ * This function allocates a bunch of stack so we don't call
3167
+ * it unless we have to.
2988
3168
  */
2989
- #if defined(HAVE_SETIMAGEPROGRESSMONITOR)
2990
- MagickBooleanType rm_progress_monitor(
2991
- const char *tag,
2992
- const MagickOffsetType of,
2993
- const MagickSizeType sp,
2994
- void *client_data)
3169
+ static void
3170
+ handle_exception(ExceptionInfo *exception, Image *imglist, ErrorRetention retention)
2995
3171
  {
2996
- volatile VALUE rval;
2997
- volatile VALUE method, offset, span;
2998
3172
 
2999
- #if defined(HAVE_LONG_LONG) // defined in Ruby's defines.h
3000
- offset = rb_ll2inum(of);
3001
- span = rb_ull2inum(sp);
3173
+ char reason[500];
3174
+ char desc[500];
3175
+ char msg[sizeof(reason)+sizeof(desc)+20];
3176
+
3177
+ #if defined(HAVE_EXCEPTIONINFO_MODULE)
3178
+ char module[200], function[200];
3179
+ char extra[sizeof(module)+sizeof(function)+20];
3180
+ unsigned long line;
3181
+ #endif
3182
+
3183
+
3184
+ memset(msg, 0, sizeof(msg));
3185
+
3186
+
3187
+ // Handle simple warning
3188
+ if (exception->severity < ErrorException)
3189
+ {
3190
+ #if defined(HAVE_SNPRINTF)
3191
+ snprintf(msg, sizeof(msg)-1, "RMagick: %s%s%s",
3002
3192
  #else
3003
- offset = rb_int2big((long)of);
3004
- span = rb_uint2big((unsigned long)sp);
3193
+ sprintf(msg, "RMagick: %.500s%s%.500s",
3005
3194
  #endif
3195
+ GetLocaleExceptionMessage(exception->severity, exception->reason),
3196
+ exception->description ? ": " : "",
3197
+ exception->description ? GetLocaleExceptionMessage(exception->severity, exception->description) : "");
3198
+ msg[sizeof(msg)-1] = '\0';
3199
+ rb_warning(msg);
3006
3200
 
3007
- method = rb_str_new2(rb_id2name(rb_frame_last_func()));
3201
+ DestroyExceptionInfo(exception);
3202
+ return;
3203
+ }
3008
3204
 
3009
- rval = rb_funcall((VALUE)client_data, ID_call, 3, method, offset, span);
3205
+ // Raise an exception. We're not coming back...
3010
3206
 
3011
- return RTEST(rval) ? MagickTrue : MagickFalse;
3012
- }
3207
+
3208
+ // Newly-created images should be destroyed, images that are part
3209
+ // of image objects should be retained but split.
3210
+ if (imglist)
3211
+ {
3212
+ if (retention == DestroyOnError)
3213
+ {
3214
+ (void) DestroyImageList(imglist);
3215
+ imglist = NULL;
3216
+ }
3217
+ else
3218
+ {
3219
+ rm_split(imglist);
3220
+ }
3221
+ }
3222
+
3223
+
3224
+ // Clone the ExceptionInfo with all arguments on the stack.
3225
+ memset(reason, 0, sizeof(reason));
3226
+ memset(desc, 0, sizeof(desc));
3227
+
3228
+ if (exception->reason)
3229
+ {
3230
+ strncpy(reason, exception->reason, sizeof(reason)-1);
3231
+ reason[sizeof(reason)-1] = '\0';
3232
+ }
3233
+ if (exception->description)
3234
+ {
3235
+ strncpy(desc, exception->description, sizeof(desc)-1);
3236
+ desc[sizeof(desc)-1] = '\0';
3237
+ }
3238
+
3239
+
3240
+ #if defined(HAVE_SNPRINTF)
3241
+ snprintf(msg, sizeof(msg)-1, "%s%s%s",
3242
+ GetLocaleExceptionMessage(exception->severity, reason),
3243
+ desc[0] ? ": " : "",
3244
+ desc[0] ? GetLocaleExceptionMessage(exception->severity, desc) : "");
3245
+ #else
3246
+ sprintf(msg, "%.*s%s%.*s",
3247
+ sizeof(reason)-1, GetLocaleExceptionMessage(exception->severity, reason),
3248
+ desc[0] ? ": " : "",
3249
+ sizeof(desc)-1, desc[0] ? GetLocaleExceptionMessage(exception->severity, desc) : "");
3013
3250
  #endif
3014
3251
 
3252
+ msg[sizeof(msg)-1] = '\0';
3015
3253
 
3016
- /*
3017
- Extern: rm_split
3018
- Purpose: Remove the ImageMagick links between images in an scene
3019
- sequence.
3020
- Notes: The images remain grouped via the ImageList
3021
- */
3022
- void
3023
- rm_split(Image *image)
3024
- {
3025
3254
 
3026
- if (!image)
3255
+ #if defined(HAVE_EXCEPTIONINFO_MODULE)
3256
+
3257
+ memset(module, 0, sizeof(module));
3258
+ memset(function, 0, sizeof(function));
3259
+ memset(extra, 0, sizeof(extra));
3260
+
3261
+ if (exception->module)
3027
3262
  {
3028
- rb_bug("RMagick FATAL: unseq called with NULL argument.");
3263
+ strncpy(module, exception->module, sizeof(module)-1);
3264
+ module[sizeof(module)-1] = '\0';
3029
3265
  }
3030
- while (image)
3266
+ if (exception->function)
3031
3267
  {
3032
- (void) RemoveFirstImageFromList(&image);
3268
+ strncpy(function, exception->function, sizeof(function)-1);
3269
+ function[sizeof(function)-1] = '\0';
3033
3270
  }
3271
+ line = exception->line;
3272
+
3273
+ #if defined(HAVE_SNPRINTF)
3274
+ snprintf(extra, sizeof(extra)-1, "%s at %s:%lu", function, module, line);
3275
+ #else
3276
+ sprintf(extra, "%.*s at %.*s:%lu", sizeof(function), function, sizeof(module), module, line);
3277
+ #endif
3278
+
3279
+ extra[sizeof(extra)-1] = '\0';
3280
+
3281
+ DestroyExceptionInfo(exception);
3282
+ raise_error(msg, extra);
3283
+
3284
+ #else
3285
+ DestroyExceptionInfo(exception);
3286
+ raise_error(msg, NULL);
3287
+ #endif
3288
+
3034
3289
  }
3290
+
3291
+
3292
+ /*
3293
+ * Extern: rm_ensure_result
3294
+ * Purpose: RMagick expected a result. If it got NULL instead raise an exception.
3295
+ */
3296
+ void rm_ensure_result(Image *image)
3297
+ {
3298
+ if (!image)
3299
+ {
3300
+ rb_raise(rb_eRuntimeError, MagickPackageName " library function failed to return a result.");
3301
+ }
3302
+ }
3303
+