rmagick 3.0.0 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


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

Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. data/.appveyor.yml +32 -6
  3. data/.circleci/config.yml +1 -1
  4. data/.gitignore +1 -0
  5. data/.rubocop.yml +9 -9
  6. data/.rubocop_todo.yml +351 -17
  7. data/.travis.yml +14 -1
  8. data/CHANGELOG.md +55 -0
  9. data/CONTRIBUTING.md +11 -18
  10. data/README.textile +2 -2
  11. data/Rakefile +1 -1
  12. data/before_install_linux.sh +56 -19
  13. data/doc/ex/sparse_color.rb +5 -0
  14. data/doc/magick.html +9 -4
  15. data/doc/rvg.html +2 -2
  16. data/doc/rvgtut.html +1 -1
  17. data/examples/histogram.rb +1 -1
  18. data/ext/RMagick/extconf.rb +90 -264
  19. data/ext/RMagick/rmagick.c +28 -6
  20. data/ext/RMagick/rmagick.h +53 -199
  21. data/ext/RMagick/rmdraw.c +52 -70
  22. data/ext/RMagick/rmenum.c +332 -274
  23. data/ext/RMagick/rmfill.c +62 -112
  24. data/ext/RMagick/rmilist.c +27 -62
  25. data/ext/RMagick/rmimage.c +424 -634
  26. data/ext/RMagick/rminfo.c +46 -37
  27. data/ext/RMagick/rmkinfo.c +47 -42
  28. data/ext/RMagick/rmmain.c +125 -180
  29. data/ext/RMagick/rmmontage.c +5 -5
  30. data/ext/RMagick/rmpixel.c +133 -62
  31. data/ext/RMagick/rmstruct.c +14 -181
  32. data/ext/RMagick/rmutil.c +195 -111
  33. data/lib/rmagick/version.rb +2 -3
  34. data/lib/rvg/deep_equal.rb +1 -1
  35. data/lib/rvg/misc.rb +4 -4
  36. data/lib/rvg/units.rb +2 -2
  37. data/rmagick.gemspec +2 -2
  38. data/spec/rmagick/ImageList1_spec.rb +2 -2
  39. data/spec/rmagick/draw_spec.rb +4 -4
  40. data/spec/rmagick/image/composite_spec.rb +6 -1
  41. data/spec/rmagick/image/properties_spec.rb +8 -8
  42. data/test/Draw.rb +414 -0
  43. data/test/Enum.rb +76 -0
  44. data/test/Fill.rb +93 -0
  45. data/test/Image1.rb +9 -1
  46. data/test/Image2.rb +14 -4
  47. data/test/Image3.rb +73 -3
  48. data/test/ImageList1.rb +22 -9
  49. data/test/ImageList2.rb +41 -9
  50. data/test/Image_attributes.rb +45 -8
  51. data/test/Info.rb +102 -6
  52. data/test/Magick.rb +8 -1
  53. data/test/PolaroidOptions.rb +23 -0
  54. data/test/test_all_basic.rb +4 -0
  55. metadata +28 -8
  56. data/.hound.yml +0 -2
  57. data/wercker.yml +0 -10
@@ -228,6 +228,27 @@ rm_check_ary_len(VALUE ary, long len)
228
228
  }
229
229
 
230
230
 
231
+ /**
232
+ * Raise exception if ary argument was invalid type
233
+ *
234
+ * No Ruby usage (internal function)
235
+ *
236
+ * @param ary the array
237
+ * @return the array that is converted type of argument object if needed
238
+ * @throw TypeError
239
+ */
240
+ VALUE
241
+ rm_check_ary_type(VALUE ary)
242
+ {
243
+ VALUE checked = rb_check_array_type(ary);
244
+ if (NIL_P(checked))
245
+ {
246
+ rb_raise(rb_eTypeError, "wrong argument type %"PRIsVALUE" was given. (must respond to :to_ary)", rb_obj_class(ary));
247
+ }
248
+ return checked;
249
+ }
250
+
251
+
231
252
  /**
232
253
  * Raise an error if the image has been destroyed.
233
254
  *
@@ -598,6 +619,21 @@ rm_app2quantum(VALUE obj)
598
619
  }
599
620
 
600
621
 
622
+ /**
623
+ * Returns a pointer to an image structure initialized to default values
624
+ *
625
+ * No Ruby usage (internal function)
626
+ *
627
+ * @param info the info
628
+ * @return the created image
629
+ */
630
+ Image *
631
+ rm_acquire_image(ImageInfo *info)
632
+ {
633
+ return AcquireImage(info);
634
+ }
635
+
636
+
601
637
  /**
602
638
  * Send the "cur_image" method to the object. If 'img' is an ImageList, then
603
639
  * cur_image is self[\@scene]. If 'img' is an image, then cur_image is simply
@@ -621,12 +657,12 @@ rm_cur_image(VALUE img)
621
657
  * No Ruby usage (internal function)
622
658
  *
623
659
  * @param image the image
624
- * @param color the color intensity as a PixelPacket
660
+ * @param color the color intensity as a PixelColor
625
661
  * @return the named color as a String
626
- * @see rm_pixelpacket_to_color_name_info
662
+ * @see rm_pixelcolor_to_color_name_info
627
663
  */
628
664
  VALUE
629
- rm_pixelpacket_to_color_name(Image *image, PixelPacket *color)
665
+ rm_pixelcolor_to_color_name(Image *image, PixelColor *color)
630
666
  {
631
667
  char name[MaxTextExtent];
632
668
  ExceptionInfo *exception;
@@ -649,38 +685,66 @@ rm_pixelpacket_to_color_name(Image *image, PixelPacket *color)
649
685
  * Notes:
650
686
  * - Simply create an Image from the Info, call QueryColorname, and then
651
687
  * destroy the Image.
652
- * - If the Info structure is NULL, creates a new one.
653
688
  * - The default depth is always used, and the matte value is set to False,
654
689
  * which means "don't use the alpha channel".
655
690
  *
656
691
  * @param info the info
657
- * @param color the color intensity as a PixelPacket
692
+ * @param color the color intensity as a PixelColor
658
693
  * @return the named color as a String
659
- * @see rm_pixelpacket_to_color_name
694
+ * @see rm_pixelcolor_to_color_name
660
695
  */
661
696
  VALUE
662
- rm_pixelpacket_to_color_name_info(Info *info, PixelPacket *color)
697
+ rm_pixelcolor_to_color_name_info(Info *info, PixelColor *color)
663
698
  {
664
699
  Image *image;
665
- Info *my_info;
666
700
  VALUE color_name;
667
701
 
668
- my_info = info ? info : CloneImageInfo(NULL);
669
-
670
- image = AcquireImage(info);
671
- image->matte = MagickFalse;
672
- color_name = rm_pixelpacket_to_color_name(image, color);
673
- (void) DestroyImage(image);
674
- if (!info)
702
+ image = rm_acquire_image(info);
703
+ if (!image)
675
704
  {
676
- (void) DestroyImageInfo(my_info);
705
+ rb_raise(rb_eNoMemError, "not enough memory to continue.");
677
706
  }
678
707
 
679
- RB_GC_GUARD(color_name);
708
+ image->matte = MagickFalse;
709
+ color_name = rm_pixelcolor_to_color_name(image, color);
710
+ (void) DestroyImage(image);
680
711
 
681
712
  return color_name;
682
713
  }
683
714
 
715
+ /**
716
+ * Initializes the MagickPixel structure.
717
+ *
718
+ * No Ruby usage (internal function)
719
+ *
720
+ * @param image the image
721
+ * @param pp the MagickPixel
722
+ */
723
+ void
724
+ rm_init_magickpixel(const Image *image, MagickPixel *pp)
725
+ {
726
+ GetMagickPixelPacket(image, pp);
727
+ }
728
+
729
+ /**
730
+ * Initializes the MagickPixel structure to the specified color.
731
+ *
732
+ * No Ruby usage (internal function)
733
+ *
734
+ * @param pp the MagickPixel
735
+ * @param color the color
736
+ */
737
+ void
738
+ rm_set_magickpixel(MagickPixel *pp, const char *color)
739
+ {
740
+ ExceptionInfo *exception;
741
+
742
+ exception = AcquireExceptionInfo();
743
+ (void) QueryMagickColor(color, pp, exception);
744
+ // This exception is ignored because the color comes from places where we control
745
+ // the value and it is very unlikely that an exception will be thrown.
746
+ (void) DestroyExceptionInfo(exception);
747
+ }
684
748
 
685
749
  /**
686
750
  * Write a temporary copy of the image to the IM registry.
@@ -773,7 +837,7 @@ rm_not_implemented(void)
773
837
  {
774
838
 
775
839
  rb_raise(rb_eNotImpError, "the `%s' method is not supported by ImageMagick "
776
- MagickLibVersionText, rb_id2name(THIS_FUNC()));
840
+ MagickLibVersionText, rb_id2name(rb_frame_this_func()));
777
841
  }
778
842
 
779
843
 
@@ -787,24 +851,21 @@ rm_not_implemented(void)
787
851
  * the ImageMagickError object in both 1.6.8 and 1.8.0.
788
852
  *
789
853
  * @param msg the error mesage
790
- * @param loc the location of the error
791
854
  * @throw ImageMagickError
792
855
  * @see www.ruby_talk.org/36408.
793
856
  */
794
857
  void
795
- rm_magick_error(const char *msg, const char *loc)
858
+ rm_magick_error(const char *msg)
796
859
  {
797
- VALUE exc, mesg, extra;
860
+ VALUE exc, mesg;
798
861
 
799
862
  mesg = rb_str_new2(msg);
800
- extra = loc ? rb_str_new2(loc) : Qnil;
801
863
 
802
- exc = rb_funcall(Class_ImageMagickError, rm_ID_new, 2, mesg, extra);
864
+ exc = rb_funcall(Class_ImageMagickError, rm_ID_new, 2, mesg, Qnil);
803
865
  (void) rb_funcall(rb_cObject, rb_intern("raise"), 1, exc);
804
866
 
805
867
  RB_GC_GUARD(exc);
806
868
  RB_GC_GUARD(mesg);
807
- RB_GC_GUARD(extra);
808
869
  }
809
870
 
810
871
 
@@ -897,7 +958,6 @@ rm_set_property(Image *image, const char *property, const char *value)
897
958
  */
898
959
  void rm_set_user_artifact(Image *images, Info *info)
899
960
  {
900
- #if defined(HAVE_SETIMAGEARTIFACT)
901
961
  Image *image;
902
962
  const char *value;
903
963
 
@@ -911,10 +971,6 @@ void rm_set_user_artifact(Image *images, Info *info)
911
971
  image = GetNextImageInList(image);
912
972
  }
913
973
  }
914
- #else
915
- images = images;
916
- info = info;
917
- #endif
918
974
  }
919
975
 
920
976
 
@@ -953,7 +1009,6 @@ rm_get_optional_arguments(VALUE img)
953
1009
  }
954
1010
 
955
1011
 
956
- #if defined(HAVE_SETIMAGEARTIFACT)
957
1012
  /**
958
1013
  * Copy image options from the Info structure to the Image structure.
959
1014
  *
@@ -979,7 +1034,6 @@ static void copy_options(Image *image, Info *info)
979
1034
  }
980
1035
  }
981
1036
  }
982
- #endif
983
1037
 
984
1038
 
985
1039
  /**
@@ -1013,7 +1067,7 @@ void rm_sync_image_options(Image *image, Info *info)
1013
1067
 
1014
1068
  if (info->colorspace != UndefinedColorspace)
1015
1069
  {
1016
- image->colorspace = info->colorspace;
1070
+ SetImageColorspace(image, info->colorspace);
1017
1071
  }
1018
1072
 
1019
1073
  if (info->compression != UndefinedCompression)
@@ -1109,12 +1163,10 @@ void rm_sync_image_options(Image *image, Info *info)
1109
1163
  image->transparent_color = info->transparent_color;
1110
1164
  }
1111
1165
 
1112
- #if defined(HAVE_ST_TYPE)
1113
1166
  if (info->type != UndefinedType)
1114
1167
  {
1115
1168
  image->type = info->type;
1116
1169
  }
1117
- #endif
1118
1170
 
1119
1171
  if (info->units != UndefinedResolution)
1120
1172
  {
@@ -1148,9 +1200,7 @@ void rm_sync_image_options(Image *image, Info *info)
1148
1200
  image->units = info->units;
1149
1201
  }
1150
1202
 
1151
- #if defined(HAVE_SETIMAGEARTIFACT)
1152
1203
  copy_options(image, info);
1153
- #endif
1154
1204
  }
1155
1205
 
1156
1206
 
@@ -1445,10 +1495,20 @@ rm_progress_monitor(
1445
1495
  const MagickSizeType sp,
1446
1496
  void *client_data)
1447
1497
  {
1448
- #if !defined(_WIN32)
1449
1498
  VALUE rval;
1450
1499
  VALUE method, offset, span;
1451
1500
 
1501
+ // Default Ruby minimum stack size
1502
+ #define RUBY_VM_THREAD_MACHINE_STACK_SIZE_MIN ( 16 * 1024 * sizeof(VALUE)) /* 64 KB or 128 KB */
1503
+
1504
+ // Check stack length manually instead of ruby_stack_check() for old Ruby.
1505
+ if (ruby_stack_length(NULL) > RUBY_VM_THREAD_MACHINE_STACK_SIZE_MIN)
1506
+ {
1507
+ // If there is not enough stack or the using stack size shows an abnormal value in Ruby,
1508
+ // skip the callback and continue ImageMagick process.
1509
+ return MagickTrue;
1510
+ }
1511
+
1452
1512
  tag = tag; // defeat gcc message
1453
1513
 
1454
1514
  #if defined(HAVE_LONG_LONG) // defined in Ruby's defines.h
@@ -1459,7 +1519,7 @@ rm_progress_monitor(
1459
1519
  span = rb_uint2big((unsigned long)sp);
1460
1520
  #endif
1461
1521
 
1462
- method = rb_str_new2(rb_id2name(THIS_FUNC()));
1522
+ method = rb_id2str(rb_frame_this_func());
1463
1523
 
1464
1524
  rval = rb_funcall((VALUE)client_data, rm_ID_call, 3, method, offset, span);
1465
1525
 
@@ -1469,9 +1529,6 @@ rm_progress_monitor(
1469
1529
  RB_GC_GUARD(span);
1470
1530
 
1471
1531
  return RTEST(rval) ? MagickTrue : MagickFalse;
1472
- #else
1473
- return MagickTrue;
1474
- #endif
1475
1532
  }
1476
1533
 
1477
1534
 
@@ -1551,6 +1608,36 @@ rm_check_image_exception(Image *imglist, ErrorRetention retention)
1551
1608
  }
1552
1609
 
1553
1610
 
1611
+ #define ERROR_MSG_SIZE 1024
1612
+ /**
1613
+ * Formats the exception into the message buffer
1614
+ *
1615
+ * No Ruby usage (internal function)
1616
+ *
1617
+ * @param severity information about the severity of the error
1618
+ * @param reason the reason for the error
1619
+ * @param description description of the error
1620
+ * @param msg the buffer where the exception message should be formated in
1621
+ */
1622
+ static void
1623
+ format_exception(const ExceptionType severity, const char *reason, const char *description, char *msg)
1624
+ {
1625
+ int len;
1626
+ memset(msg, 0, sizeof(ERROR_MSG_SIZE));
1627
+
1628
+ #if defined(HAVE_SNPRINTF)
1629
+ len = snprintf(msg, ERROR_MSG_SIZE, "%s%s%s",
1630
+ #else
1631
+ len = sprintf(msg, "%.500s%s%.500s",
1632
+ #endif
1633
+ GetLocaleExceptionMessage(severity, reason),
1634
+ description ? ": " : "",
1635
+ description ? GetLocaleExceptionMessage(severity, description) : "");
1636
+
1637
+ msg[len] = '\0';
1638
+ }
1639
+
1640
+
1554
1641
  /**
1555
1642
  * Call handle_exception if there is an exception to handle.
1556
1643
  *
@@ -1586,11 +1673,10 @@ rm_check_exception(ExceptionInfo *exception, Image *imglist, ErrorRetention rete
1586
1673
  void
1587
1674
  rm_warning_handler(const ExceptionType severity, const char *reason, const char *description)
1588
1675
  {
1589
- ExceptionType dummy;
1590
-
1591
- rb_warning("RMagick: %s: `%s'", reason, description);
1592
- dummy = severity;
1593
- dummy = dummy;
1676
+ rb_warning("RMagick: %s%s%s",
1677
+ GetLocaleExceptionMessage(severity, reason),
1678
+ description ? ": " : "",
1679
+ description ? GetLocaleExceptionMessage(severity, description) : "");
1594
1680
  }
1595
1681
 
1596
1682
 
@@ -1599,28 +1685,18 @@ rm_warning_handler(const ExceptionType severity, const char *reason, const char
1599
1685
  *
1600
1686
  * No Ruby usage (internal function)
1601
1687
  *
1602
- * @param severity information about the severity of the error (ignored)
1688
+ * @param severity information about the severity of the error
1603
1689
  * @param reason the reason for the error
1604
1690
  * @param description description of the error
1605
1691
  */
1606
1692
  void
1607
1693
  rm_error_handler(const ExceptionType severity, const char *reason, const char *description)
1608
1694
  {
1609
- char msg[500];
1610
- int len;
1611
- ExceptionType dummy;
1695
+ char msg[ERROR_MSG_SIZE];
1612
1696
 
1613
- memset(msg, 0, sizeof(msg));
1614
- #if defined(HAVE_SNPRINTF)
1615
- len = snprintf(msg, sizeof(msg), "%s: `%s'", reason, description);
1616
- #else
1617
- len = sprintf(msg, "%.250s: `%.240s'", reason, description);
1618
- #endif
1619
- msg[len] = '\0';
1697
+ format_exception(severity, reason, description, msg);
1620
1698
 
1621
- rm_magick_error(msg, NULL);
1622
- dummy = severity;
1623
- dummy = dummy;
1699
+ rm_magick_error(msg);
1624
1700
  }
1625
1701
 
1626
1702
 
@@ -1631,14 +1707,16 @@ rm_error_handler(const ExceptionType severity, const char *reason, const char *d
1631
1707
  *
1632
1708
  * @param severity information about the severity of the error
1633
1709
  * @param reason the reason for the error
1634
- * @param description description of the error (ignored)
1710
+ * @param description description of the error
1635
1711
  * @throw FatalImageMagickError
1636
1712
  */
1637
1713
  void
1638
1714
  rm_fatal_error_handler(const ExceptionType severity, const char *reason, const char *description)
1639
1715
  {
1640
- rb_raise(Class_FatalImageMagickError, "%s", GetLocaleExceptionMessage(severity, reason));
1641
- description = description;
1716
+ rb_raise(Class_FatalImageMagickError, "%s%s%s",
1717
+ GetLocaleExceptionMessage(severity, reason),
1718
+ description ? ": " : "",
1719
+ description ? GetLocaleExceptionMessage(severity, description) : "");
1642
1720
  }
1643
1721
 
1644
1722
 
@@ -1657,27 +1735,12 @@ rm_fatal_error_handler(const ExceptionType severity, const char *reason, const c
1657
1735
  static void
1658
1736
  handle_exception(ExceptionInfo *exception, Image *imglist, ErrorRetention retention)
1659
1737
  {
1660
-
1661
- char reason[500];
1662
- char desc[500];
1663
- char msg[sizeof(reason)+sizeof(desc)+20];
1664
-
1665
- memset(msg, 0, sizeof(msg));
1666
-
1738
+ char msg[ERROR_MSG_SIZE];
1667
1739
 
1668
1740
  // Handle simple warning
1669
1741
  if (exception->severity < ErrorException)
1670
1742
  {
1671
- #if defined(HAVE_SNPRINTF)
1672
- snprintf(msg, sizeof(msg)-1, "RMagick: %s%s%s",
1673
- #else
1674
- sprintf(msg, "RMagick: %.500s%s%.500s",
1675
- #endif
1676
- GetLocaleExceptionMessage(exception->severity, exception->reason),
1677
- exception->description ? ": " : "",
1678
- exception->description ? GetLocaleExceptionMessage(exception->severity, exception->description) : "");
1679
- msg[sizeof(msg)-1] = '\0';
1680
- rb_warning("%s", msg);
1743
+ rm_warning_handler(exception->severity, exception->reason, exception->description);
1681
1744
 
1682
1745
  // Caller deletes ExceptionInfo...
1683
1746
 
@@ -1702,40 +1765,11 @@ handle_exception(ExceptionInfo *exception, Image *imglist, ErrorRetention retent
1702
1765
  }
1703
1766
  }
1704
1767
 
1705
-
1706
- // Clone the ExceptionInfo with all arguments on the stack.
1707
- memset(reason, 0, sizeof(reason));
1708
- memset(desc, 0, sizeof(desc));
1709
-
1710
- if (exception->reason)
1711
- {
1712
- strncpy(reason, exception->reason, sizeof(reason)-1);
1713
- reason[sizeof(reason)-1] = '\0';
1714
- }
1715
- if (exception->description)
1716
- {
1717
- strncpy(desc, exception->description, sizeof(desc)-1);
1718
- desc[sizeof(desc)-1] = '\0';
1719
- }
1720
-
1721
-
1722
- #if defined(HAVE_SNPRINTF)
1723
- snprintf(msg, sizeof(msg)-1, "%s%s%s",
1724
- GetLocaleExceptionMessage(exception->severity, reason),
1725
- desc[0] ? ": " : "",
1726
- desc[0] ? GetLocaleExceptionMessage(exception->severity, desc) : "");
1727
- #else
1728
- sprintf(msg, "%.*s%s%.*s",
1729
- sizeof(reason)-1, GetLocaleExceptionMessage(exception->severity, reason),
1730
- desc[0] ? ": " : "",
1731
- sizeof(desc)-1, desc[0] ? GetLocaleExceptionMessage(exception->severity, desc) : "");
1732
- #endif
1733
-
1734
- msg[sizeof(msg)-1] = '\0';
1768
+ format_exception(exception->severity, exception->reason, exception->description, msg);
1735
1769
 
1736
1770
  (void) DestroyExceptionInfo(exception);
1737
- rm_magick_error(msg, NULL);
1738
1771
 
1772
+ rm_magick_error(msg);
1739
1773
  }
1740
1774
 
1741
1775
 
@@ -1756,3 +1790,53 @@ rm_ensure_result(Image *image)
1756
1790
  }
1757
1791
  }
1758
1792
 
1793
+
1794
+ /**
1795
+ * Checks if an error should be raised for the exception.
1796
+ *
1797
+ * No Ruby usage (internal function)
1798
+ *
1799
+ * @param exception information about the exception
1800
+ * @param retention retention strategy for the exception in case there was no error
1801
+ */
1802
+ MagickBooleanType
1803
+ rm_should_raise_exception(ExceptionInfo *exception, const ExceptionRetention retention)
1804
+ {
1805
+ if (exception->severity < ErrorException)
1806
+ {
1807
+ if (exception->severity != UndefinedException)
1808
+ {
1809
+ rm_warning_handler(exception->severity, exception->reason, exception->description);
1810
+ }
1811
+
1812
+ if (retention == DestroyExceptionRetention)
1813
+ {
1814
+ (void) DestroyExceptionInfo(exception);
1815
+ }
1816
+
1817
+ return MagickFalse;
1818
+ }
1819
+
1820
+ return MagickTrue;
1821
+ }
1822
+
1823
+
1824
+ /**
1825
+ * Raises an exception.
1826
+ *
1827
+ * No Ruby usage (internal function)
1828
+ *
1829
+ * @param exception information about the exception
1830
+ */
1831
+ void
1832
+ rm_raise_exception(ExceptionInfo *exception)
1833
+ {
1834
+ char msg[ERROR_MSG_SIZE];
1835
+
1836
+ format_exception(exception->severity, exception->reason, exception->description, msg);
1837
+
1838
+ (void) DestroyExceptionInfo(exception);
1839
+
1840
+ rm_magick_error(msg);
1841
+ }
1842
+