rmagick-windows 2.16.1
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.
- checksums.yaml +7 -0
- data/.editorconfig +14 -0
- data/.gitignore +23 -0
- data/.hound.yml +2 -0
- data/.rspec +1 -0
- data/.rubocop.yml +340 -0
- data/.simplecov +27 -0
- data/.travis.yml +60 -0
- data/CHANGELOG.md +915 -0
- data/CODE_OF_CONDUCT.md +13 -0
- data/CONTRIBUTING.md +50 -0
- data/Doxyfile +1514 -0
- data/Gemfile +10 -0
- data/LICENSE +20 -0
- data/README.textile +257 -0
- data/Rakefile +188 -0
- data/before_install_linux.sh +32 -0
- data/before_install_osx.sh +2 -0
- data/deprecated/RMagick.rb +6 -0
- data/doc/.cvsignore +1 -0
- data/doc/comtasks.html +287 -0
- data/doc/constants.html +1581 -0
- data/doc/css/doc.css +299 -0
- data/doc/css/popup.css +34 -0
- data/doc/css/ref.css +67 -0
- data/doc/draw.html +3272 -0
- data/doc/ex/InitialCoords.rb +22 -0
- data/doc/ex/NewCoordSys.rb +30 -0
- data/doc/ex/OrigCoordSys.rb +16 -0
- data/doc/ex/PreserveAspectRatio.rb +204 -0
- data/doc/ex/RotateScale.rb +36 -0
- data/doc/ex/Skew.rb +38 -0
- data/doc/ex/Use01.rb +15 -0
- data/doc/ex/Use02.rb +20 -0
- data/doc/ex/Use03.rb +16 -0
- data/doc/ex/ViewBox.rb +31 -0
- data/doc/ex/adaptive_threshold.rb +9 -0
- data/doc/ex/add_noise.rb +16 -0
- data/doc/ex/affine.rb +48 -0
- data/doc/ex/affine_transform.rb +20 -0
- data/doc/ex/arc.rb +49 -0
- data/doc/ex/arcpath.rb +32 -0
- data/doc/ex/arcs01.rb +28 -0
- data/doc/ex/arcs02.rb +59 -0
- data/doc/ex/average.rb +15 -0
- data/doc/ex/axes.rb +64 -0
- data/doc/ex/baseline_shift01.rb +17 -0
- data/doc/ex/bilevel_channel.rb +8 -0
- data/doc/ex/blur_image.rb +12 -0
- data/doc/ex/border.rb +10 -0
- data/doc/ex/bounding_box.rb +42 -0
- data/doc/ex/cbezier1.rb +41 -0
- data/doc/ex/cbezier2.rb +41 -0
- data/doc/ex/cbezier3.rb +41 -0
- data/doc/ex/cbezier4.rb +42 -0
- data/doc/ex/cbezier5.rb +42 -0
- data/doc/ex/cbezier6.rb +53 -0
- data/doc/ex/channel.rb +25 -0
- data/doc/ex/charcoal.rb +12 -0
- data/doc/ex/chop.rb +29 -0
- data/doc/ex/circle.rb +33 -0
- data/doc/ex/circle01.rb +16 -0
- data/doc/ex/clip_path.rb +60 -0
- data/doc/ex/coalesce.rb +57 -0
- data/doc/ex/color_fill_to_border.rb +29 -0
- data/doc/ex/color_floodfill.rb +28 -0
- data/doc/ex/color_histogram.rb +47 -0
- data/doc/ex/color_reset.rb +11 -0
- data/doc/ex/colorize.rb +16 -0
- data/doc/ex/colors.rb +64 -0
- data/doc/ex/compose_mask.rb +22 -0
- data/doc/ex/composite.rb +133 -0
- data/doc/ex/composite_layers.rb +53 -0
- data/doc/ex/composite_tiled.rb +21 -0
- data/doc/ex/contrast.rb +36 -0
- data/doc/ex/crop.rb +31 -0
- data/doc/ex/crop_with_gravity.rb +42 -0
- data/doc/ex/cubic01.rb +43 -0
- data/doc/ex/cubic02.rb +91 -0
- data/doc/ex/cycle_colormap.rb +21 -0
- data/doc/ex/dissolve.rb +12 -0
- data/doc/ex/drawcomp.rb +42 -0
- data/doc/ex/drop_shadow.rb +60 -0
- data/doc/ex/edge.rb +11 -0
- data/doc/ex/ellipse.rb +45 -0
- data/doc/ex/ellipse01.rb +21 -0
- data/doc/ex/emboss.rb +11 -0
- data/doc/ex/enhance.rb +28 -0
- data/doc/ex/equalize.rb +11 -0
- data/doc/ex/evenodd.rb +42 -0
- data/doc/ex/fill_pattern.rb +23 -0
- data/doc/ex/flatten_images.rb +36 -0
- data/doc/ex/flip.rb +11 -0
- data/doc/ex/flop.rb +11 -0
- data/doc/ex/font_styles.rb +32 -0
- data/doc/ex/fonts.rb +20 -0
- data/doc/ex/frame.rb +12 -0
- data/doc/ex/gaussian_blur.rb +11 -0
- data/doc/ex/get_multiline_type_metrics.rb +41 -0
- data/doc/ex/get_pixels.rb +47 -0
- data/doc/ex/get_type_metrics.rb +141 -0
- data/doc/ex/gradientfill.rb +27 -0
- data/doc/ex/grav.rb +45 -0
- data/doc/ex/gravity.rb +80 -0
- data/doc/ex/group.rb +26 -0
- data/doc/ex/hatchfill.rb +27 -0
- data/doc/ex/image.rb +44 -0
- data/doc/ex/images/Apple.miff +0 -0
- data/doc/ex/images/Ballerina.jpg +0 -0
- data/doc/ex/images/Ballerina3.jpg +0 -0
- data/doc/ex/images/Button_0.gif +0 -0
- data/doc/ex/images/Button_1.gif +0 -0
- data/doc/ex/images/Button_2.gif +0 -0
- data/doc/ex/images/Button_3.gif +0 -0
- data/doc/ex/images/Button_4.gif +0 -0
- data/doc/ex/images/Button_5.gif +0 -0
- data/doc/ex/images/Button_6.gif +0 -0
- data/doc/ex/images/Button_7.gif +0 -0
- data/doc/ex/images/Button_8.gif +0 -0
- data/doc/ex/images/Button_9.gif +0 -0
- data/doc/ex/images/Button_A.gif +0 -0
- data/doc/ex/images/Button_B.gif +0 -0
- data/doc/ex/images/Button_C.gif +0 -0
- data/doc/ex/images/Button_D.gif +0 -0
- data/doc/ex/images/Button_E.gif +0 -0
- data/doc/ex/images/Button_F.gif +0 -0
- data/doc/ex/images/Button_G.gif +0 -0
- data/doc/ex/images/Button_H.gif +0 -0
- data/doc/ex/images/Button_I.gif +0 -0
- data/doc/ex/images/Button_J.gif +0 -0
- data/doc/ex/images/Button_K.gif +0 -0
- data/doc/ex/images/Button_L.gif +0 -0
- data/doc/ex/images/Button_M.gif +0 -0
- data/doc/ex/images/Button_N.gif +0 -0
- data/doc/ex/images/Button_O.gif +0 -0
- data/doc/ex/images/Button_P.gif +0 -0
- data/doc/ex/images/Button_Q.gif +0 -0
- data/doc/ex/images/Button_R.gif +0 -0
- data/doc/ex/images/Button_S.gif +0 -0
- data/doc/ex/images/Button_T.gif +0 -0
- data/doc/ex/images/Button_U.gif +0 -0
- data/doc/ex/images/Button_V.gif +0 -0
- data/doc/ex/images/Button_W.gif +0 -0
- data/doc/ex/images/Button_X.gif +0 -0
- data/doc/ex/images/Button_Y.gif +0 -0
- data/doc/ex/images/Button_Z.gif +0 -0
- data/doc/ex/images/Cheetah.jpg +0 -0
- data/doc/ex/images/Coffee.wmf +0 -0
- data/doc/ex/images/Flower_Hat.jpg +0 -0
- data/doc/ex/images/Gold_Statue.jpg +0 -0
- data/doc/ex/images/Hot_Air_Balloons.jpg +0 -0
- data/doc/ex/images/Hot_Air_Balloons_H.jpg +0 -0
- data/doc/ex/images/Leaf.miff +0 -0
- data/doc/ex/images/No.wmf +0 -0
- data/doc/ex/images/Polynesia.jpg +0 -0
- data/doc/ex/images/Red_Rocks.jpg +0 -0
- data/doc/ex/images/Rocks_On_Beach.miff +0 -0
- data/doc/ex/images/Shorts.jpg +0 -0
- data/doc/ex/images/Snake.wmf +0 -0
- data/doc/ex/images/Violin.jpg +0 -0
- data/doc/ex/images/Yellow_Rose.miff +0 -0
- data/doc/ex/images/big-duck.gif +0 -0
- data/doc/ex/images/duck.gif +0 -0
- data/doc/ex/images/duck0.gif +0 -0
- data/doc/ex/images/duck1.gif +0 -0
- data/doc/ex/images/duck10.gif +0 -0
- data/doc/ex/images/duck11.gif +0 -0
- data/doc/ex/images/duck12.gif +0 -0
- data/doc/ex/images/duck13.gif +0 -0
- data/doc/ex/images/duck14.gif +0 -0
- data/doc/ex/images/duck15.gif +0 -0
- data/doc/ex/images/duck2.gif +0 -0
- data/doc/ex/images/duck3.gif +0 -0
- data/doc/ex/images/duck4.gif +0 -0
- data/doc/ex/images/duck5.gif +0 -0
- data/doc/ex/images/duck6.gif +0 -0
- data/doc/ex/images/duck7.gif +0 -0
- data/doc/ex/images/duck8.gif +0 -0
- data/doc/ex/images/duck9.gif +0 -0
- data/doc/ex/images/graydient230x6.gif +0 -0
- data/doc/ex/images/image_with_profile.jpg +0 -0
- data/doc/ex/images/logo400x83.gif +0 -0
- data/doc/ex/images/model.miff +0 -0
- data/doc/ex/images/notimplemented.gif +0 -0
- data/doc/ex/images/smile.miff +0 -0
- data/doc/ex/images/spin.gif +0 -0
- data/doc/ex/implode.rb +34 -0
- data/doc/ex/level.rb +11 -0
- data/doc/ex/level_colors.rb +11 -0
- data/doc/ex/line.rb +41 -0
- data/doc/ex/line01.rb +21 -0
- data/doc/ex/mask.rb +35 -0
- data/doc/ex/matte_fill_to_border.rb +39 -0
- data/doc/ex/matte_floodfill.rb +32 -0
- data/doc/ex/matte_replace.rb +39 -0
- data/doc/ex/median_filter.rb +28 -0
- data/doc/ex/modulate.rb +11 -0
- data/doc/ex/mono.rb +23 -0
- data/doc/ex/morph.rb +25 -0
- data/doc/ex/mosaic.rb +35 -0
- data/doc/ex/motion_blur.rb +11 -0
- data/doc/ex/negate.rb +11 -0
- data/doc/ex/negate_channel.rb +9 -0
- data/doc/ex/nested_rvg.rb +21 -0
- data/doc/ex/nonzero.rb +42 -0
- data/doc/ex/normalize.rb +11 -0
- data/doc/ex/oil_paint.rb +11 -0
- data/doc/ex/opacity.rb +37 -0
- data/doc/ex/ordered_dither.rb +11 -0
- data/doc/ex/path.rb +63 -0
- data/doc/ex/pattern1.rb +25 -0
- data/doc/ex/pattern2.rb +26 -0
- data/doc/ex/polaroid.rb +27 -0
- data/doc/ex/polygon.rb +23 -0
- data/doc/ex/polygon01.rb +21 -0
- data/doc/ex/polyline.rb +22 -0
- data/doc/ex/polyline01.rb +21 -0
- data/doc/ex/posterize.rb +8 -0
- data/doc/ex/preview.rb +8 -0
- data/doc/ex/qbezierpath.rb +52 -0
- data/doc/ex/quad01.rb +34 -0
- data/doc/ex/quantize-m.rb +25 -0
- data/doc/ex/radial_blur.rb +9 -0
- data/doc/ex/raise.rb +8 -0
- data/doc/ex/random_threshold_channel.rb +13 -0
- data/doc/ex/rect01.rb +14 -0
- data/doc/ex/rect02.rb +20 -0
- data/doc/ex/rectangle.rb +34 -0
- data/doc/ex/reduce_noise.rb +28 -0
- data/doc/ex/remap.rb +11 -0
- data/doc/ex/remap_images.rb +19 -0
- data/doc/ex/resize_to_fill.rb +8 -0
- data/doc/ex/resize_to_fit.rb +8 -0
- data/doc/ex/roll.rb +9 -0
- data/doc/ex/rotate.rb +44 -0
- data/doc/ex/rotate_f.rb +14 -0
- data/doc/ex/roundrect.rb +33 -0
- data/doc/ex/rubyname.rb +30 -0
- data/doc/ex/rvg_clippath.rb +12 -0
- data/doc/ex/rvg_linecap.rb +42 -0
- data/doc/ex/rvg_linejoin.rb +40 -0
- data/doc/ex/rvg_opacity.rb +18 -0
- data/doc/ex/rvg_pattern.rb +26 -0
- data/doc/ex/rvg_stroke_dasharray.rb +11 -0
- data/doc/ex/segment.rb +11 -0
- data/doc/ex/sepiatone.rb +7 -0
- data/doc/ex/shade.rb +11 -0
- data/doc/ex/shadow.rb +30 -0
- data/doc/ex/shave.rb +15 -0
- data/doc/ex/shear.rb +10 -0
- data/doc/ex/sketch.rb +17 -0
- data/doc/ex/skewx.rb +51 -0
- data/doc/ex/skewy.rb +47 -0
- data/doc/ex/smile.rb +125 -0
- data/doc/ex/solarize.rb +11 -0
- data/doc/ex/sparse_color.rb +54 -0
- data/doc/ex/splice.rb +8 -0
- data/doc/ex/spread.rb +11 -0
- data/doc/ex/stegano.rb +55 -0
- data/doc/ex/stroke_dasharray.rb +42 -0
- data/doc/ex/stroke_fill.rb +10 -0
- data/doc/ex/stroke_linecap.rb +44 -0
- data/doc/ex/stroke_linejoin.rb +48 -0
- data/doc/ex/stroke_width.rb +49 -0
- data/doc/ex/swirl.rb +17 -0
- data/doc/ex/text.rb +37 -0
- data/doc/ex/text01.rb +16 -0
- data/doc/ex/text_align.rb +36 -0
- data/doc/ex/text_antialias.rb +37 -0
- data/doc/ex/text_styles.rb +19 -0
- data/doc/ex/text_undercolor.rb +28 -0
- data/doc/ex/texture_fill_to_border.rb +34 -0
- data/doc/ex/texture_floodfill.rb +32 -0
- data/doc/ex/texturefill.rb +24 -0
- data/doc/ex/threshold.rb +13 -0
- data/doc/ex/to_blob.rb +13 -0
- data/doc/ex/translate.rb +39 -0
- data/doc/ex/transparent.rb +38 -0
- data/doc/ex/transpose.rb +9 -0
- data/doc/ex/transverse.rb +9 -0
- data/doc/ex/tref01.rb +24 -0
- data/doc/ex/triangle01.rb +15 -0
- data/doc/ex/trim.rb +23 -0
- data/doc/ex/tspan01.rb +17 -0
- data/doc/ex/tspan02.rb +17 -0
- data/doc/ex/tspan03.rb +19 -0
- data/doc/ex/unsharp_mask.rb +28 -0
- data/doc/ex/viewex.rb +33 -0
- data/doc/ex/vignette.rb +12 -0
- data/doc/ex/watermark.rb +27 -0
- data/doc/ex/wave.rb +9 -0
- data/doc/ex/wet_floor.rb +58 -0
- data/doc/ex/writing_mode01.rb +26 -0
- data/doc/ex/writing_mode02.rb +26 -0
- data/doc/ilist.html +2056 -0
- data/doc/image1.html +4680 -0
- data/doc/image2.html +3665 -0
- data/doc/image3.html +4522 -0
- data/doc/imageattrs.html +1638 -0
- data/doc/imusage.html +514 -0
- data/doc/index.html +416 -0
- data/doc/info.html +1499 -0
- data/doc/magick.html +565 -0
- data/doc/optequiv.html +2435 -0
- data/doc/rvg.html +975 -0
- data/doc/rvgclip.html +248 -0
- data/doc/rvggroup.html +305 -0
- data/doc/rvgimage.html +289 -0
- data/doc/rvgpattern.html +475 -0
- data/doc/rvgshape.html +406 -0
- data/doc/rvgstyle.html +270 -0
- data/doc/rvgtext.html +465 -0
- data/doc/rvgtspan.html +238 -0
- data/doc/rvgtut.html +530 -0
- data/doc/rvguse.html +145 -0
- data/doc/rvgxform.html +294 -0
- data/doc/scripts/doc.js +22 -0
- data/doc/scripts/stripeTables.js +23 -0
- data/doc/struct.html +1339 -0
- data/doc/usage.html +1621 -0
- data/examples/constitute.rb +7 -0
- data/examples/crop_with_gravity.rb +42 -0
- data/examples/demo.rb +324 -0
- data/examples/describe.rb +43 -0
- data/examples/find_similar_region.rb +34 -0
- data/examples/histogram.rb +321 -0
- data/examples/identify.rb +185 -0
- data/examples/image_opacity.rb +29 -0
- data/examples/import_export.rb +31 -0
- data/examples/pattern_fill.rb +38 -0
- data/examples/rotating_text.rb +44 -0
- data/examples/spinner.rb +49 -0
- data/examples/thumbnail.rb +64 -0
- data/examples/vignette.rb +78 -0
- data/ext/RMagick/extconf.rb +548 -0
- data/ext/RMagick/rmagick.c +401 -0
- data/ext/RMagick/rmagick.h +1287 -0
- data/ext/RMagick/rmdraw.c +2022 -0
- data/ext/RMagick/rmenum.c +1235 -0
- data/ext/RMagick/rmfill.c +720 -0
- data/ext/RMagick/rmilist.c +1270 -0
- data/ext/RMagick/rmimage.c +15427 -0
- data/ext/RMagick/rminfo.c +2590 -0
- data/ext/RMagick/rmmain.c +1741 -0
- data/ext/RMagick/rmmontage.c +519 -0
- data/ext/RMagick/rmpixel.c +1114 -0
- data/ext/RMagick/rmstruct.c +1124 -0
- data/ext/RMagick/rmutil.c +1754 -0
- data/lib/rmagick.rb +1 -0
- data/lib/rmagick/version.rb +6 -0
- data/lib/rmagick_internal.rb +1947 -0
- data/lib/rvg/clippath.rb +45 -0
- data/lib/rvg/container.rb +122 -0
- data/lib/rvg/deep_equal.rb +52 -0
- data/lib/rvg/describable.rb +47 -0
- data/lib/rvg/embellishable.rb +391 -0
- data/lib/rvg/misc.rb +723 -0
- data/lib/rvg/paint.rb +50 -0
- data/lib/rvg/pathdata.rb +126 -0
- data/lib/rvg/rvg.rb +283 -0
- data/lib/rvg/stretchable.rb +165 -0
- data/lib/rvg/stylable.rb +116 -0
- data/lib/rvg/text.rb +172 -0
- data/lib/rvg/transformable.rb +126 -0
- data/lib/rvg/units.rb +63 -0
- data/rmagick.gemspec +46 -0
- data/spec/rmagick/ImageList1_spec.rb +24 -0
- data/spec/rmagick/draw_spec.rb +156 -0
- data/spec/rmagick/image/blue_shift_spec.rb +16 -0
- data/spec/rmagick/image/composite_spec.rb +140 -0
- data/spec/rmagick/image/constitute_spec.rb +15 -0
- data/spec/rmagick/image/dispatch_spec.rb +18 -0
- data/spec/rmagick/image/from_blob_spec.rb +14 -0
- data/spec/rmagick/image/ping_spec.rb +14 -0
- data/spec/rmagick/image/properties_spec.rb +29 -0
- data/spec/spec_helper.rb +4 -0
- data/test/Image1.rb +565 -0
- data/test/Image2.rb +1304 -0
- data/test/Image3.rb +1030 -0
- data/test/ImageList1.rb +806 -0
- data/test/ImageList2.rb +385 -0
- data/test/Image_attributes.rb +697 -0
- data/test/Import_Export.rb +121 -0
- data/test/Info.rb +345 -0
- data/test/Magick.rb +321 -0
- data/test/Pixel.rb +116 -0
- data/test/Preview.rb +57 -0
- data/test/cmyk.icm +0 -0
- data/test/srgb.icm +0 -0
- data/test/test_all_basic.rb +38 -0
- data/test/tmpnam_test.rb +50 -0
- data/wercker.yml +10 -0
- metadata +509 -0
@@ -0,0 +1,1754 @@
|
|
1
|
+
/**************************************************************************//**
|
2
|
+
* Utility functions for RMagick.
|
3
|
+
*
|
4
|
+
* Copyright © 2002 - 2009 by Timothy P. Hunter
|
5
|
+
*
|
6
|
+
* Changes since Nov. 2009 copyright © by Benjamin Thomas and Omer Bar-or
|
7
|
+
*
|
8
|
+
* @file rmutil.c
|
9
|
+
* @version $Id: rmutil.c,v 1.182 2009/12/21 10:34:58 baror Exp $
|
10
|
+
* @author Tim Hunter
|
11
|
+
******************************************************************************/
|
12
|
+
|
13
|
+
#include "rmagick.h"
|
14
|
+
#include <errno.h>
|
15
|
+
|
16
|
+
static void handle_exception(ExceptionInfo *, Image *, ErrorRetention);
|
17
|
+
|
18
|
+
|
19
|
+
/**
|
20
|
+
* ImageMagick safe version of malloc.
|
21
|
+
*
|
22
|
+
* No Ruby usage (internal function)
|
23
|
+
*
|
24
|
+
* Notes:
|
25
|
+
* - Use when managing memory that ImageMagick may have allocated or may free.
|
26
|
+
* - If malloc fails, it raises an exception.
|
27
|
+
* - magick_safe_malloc and magick_safe_realloc prevent exceptions caused by
|
28
|
+
* integer overflow. Added in 6.3.5-9 but backwards compatible with prior
|
29
|
+
* releases.
|
30
|
+
*
|
31
|
+
* @param count the number of quantum elements to allocate
|
32
|
+
* @param quantum the number of bytes in each quantum
|
33
|
+
* @return a pointer to a block of memory that is at least count*quantum
|
34
|
+
*/
|
35
|
+
void *
|
36
|
+
magick_safe_malloc(const size_t count, const size_t quantum)
|
37
|
+
{
|
38
|
+
void *ptr;
|
39
|
+
|
40
|
+
ptr = AcquireQuantumMemory(count, quantum);
|
41
|
+
if (!ptr)
|
42
|
+
{
|
43
|
+
rb_raise(rb_eNoMemError, "not enough memory to continue");
|
44
|
+
}
|
45
|
+
return ptr;
|
46
|
+
}
|
47
|
+
|
48
|
+
|
49
|
+
/**
|
50
|
+
* ImageMagick version of malloc.
|
51
|
+
*
|
52
|
+
* No Ruby usage (internal function)
|
53
|
+
*
|
54
|
+
* @param size the size of memory to allocate
|
55
|
+
* @return pointer to a block of memory
|
56
|
+
*/
|
57
|
+
void *
|
58
|
+
magick_malloc(const size_t size)
|
59
|
+
{
|
60
|
+
void *ptr;
|
61
|
+
ptr = AcquireMagickMemory(size);
|
62
|
+
if (!ptr)
|
63
|
+
{
|
64
|
+
rb_raise(rb_eNoMemError, "not enough memory to continue");
|
65
|
+
}
|
66
|
+
|
67
|
+
return ptr;
|
68
|
+
}
|
69
|
+
|
70
|
+
|
71
|
+
/**
|
72
|
+
* ImageMagick version of free.
|
73
|
+
*
|
74
|
+
* No Ruby usage (internal function)
|
75
|
+
*
|
76
|
+
* @param ptr pointer to the existing block of memory
|
77
|
+
*/
|
78
|
+
void
|
79
|
+
magick_free(void *ptr)
|
80
|
+
{
|
81
|
+
(void) RelinquishMagickMemory(ptr);
|
82
|
+
}
|
83
|
+
|
84
|
+
|
85
|
+
/**
|
86
|
+
* ImageMagick safe version of realloc.
|
87
|
+
*
|
88
|
+
* No Ruby usage (internal function)
|
89
|
+
*
|
90
|
+
* Notes:
|
91
|
+
* - Use when managing memory that ImageMagick may have allocated or may free.
|
92
|
+
* - If malloc fails, it raises an exception.
|
93
|
+
* - magick_safe_malloc and magick_safe_realloc prevent exceptions caused by
|
94
|
+
* integer overflow. Added in 6.3.5-9 but backwards compatible with prior
|
95
|
+
* releases.
|
96
|
+
*
|
97
|
+
* @param memory the existing block of memory
|
98
|
+
* @param count the number of quantum elements to allocate
|
99
|
+
* @param quantum the number of bytes in each quantum
|
100
|
+
* @return a pointer to a block of memory that is at least count*quantum in size
|
101
|
+
*/
|
102
|
+
void *
|
103
|
+
magick_safe_realloc(void *memory, const size_t count, const size_t quantum)
|
104
|
+
{
|
105
|
+
void *v;
|
106
|
+
v = ResizeQuantumMemory(memory, count, quantum);
|
107
|
+
if (!v)
|
108
|
+
{
|
109
|
+
rb_raise(rb_eNoMemError, "not enough memory to continue");
|
110
|
+
}
|
111
|
+
return v;
|
112
|
+
}
|
113
|
+
|
114
|
+
|
115
|
+
/**
|
116
|
+
* ImageMagick version of realloc.
|
117
|
+
*
|
118
|
+
* No Ruby usage (internal function)
|
119
|
+
*
|
120
|
+
* @param ptr pointer to the existing block of memory
|
121
|
+
* @param size the new size of memory to allocate
|
122
|
+
* @return pointer to a block of memory
|
123
|
+
*/
|
124
|
+
void *
|
125
|
+
magick_realloc(void *ptr, const size_t size)
|
126
|
+
{
|
127
|
+
void *v;
|
128
|
+
v = ResizeMagickMemory(ptr, size);
|
129
|
+
if (!v)
|
130
|
+
{
|
131
|
+
rb_raise(rb_eNoMemError, "not enough memory to continue");
|
132
|
+
}
|
133
|
+
return v;
|
134
|
+
}
|
135
|
+
|
136
|
+
|
137
|
+
/**
|
138
|
+
* Make a copy of a string in malloc'd memory.
|
139
|
+
*
|
140
|
+
* No Ruby usage (internal function)
|
141
|
+
*
|
142
|
+
* Notes:
|
143
|
+
* - Any existing string pointed to by *new_str is freed.
|
144
|
+
* - CloneString asserts if no memory. No need to check its return value.
|
145
|
+
*
|
146
|
+
* @param new_str pointer to the new string
|
147
|
+
* @param str the string to copy
|
148
|
+
*/
|
149
|
+
void
|
150
|
+
magick_clone_string(char **new_str, const char *str)
|
151
|
+
{
|
152
|
+
(void) CloneString(new_str, str);
|
153
|
+
}
|
154
|
+
|
155
|
+
|
156
|
+
/**
|
157
|
+
* Compare s1 and s2 ignoring case.
|
158
|
+
*
|
159
|
+
* No Ruby usage (internal function)
|
160
|
+
*
|
161
|
+
* @param s1 the first string
|
162
|
+
* @param s2 the second string
|
163
|
+
* @return same as strcmp(3)
|
164
|
+
*/
|
165
|
+
int
|
166
|
+
rm_strcasecmp(const char *s1, const char *s2)
|
167
|
+
{
|
168
|
+
while (*s1 && *s2)
|
169
|
+
{
|
170
|
+
if (toupper(*s1) != toupper(*s2))
|
171
|
+
{
|
172
|
+
break;
|
173
|
+
}
|
174
|
+
s1 += 1;
|
175
|
+
s2 += 1;
|
176
|
+
}
|
177
|
+
return (int)(*s1 - *s2);
|
178
|
+
}
|
179
|
+
|
180
|
+
|
181
|
+
/**
|
182
|
+
* Compare s1 and s2 ignoring case.
|
183
|
+
*
|
184
|
+
* No Ruby usage (internal function)
|
185
|
+
*
|
186
|
+
* @param s1 the first string
|
187
|
+
* @param s2 the second string
|
188
|
+
* @param n number of characters to compare
|
189
|
+
* @return same as strcmp(3)
|
190
|
+
*/
|
191
|
+
int
|
192
|
+
rm_strncasecmp(const char *s1, const char *s2, size_t n)
|
193
|
+
{
|
194
|
+
if (n == 0)
|
195
|
+
{
|
196
|
+
return 0;
|
197
|
+
}
|
198
|
+
while (toupper(*s1) == toupper(*s2))
|
199
|
+
{
|
200
|
+
if (--n == 0 || *s1 == '\0')
|
201
|
+
{
|
202
|
+
return 0;
|
203
|
+
}
|
204
|
+
s1 += 1;
|
205
|
+
s2 += 1;
|
206
|
+
}
|
207
|
+
return (int)(*s1 - *s2);
|
208
|
+
}
|
209
|
+
|
210
|
+
|
211
|
+
/**
|
212
|
+
* Raise exception if array too short.
|
213
|
+
*
|
214
|
+
* No Ruby usage (internal function)
|
215
|
+
*
|
216
|
+
* @param ary the array
|
217
|
+
* @param len the minimum length
|
218
|
+
* @throw IndexError
|
219
|
+
*/
|
220
|
+
void
|
221
|
+
rm_check_ary_len(VALUE ary, long len)
|
222
|
+
{
|
223
|
+
if (RARRAY_LEN(ary) < len)
|
224
|
+
{
|
225
|
+
rb_raise(rb_eIndexError, "not enough elements in array - expecting %ld, got %ld",
|
226
|
+
len, (long)RARRAY_LEN(ary));
|
227
|
+
}
|
228
|
+
}
|
229
|
+
|
230
|
+
|
231
|
+
/**
|
232
|
+
* Raise an error if the image has been destroyed.
|
233
|
+
*
|
234
|
+
* No Ruby usage (internal function)
|
235
|
+
*
|
236
|
+
* @param obj the image
|
237
|
+
* @return the C image structure for the image
|
238
|
+
* @throw DestroyedImageError
|
239
|
+
*/
|
240
|
+
Image *
|
241
|
+
rm_check_destroyed(VALUE obj)
|
242
|
+
{
|
243
|
+
Image *image;
|
244
|
+
|
245
|
+
Data_Get_Struct(obj, Image, image);
|
246
|
+
if (!image)
|
247
|
+
{
|
248
|
+
rb_raise(Class_DestroyedImageError, "destroyed image");
|
249
|
+
}
|
250
|
+
|
251
|
+
return image;
|
252
|
+
}
|
253
|
+
|
254
|
+
|
255
|
+
/**
|
256
|
+
* Raise an error if the image has been destroyed or is frozen.
|
257
|
+
*
|
258
|
+
* No Ruby usage (internal function)
|
259
|
+
*
|
260
|
+
* @param obj the image
|
261
|
+
* @return the C image structure for the image
|
262
|
+
*/
|
263
|
+
Image *
|
264
|
+
rm_check_frozen(VALUE obj)
|
265
|
+
{
|
266
|
+
Image *image = rm_check_destroyed(obj);
|
267
|
+
rb_check_frozen(obj);
|
268
|
+
return image;
|
269
|
+
}
|
270
|
+
|
271
|
+
|
272
|
+
/**
|
273
|
+
* Overrides freeze in classes that can't be frozen.
|
274
|
+
*
|
275
|
+
* No Ruby usage (internal function)
|
276
|
+
*
|
277
|
+
* @param obj the object of the class to override
|
278
|
+
* @return 0
|
279
|
+
* @throw TypeError
|
280
|
+
*/
|
281
|
+
VALUE
|
282
|
+
rm_no_freeze(VALUE obj)
|
283
|
+
{
|
284
|
+
rb_raise(rb_eTypeError, "can't freeze %s", rb_class2name(CLASS_OF(obj)));
|
285
|
+
return (VALUE)0;
|
286
|
+
}
|
287
|
+
|
288
|
+
|
289
|
+
/**
|
290
|
+
* Return obj.to_s, or obj if obj is already a string.
|
291
|
+
*
|
292
|
+
* No Ruby usage (internal function)
|
293
|
+
*
|
294
|
+
* @param obj a Ruby object
|
295
|
+
* @return a String representation of obj
|
296
|
+
*/
|
297
|
+
VALUE
|
298
|
+
rm_to_s(VALUE obj)
|
299
|
+
{
|
300
|
+
|
301
|
+
if (TYPE(obj) != T_STRING)
|
302
|
+
{
|
303
|
+
return rb_funcall(obj, rm_ID_to_s, 0);
|
304
|
+
}
|
305
|
+
return obj;
|
306
|
+
}
|
307
|
+
|
308
|
+
|
309
|
+
/**
|
310
|
+
* Supply our own version of the "obsolete" rb_str2cstr.
|
311
|
+
*
|
312
|
+
* No Ruby usage (internal function)
|
313
|
+
*
|
314
|
+
* @param str the Ruby string
|
315
|
+
* @param len pointer to a long in which to store the number of characters
|
316
|
+
* @return a C string version of str
|
317
|
+
*/
|
318
|
+
char *
|
319
|
+
rm_str2cstr(VALUE str, long *len)
|
320
|
+
{
|
321
|
+
StringValue(str);
|
322
|
+
if (len)
|
323
|
+
{
|
324
|
+
*len = RSTRING_LEN(str);
|
325
|
+
}
|
326
|
+
return RSTRING_PTR(str);
|
327
|
+
}
|
328
|
+
|
329
|
+
|
330
|
+
/**
|
331
|
+
* Try to convert the argument to a double, raise an exception if fail.
|
332
|
+
*
|
333
|
+
* No Ruby usage (internal function)
|
334
|
+
*
|
335
|
+
* @param arg the argument
|
336
|
+
* @return arg
|
337
|
+
*/
|
338
|
+
static VALUE
|
339
|
+
arg_is_number(VALUE arg)
|
340
|
+
{
|
341
|
+
double d;
|
342
|
+
d = NUM2DBL(arg);
|
343
|
+
d = d; // satisfy icc
|
344
|
+
return arg;
|
345
|
+
}
|
346
|
+
|
347
|
+
|
348
|
+
/**
|
349
|
+
* Called when `rb_str_to_str' raises an exception.
|
350
|
+
*
|
351
|
+
* No Ruby usage (internal function)
|
352
|
+
*
|
353
|
+
* @param arg the argument
|
354
|
+
* @return 0
|
355
|
+
* @throw TypeError
|
356
|
+
*/
|
357
|
+
static VALUE
|
358
|
+
rescue_not_str(VALUE arg)
|
359
|
+
{
|
360
|
+
rb_raise(rb_eTypeError, "argument must be a number or a string in the form 'NN%%' (%s given)",
|
361
|
+
rb_class2name(CLASS_OF(arg)));
|
362
|
+
return (VALUE)0;
|
363
|
+
}
|
364
|
+
|
365
|
+
|
366
|
+
/**
|
367
|
+
* Return a double between 0.0 and max (the second argument), inclusive. If the
|
368
|
+
* argument is a number convert to a Float object, otherwise it's supposed to be
|
369
|
+
* a string in the form * "NN%". Convert to a number and then to a Float.
|
370
|
+
*
|
371
|
+
* No Ruby usage (internal function)
|
372
|
+
*
|
373
|
+
* @param arg the argument
|
374
|
+
* @param max the maximum allowed value
|
375
|
+
* @return a double
|
376
|
+
*/
|
377
|
+
double
|
378
|
+
rm_percentage(VALUE arg, double max)
|
379
|
+
{
|
380
|
+
double pct;
|
381
|
+
long pct_long;
|
382
|
+
char *pct_str, *end;
|
383
|
+
int not_num;
|
384
|
+
|
385
|
+
// Try to convert the argument to a number. If failure, sets not_num to non-zero.
|
386
|
+
(void) rb_protect(arg_is_number, arg, ¬_num);
|
387
|
+
|
388
|
+
if (not_num)
|
389
|
+
{
|
390
|
+
arg = rb_rescue(rb_str_to_str, arg, rescue_not_str, arg);
|
391
|
+
pct_str = StringValuePtr(arg);
|
392
|
+
errno = 0;
|
393
|
+
pct_long = strtol(pct_str, &end, 10);
|
394
|
+
if (errno == ERANGE)
|
395
|
+
{
|
396
|
+
rb_raise(rb_eRangeError, "`%s' out of range", pct_str);
|
397
|
+
}
|
398
|
+
if (*end != '\0' && *end != '%')
|
399
|
+
{
|
400
|
+
rb_raise(rb_eArgError, "expected percentage, got `%s'", pct_str);
|
401
|
+
}
|
402
|
+
|
403
|
+
if (*end == '%' && pct_long != 0)
|
404
|
+
{
|
405
|
+
pct = (((double)pct_long) / 100.0) * max;
|
406
|
+
}
|
407
|
+
else
|
408
|
+
{
|
409
|
+
pct = (double) pct_long;
|
410
|
+
}
|
411
|
+
if (pct < 0.0)
|
412
|
+
{
|
413
|
+
rb_raise(rb_eArgError, "percentages may not be negative (got `%s')", pct_str);
|
414
|
+
}
|
415
|
+
}
|
416
|
+
else
|
417
|
+
{
|
418
|
+
pct = NUM2DBL(arg);
|
419
|
+
if (pct < 0.0)
|
420
|
+
{
|
421
|
+
rb_raise(rb_eArgError, "percentages may not be negative (got `%g')", pct);
|
422
|
+
}
|
423
|
+
}
|
424
|
+
|
425
|
+
return pct;
|
426
|
+
}
|
427
|
+
|
428
|
+
|
429
|
+
/**
|
430
|
+
* Return 0 if rb_num2dbl doesn't raise an exception.
|
431
|
+
*
|
432
|
+
* No Ruby usage (internal function)
|
433
|
+
*
|
434
|
+
* @param obj the object to convert to a double
|
435
|
+
* @return 0
|
436
|
+
*/
|
437
|
+
static VALUE
|
438
|
+
check_num2dbl(VALUE obj)
|
439
|
+
{
|
440
|
+
(void) rb_num2dbl(obj);
|
441
|
+
return INT2FIX(1);
|
442
|
+
}
|
443
|
+
|
444
|
+
|
445
|
+
/**
|
446
|
+
* Called if rb_num2dbl raises an exception.
|
447
|
+
*
|
448
|
+
* No Ruby usage (internal function)
|
449
|
+
*
|
450
|
+
* @param ignored a Ruby object (unused)
|
451
|
+
* @return 0
|
452
|
+
*/
|
453
|
+
static VALUE
|
454
|
+
rescue_not_dbl(VALUE ignored)
|
455
|
+
{
|
456
|
+
ignored = ignored; // defeat gcc message
|
457
|
+
return INT2FIX(0);
|
458
|
+
}
|
459
|
+
|
460
|
+
|
461
|
+
/**
|
462
|
+
* Return 1 if the object can be converted to a double, 0 otherwise.
|
463
|
+
*
|
464
|
+
* No Ruby usage (internal function)
|
465
|
+
*
|
466
|
+
* @param obj the object
|
467
|
+
* @return 1 or 0
|
468
|
+
*/
|
469
|
+
int
|
470
|
+
rm_check_num2dbl(VALUE obj)
|
471
|
+
{
|
472
|
+
return FIX2INT(rb_rescue(check_num2dbl, obj, rescue_not_dbl, (VALUE)0));
|
473
|
+
}
|
474
|
+
|
475
|
+
|
476
|
+
/**
|
477
|
+
* Given a string in the form NN% return the corresponding double.
|
478
|
+
*
|
479
|
+
* No Ruby usage (internal function)
|
480
|
+
*
|
481
|
+
* @param str the string
|
482
|
+
* @return a double
|
483
|
+
*/
|
484
|
+
double
|
485
|
+
rm_str_to_pct(VALUE str)
|
486
|
+
{
|
487
|
+
long pct;
|
488
|
+
char *pct_str, *end;
|
489
|
+
|
490
|
+
str = rb_rescue(rb_str_to_str, str, rescue_not_str, str);
|
491
|
+
pct_str = StringValuePtr(str);
|
492
|
+
errno = 0;
|
493
|
+
pct = strtol(pct_str, &end, 10);
|
494
|
+
|
495
|
+
if (errno == ERANGE)
|
496
|
+
{
|
497
|
+
rb_raise(rb_eRangeError, "`%s' out of range", pct_str);
|
498
|
+
}
|
499
|
+
if (*end != '%')
|
500
|
+
{
|
501
|
+
rb_raise(rb_eArgError, "expected percentage, got `%s'", pct_str);
|
502
|
+
}
|
503
|
+
if (pct < 0L)
|
504
|
+
{
|
505
|
+
rb_raise(rb_eArgError, "percentages may not be negative (got `%s')", pct_str);
|
506
|
+
}
|
507
|
+
|
508
|
+
return pct / 100.0;
|
509
|
+
}
|
510
|
+
|
511
|
+
|
512
|
+
/**
|
513
|
+
* If the argument is a number, convert it to a double. Otherwise it's supposed
|
514
|
+
* to be a string in the form 'NN%'. Return a percentage of QuantumRange.
|
515
|
+
*
|
516
|
+
* No Ruby usage (internal function)
|
517
|
+
*
|
518
|
+
* @param fuzz_arg the fuzz argument
|
519
|
+
* @return a double
|
520
|
+
* @see Image_fuzz
|
521
|
+
* @see Image_fuzz_eq
|
522
|
+
*/
|
523
|
+
double
|
524
|
+
rm_fuzz_to_dbl(VALUE fuzz_arg)
|
525
|
+
{
|
526
|
+
double fuzz;
|
527
|
+
char *fuzz_str, *end;
|
528
|
+
int not_num;
|
529
|
+
|
530
|
+
// Try to convert the argument to a number. If failure, sets not_num to non-zero.
|
531
|
+
(void) rb_protect(arg_is_number, fuzz_arg, ¬_num);
|
532
|
+
|
533
|
+
if (not_num)
|
534
|
+
{
|
535
|
+
// Convert to string, issue error message if failure.
|
536
|
+
fuzz_arg = rb_rescue(rb_str_to_str, fuzz_arg, rescue_not_str, fuzz_arg);
|
537
|
+
fuzz_str = StringValuePtr(fuzz_arg);
|
538
|
+
errno = 0;
|
539
|
+
fuzz = strtod(fuzz_str, &end);
|
540
|
+
if (errno == ERANGE)
|
541
|
+
{
|
542
|
+
rb_raise(rb_eRangeError, "`%s' out of range", fuzz_str);
|
543
|
+
}
|
544
|
+
if(*end == '%')
|
545
|
+
{
|
546
|
+
if (fuzz < 0.0)
|
547
|
+
{
|
548
|
+
rb_raise(rb_eArgError, "percentages may not be negative (got `%s')", fuzz_str);
|
549
|
+
}
|
550
|
+
fuzz = (fuzz * QuantumRange) / 100.0;
|
551
|
+
}
|
552
|
+
else if(*end != '\0')
|
553
|
+
{
|
554
|
+
rb_raise(rb_eArgError, "expected percentage, got `%s'", fuzz_str);
|
555
|
+
}
|
556
|
+
}
|
557
|
+
else
|
558
|
+
{
|
559
|
+
fuzz = NUM2DBL(fuzz_arg);
|
560
|
+
if (fuzz < 0.0)
|
561
|
+
{
|
562
|
+
rb_raise(rb_eArgError, "fuzz may not be negative (got `%g')", fuzz);
|
563
|
+
}
|
564
|
+
}
|
565
|
+
|
566
|
+
return fuzz;
|
567
|
+
}
|
568
|
+
|
569
|
+
|
570
|
+
/**
|
571
|
+
* Convert a application-supplied number to a Quantum. If the object is a Float,
|
572
|
+
* truncate it before converting.
|
573
|
+
*
|
574
|
+
* No Ruby usage (internal function)
|
575
|
+
*
|
576
|
+
* Notes:
|
577
|
+
* - Ruby says that 2147483647.5 doesn't fit into an unsigned long. If you
|
578
|
+
* truncate it, it works.
|
579
|
+
* - Should use this only when the input value is possibly subject to this
|
580
|
+
* problem.
|
581
|
+
*
|
582
|
+
* @param obj the application-supplied number
|
583
|
+
* @return a Quantum
|
584
|
+
*/
|
585
|
+
Quantum
|
586
|
+
rm_app2quantum(VALUE obj)
|
587
|
+
{
|
588
|
+
VALUE v = obj;
|
589
|
+
|
590
|
+
if (TYPE(obj) == T_FLOAT)
|
591
|
+
{
|
592
|
+
v = rb_funcall(obj, rm_ID_to_i, 0);
|
593
|
+
}
|
594
|
+
|
595
|
+
RB_GC_GUARD(v);
|
596
|
+
|
597
|
+
return NUM2QUANTUM(v);
|
598
|
+
}
|
599
|
+
|
600
|
+
|
601
|
+
/**
|
602
|
+
* Send the "cur_image" method to the object. If 'img' is an ImageList, then
|
603
|
+
* cur_image is self[\@scene]. If 'img' is an image, then cur_image is simply
|
604
|
+
* 'self'.
|
605
|
+
*
|
606
|
+
* No Ruby usage (internal function)
|
607
|
+
*
|
608
|
+
* @param img the object
|
609
|
+
* @return the return value from "cur_image"
|
610
|
+
*/
|
611
|
+
VALUE
|
612
|
+
rm_cur_image(VALUE img)
|
613
|
+
{
|
614
|
+
return rb_funcall(img, rm_ID_cur_image, 0);
|
615
|
+
}
|
616
|
+
|
617
|
+
|
618
|
+
/**
|
619
|
+
* Map the color intensity to a named color.
|
620
|
+
*
|
621
|
+
* No Ruby usage (internal function)
|
622
|
+
*
|
623
|
+
* @param image the image
|
624
|
+
* @param color the color intensity as a PixelPacket
|
625
|
+
* @return the named color as a String
|
626
|
+
* @see rm_pixelpacket_to_color_name_info
|
627
|
+
*/
|
628
|
+
VALUE
|
629
|
+
rm_pixelpacket_to_color_name(Image *image, PixelPacket *color)
|
630
|
+
{
|
631
|
+
char name[MaxTextExtent];
|
632
|
+
ExceptionInfo *exception;
|
633
|
+
|
634
|
+
exception = AcquireExceptionInfo();
|
635
|
+
|
636
|
+
(void) QueryColorname(image, color, X11Compliance, name, exception);
|
637
|
+
CHECK_EXCEPTION()
|
638
|
+
(void) DestroyExceptionInfo(exception);
|
639
|
+
|
640
|
+
return rb_str_new2(name);
|
641
|
+
}
|
642
|
+
|
643
|
+
|
644
|
+
/**
|
645
|
+
* Map the color intensity to a named color.
|
646
|
+
*
|
647
|
+
* No Ruby usage (internal function)
|
648
|
+
*
|
649
|
+
* Notes:
|
650
|
+
* - Simply create an Image from the Info, call QueryColorname, and then
|
651
|
+
* destroy the Image.
|
652
|
+
* - If the Info structure is NULL, creates a new one.
|
653
|
+
* - The default depth is always used, and the matte value is set to False,
|
654
|
+
* which means "don't use the alpha channel".
|
655
|
+
*
|
656
|
+
* @param info the info
|
657
|
+
* @param color the color intensity as a PixelPacket
|
658
|
+
* @return the named color as a String
|
659
|
+
* @see rm_pixelpacket_to_color_name
|
660
|
+
*/
|
661
|
+
VALUE
|
662
|
+
rm_pixelpacket_to_color_name_info(Info *info, PixelPacket *color)
|
663
|
+
{
|
664
|
+
Image *image;
|
665
|
+
Info *my_info;
|
666
|
+
VALUE color_name;
|
667
|
+
|
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)
|
675
|
+
{
|
676
|
+
(void) DestroyImageInfo(my_info);
|
677
|
+
}
|
678
|
+
|
679
|
+
RB_GC_GUARD(color_name);
|
680
|
+
|
681
|
+
return color_name;
|
682
|
+
}
|
683
|
+
|
684
|
+
|
685
|
+
/**
|
686
|
+
* Write a temporary copy of the image to the IM registry.
|
687
|
+
*
|
688
|
+
* No Ruby usage (internal function)
|
689
|
+
*
|
690
|
+
* Notes:
|
691
|
+
* - The `temp_name' argument must point to an char array of size
|
692
|
+
* MaxTextExtent.
|
693
|
+
*
|
694
|
+
* @param image the image
|
695
|
+
* @param temp_name the temporary name to use
|
696
|
+
* @return the "filename" of the registered image
|
697
|
+
*/
|
698
|
+
void
|
699
|
+
rm_write_temp_image(Image *image, char *temp_name)
|
700
|
+
{
|
701
|
+
|
702
|
+
#define TMPNAM_CLASS_VAR "@@_tmpnam_"
|
703
|
+
|
704
|
+
MagickBooleanType okay;
|
705
|
+
ExceptionInfo *exception;
|
706
|
+
VALUE id_value;
|
707
|
+
int id;
|
708
|
+
|
709
|
+
exception = AcquireExceptionInfo();
|
710
|
+
|
711
|
+
|
712
|
+
// 'id' is always the value of its previous use
|
713
|
+
if (rb_cvar_defined(Module_Magick, rb_intern(TMPNAM_CLASS_VAR)) == Qtrue)
|
714
|
+
{
|
715
|
+
id_value = rb_cv_get(Module_Magick, TMPNAM_CLASS_VAR);
|
716
|
+
id = FIX2INT(id_value);
|
717
|
+
}
|
718
|
+
else
|
719
|
+
{
|
720
|
+
id = 0;
|
721
|
+
rb_cv_set(Module_Magick, TMPNAM_CLASS_VAR, INT2FIX(id));
|
722
|
+
}
|
723
|
+
|
724
|
+
id += 1;
|
725
|
+
rb_cv_set(Module_Magick, TMPNAM_CLASS_VAR, INT2FIX(id));
|
726
|
+
sprintf(temp_name, "mpri:%d", id);
|
727
|
+
|
728
|
+
// Omit "mpri:" from filename to form the key
|
729
|
+
okay = SetImageRegistry(ImageRegistryType, temp_name+5, image, exception);
|
730
|
+
CHECK_EXCEPTION()
|
731
|
+
DestroyExceptionInfo(exception);
|
732
|
+
if (!okay)
|
733
|
+
{
|
734
|
+
rb_raise(rb_eRuntimeError, "SetImageRegistry failed.");
|
735
|
+
}
|
736
|
+
|
737
|
+
RB_GC_GUARD(id_value);
|
738
|
+
}
|
739
|
+
|
740
|
+
|
741
|
+
/**
|
742
|
+
* Delete the temporary image from the registry.
|
743
|
+
*
|
744
|
+
* No Ruby usage (internal function)
|
745
|
+
*
|
746
|
+
* @param temp_name the name of temporary image in the registry.
|
747
|
+
*/
|
748
|
+
void
|
749
|
+
rm_delete_temp_image(char *temp_name)
|
750
|
+
{
|
751
|
+
MagickBooleanType okay = DeleteImageRegistry(temp_name+5);
|
752
|
+
|
753
|
+
if (!okay)
|
754
|
+
{
|
755
|
+
rb_warn("DeleteImageRegistry failed for `%s'", temp_name);
|
756
|
+
}
|
757
|
+
}
|
758
|
+
|
759
|
+
|
760
|
+
/**
|
761
|
+
* Raise NotImplementedError.
|
762
|
+
*
|
763
|
+
* No Ruby usage (internal function)
|
764
|
+
*
|
765
|
+
* Notes:
|
766
|
+
* - Called when a xMagick API is not available.
|
767
|
+
* - Replaces Ruby's rb_notimplement function.
|
768
|
+
*
|
769
|
+
* @throw NotImpError
|
770
|
+
*/
|
771
|
+
void
|
772
|
+
rm_not_implemented(void)
|
773
|
+
{
|
774
|
+
|
775
|
+
rb_raise(rb_eNotImpError, "the `%s' method is not supported by ImageMagick "
|
776
|
+
MagickLibVersionText, rb_id2name(THIS_FUNC()));
|
777
|
+
}
|
778
|
+
|
779
|
+
|
780
|
+
/**
|
781
|
+
* Create a new ImageMagickError object and raise an exception.
|
782
|
+
*
|
783
|
+
* No Ruby usage (internal function)
|
784
|
+
*
|
785
|
+
* Notes:
|
786
|
+
* - This funky technique allows me to safely add additional information to
|
787
|
+
* the ImageMagickError object in both 1.6.8 and 1.8.0.
|
788
|
+
*
|
789
|
+
* @param msg the error mesage
|
790
|
+
* @param loc the location of the error
|
791
|
+
* @throw ImageMagickError
|
792
|
+
* @see www.ruby_talk.org/36408.
|
793
|
+
*/
|
794
|
+
void
|
795
|
+
rm_magick_error(const char *msg, const char *loc)
|
796
|
+
{
|
797
|
+
VALUE exc, mesg, extra;
|
798
|
+
|
799
|
+
mesg = rb_str_new2(msg);
|
800
|
+
extra = loc ? rb_str_new2(loc) : Qnil;
|
801
|
+
|
802
|
+
exc = rb_funcall(Class_ImageMagickError, rm_ID_new, 2, mesg, extra);
|
803
|
+
(void) rb_funcall(rb_cObject, rb_intern("raise"), 1, exc);
|
804
|
+
|
805
|
+
RB_GC_GUARD(exc);
|
806
|
+
RB_GC_GUARD(mesg);
|
807
|
+
RB_GC_GUARD(extra);
|
808
|
+
}
|
809
|
+
|
810
|
+
|
811
|
+
/**
|
812
|
+
* Initialize a new ImageMagickError object - store the "loc" string in the
|
813
|
+
* \@magick_location instance variable.
|
814
|
+
*
|
815
|
+
* Ruby usage:
|
816
|
+
* - @verbatim ImageMagickError#initialize(msg) @endverbatim
|
817
|
+
* - @verbatim ImageMagickError#initialize(msg, loc) @endverbatim
|
818
|
+
*
|
819
|
+
* Notes:
|
820
|
+
* - Default loc is nil
|
821
|
+
*
|
822
|
+
* @param argc number of input arguments
|
823
|
+
* @param argv array of input arguments
|
824
|
+
* @param self this object
|
825
|
+
* @return self
|
826
|
+
*/
|
827
|
+
VALUE
|
828
|
+
ImageMagickError_initialize(int argc, VALUE *argv, VALUE self)
|
829
|
+
{
|
830
|
+
VALUE super_argv[1] = {(VALUE)0};
|
831
|
+
int super_argc = 0;
|
832
|
+
VALUE extra = Qnil;
|
833
|
+
|
834
|
+
switch(argc)
|
835
|
+
{
|
836
|
+
case 2:
|
837
|
+
extra = argv[1];
|
838
|
+
case 1:
|
839
|
+
super_argv[0] = argv[0];
|
840
|
+
super_argc = 1;
|
841
|
+
case 0:
|
842
|
+
break;
|
843
|
+
default:
|
844
|
+
rb_raise(rb_eArgError, "wrong number of arguments (%d for 0 to 2)", argc);
|
845
|
+
}
|
846
|
+
|
847
|
+
(void) rb_call_super(super_argc, (const VALUE *)super_argv);
|
848
|
+
(void) rb_iv_set(self, "@"MAGICK_LOC, extra);
|
849
|
+
|
850
|
+
RB_GC_GUARD(extra);
|
851
|
+
|
852
|
+
return self;
|
853
|
+
}
|
854
|
+
|
855
|
+
|
856
|
+
/**
|
857
|
+
* Backport GetImageProperty for pre-6.3.1 versions of ImageMagick.
|
858
|
+
*
|
859
|
+
* No Ruby usage (internal function)
|
860
|
+
*
|
861
|
+
* @param img the image
|
862
|
+
* @param property the property name
|
863
|
+
* @return the property value
|
864
|
+
*/
|
865
|
+
const char *
|
866
|
+
rm_get_property(const Image *img, const char *property)
|
867
|
+
{
|
868
|
+
return GetImageProperty(img, property);
|
869
|
+
}
|
870
|
+
|
871
|
+
|
872
|
+
/**
|
873
|
+
* Backport SetImageProperty for pre-6.3.1 versions of ImageMagick.
|
874
|
+
*
|
875
|
+
* No Ruby usage (internal function)
|
876
|
+
*
|
877
|
+
* @param image the image
|
878
|
+
* @param property the property name
|
879
|
+
* @param value the property value
|
880
|
+
* @return true if successful, otherwise false
|
881
|
+
*/
|
882
|
+
MagickBooleanType
|
883
|
+
rm_set_property(Image *image, const char *property, const char *value)
|
884
|
+
{
|
885
|
+
return SetImageProperty(image, property, value);
|
886
|
+
}
|
887
|
+
|
888
|
+
|
889
|
+
/**
|
890
|
+
* If a "user" option is present in the Info, assign its value to a "user"
|
891
|
+
* artifact in each image.
|
892
|
+
*
|
893
|
+
* No Ruby usage (internal function)
|
894
|
+
*
|
895
|
+
* @param images a list of images
|
896
|
+
* @param info the info
|
897
|
+
*/
|
898
|
+
void rm_set_user_artifact(Image *images, Info *info)
|
899
|
+
{
|
900
|
+
#if defined(HAVE_SETIMAGEARTIFACT)
|
901
|
+
Image *image;
|
902
|
+
const char *value;
|
903
|
+
|
904
|
+
value = GetImageOption(info, "user");
|
905
|
+
if (value)
|
906
|
+
{
|
907
|
+
image = GetFirstImageInList(images);
|
908
|
+
while (image)
|
909
|
+
{
|
910
|
+
(void) SetImageArtifact(image, "user", value);
|
911
|
+
image = GetNextImageInList(image);
|
912
|
+
}
|
913
|
+
}
|
914
|
+
#else
|
915
|
+
images = images;
|
916
|
+
info = info;
|
917
|
+
#endif
|
918
|
+
}
|
919
|
+
|
920
|
+
|
921
|
+
/**
|
922
|
+
* Collect optional method arguments via Magick::OptionalMethodArguments.
|
923
|
+
*
|
924
|
+
* No Ruby usage (internal function)
|
925
|
+
*
|
926
|
+
* Notes:
|
927
|
+
* - Creates an instance of Magick::OptionalMethodArguments, then yields to a
|
928
|
+
* block in the context of the instance.
|
929
|
+
*
|
930
|
+
* @param img the image
|
931
|
+
*/
|
932
|
+
void
|
933
|
+
rm_get_optional_arguments(VALUE img)
|
934
|
+
{
|
935
|
+
VALUE optional_method_arguments;
|
936
|
+
VALUE opt_args;
|
937
|
+
VALUE argv[1];
|
938
|
+
|
939
|
+
// opt_args = Magick::OptionalMethodArguments.new(img)
|
940
|
+
// opt_args.instance_eval { block }
|
941
|
+
if (rb_block_given_p())
|
942
|
+
{
|
943
|
+
optional_method_arguments = rb_const_get_from(Module_Magick, rb_intern("OptionalMethodArguments"));
|
944
|
+
argv[0] = img;
|
945
|
+
opt_args = rb_class_new_instance(1, argv, optional_method_arguments);
|
946
|
+
(void) rb_obj_instance_eval(0, NULL, opt_args);
|
947
|
+
}
|
948
|
+
|
949
|
+
RB_GC_GUARD(optional_method_arguments);
|
950
|
+
RB_GC_GUARD(opt_args);
|
951
|
+
|
952
|
+
return;
|
953
|
+
}
|
954
|
+
|
955
|
+
|
956
|
+
#if defined(HAVE_SETIMAGEARTIFACT)
|
957
|
+
/**
|
958
|
+
* Copy image options from the Info structure to the Image structure.
|
959
|
+
*
|
960
|
+
* No Ruby usage (internal function)
|
961
|
+
*
|
962
|
+
* @param image the Image structure to modify
|
963
|
+
* @param info the Info structure
|
964
|
+
*/
|
965
|
+
static void copy_options(Image *image, Info *info)
|
966
|
+
{
|
967
|
+
char property[MaxTextExtent];
|
968
|
+
const char *value, *option;
|
969
|
+
|
970
|
+
ResetImageOptionIterator(info);
|
971
|
+
for (option = GetNextImageOption(info); option; option = GetNextImageOption(info))
|
972
|
+
{
|
973
|
+
value = GetImageOption(info,option);
|
974
|
+
if (value)
|
975
|
+
{
|
976
|
+
strncpy(property, value, MaxTextExtent);
|
977
|
+
property[MaxTextExtent-1] = '\0';
|
978
|
+
(void) SetImageArtifact(image, property, value);
|
979
|
+
}
|
980
|
+
}
|
981
|
+
}
|
982
|
+
#endif
|
983
|
+
|
984
|
+
|
985
|
+
/**
|
986
|
+
* Propagate ImageInfo values to the Image
|
987
|
+
*
|
988
|
+
* No Ruby usage (internal function)
|
989
|
+
*
|
990
|
+
* @param image the Image structure to modify
|
991
|
+
* @param info the Info structure
|
992
|
+
* @see SyncImageSettings in mogrify.c in ImageMagick
|
993
|
+
*/
|
994
|
+
void rm_sync_image_options(Image *image, Info *info)
|
995
|
+
{
|
996
|
+
MagickStatusType flags;
|
997
|
+
GeometryInfo geometry_info;
|
998
|
+
const char *option;
|
999
|
+
|
1000
|
+
// The option strings will be set only when their attribute values were
|
1001
|
+
// set in the optional argument block.
|
1002
|
+
option = GetImageOption(info,"background");
|
1003
|
+
if (option)
|
1004
|
+
{
|
1005
|
+
image->background_color = info->background_color;
|
1006
|
+
}
|
1007
|
+
|
1008
|
+
option = GetImageOption(info,"bordercolor");
|
1009
|
+
if (option)
|
1010
|
+
{
|
1011
|
+
image->border_color = info->border_color;
|
1012
|
+
}
|
1013
|
+
|
1014
|
+
if (info->colorspace != UndefinedColorspace)
|
1015
|
+
{
|
1016
|
+
image->colorspace = info->colorspace;
|
1017
|
+
}
|
1018
|
+
|
1019
|
+
if (info->compression != UndefinedCompression)
|
1020
|
+
{
|
1021
|
+
image->compression = info->compression;
|
1022
|
+
}
|
1023
|
+
|
1024
|
+
option = GetImageOption(info, "delay");
|
1025
|
+
if (option)
|
1026
|
+
{
|
1027
|
+
image->delay = strtoul(option, NULL, 0);
|
1028
|
+
}
|
1029
|
+
|
1030
|
+
if (info->density)
|
1031
|
+
{
|
1032
|
+
flags = ParseGeometry(info->density, &geometry_info);
|
1033
|
+
image->x_resolution = geometry_info.rho;
|
1034
|
+
image->y_resolution = geometry_info.sigma;
|
1035
|
+
if ((flags & SigmaValue) == 0)
|
1036
|
+
{
|
1037
|
+
image->y_resolution = image->x_resolution;
|
1038
|
+
}
|
1039
|
+
}
|
1040
|
+
|
1041
|
+
if (info->depth != 0)
|
1042
|
+
{
|
1043
|
+
image->depth = info->depth;
|
1044
|
+
}
|
1045
|
+
|
1046
|
+
option = GetImageOption(info, "dispose");
|
1047
|
+
if (option)
|
1048
|
+
{
|
1049
|
+
image->dispose = rm_dispose_to_enum(option);
|
1050
|
+
}
|
1051
|
+
|
1052
|
+
if (info->extract)
|
1053
|
+
{
|
1054
|
+
ParseAbsoluteGeometry(info->extract, &image->extract_info);
|
1055
|
+
}
|
1056
|
+
|
1057
|
+
if (info->fuzz != 0.0)
|
1058
|
+
{
|
1059
|
+
image->fuzz = info->fuzz;
|
1060
|
+
}
|
1061
|
+
|
1062
|
+
option = GetImageOption(info, "gravity");
|
1063
|
+
if (option)
|
1064
|
+
{
|
1065
|
+
image->gravity = rm_gravity_to_enum(option);
|
1066
|
+
}
|
1067
|
+
|
1068
|
+
if (info->interlace != NoInterlace)
|
1069
|
+
{
|
1070
|
+
image->interlace = info->interlace;
|
1071
|
+
}
|
1072
|
+
|
1073
|
+
option = GetImageOption(info,"mattecolor");
|
1074
|
+
if (option)
|
1075
|
+
{
|
1076
|
+
image->matte_color = info->matte_color;
|
1077
|
+
}
|
1078
|
+
|
1079
|
+
if (info->orientation != UndefinedOrientation)
|
1080
|
+
{
|
1081
|
+
image->orientation = info->orientation;
|
1082
|
+
}
|
1083
|
+
|
1084
|
+
if (info->page)
|
1085
|
+
{
|
1086
|
+
(void)ParseAbsoluteGeometry(info->page, &image->page);
|
1087
|
+
}
|
1088
|
+
|
1089
|
+
if (info->quality != 0UL)
|
1090
|
+
{
|
1091
|
+
image->quality = info->quality;
|
1092
|
+
}
|
1093
|
+
|
1094
|
+
option = GetImageOption(info, "scene");
|
1095
|
+
if (option)
|
1096
|
+
{
|
1097
|
+
image->scene = info->scene;
|
1098
|
+
}
|
1099
|
+
|
1100
|
+
option = GetImageOption(info, "tile-offset");
|
1101
|
+
if (option)
|
1102
|
+
{
|
1103
|
+
(void)ParseAbsoluteGeometry(option, &image->tile_offset);
|
1104
|
+
}
|
1105
|
+
|
1106
|
+
option = GetImageOption(info, "transparent");
|
1107
|
+
if (option)
|
1108
|
+
{
|
1109
|
+
image->transparent_color = info->transparent_color;
|
1110
|
+
}
|
1111
|
+
|
1112
|
+
#if defined(HAVE_ST_TYPE)
|
1113
|
+
if (info->type != UndefinedType)
|
1114
|
+
{
|
1115
|
+
image->type = info->type;
|
1116
|
+
}
|
1117
|
+
#endif
|
1118
|
+
|
1119
|
+
if (info->units != UndefinedResolution)
|
1120
|
+
{
|
1121
|
+
if (image->units != info->units)
|
1122
|
+
{
|
1123
|
+
switch (image->units)
|
1124
|
+
{
|
1125
|
+
case PixelsPerInchResolution:
|
1126
|
+
{
|
1127
|
+
if (info->units == PixelsPerCentimeterResolution)
|
1128
|
+
{
|
1129
|
+
image->x_resolution /= 2.54;
|
1130
|
+
image->y_resolution /= 2.54;
|
1131
|
+
}
|
1132
|
+
break;
|
1133
|
+
}
|
1134
|
+
case PixelsPerCentimeterResolution:
|
1135
|
+
{
|
1136
|
+
if (info->units == PixelsPerInchResolution)
|
1137
|
+
{
|
1138
|
+
image->x_resolution *= 2.54;
|
1139
|
+
image->y_resolution *= 2.54;
|
1140
|
+
}
|
1141
|
+
break;
|
1142
|
+
}
|
1143
|
+
default:
|
1144
|
+
break;
|
1145
|
+
}
|
1146
|
+
}
|
1147
|
+
|
1148
|
+
image->units = info->units;
|
1149
|
+
}
|
1150
|
+
|
1151
|
+
#if defined(HAVE_SETIMAGEARTIFACT)
|
1152
|
+
copy_options(image, info);
|
1153
|
+
#endif
|
1154
|
+
}
|
1155
|
+
|
1156
|
+
|
1157
|
+
/**
|
1158
|
+
* Replicate old (ImageMagick < 6.3.2) EXIF:* functionality using
|
1159
|
+
* GetImageProperty by returning the exif entries as a single string, separated
|
1160
|
+
* by \n's. Do this so that RMagick.rb works no matter which version of
|
1161
|
+
* ImageMagick is in use.
|
1162
|
+
*
|
1163
|
+
* No Ruby usage (internal function)
|
1164
|
+
*
|
1165
|
+
* @param image the image
|
1166
|
+
* @return string representation of exif properties
|
1167
|
+
* @see magick/identify.c in ImageMagick
|
1168
|
+
*/
|
1169
|
+
VALUE
|
1170
|
+
rm_exif_by_entry(Image *image)
|
1171
|
+
{
|
1172
|
+
const char *property, *value;
|
1173
|
+
char *str;
|
1174
|
+
size_t len = 0, property_l, value_l;
|
1175
|
+
VALUE v;
|
1176
|
+
|
1177
|
+
(void) GetImageProperty(image, "exif:*");
|
1178
|
+
ResetImagePropertyIterator(image);
|
1179
|
+
property = GetNextImageProperty(image);
|
1180
|
+
|
1181
|
+
// Measure the exif properties and values
|
1182
|
+
while (property)
|
1183
|
+
{
|
1184
|
+
// ignore properties that don't start with "exif:"
|
1185
|
+
property_l = strlen(property);
|
1186
|
+
if (property_l > 5 && rm_strncasecmp(property, "exif:", 5) == 0)
|
1187
|
+
{
|
1188
|
+
if (len > 0)
|
1189
|
+
{
|
1190
|
+
len += 1; // there will be a \n between property=value entries
|
1191
|
+
}
|
1192
|
+
len += property_l - 5;
|
1193
|
+
value = GetImageProperty(image,property);
|
1194
|
+
if (value)
|
1195
|
+
{
|
1196
|
+
// add 1 for the = between property and value
|
1197
|
+
len += 1 + strlen(value);
|
1198
|
+
}
|
1199
|
+
}
|
1200
|
+
property = GetNextImageProperty(image);
|
1201
|
+
}
|
1202
|
+
|
1203
|
+
if (len == 0)
|
1204
|
+
{
|
1205
|
+
return Qnil;
|
1206
|
+
}
|
1207
|
+
str = xmalloc(len);
|
1208
|
+
len = 0;
|
1209
|
+
|
1210
|
+
// Copy the exif properties and values into the string.
|
1211
|
+
ResetImagePropertyIterator(image);
|
1212
|
+
property = GetNextImageProperty(image);
|
1213
|
+
|
1214
|
+
while (property)
|
1215
|
+
{
|
1216
|
+
property_l = strlen(property);
|
1217
|
+
if (property_l > 5 && rm_strncasecmp(property, "exif:", 5) == 0)
|
1218
|
+
{
|
1219
|
+
if (len > 0)
|
1220
|
+
{
|
1221
|
+
str[len++] = '\n';
|
1222
|
+
}
|
1223
|
+
memcpy(str+len, property+5, property_l-5);
|
1224
|
+
len += property_l - 5;
|
1225
|
+
value = GetImageProperty(image,property);
|
1226
|
+
if (value)
|
1227
|
+
{
|
1228
|
+
value_l = strlen(value);
|
1229
|
+
str[len++] = '=';
|
1230
|
+
memcpy(str+len, value, value_l);
|
1231
|
+
len += value_l;
|
1232
|
+
}
|
1233
|
+
}
|
1234
|
+
property = GetNextImageProperty(image);
|
1235
|
+
}
|
1236
|
+
|
1237
|
+
v = rb_str_new(str, len);
|
1238
|
+
xfree(str);
|
1239
|
+
|
1240
|
+
RB_GC_GUARD(v);
|
1241
|
+
|
1242
|
+
return v;
|
1243
|
+
}
|
1244
|
+
|
1245
|
+
|
1246
|
+
/**
|
1247
|
+
* Replicate old (ImageMagick < 6.3.2) EXIF:! functionality using
|
1248
|
+
* GetImageProperty by returning the exif entries as a single string, separated
|
1249
|
+
* by \n's. Do this so that RMagick.rb works no matter which version of
|
1250
|
+
* ImageMagick is in use.
|
1251
|
+
*
|
1252
|
+
* No Ruby usage (internal function)
|
1253
|
+
*
|
1254
|
+
* @param image the image
|
1255
|
+
* @return string representation of exif properties
|
1256
|
+
* @see magick/identify.c in ImageMagick
|
1257
|
+
*/
|
1258
|
+
VALUE
|
1259
|
+
rm_exif_by_number(Image *image)
|
1260
|
+
{
|
1261
|
+
const char *property, *value;
|
1262
|
+
char *str;
|
1263
|
+
size_t len = 0, property_l, value_l;
|
1264
|
+
VALUE v;
|
1265
|
+
|
1266
|
+
(void) GetImageProperty(image, "exif:!");
|
1267
|
+
ResetImagePropertyIterator(image);
|
1268
|
+
property = GetNextImageProperty(image);
|
1269
|
+
|
1270
|
+
// Measure the exif properties and values
|
1271
|
+
while (property)
|
1272
|
+
{
|
1273
|
+
// ignore properties that don't start with "#"
|
1274
|
+
property_l = strlen(property);
|
1275
|
+
if (property_l > 1 && property[0] == '#')
|
1276
|
+
{
|
1277
|
+
if (len > 0)
|
1278
|
+
{
|
1279
|
+
len += 1; // there will be a \n between property=value entries
|
1280
|
+
}
|
1281
|
+
len += property_l;
|
1282
|
+
value = GetImageProperty(image,property);
|
1283
|
+
if (value)
|
1284
|
+
{
|
1285
|
+
// add 1 for the = between property and value
|
1286
|
+
len += 1 + strlen(value);
|
1287
|
+
}
|
1288
|
+
}
|
1289
|
+
property = GetNextImageProperty(image);
|
1290
|
+
}
|
1291
|
+
|
1292
|
+
if (len == 0)
|
1293
|
+
{
|
1294
|
+
return Qnil;
|
1295
|
+
}
|
1296
|
+
str = xmalloc(len);
|
1297
|
+
len = 0;
|
1298
|
+
|
1299
|
+
// Copy the exif properties and values into the string.
|
1300
|
+
ResetImagePropertyIterator(image);
|
1301
|
+
property = GetNextImageProperty(image);
|
1302
|
+
|
1303
|
+
while (property)
|
1304
|
+
{
|
1305
|
+
property_l = strlen(property);
|
1306
|
+
if (property_l > 1 && property[0] == '#')
|
1307
|
+
{
|
1308
|
+
if (len > 0)
|
1309
|
+
{
|
1310
|
+
str[len++] = '\n';
|
1311
|
+
}
|
1312
|
+
memcpy(str+len, property, property_l);
|
1313
|
+
len += property_l;
|
1314
|
+
value = GetImageProperty(image,property);
|
1315
|
+
if (value)
|
1316
|
+
{
|
1317
|
+
value_l = strlen(value);
|
1318
|
+
str[len++] = '=';
|
1319
|
+
memcpy(str+len, value, value_l);
|
1320
|
+
len += value_l;
|
1321
|
+
}
|
1322
|
+
}
|
1323
|
+
property = GetNextImageProperty(image);
|
1324
|
+
}
|
1325
|
+
|
1326
|
+
v = rb_str_new(str, len);
|
1327
|
+
xfree(str);
|
1328
|
+
|
1329
|
+
RB_GC_GUARD(v);
|
1330
|
+
|
1331
|
+
return v;
|
1332
|
+
}
|
1333
|
+
|
1334
|
+
|
1335
|
+
/**
|
1336
|
+
* Get the values from a Geometry object and return them in C variables.
|
1337
|
+
*
|
1338
|
+
* No Ruby usage (internal function)
|
1339
|
+
*
|
1340
|
+
* Notes:
|
1341
|
+
* - No return value: modifies x, y, width, height, and flag
|
1342
|
+
*
|
1343
|
+
* @param geom the Geometry object
|
1344
|
+
* @param x pointer to the x position of the start of the rectangle
|
1345
|
+
* @param y pointer to the y position of the start of the rectangle
|
1346
|
+
* @param width pointer to the width of the rectangle
|
1347
|
+
* @param height pointer to the height of the rectangle
|
1348
|
+
* @param flag pointer to the Geometry's flag
|
1349
|
+
*/
|
1350
|
+
void
|
1351
|
+
rm_get_geometry(
|
1352
|
+
VALUE geom,
|
1353
|
+
long *x,
|
1354
|
+
long *y,
|
1355
|
+
unsigned long *width,
|
1356
|
+
unsigned long *height,
|
1357
|
+
int *flag)
|
1358
|
+
{
|
1359
|
+
VALUE v;
|
1360
|
+
|
1361
|
+
v = rb_funcall(geom, rm_ID_x, 0);
|
1362
|
+
*x = NUM2LONG(v);
|
1363
|
+
v = rb_funcall(geom, rm_ID_y, 0);
|
1364
|
+
*y = NUM2LONG(v);
|
1365
|
+
v = rb_funcall(geom, rm_ID_width, 0);
|
1366
|
+
*width = NUM2ULONG(v);
|
1367
|
+
v = rb_funcall(geom, rm_ID_height, 0);
|
1368
|
+
*height = NUM2ULONG(v);
|
1369
|
+
|
1370
|
+
// Getting the flag field is a bit more difficult since it's
|
1371
|
+
// supposed to be an instance of the GeometryValue Enum class. We
|
1372
|
+
// may not know the VALUE for the GeometryValue class, and we
|
1373
|
+
// need to check that the flag field is an instance of that class.
|
1374
|
+
if (flag)
|
1375
|
+
{
|
1376
|
+
MagickEnum *magick_enum;
|
1377
|
+
|
1378
|
+
v = rb_funcall(geom, rm_ID_flag, 0);
|
1379
|
+
if (!Class_GeometryValue)
|
1380
|
+
{
|
1381
|
+
Class_GeometryValue = rb_const_get(Module_Magick, rm_ID_GeometryValue);
|
1382
|
+
}
|
1383
|
+
if (CLASS_OF(v) != Class_GeometryValue)
|
1384
|
+
{
|
1385
|
+
rb_raise(rb_eTypeError, "wrong enumeration type - expected %s, got %s"
|
1386
|
+
, rb_class2name(Class_GeometryValue),rb_class2name(CLASS_OF(v)));
|
1387
|
+
}
|
1388
|
+
Data_Get_Struct(v, MagickEnum, magick_enum);
|
1389
|
+
*flag = magick_enum->val;
|
1390
|
+
}
|
1391
|
+
|
1392
|
+
}
|
1393
|
+
|
1394
|
+
|
1395
|
+
/**
|
1396
|
+
* Clone an image, handle errors.
|
1397
|
+
*
|
1398
|
+
* No Ruby usage (internal function)
|
1399
|
+
*
|
1400
|
+
* Notes:
|
1401
|
+
* - Don't trace creation - the clone may not be used as an Image object. Let
|
1402
|
+
* the caller do the trace if desired.
|
1403
|
+
*
|
1404
|
+
* @param image the image to clone
|
1405
|
+
* @return the cloned image
|
1406
|
+
*/
|
1407
|
+
Image *
|
1408
|
+
rm_clone_image(Image *image)
|
1409
|
+
{
|
1410
|
+
Image *clone;
|
1411
|
+
ExceptionInfo *exception;
|
1412
|
+
|
1413
|
+
exception = AcquireExceptionInfo();
|
1414
|
+
clone = CloneImage(image, 0, 0, MagickTrue, exception);
|
1415
|
+
if (!clone)
|
1416
|
+
{
|
1417
|
+
rb_raise(rb_eNoMemError, "not enough memory to continue");
|
1418
|
+
}
|
1419
|
+
rm_check_exception(exception, clone, DestroyOnError);
|
1420
|
+
(void) DestroyExceptionInfo(exception);
|
1421
|
+
|
1422
|
+
return clone;
|
1423
|
+
}
|
1424
|
+
|
1425
|
+
|
1426
|
+
/**
|
1427
|
+
* SetImage(Info)ProgressMonitor exit.
|
1428
|
+
*
|
1429
|
+
* No Ruby usage (internal function)
|
1430
|
+
*
|
1431
|
+
* Notes:
|
1432
|
+
* - ImageMagick's "tag" argument is unused. We pass along the method name
|
1433
|
+
* instead.
|
1434
|
+
*
|
1435
|
+
* @param tag ImageMagick argument (unused)
|
1436
|
+
* @param of the offset type
|
1437
|
+
* @param sp the size type
|
1438
|
+
* @param client_data pointer to the progress method to call
|
1439
|
+
* @return true if calling client_data returns a non-nil value, otherwise false
|
1440
|
+
*/
|
1441
|
+
MagickBooleanType
|
1442
|
+
rm_progress_monitor(
|
1443
|
+
const char *tag,
|
1444
|
+
const MagickOffsetType of,
|
1445
|
+
const MagickSizeType sp,
|
1446
|
+
void *client_data)
|
1447
|
+
{
|
1448
|
+
VALUE rval;
|
1449
|
+
VALUE method, offset, span;
|
1450
|
+
|
1451
|
+
tag = tag; // defeat gcc message
|
1452
|
+
|
1453
|
+
#if defined(HAVE_LONG_LONG) // defined in Ruby's defines.h
|
1454
|
+
offset = rb_ll2inum(of);
|
1455
|
+
span = rb_ull2inum(sp);
|
1456
|
+
#else
|
1457
|
+
offset = rb_int2big((long)of);
|
1458
|
+
span = rb_uint2big((unsigned long)sp);
|
1459
|
+
#endif
|
1460
|
+
|
1461
|
+
method = rb_str_new2(rb_id2name(THIS_FUNC()));
|
1462
|
+
|
1463
|
+
rval = rb_funcall((VALUE)client_data, rm_ID_call, 3, method, offset, span);
|
1464
|
+
|
1465
|
+
RB_GC_GUARD(rval);
|
1466
|
+
RB_GC_GUARD(method);
|
1467
|
+
RB_GC_GUARD(offset);
|
1468
|
+
RB_GC_GUARD(span);
|
1469
|
+
|
1470
|
+
return RTEST(rval) ? MagickTrue : MagickFalse;
|
1471
|
+
}
|
1472
|
+
|
1473
|
+
|
1474
|
+
/**
|
1475
|
+
* Remove the ImageMagick links between images in an scene sequence.
|
1476
|
+
*
|
1477
|
+
* No Ruby usage (internal function)
|
1478
|
+
*
|
1479
|
+
* Notes:
|
1480
|
+
* - The images remain grouped via the ImageList
|
1481
|
+
*
|
1482
|
+
* @param image the image
|
1483
|
+
*/
|
1484
|
+
void
|
1485
|
+
rm_split(Image *image)
|
1486
|
+
{
|
1487
|
+
|
1488
|
+
if (!image)
|
1489
|
+
{
|
1490
|
+
rb_bug("RMagick FATAL: split called with NULL argument.");
|
1491
|
+
}
|
1492
|
+
while (image)
|
1493
|
+
{
|
1494
|
+
(void) RemoveFirstImageFromList(&image);
|
1495
|
+
}
|
1496
|
+
}
|
1497
|
+
|
1498
|
+
|
1499
|
+
/**
|
1500
|
+
* If an ExceptionInfo struct in a list of images indicates a warning, issue a
|
1501
|
+
* warning message. If an ExceptionInfo struct indicates an error, raise an
|
1502
|
+
* exception and optionally destroy the images.
|
1503
|
+
*
|
1504
|
+
* No Ruby usage (internal function)
|
1505
|
+
*
|
1506
|
+
* @param imglist the list of images
|
1507
|
+
* @param retention retention strategy in case of an error (either RetainOnError
|
1508
|
+
* or DestroyOnError)
|
1509
|
+
*/
|
1510
|
+
void
|
1511
|
+
rm_check_image_exception(Image *imglist, ErrorRetention retention)
|
1512
|
+
{
|
1513
|
+
ExceptionInfo *exception;
|
1514
|
+
Image *badboy = NULL;
|
1515
|
+
Image *image;
|
1516
|
+
|
1517
|
+
if (imglist == NULL)
|
1518
|
+
{
|
1519
|
+
return;
|
1520
|
+
}
|
1521
|
+
|
1522
|
+
exception = AcquireExceptionInfo();
|
1523
|
+
|
1524
|
+
// Find the image with the highest severity
|
1525
|
+
image = GetFirstImageInList(imglist);
|
1526
|
+
while (image)
|
1527
|
+
{
|
1528
|
+
if (image->exception.severity != UndefinedException)
|
1529
|
+
{
|
1530
|
+
if (!badboy || image->exception.severity > badboy->exception.severity)
|
1531
|
+
{
|
1532
|
+
badboy = image;
|
1533
|
+
InheritException(exception, &badboy->exception);
|
1534
|
+
}
|
1535
|
+
|
1536
|
+
ClearMagickException(&image->exception);
|
1537
|
+
}
|
1538
|
+
image = GetNextImageInList(image);
|
1539
|
+
}
|
1540
|
+
|
1541
|
+
if (badboy)
|
1542
|
+
{
|
1543
|
+
rm_check_exception(exception, imglist, retention);
|
1544
|
+
}
|
1545
|
+
|
1546
|
+
(void) DestroyExceptionInfo(exception);
|
1547
|
+
}
|
1548
|
+
|
1549
|
+
|
1550
|
+
/**
|
1551
|
+
* Call handle_exception if there is an exception to handle.
|
1552
|
+
*
|
1553
|
+
* No Ruby usage (internal function)
|
1554
|
+
*
|
1555
|
+
* @param exception information about the exception
|
1556
|
+
* @param imglist the images that caused the exception
|
1557
|
+
* @param retention retention strategy in case of an error (either RetainOnError
|
1558
|
+
* or DestroyOnError)
|
1559
|
+
*/
|
1560
|
+
void
|
1561
|
+
rm_check_exception(ExceptionInfo *exception, Image *imglist, ErrorRetention retention)
|
1562
|
+
{
|
1563
|
+
if (exception->severity == UndefinedException)
|
1564
|
+
{
|
1565
|
+
return;
|
1566
|
+
}
|
1567
|
+
|
1568
|
+
handle_exception(exception, imglist, retention);
|
1569
|
+
}
|
1570
|
+
|
1571
|
+
|
1572
|
+
|
1573
|
+
/**
|
1574
|
+
* Called from ImageMagick for a warning.
|
1575
|
+
*
|
1576
|
+
* No Ruby usage (internal function)
|
1577
|
+
*
|
1578
|
+
* @param severity information about the severity of the warning (ignored)
|
1579
|
+
* @param reason the reason for the warning
|
1580
|
+
* @param description description of the warning
|
1581
|
+
*/
|
1582
|
+
void
|
1583
|
+
rm_warning_handler(const ExceptionType severity, const char *reason, const char *description)
|
1584
|
+
{
|
1585
|
+
ExceptionType dummy;
|
1586
|
+
|
1587
|
+
rb_warning("RMagick: %s: `%s'", reason, description);
|
1588
|
+
dummy = severity;
|
1589
|
+
dummy = dummy;
|
1590
|
+
}
|
1591
|
+
|
1592
|
+
|
1593
|
+
/**
|
1594
|
+
* Called from ImageMagick for a error.
|
1595
|
+
*
|
1596
|
+
* No Ruby usage (internal function)
|
1597
|
+
*
|
1598
|
+
* @param severity information about the severity of the error (ignored)
|
1599
|
+
* @param reason the reason for the error
|
1600
|
+
* @param description description of the error
|
1601
|
+
*/
|
1602
|
+
void
|
1603
|
+
rm_error_handler(const ExceptionType severity, const char *reason, const char *description)
|
1604
|
+
{
|
1605
|
+
char msg[500];
|
1606
|
+
int len;
|
1607
|
+
ExceptionType dummy;
|
1608
|
+
|
1609
|
+
memset(msg, 0, sizeof(msg));
|
1610
|
+
#if defined(HAVE_SNPRINTF)
|
1611
|
+
len = snprintf(msg, sizeof(msg), "%s: `%s'", reason, description);
|
1612
|
+
#else
|
1613
|
+
len = sprintf(msg, "%.250s: `%.240s'", reason, description);
|
1614
|
+
#endif
|
1615
|
+
msg[len] = '\0';
|
1616
|
+
|
1617
|
+
rm_magick_error(msg, NULL);
|
1618
|
+
dummy = severity;
|
1619
|
+
dummy = dummy;
|
1620
|
+
}
|
1621
|
+
|
1622
|
+
|
1623
|
+
/**
|
1624
|
+
* Called from ImageMagick for a fatal error.
|
1625
|
+
*
|
1626
|
+
* No Ruby usage (internal function)
|
1627
|
+
*
|
1628
|
+
* @param severity information about the severity of the error
|
1629
|
+
* @param reason the reason for the error
|
1630
|
+
* @param description description of the error (ignored)
|
1631
|
+
* @throw FatalImageMagickError
|
1632
|
+
*/
|
1633
|
+
void
|
1634
|
+
rm_fatal_error_handler(const ExceptionType severity, const char *reason, const char *description)
|
1635
|
+
{
|
1636
|
+
rb_raise(Class_FatalImageMagickError, "%s", GetLocaleExceptionMessage(severity, reason));
|
1637
|
+
description = description;
|
1638
|
+
}
|
1639
|
+
|
1640
|
+
|
1641
|
+
/**
|
1642
|
+
* Called when rm_check_exception determines that we need to either issue a
|
1643
|
+
* warning message or raise an exception. This function allocates a bunch of
|
1644
|
+
* stack so we don't call it unless we have to.
|
1645
|
+
*
|
1646
|
+
* No Ruby usage (internal function)
|
1647
|
+
*
|
1648
|
+
* @param exception information about the exception
|
1649
|
+
* @param imglist the images that caused the exception
|
1650
|
+
* @param retention retention strategy in case of an error (either RetainOnError
|
1651
|
+
* or DestroyOnError)
|
1652
|
+
*/
|
1653
|
+
static void
|
1654
|
+
handle_exception(ExceptionInfo *exception, Image *imglist, ErrorRetention retention)
|
1655
|
+
{
|
1656
|
+
|
1657
|
+
char reason[500];
|
1658
|
+
char desc[500];
|
1659
|
+
char msg[sizeof(reason)+sizeof(desc)+20];
|
1660
|
+
|
1661
|
+
memset(msg, 0, sizeof(msg));
|
1662
|
+
|
1663
|
+
|
1664
|
+
// Handle simple warning
|
1665
|
+
if (exception->severity < ErrorException)
|
1666
|
+
{
|
1667
|
+
#if defined(HAVE_SNPRINTF)
|
1668
|
+
snprintf(msg, sizeof(msg)-1, "RMagick: %s%s%s",
|
1669
|
+
#else
|
1670
|
+
sprintf(msg, "RMagick: %.500s%s%.500s",
|
1671
|
+
#endif
|
1672
|
+
GetLocaleExceptionMessage(exception->severity, exception->reason),
|
1673
|
+
exception->description ? ": " : "",
|
1674
|
+
exception->description ? GetLocaleExceptionMessage(exception->severity, exception->description) : "");
|
1675
|
+
msg[sizeof(msg)-1] = '\0';
|
1676
|
+
rb_warning("%s", msg);
|
1677
|
+
|
1678
|
+
// Caller deletes ExceptionInfo...
|
1679
|
+
|
1680
|
+
return;
|
1681
|
+
}
|
1682
|
+
|
1683
|
+
// Raise an exception. We're not coming back...
|
1684
|
+
|
1685
|
+
|
1686
|
+
// Newly-created images should be destroyed, images that are part
|
1687
|
+
// of image objects should be retained but split.
|
1688
|
+
if (imglist)
|
1689
|
+
{
|
1690
|
+
if (retention == DestroyOnError)
|
1691
|
+
{
|
1692
|
+
(void) DestroyImageList(imglist);
|
1693
|
+
imglist = NULL;
|
1694
|
+
}
|
1695
|
+
else
|
1696
|
+
{
|
1697
|
+
rm_split(imglist);
|
1698
|
+
}
|
1699
|
+
}
|
1700
|
+
|
1701
|
+
|
1702
|
+
// Clone the ExceptionInfo with all arguments on the stack.
|
1703
|
+
memset(reason, 0, sizeof(reason));
|
1704
|
+
memset(desc, 0, sizeof(desc));
|
1705
|
+
|
1706
|
+
if (exception->reason)
|
1707
|
+
{
|
1708
|
+
strncpy(reason, exception->reason, sizeof(reason)-1);
|
1709
|
+
reason[sizeof(reason)-1] = '\0';
|
1710
|
+
}
|
1711
|
+
if (exception->description)
|
1712
|
+
{
|
1713
|
+
strncpy(desc, exception->description, sizeof(desc)-1);
|
1714
|
+
desc[sizeof(desc)-1] = '\0';
|
1715
|
+
}
|
1716
|
+
|
1717
|
+
|
1718
|
+
#if defined(HAVE_SNPRINTF)
|
1719
|
+
snprintf(msg, sizeof(msg)-1, "%s%s%s",
|
1720
|
+
GetLocaleExceptionMessage(exception->severity, reason),
|
1721
|
+
desc[0] ? ": " : "",
|
1722
|
+
desc[0] ? GetLocaleExceptionMessage(exception->severity, desc) : "");
|
1723
|
+
#else
|
1724
|
+
sprintf(msg, "%.*s%s%.*s",
|
1725
|
+
sizeof(reason)-1, GetLocaleExceptionMessage(exception->severity, reason),
|
1726
|
+
desc[0] ? ": " : "",
|
1727
|
+
sizeof(desc)-1, desc[0] ? GetLocaleExceptionMessage(exception->severity, desc) : "");
|
1728
|
+
#endif
|
1729
|
+
|
1730
|
+
msg[sizeof(msg)-1] = '\0';
|
1731
|
+
|
1732
|
+
(void) DestroyExceptionInfo(exception);
|
1733
|
+
rm_magick_error(msg, NULL);
|
1734
|
+
|
1735
|
+
}
|
1736
|
+
|
1737
|
+
|
1738
|
+
/**
|
1739
|
+
* RMagick expected a result. If it got NULL instead raise an exception.
|
1740
|
+
*
|
1741
|
+
* No Ruby usage (internal function)
|
1742
|
+
*
|
1743
|
+
* @param image the expected result
|
1744
|
+
* @throw RuntimeError
|
1745
|
+
*/
|
1746
|
+
void
|
1747
|
+
rm_ensure_result(Image *image)
|
1748
|
+
{
|
1749
|
+
if (!image)
|
1750
|
+
{
|
1751
|
+
rb_raise(rb_eRuntimeError, MagickPackageName " library function failed to return a result.");
|
1752
|
+
}
|
1753
|
+
}
|
1754
|
+
|