rmagick 7.1.3 → 7.1.5
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 +4 -4
- data/CHANGELOG.md +36 -0
- data/ext/RMagick/rmagick.h +1 -0
- data/ext/RMagick/rmimage.cpp +120 -33
- data/ext/RMagick/rminfo.cpp +37 -3
- data/ext/RMagick/rmmontage.cpp +13 -2
- data/ext/RMagick/rmutil.cpp +44 -0
- data/lib/rmagick/version.rb +1 -1
- data/lib/rmagick_internal.rb +19 -7
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b0652dce5387352787bef0e59b1548a5c36b6f80a66b8ec9ab4c7f03828f5d0f
|
|
4
|
+
data.tar.gz: 6d286a5f5649816c5cf1f821969783fb6ebef9f5a81b4502719f498869f926f9
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 4ab4ce5e26eed8275df1cdc1130da0c5bb717fdca8f472c89b26a5aea37579a17e9bc4d9a34aa0c272a4b26242c03c2acbd9b690484b503ddfdf7220fc075cf2
|
|
7
|
+
data.tar.gz: c5ee3eddbed492432ae70f34680a3d9a768fec6ba33bd3c97eca98262f29fd81d2037f56f8e8018ee0afc0a43896ad7186ee5f779da559f9d14ccc05aa28c3cb
|
data/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,42 @@
|
|
|
3
3
|
All notable changes to this project are documented in this file.
|
|
4
4
|
This project adheres to [Semantic Versioning](http://semver.org/).
|
|
5
5
|
|
|
6
|
+
## RMagick 7.1.5
|
|
7
|
+
|
|
8
|
+
> [!IMPORTANT]
|
|
9
|
+
> More strings that ImageMagick would read from a file now raise `ArgumentError`.
|
|
10
|
+
>
|
|
11
|
+
> `Montage#title=` and the `caption`, `comment` and `label` options, set through `Info#caption=`, `#comment=`, `#label=` or `Info#[]=`, now reject a value whose first non-blank character is `@`, as `Image#polaroid` has done since 7.1.4. ImageMagick read the file it named and put its contents into the montage or into the metadata of the image being read. These checks and the one in `Image#polaroid` also reject a `%[fx:@...]`, `%[hex:@...]` or `%[pixel:@...]` escape, which ImageMagick 7 reads from the named file as well, and their message now says the value "must not name a file with '@'".
|
|
12
|
+
>
|
|
13
|
+
> `Image#profile!` now accepts only the profile formats of ImageMagick's META coder (8BIM, APP1, EXIF, ICC, ICM, IPTC, XMP and their variants) and raises `ArgumentError` for any other name. It decoded the profile with the coder of whatever name it was given, so a profile named `msl` copied from an uploaded image ran as an MSL script.
|
|
14
|
+
|
|
15
|
+
Breaking Changes
|
|
16
|
+
|
|
17
|
+
* Accept only META profile formats in Image#profile! instead of decoding the profile with the coder of that name (#1873)
|
|
18
|
+
* Reject a Montage#title beginning with '@' instead of reading that file (#1874)
|
|
19
|
+
* Reject an Info#caption, #comment or #label value beginning with '@' instead of reading that file (#1875)
|
|
20
|
+
* Also reject %[fx:@...], %[hex:@...] and %[pixel:@...] escapes where a value beginning with '@' is rejected (#1876)
|
|
21
|
+
|
|
22
|
+
Bug Fixes
|
|
23
|
+
|
|
24
|
+
* Fix stack buffer overflow in Image#inspect with a long format name (#1877)
|
|
25
|
+
|
|
26
|
+
## RMagick 7.1.4
|
|
27
|
+
|
|
28
|
+
> [!IMPORTANT]
|
|
29
|
+
> Four kinds of input that used to be accepted now raise `ArgumentError`.
|
|
30
|
+
>
|
|
31
|
+
> Three of them were ways for a string RMagick documents as a value to be read back as part of an ImageMagick program: an opacity of `"1%\nimage Over 0,0 80,80 'secret.png'\n1%"`, a `Draw#pattern` name carrying the same payload, and a `Caption` property of `"@/etc/passwd"` arriving in the metadata of an uploaded image. ImageMagick executed the injected primitive, or read the named file and drew its contents into the returned image. `Image#dispatch` is the fourth: a `map` containing a NUL byte is now rejected rather than sized with the byte length while ImageMagick fills only what precedes the NUL.
|
|
32
|
+
>
|
|
33
|
+
> `Image#export_pixels_to_str` with `Magick::LongPixel` also returns half as many bytes on LP64, and `Image#import_pixels` takes a buffer of that size. RMagick reserved `sizeof(unsigned long)` per element while ImageMagick reads and writes `unsigned int`, so the second half of the string was never written and carried whatever the heap held. `Image#colormap` returned uninitialized memory the same way, as the previous colour of an entry it had just created.
|
|
34
|
+
|
|
35
|
+
Breaking Changes
|
|
36
|
+
|
|
37
|
+
* Reject an opacity percentage that is not a plain number from 0% to 100% (#1867)
|
|
38
|
+
* Restrict a Draw#pattern name to letters, digits, hyphen, period and underscore (#1869)
|
|
39
|
+
* Return LongPixel pixel data as unsigned int, without the uninitialized padding Image#export_pixels_to_str used to append (#1870)
|
|
40
|
+
* Reject a Caption property beginning with '@' in Image#polaroid instead of reading that file (#1871)
|
|
41
|
+
|
|
6
42
|
## RMagick 7.1.3
|
|
7
43
|
|
|
8
44
|
Bug Fixes
|
data/ext/RMagick/rmagick.h
CHANGED
|
@@ -1159,6 +1159,7 @@ extern VALUE rm_no_freeze(VALUE) ATTRIBUTE_NORETURN;
|
|
|
1159
1159
|
extern int rm_strcasecmp(const char *, const char *);
|
|
1160
1160
|
extern int rm_strncasecmp(const char *, const char *, size_t);
|
|
1161
1161
|
extern size_t rm_strnlen_s(const char *, size_t);
|
|
1162
|
+
extern bool rm_has_file_reference(const char *);
|
|
1162
1163
|
extern void rm_check_ary_len(VALUE, long);
|
|
1163
1164
|
extern VALUE rm_check_ary_type(VALUE ary);
|
|
1164
1165
|
extern Image *rm_check_destroyed(VALUE);
|
data/ext/RMagick/rmimage.cpp
CHANGED
|
@@ -2900,6 +2900,35 @@ Image_color_histogram(VALUE self)
|
|
|
2900
2900
|
}
|
|
2901
2901
|
|
|
2902
2902
|
|
|
2903
|
+
/**
|
|
2904
|
+
* Return true if the format is one handled by ImageMagick's META coder. set_profile
|
|
2905
|
+
* decodes the profile with the coder of that name, so any other format would run an
|
|
2906
|
+
* unrelated decoder (MSL, MVG, SVG, ...) on the profile bytes.
|
|
2907
|
+
*
|
|
2908
|
+
* No Ruby usage (internal function)
|
|
2909
|
+
*
|
|
2910
|
+
* @param format the format name
|
|
2911
|
+
* @return true if the format is a META profile format, otherwise false
|
|
2912
|
+
*/
|
|
2913
|
+
static bool
|
|
2914
|
+
is_meta_profile_format(const char *format)
|
|
2915
|
+
{
|
|
2916
|
+
static const char *meta_formats[] = {
|
|
2917
|
+
"8BIM", "8BIMTEXT", "8BIMWTEXT", "APP1", "APP1JPEG", "EXIF",
|
|
2918
|
+
"ICC", "ICM", "IPTC", "IPTCTEXT", "IPTCWTEXT", "XMP"
|
|
2919
|
+
};
|
|
2920
|
+
|
|
2921
|
+
for (size_t i = 0; i < sizeof(meta_formats) / sizeof(meta_formats[0]); i++)
|
|
2922
|
+
{
|
|
2923
|
+
if (rm_strcasecmp(format, meta_formats[i]) == 0)
|
|
2924
|
+
{
|
|
2925
|
+
return true;
|
|
2926
|
+
}
|
|
2927
|
+
}
|
|
2928
|
+
return false;
|
|
2929
|
+
}
|
|
2930
|
+
|
|
2931
|
+
|
|
2903
2932
|
/**
|
|
2904
2933
|
* Store all the profiles in the profile in the target image. Called from
|
|
2905
2934
|
* Image_color_profile_eq and Image_iptc_profile_eq.
|
|
@@ -2927,10 +2956,17 @@ set_profile(VALUE self, const char *name, VALUE profile)
|
|
|
2927
2956
|
|
|
2928
2957
|
profile_blob = rm_str2cstr(&profile, &profile_length);
|
|
2929
2958
|
|
|
2959
|
+
// Reject the name before GetMagickInfo(), which loads the coder module it names
|
|
2960
|
+
// ("*" loads all of them).
|
|
2961
|
+
if (!is_meta_profile_format(name))
|
|
2962
|
+
{
|
|
2963
|
+
rb_raise(rb_eArgError, "unknown name: %s", name);
|
|
2964
|
+
}
|
|
2965
|
+
|
|
2930
2966
|
exception = AcquireExceptionInfo();
|
|
2931
2967
|
m = GetMagickInfo(name, exception);
|
|
2932
2968
|
CHECK_EXCEPTION();
|
|
2933
|
-
if (!m)
|
|
2969
|
+
if (!m || !is_meta_profile_format(m->name))
|
|
2934
2970
|
{
|
|
2935
2971
|
DestroyExceptionInfo(exception);
|
|
2936
2972
|
rb_raise(rb_eArgError, "unknown name: %s", name);
|
|
@@ -3295,7 +3331,7 @@ Image_colormap(int argc, VALUE *argv, VALUE self)
|
|
|
3295
3331
|
image->colormap = (PixelColor *)magick_safe_realloc(image->colormap, (idx+1), sizeof(PixelColor));
|
|
3296
3332
|
}
|
|
3297
3333
|
|
|
3298
|
-
for (i = image->colors; i
|
|
3334
|
+
for (i = image->colors; i <= idx; i++)
|
|
3299
3335
|
{
|
|
3300
3336
|
image->colormap[i] = black;
|
|
3301
3337
|
}
|
|
@@ -5758,7 +5794,8 @@ Image_dispatch(int argc, VALUE *argv, VALUE self)
|
|
|
5758
5794
|
y = NUM2LONG(argv[1]);
|
|
5759
5795
|
columns = NUM2ULONG(argv[2]);
|
|
5760
5796
|
rows = NUM2ULONG(argv[3]);
|
|
5761
|
-
map =
|
|
5797
|
+
map = StringValueCStr(argv[4]);
|
|
5798
|
+
mapL = strlen(map);
|
|
5762
5799
|
if (argc == 6)
|
|
5763
5800
|
{
|
|
5764
5801
|
stg_type = RTEST(argv[5]) ? DoublePixel : QuantumPixel;
|
|
@@ -6903,7 +6940,7 @@ Image_export_pixels_to_str(int argc, VALUE *argv, VALUE self)
|
|
|
6903
6940
|
sz = sizeof(float);
|
|
6904
6941
|
break;
|
|
6905
6942
|
case LongPixel:
|
|
6906
|
-
sz = sizeof(unsigned
|
|
6943
|
+
sz = sizeof(unsigned int);
|
|
6907
6944
|
break;
|
|
6908
6945
|
case QuantumPixel:
|
|
6909
6946
|
sz = sizeof(Quantum);
|
|
@@ -8174,7 +8211,7 @@ Image_import_pixels(int argc, VALUE *argv, VALUE self)
|
|
|
8174
8211
|
type_sz = sizeof(unsigned short);
|
|
8175
8212
|
break;
|
|
8176
8213
|
case LongPixel:
|
|
8177
|
-
type_sz = sizeof(unsigned
|
|
8214
|
+
type_sz = sizeof(unsigned int);
|
|
8178
8215
|
break;
|
|
8179
8216
|
case DoublePixel:
|
|
8180
8217
|
type_sz = sizeof(double);
|
|
@@ -8304,6 +8341,42 @@ Image_import_pixels(int argc, VALUE *argv, VALUE self)
|
|
|
8304
8341
|
}
|
|
8305
8342
|
|
|
8306
8343
|
|
|
8344
|
+
/**
|
|
8345
|
+
* Append formatted text to the buffer used by build_inspect_string.
|
|
8346
|
+
*
|
|
8347
|
+
* No Ruby usage (internal function)
|
|
8348
|
+
*
|
|
8349
|
+
* Notes:
|
|
8350
|
+
* - vsnprintf returns the length of the untruncated text, so only the bytes
|
|
8351
|
+
* that actually fit are counted. The returned offset never exceeds len-1,
|
|
8352
|
+
* so once the buffer is full later appends add nothing to it.
|
|
8353
|
+
*
|
|
8354
|
+
* @param buffer buffer for the output string
|
|
8355
|
+
* @param len length of buffer
|
|
8356
|
+
* @param x # bytes used in buffer, at most len-1
|
|
8357
|
+
* @param format printf-style format string
|
|
8358
|
+
* @return the new # bytes used in buffer, at most len-1
|
|
8359
|
+
* @see build_inspect_string
|
|
8360
|
+
*/
|
|
8361
|
+
static int
|
|
8362
|
+
append_inspect_string(char *buffer, size_t len, int x, const char *format, ...)
|
|
8363
|
+
{
|
|
8364
|
+
va_list args;
|
|
8365
|
+
int n;
|
|
8366
|
+
|
|
8367
|
+
va_start(args, format);
|
|
8368
|
+
n = vsnprintf(buffer+x, len-x, format, args);
|
|
8369
|
+
va_end(args);
|
|
8370
|
+
|
|
8371
|
+
if (n > 0)
|
|
8372
|
+
{
|
|
8373
|
+
x += (int)min((size_t)n, len-1-x);
|
|
8374
|
+
}
|
|
8375
|
+
|
|
8376
|
+
return x;
|
|
8377
|
+
}
|
|
8378
|
+
|
|
8379
|
+
|
|
8307
8380
|
/**
|
|
8308
8381
|
* Override Object#inspect - return a string description of the image.
|
|
8309
8382
|
*
|
|
@@ -8327,56 +8400,56 @@ build_inspect_string(Image *image, char *buffer, size_t len)
|
|
|
8327
8400
|
// Print magick filename if different from current filename.
|
|
8328
8401
|
if (*image->magick_filename != '\0' && strcmp(image->magick_filename, image->filename) != 0)
|
|
8329
8402
|
{
|
|
8330
|
-
x
|
|
8403
|
+
x = append_inspect_string(buffer, len, x, "%.1024s=>", image->magick_filename);
|
|
8331
8404
|
}
|
|
8332
8405
|
// Print current filename.
|
|
8333
|
-
x
|
|
8406
|
+
x = append_inspect_string(buffer, len, x, "%.1024s", image->filename);
|
|
8334
8407
|
// Print scene number.
|
|
8335
8408
|
if ((GetPreviousImageInList(image) != NULL) && (GetNextImageInList(image) != NULL) && image->scene > 0)
|
|
8336
8409
|
{
|
|
8337
|
-
x
|
|
8410
|
+
x = append_inspect_string(buffer, len, x, "[%" RMIuSIZE "]", image->scene);
|
|
8338
8411
|
}
|
|
8339
8412
|
// Print format
|
|
8340
|
-
x
|
|
8413
|
+
x = append_inspect_string(buffer, len, x, " %s ", image->magick);
|
|
8341
8414
|
|
|
8342
8415
|
// Print magick columnsXrows if different from current.
|
|
8343
8416
|
if (image->magick_columns != 0 || image->magick_rows != 0)
|
|
8344
8417
|
{
|
|
8345
8418
|
if (image->magick_columns != image->columns || image->magick_rows != image->rows)
|
|
8346
8419
|
{
|
|
8347
|
-
x
|
|
8420
|
+
x = append_inspect_string(buffer, len, x, "%" RMIuSIZE "x%" RMIuSIZE "=>", image->magick_columns, image->magick_rows);
|
|
8348
8421
|
}
|
|
8349
8422
|
}
|
|
8350
8423
|
|
|
8351
|
-
x
|
|
8424
|
+
x = append_inspect_string(buffer, len, x, "%" RMIuSIZE "x%" RMIuSIZE " ", image->columns, image->rows);
|
|
8352
8425
|
|
|
8353
8426
|
// Print current columnsXrows
|
|
8354
8427
|
if ( image->page.width != 0 || image->page.height != 0
|
|
8355
8428
|
|| image->page.x != 0 || image->page.y != 0)
|
|
8356
8429
|
{
|
|
8357
|
-
x
|
|
8358
|
-
|
|
8359
|
-
|
|
8430
|
+
x = append_inspect_string(buffer, len, x, "%" RMIuSIZE "x%" RMIuSIZE "+%" RMIdSIZE "+%" RMIdSIZE " ",
|
|
8431
|
+
image->page.width, image->page.height,
|
|
8432
|
+
image->page.x, image->page.y);
|
|
8360
8433
|
}
|
|
8361
8434
|
|
|
8362
8435
|
if (image->storage_class == DirectClass)
|
|
8363
8436
|
{
|
|
8364
|
-
x
|
|
8437
|
+
x = append_inspect_string(buffer, len, x, "DirectClass ");
|
|
8365
8438
|
if (image->total_colors != 0)
|
|
8366
8439
|
{
|
|
8367
8440
|
if (image->total_colors >= (unsigned long)(1 << 24))
|
|
8368
8441
|
{
|
|
8369
|
-
x
|
|
8442
|
+
x = append_inspect_string(buffer, len, x, "%" RMIuSIZE "mc ", image->total_colors/1024/1024);
|
|
8370
8443
|
}
|
|
8371
8444
|
else
|
|
8372
8445
|
{
|
|
8373
8446
|
if (image->total_colors >= (unsigned long)(1 << 16))
|
|
8374
8447
|
{
|
|
8375
|
-
x
|
|
8448
|
+
x = append_inspect_string(buffer, len, x, "%" RMIuSIZE "kc ", image->total_colors/1024);
|
|
8376
8449
|
}
|
|
8377
8450
|
else
|
|
8378
8451
|
{
|
|
8379
|
-
x
|
|
8452
|
+
x = append_inspect_string(buffer, len, x, "%" RMIuSIZE "c ", image->total_colors);
|
|
8380
8453
|
}
|
|
8381
8454
|
}
|
|
8382
8455
|
}
|
|
@@ -8387,39 +8460,39 @@ build_inspect_string(Image *image, char *buffer, size_t len)
|
|
|
8387
8460
|
// building with GM. GM defines that field as an unsigned int.
|
|
8388
8461
|
if (image->total_colors <= image->colors)
|
|
8389
8462
|
{
|
|
8390
|
-
x
|
|
8463
|
+
x = append_inspect_string(buffer, len, x, "PseudoClass %ldc ", (long) image->colors);
|
|
8391
8464
|
}
|
|
8392
8465
|
else
|
|
8393
8466
|
{
|
|
8394
|
-
x
|
|
8467
|
+
x = append_inspect_string(buffer, len, x, "PseudoClass %" RMIuSIZE "=>%" RMIuSIZE "c ", image->total_colors, image->colors);
|
|
8395
8468
|
if (image->error.mean_error_per_pixel != 0.0)
|
|
8396
8469
|
{
|
|
8397
|
-
x
|
|
8398
|
-
|
|
8399
|
-
|
|
8400
|
-
|
|
8470
|
+
x = append_inspect_string(buffer, len, x, "%ld/%.6f/%.6fdb ",
|
|
8471
|
+
(long) (image->error.mean_error_per_pixel+0.5),
|
|
8472
|
+
image->error.normalized_mean_error,
|
|
8473
|
+
image->error.normalized_maximum_error);
|
|
8401
8474
|
}
|
|
8402
8475
|
}
|
|
8403
8476
|
}
|
|
8404
8477
|
|
|
8405
8478
|
// Print bit depth
|
|
8406
8479
|
quantum_depth = GetImageQuantumDepth(image, MagickTrue);
|
|
8407
|
-
x
|
|
8480
|
+
x = append_inspect_string(buffer, len, x, "%lu-bit", quantum_depth);
|
|
8408
8481
|
|
|
8409
8482
|
// Print blob info if appropriate.
|
|
8410
8483
|
if (GetBlobSize(image) != 0)
|
|
8411
8484
|
{
|
|
8412
8485
|
if (GetBlobSize(image) >= (1 << 24))
|
|
8413
8486
|
{
|
|
8414
|
-
x
|
|
8487
|
+
x = append_inspect_string(buffer, len, x, " %lumb", (unsigned long) (GetBlobSize(image)/1024/1024));
|
|
8415
8488
|
}
|
|
8416
8489
|
else if (GetBlobSize(image) >= 1024)
|
|
8417
8490
|
{
|
|
8418
|
-
x
|
|
8491
|
+
x = append_inspect_string(buffer, len, x, " %lukb", (unsigned long) (GetBlobSize(image)/1024));
|
|
8419
8492
|
}
|
|
8420
8493
|
else
|
|
8421
8494
|
{
|
|
8422
|
-
x
|
|
8495
|
+
x = append_inspect_string(buffer, len, x, " %lub", (unsigned long) GetBlobSize(image));
|
|
8423
8496
|
}
|
|
8424
8497
|
}
|
|
8425
8498
|
|
|
@@ -8439,7 +8512,7 @@ build_inspect_string(Image *image, char *buffer, size_t len)
|
|
|
8439
8512
|
}
|
|
8440
8513
|
}
|
|
8441
8514
|
|
|
8442
|
-
assert(x < (int)
|
|
8515
|
+
assert(x < (int)len);
|
|
8443
8516
|
buffer[x] = '\0';
|
|
8444
8517
|
|
|
8445
8518
|
return;
|
|
@@ -10867,7 +10940,9 @@ Image_pixel_interpolation_method_eq(VALUE self, VALUE method)
|
|
|
10867
10940
|
|
|
10868
10941
|
/**
|
|
10869
10942
|
* Produce an image that looks like a Polaroid instant picture. If the image has a "Caption"
|
|
10870
|
-
* property, the value is used as a caption.
|
|
10943
|
+
* property, the value is used as a caption. A caption whose first non-blank character is '@',
|
|
10944
|
+
* or that contains a %[fx:@...], %[hex:@...] or %[pixel:@...] escape, is rejected because
|
|
10945
|
+
* ImageMagick reads the file it names.
|
|
10871
10946
|
*
|
|
10872
10947
|
* The following annotate attributes control the label rendering:
|
|
10873
10948
|
* align, decorate, density, encoding, fill, font, font_family, font_stretch, font_style,
|
|
@@ -10888,6 +10963,7 @@ Image_pixel_interpolation_method_eq(VALUE self, VALUE method)
|
|
|
10888
10963
|
* @yieldparam opt [Magick::Image::PolaroidOptions]
|
|
10889
10964
|
*
|
|
10890
10965
|
* @return [Magick::Image] a new image
|
|
10966
|
+
* @raise [ArgumentError] if the "Caption" property names a file with '@'
|
|
10891
10967
|
*/
|
|
10892
10968
|
VALUE
|
|
10893
10969
|
Image_polaroid(int argc, VALUE *argv, VALUE self)
|
|
@@ -10897,9 +10973,7 @@ Image_polaroid(int argc, VALUE *argv, VALUE self)
|
|
|
10897
10973
|
double angle = -5.0;
|
|
10898
10974
|
Draw *draw;
|
|
10899
10975
|
ExceptionInfo *exception;
|
|
10900
|
-
#if defined(IMAGEMAGICK_7)
|
|
10901
10976
|
const char *caption;
|
|
10902
|
-
#endif
|
|
10903
10977
|
|
|
10904
10978
|
image = rm_check_destroyed(self);
|
|
10905
10979
|
|
|
@@ -10924,6 +10998,17 @@ Image_polaroid(int argc, VALUE *argv, VALUE self)
|
|
|
10924
10998
|
exception = AcquireExceptionInfo();
|
|
10925
10999
|
#if defined(IMAGEMAGICK_7)
|
|
10926
11000
|
caption = GetImageProperty(clone, "Caption", exception);
|
|
11001
|
+
#else
|
|
11002
|
+
caption = GetImageProperty(clone, "Caption");
|
|
11003
|
+
#endif
|
|
11004
|
+
if (caption && rm_has_file_reference(caption))
|
|
11005
|
+
{
|
|
11006
|
+
DestroyImage(clone);
|
|
11007
|
+
DestroyExceptionInfo(exception);
|
|
11008
|
+
rb_raise(rb_eArgError, "the Caption property must not name a file with '@'");
|
|
11009
|
+
}
|
|
11010
|
+
|
|
11011
|
+
#if defined(IMAGEMAGICK_7)
|
|
10927
11012
|
GVL_STRUCT_TYPE(PolaroidImage) args = { clone, draw->info, caption, angle, image->interpolate, exception };
|
|
10928
11013
|
new_image = (Image *)CALL_FUNC_WITHOUT_GVL(GVL_FUNC(PolaroidImage), &args);
|
|
10929
11014
|
#else
|
|
@@ -11024,11 +11109,13 @@ Image_preview(VALUE self, VALUE preview)
|
|
|
11024
11109
|
|
|
11025
11110
|
/**
|
|
11026
11111
|
* Set the image profile. If "profile" is nil, deletes the profile. Otherwise "profile" must be a
|
|
11027
|
-
* string containing the specified profile
|
|
11112
|
+
* string containing the specified profile, and "name" must be one of the profile formats of
|
|
11113
|
+
* ImageMagick's META coder (8BIM, APP1, EXIF, ICC, ICM, IPTC, XMP and their variants).
|
|
11028
11114
|
*
|
|
11029
11115
|
* @param name [String, nil] The profile name, or "*" to represent all the profiles in the image.
|
|
11030
11116
|
* @param profile [String] The profile value, or nil to cause the profile to be removed.
|
|
11031
11117
|
* @return [Magick::Image] self
|
|
11118
|
+
* @raise [ArgumentError] if "profile" is not nil and "name" is not a META profile format
|
|
11032
11119
|
*/
|
|
11033
11120
|
VALUE
|
|
11034
11121
|
Image_profile_bang(VALUE self, VALUE name, VALUE profile)
|
data/ext/RMagick/rminfo.cpp
CHANGED
|
@@ -47,6 +47,25 @@ get_option(VALUE self, const char *key)
|
|
|
47
47
|
return Qnil;
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
+
/**
|
|
51
|
+
* Raise ArgumentError if the option is one that ReadImage runs through
|
|
52
|
+
* InterpretImageProperties() and the value would make it read the file it names.
|
|
53
|
+
*
|
|
54
|
+
* No Ruby usage (internal function)
|
|
55
|
+
*
|
|
56
|
+
* @param key the option key
|
|
57
|
+
* @param value the value
|
|
58
|
+
*/
|
|
59
|
+
static void
|
|
60
|
+
check_interpreted_option(const char *key, const char *value)
|
|
61
|
+
{
|
|
62
|
+
if ((rm_strcasecmp(key, "caption") == 0 || rm_strcasecmp(key, "comment") == 0 || rm_strcasecmp(key, "label") == 0)
|
|
63
|
+
&& rm_has_file_reference(value))
|
|
64
|
+
{
|
|
65
|
+
rb_raise(rb_eArgError, "the %s option must not name a file with '@'", key);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
50
69
|
/**
|
|
51
70
|
* Set the specified option to this value. If the value is nil just unset any
|
|
52
71
|
* current value.
|
|
@@ -74,6 +93,7 @@ set_option(VALUE self, const char *key, VALUE string)
|
|
|
74
93
|
char *value;
|
|
75
94
|
|
|
76
95
|
value = StringValueCStr(string);
|
|
96
|
+
check_interpreted_option(key, value);
|
|
77
97
|
SetImageOption(info, key, value);
|
|
78
98
|
}
|
|
79
99
|
return string;
|
|
@@ -306,6 +326,9 @@ Info_aref(int argc, VALUE *argv, VALUE self)
|
|
|
306
326
|
*
|
|
307
327
|
* - Essentially the same function as {Info#define} but paired with {Info#[]}
|
|
308
328
|
* - If the value is nil it is equivalent to {Info#undefine}.
|
|
329
|
+
* - A value whose first non-blank character is '@', or that contains a %[fx:@...], %[hex:@...] or
|
|
330
|
+
* %[pixel:@...] escape, is rejected for the "caption", "comment" and "label" keys because
|
|
331
|
+
* ImageMagick reads the file it names.
|
|
309
332
|
*
|
|
310
333
|
* @overload []=(format, key)
|
|
311
334
|
* @param format [String] An image format name such as "ps" or "tiff".
|
|
@@ -315,6 +338,7 @@ Info_aref(int argc, VALUE *argv, VALUE self)
|
|
|
315
338
|
* @param key [String] A string that identifies the option.
|
|
316
339
|
*
|
|
317
340
|
* @return [Magick::Image::Info] self
|
|
341
|
+
* @raise [ArgumentError] if the "caption", "comment" or "label" value names a file with '@'
|
|
318
342
|
* @see #[]
|
|
319
343
|
* @see #define
|
|
320
344
|
* @see #undefine
|
|
@@ -368,6 +392,7 @@ Info_aset(int argc, VALUE *argv, VALUE self)
|
|
|
368
392
|
/* Allow any argument that supports to_s */
|
|
369
393
|
value = rb_String(value);
|
|
370
394
|
value_p = StringValueCStr(value);
|
|
395
|
+
check_interpreted_option(ckey, value_p);
|
|
371
396
|
|
|
372
397
|
okay = SetImageOption(info, ckey, value_p);
|
|
373
398
|
if (!okay)
|
|
@@ -552,10 +577,13 @@ Info_caption(VALUE self)
|
|
|
552
577
|
|
|
553
578
|
|
|
554
579
|
/**
|
|
555
|
-
* Assigns a caption to an image.
|
|
580
|
+
* Assigns a caption to an image. A caption whose first non-blank character is '@', or that
|
|
581
|
+
* contains a %[fx:@...], %[hex:@...] or %[pixel:@...] escape, is rejected because ImageMagick
|
|
582
|
+
* reads the file it names.
|
|
556
583
|
*
|
|
557
584
|
* @param caption [String] the caption
|
|
558
585
|
* @return [String] the given value
|
|
586
|
+
* @raise [ArgumentError] if the caption names a file with '@'
|
|
559
587
|
*/
|
|
560
588
|
VALUE
|
|
561
589
|
Info_caption_eq(VALUE self, VALUE caption)
|
|
@@ -637,10 +665,13 @@ VALUE Info_comment(VALUE self)
|
|
|
637
665
|
}
|
|
638
666
|
|
|
639
667
|
/**
|
|
640
|
-
* Set the comment
|
|
668
|
+
* Set the comment. A comment whose first non-blank character is '@', or that contains a
|
|
669
|
+
* %[fx:@...], %[hex:@...] or %[pixel:@...] escape, is rejected because ImageMagick reads the
|
|
670
|
+
* file it names.
|
|
641
671
|
*
|
|
642
672
|
* @param string [String] the comment
|
|
643
673
|
* @return [String] the given comment
|
|
674
|
+
* @raise [ArgumentError] if the comment names a file with '@'
|
|
644
675
|
*/
|
|
645
676
|
VALUE Info_comment_eq(VALUE self, VALUE string)
|
|
646
677
|
{
|
|
@@ -1529,10 +1560,13 @@ VALUE Info_label(VALUE self)
|
|
|
1529
1560
|
}
|
|
1530
1561
|
|
|
1531
1562
|
/**
|
|
1532
|
-
* Set the label.
|
|
1563
|
+
* Set the label. A label whose first non-blank character is '@', or that contains a
|
|
1564
|
+
* %[fx:@...], %[hex:@...] or %[pixel:@...] escape, is rejected because ImageMagick reads the
|
|
1565
|
+
* file it names.
|
|
1533
1566
|
*
|
|
1534
1567
|
* @param string [String] the label
|
|
1535
1568
|
* @return [String] the given label
|
|
1569
|
+
* @raise [ArgumentError] if the label names a file with '@'
|
|
1536
1570
|
*/
|
|
1537
1571
|
VALUE Info_label_eq(VALUE self, VALUE string)
|
|
1538
1572
|
{
|
data/ext/RMagick/rmmontage.cpp
CHANGED
|
@@ -442,18 +442,29 @@ Montage_tile_eq(VALUE self, VALUE tile_arg)
|
|
|
442
442
|
|
|
443
443
|
|
|
444
444
|
/**
|
|
445
|
-
* Set title value.
|
|
445
|
+
* Set title value. A title whose first non-blank character is '@', or that contains a
|
|
446
|
+
* %[fx:@...], %[hex:@...] or %[pixel:@...] escape, is rejected because ImageMagick reads the
|
|
447
|
+
* file it names.
|
|
446
448
|
*
|
|
447
449
|
* @param title [String] the title
|
|
448
450
|
* @return [String] the given title
|
|
451
|
+
* @raise [ArgumentError] if the title names a file with '@'
|
|
449
452
|
*/
|
|
450
453
|
VALUE
|
|
451
454
|
Montage_title_eq(VALUE self, VALUE title)
|
|
452
455
|
{
|
|
453
456
|
Montage *montage;
|
|
457
|
+
const char *title_cstr;
|
|
454
458
|
|
|
455
459
|
TypedData_Get_Struct(self, Montage, &rm_montage_data_type, montage);
|
|
456
|
-
|
|
460
|
+
title_cstr = StringValueCStr(title);
|
|
461
|
+
|
|
462
|
+
if (rm_has_file_reference(title_cstr))
|
|
463
|
+
{
|
|
464
|
+
rb_raise(rb_eArgError, "the title must not name a file with '@'");
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
magick_clone_string(&montage->info->title, title_cstr);
|
|
457
468
|
return title;
|
|
458
469
|
}
|
|
459
470
|
|
data/ext/RMagick/rmutil.cpp
CHANGED
|
@@ -221,6 +221,50 @@ rm_strnlen_s(const char *str, size_t strsz)
|
|
|
221
221
|
}
|
|
222
222
|
|
|
223
223
|
|
|
224
|
+
/**
|
|
225
|
+
* Return true if InterpretImageProperties() would read a file the string names, that is, if its
|
|
226
|
+
* first non-blank character is '@', or if it contains a %[fx:...], %[hex:...] or %[pixel:...]
|
|
227
|
+
* escape whose expression begins with '@'.
|
|
228
|
+
*
|
|
229
|
+
* ImageMagick 7 reads such an expression from the file it names, with no blank skipped before
|
|
230
|
+
* the '@'. It also interprets a %[...] inside an fx expression, even after "%%" since '%' is the
|
|
231
|
+
* modulo operator there, so every "%[" in the string is checked. The prefixes are compared with
|
|
232
|
+
* LocaleNCompare() as ImageMagick does. ImageMagick 6 does not read these expressions, but the
|
|
233
|
+
* check is the same for both.
|
|
234
|
+
*
|
|
235
|
+
* No Ruby usage (internal function)
|
|
236
|
+
*
|
|
237
|
+
* @param str the string
|
|
238
|
+
* @return true if the string names a file to read, otherwise false
|
|
239
|
+
*/
|
|
240
|
+
bool
|
|
241
|
+
rm_has_file_reference(const char *str)
|
|
242
|
+
{
|
|
243
|
+
const char *p;
|
|
244
|
+
|
|
245
|
+
p = str;
|
|
246
|
+
while (isspace((int) ((unsigned char) *p)))
|
|
247
|
+
{
|
|
248
|
+
p++;
|
|
249
|
+
}
|
|
250
|
+
if (*p == '@')
|
|
251
|
+
{
|
|
252
|
+
return true;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
for (p = strstr(str, "%["); p != NULL; p = strstr(p + 2, "%["))
|
|
256
|
+
{
|
|
257
|
+
if (LocaleNCompare(p + 2, "fx:@", 4) == 0
|
|
258
|
+
|| LocaleNCompare(p + 2, "hex:@", 5) == 0
|
|
259
|
+
|| LocaleNCompare(p + 2, "pixel:@", 7) == 0)
|
|
260
|
+
{
|
|
261
|
+
return true;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
return false;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
|
|
224
268
|
/**
|
|
225
269
|
* Raise exception if array too short.
|
|
226
270
|
*
|
data/lib/rmagick/version.rb
CHANGED
data/lib/rmagick_internal.rb
CHANGED
|
@@ -228,7 +228,12 @@ module Magick
|
|
|
228
228
|
end
|
|
229
229
|
|
|
230
230
|
def to_opacity(opacity)
|
|
231
|
-
|
|
231
|
+
if opacity.is_a?(String) && opacity.end_with?('%')
|
|
232
|
+
percentage = /\A(\d*\.?\d+(?:[eE][-+]?\d+)?)%\z/.match(opacity)
|
|
233
|
+
Kernel.raise ArgumentError, 'opacity must be a percentage between 0% and 100%' unless percentage && Float(percentage[1]) <= 100
|
|
234
|
+
|
|
235
|
+
return opacity
|
|
236
|
+
end
|
|
232
237
|
|
|
233
238
|
value = Float(opacity)
|
|
234
239
|
Kernel.raise ArgumentError, 'opacity must be >= 0 and <= 1.0' if value < 0 || value > 1.0
|
|
@@ -448,14 +453,21 @@ module Magick
|
|
|
448
453
|
# draw the pattern. Reference the pattern by using its name
|
|
449
454
|
# as the argument to the 'fill' or 'stroke' methods
|
|
450
455
|
def pattern(name, x, y, width, height)
|
|
456
|
+
name = to_string(name)
|
|
457
|
+
Kernel.raise ArgumentError, 'pattern name must consist of letters, digits, hyphen, period and underscore' unless /\A[\w.-]+\z/.match?(name)
|
|
458
|
+
|
|
459
|
+
viewport = sprintf('%g %g %g %g', x, y, width, height)
|
|
460
|
+
|
|
451
461
|
push('defs')
|
|
452
|
-
push("pattern #{
|
|
462
|
+
push("pattern #{name} " + viewport)
|
|
453
463
|
push('graphic-context')
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
464
|
+
begin
|
|
465
|
+
yield
|
|
466
|
+
ensure
|
|
467
|
+
pop('graphic-context')
|
|
468
|
+
pop('pattern')
|
|
469
|
+
pop('defs')
|
|
470
|
+
end
|
|
459
471
|
end
|
|
460
472
|
|
|
461
473
|
# Set point to fill color.
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rmagick
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 7.1.
|
|
4
|
+
version: 7.1.5
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Tim Hunter
|
|
@@ -143,7 +143,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
143
143
|
version: '0'
|
|
144
144
|
requirements:
|
|
145
145
|
- ImageMagick 6.9.0+ (for ImageMagick 6) or 7.1.0+ (for ImageMagick 7)
|
|
146
|
-
rubygems_version: 4.0.
|
|
146
|
+
rubygems_version: 4.0.20
|
|
147
147
|
specification_version: 4
|
|
148
148
|
summary: Ruby binding to ImageMagick
|
|
149
149
|
test_files: []
|