Skip to content

Commit 122813f

Browse files
jcupittkleisauke
andauthored
add magickload_source (#4592)
* add magickload_source test with eg.: ``` $ cat MARBLES.BMP | vips magickload_source "[descriptor=0]" x.v $ cat MARBLES.BMP | vipsthumbnail stdin -o x.jpg ``` ImageMagick doesn't support generic IO, so it just maps the source into memory and uses the buffer interface. magick6 and magick7. * add a test * Update libvips/foreign/magick6load.c Co-authored-by: Kleis Auke Wolthuizen <github@kleisauke.nl> * Update libvips/foreign/magick7load.c Co-authored-by: Kleis Auke Wolthuizen <github@kleisauke.nl> * use the filename interface if possible ie. if the source has an associated filename * add C API wrapper * fix imagemagick6 support --------- Co-authored-by: Kleis Auke Wolthuizen <github@kleisauke.nl>
1 parent 7ce659e commit 122813f

File tree

8 files changed

+262
-1
lines changed

8 files changed

+262
-1
lines changed

ChangeLog

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ master
22

33
- add dcrawload, dcrawload_source, dcrawload_buffer: load raw camera files
44
using libraw [lxsameer]
5+
- add magickload_source: load from a source with imagemagick
56

67
8.17.1
78

libvips/foreign/foreign.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3000,8 +3000,10 @@ vips_foreign_operation_init(void)
30003000

30013001
extern GType vips_foreign_load_magick_file_get_type(void);
30023002
extern GType vips_foreign_load_magick_buffer_get_type(void);
3003+
extern GType vips_foreign_load_magick_source_get_type(void);
30033004
extern GType vips_foreign_load_magick7_file_get_type(void);
30043005
extern GType vips_foreign_load_magick7_buffer_get_type(void);
3006+
extern GType vips_foreign_load_magick7_source_get_type(void);
30053007

30063008
extern GType vips_foreign_save_magick_file_get_type(void);
30073009
extern GType vips_foreign_save_magick_buffer_get_type(void);
@@ -3234,11 +3236,13 @@ vips_foreign_operation_init(void)
32343236
#ifdef HAVE_MAGICK6
32353237
vips_foreign_load_magick_file_get_type();
32363238
vips_foreign_load_magick_buffer_get_type();
3239+
vips_foreign_load_magick_source_get_type();
32373240
#endif /*HAVE_MAGICK6*/
32383241

32393242
#ifdef HAVE_MAGICK7
32403243
vips_foreign_load_magick7_file_get_type();
32413244
vips_foreign_load_magick7_buffer_get_type();
3245+
vips_foreign_load_magick7_source_get_type();
32423246
#endif /*HAVE_MAGICK7*/
32433247
#endif /*defined(ENABLE_MAGICKLOAD) && !defined(MAGICK_MODULE)*/
32443248

libvips/foreign/magick6load.c

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1074,6 +1074,113 @@ vips_foreign_load_magick_buffer_init(VipsForeignLoadMagickBuffer *buffer)
10741074
{
10751075
}
10761076

1077+
typedef struct _VipsForeignLoadMagickSource {
1078+
VipsForeignLoadMagick parent_object;
1079+
1080+
VipsSource *source;
1081+
1082+
} VipsForeignLoadMagickSource;
1083+
1084+
typedef VipsForeignLoadMagickClass VipsForeignLoadMagickSourceClass;
1085+
1086+
G_DEFINE_TYPE(VipsForeignLoadMagickSource, vips_foreign_load_magick_source,
1087+
vips_foreign_load_magick_get_type());
1088+
1089+
static gboolean
1090+
vips_foreign_load_magick_source_is_a_source(VipsSource *source)
1091+
{
1092+
const unsigned char *p;
1093+
1094+
// just use the first 100 bytes, we don't want to force too much into
1095+
// memory
1096+
return (p = vips_source_sniff(source, 100)) &&
1097+
magick_ismagick(p, 100);
1098+
}
1099+
1100+
/* Unfortunately, libMagick does not support header-only reads very well. See
1101+
*
1102+
* http://www.imagemagick.org/discourse-server/viewtopic.php?f=1&t=20017
1103+
*
1104+
* Test especially with BMP, GIF, TGA. So we are forced to read the entire
1105+
* image in the @header() method.
1106+
*/
1107+
static int
1108+
vips_foreign_load_magick_source_header(VipsForeignLoad *load)
1109+
{
1110+
VipsForeignLoadMagick *magick = (VipsForeignLoadMagick *) load;
1111+
VipsForeignLoadMagickSource *magick_source =
1112+
(VipsForeignLoadMagickSource *) load;
1113+
VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(magick);
1114+
1115+
#ifdef DEBUG
1116+
printf("vips_foreign_load_magick_source_header: %p\n", load);
1117+
#endif /*DEBUG*/
1118+
1119+
if (vips_source_is_file(magick_source->source)) {
1120+
const char *filename =
1121+
vips_connection_filename(VIPS_CONNECTION(magick_source->source));
1122+
1123+
g_strlcpy(magick->image_info->filename, filename, MagickPathExtent);
1124+
magick_sniff_file(magick->image_info, filename);
1125+
magick->image = ReadImage(magick->image_info, magick->exception);
1126+
}
1127+
else {
1128+
size_t length;
1129+
const void *data;
1130+
1131+
if (!(data = vips_source_map(magick_source->source, &length)))
1132+
return -1;
1133+
magick_sniff_bytes(magick->image_info, data, length);
1134+
magick->image = BlobToImage(magick->image_info,
1135+
data, length, magick->exception);
1136+
}
1137+
1138+
/* It would be great if we could PingImage and just read the header,
1139+
* but sadly many IM coders do not support ping. The critical one for
1140+
* us is DICOM. TGA also has issues.
1141+
*/
1142+
if (!magick->image) {
1143+
magick_vips_error(class->nickname, magick->exception);
1144+
vips_error(class->nickname, _("unable to read source"));
1145+
return -1;
1146+
}
1147+
1148+
if (vips_foreign_load_magick_load(magick))
1149+
return -1;
1150+
1151+
return 0;
1152+
}
1153+
1154+
static void
1155+
vips_foreign_load_magick_source_class_init(
1156+
VipsForeignLoadMagickSourceClass *class)
1157+
{
1158+
GObjectClass *gobject_class = G_OBJECT_CLASS(class);
1159+
VipsObjectClass *object_class = (VipsObjectClass *) class;
1160+
VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class;
1161+
1162+
gobject_class->set_property = vips_object_set_property;
1163+
gobject_class->get_property = vips_object_get_property;
1164+
1165+
object_class->nickname = "magickload_source";
1166+
object_class->description = _("load source with ImageMagick");
1167+
1168+
load_class->is_a_source = vips_foreign_load_magick_source_is_a_source;
1169+
load_class->header = vips_foreign_load_magick_source_header;
1170+
1171+
VIPS_ARG_OBJECT(class, "source", 1,
1172+
_("Source"),
1173+
_("Source to load from"),
1174+
VIPS_ARGUMENT_REQUIRED_INPUT,
1175+
G_STRUCT_OFFSET(VipsForeignLoadMagickSource, source),
1176+
VIPS_TYPE_SOURCE);
1177+
}
1178+
1179+
static void
1180+
vips_foreign_load_magick_source_init(VipsForeignLoadMagickSource *source)
1181+
{
1182+
}
1183+
10771184
#endif /*HAVE_MAGICK6*/
10781185

10791186
#endif /*ENABLE_MAGICKLOAD*/

libvips/foreign/magick7load.c

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -939,6 +939,112 @@ vips_foreign_load_magick7_buffer_init(VipsForeignLoadMagick7Buffer *buffer)
939939
{
940940
}
941941

942+
typedef struct _VipsForeignLoadMagick7Source {
943+
VipsForeignLoadMagick7 parent_object;
944+
945+
VipsSource *source;
946+
947+
} VipsForeignLoadMagick7Source;
948+
949+
typedef VipsForeignLoadMagick7Class VipsForeignLoadMagick7SourceClass;
950+
951+
G_DEFINE_TYPE(VipsForeignLoadMagick7Source, vips_foreign_load_magick7_source,
952+
vips_foreign_load_magick7_get_type());
953+
954+
static gboolean
955+
vips_foreign_load_magick7_source_is_a_source(VipsSource *source)
956+
{
957+
const unsigned char *p;
958+
959+
// just use the first 100 bytes, we don't want to force too much into
960+
// memory
961+
return (p = vips_source_sniff(source, 100)) &&
962+
magick_ismagick(p, 100);
963+
}
964+
965+
/* Unfortunately, libMagick7 does not support header-only reads very well. See
966+
*
967+
* http://www.imagemagick7.org/discourse-server/viewtopic.php?f=1&t=20017
968+
*
969+
* Test especially with BMP, GIF, TGA. So we are forced to read the entire
970+
* image in the @header() method.
971+
*/
972+
static int
973+
vips_foreign_load_magick7_source_header(VipsForeignLoad *load)
974+
{
975+
VipsForeignLoadMagick7 *magick7 = (VipsForeignLoadMagick7 *) load;
976+
VipsForeignLoadMagick7Source *magick7_source =
977+
(VipsForeignLoadMagick7Source *) load;
978+
979+
#ifdef DEBUG
980+
printf("vips_foreign_load_magick7_source_header: %p\n", load);
981+
#endif /*DEBUG*/
982+
983+
if (vips_source_is_file(magick7_source->source)) {
984+
const char *filename =
985+
vips_connection_filename(VIPS_CONNECTION(magick7_source->source));
986+
987+
g_strlcpy(magick7->image_info->filename, filename, MaxTextExtent);
988+
magick_sniff_file(magick7->image_info, filename);
989+
magick7->image = ReadImage(magick7->image_info, magick7->exception);
990+
}
991+
else {
992+
size_t length;
993+
const void *data;
994+
995+
if (!(data = vips_source_map(magick7_source->source, &length)))
996+
return -1;
997+
998+
magick_sniff_bytes(magick7->image_info, data, length);
999+
magick7->image = BlobToImage(magick7->image_info, data, length,
1000+
magick7->exception);
1001+
}
1002+
1003+
/* It would be great if we could PingImage and just read the header,
1004+
* but sadly many IM coders do not support ping. The critical one for
1005+
* us is DICOM. TGA also has issues.
1006+
*/
1007+
if (!magick7->image) {
1008+
vips_foreign_load_magick7_error(magick7);
1009+
return -1;
1010+
}
1011+
1012+
if (vips_foreign_load_magick7_load(magick7))
1013+
return -1;
1014+
1015+
return 0;
1016+
}
1017+
1018+
static void
1019+
vips_foreign_load_magick7_source_class_init(
1020+
VipsForeignLoadMagick7SourceClass *class)
1021+
{
1022+
GObjectClass *gobject_class = G_OBJECT_CLASS(class);
1023+
VipsObjectClass *object_class = (VipsObjectClass *) class;
1024+
VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class;
1025+
1026+
gobject_class->set_property = vips_object_set_property;
1027+
gobject_class->get_property = vips_object_get_property;
1028+
1029+
object_class->nickname = "magickload_source";
1030+
object_class->description = _("load source with ImageMagick7");
1031+
1032+
load_class->is_a_source = vips_foreign_load_magick7_source_is_a_source;
1033+
load_class->header = vips_foreign_load_magick7_source_header;
1034+
1035+
VIPS_ARG_OBJECT(class, "source", 1,
1036+
_("Source"),
1037+
_("Source to load from"),
1038+
VIPS_ARGUMENT_REQUIRED_INPUT,
1039+
G_STRUCT_OFFSET(VipsForeignLoadMagick7Source, source),
1040+
VIPS_TYPE_SOURCE);
1041+
}
1042+
1043+
static void
1044+
vips_foreign_load_magick7_source_init(VipsForeignLoadMagick7Source *source)
1045+
{
1046+
}
1047+
9421048
#endif /*HAVE_MAGICK7*/
9431049

9441050
#endif /*ENABLE_MAGICKLOAD*/

libvips/foreign/magickload.c

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,3 +156,35 @@ vips_magickload_buffer(void *buf, size_t len, VipsImage **out, ...)
156156

157157
return result;
158158
}
159+
160+
/**
161+
* vips_magickload_source:
162+
* @source: source to load
163+
* @out: (out): image to write
164+
* @...: `NULL`-terminated list of optional named arguments
165+
*
166+
* Exactly as [ctor@Image.magickload], but read from a source.
167+
*
168+
* ::: tip "Optional arguments"
169+
* * @page: `gint`, load from this page
170+
* * @n: `gint`, load this many pages
171+
* * @density: `gchararray`, canvas resolution for rendering vector formats
172+
* like SVG
173+
*
174+
* ::: seealso
175+
* [ctor@Image.magickload].
176+
*
177+
* Returns: 0 on success, -1 on error.
178+
*/
179+
int
180+
vips_magickload_source(VipsSource *source, VipsImage **out, ...)
181+
{
182+
va_list ap;
183+
int result;
184+
185+
va_start(ap, out);
186+
result = vips_call_split("magickload_source", ap, source, out);
187+
va_end(ap);
188+
189+
return result;
190+
}

libvips/include/vips/foreign.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -716,6 +716,9 @@ VIPS_API
716716
int vips_magickload_buffer(void *buf, size_t len, VipsImage **out, ...)
717717
G_GNUC_NULL_TERMINATED;
718718
VIPS_API
719+
int vips_magickload_source(VipsSource *source, VipsImage **out, ...)
720+
G_GNUC_NULL_TERMINATED;
721+
VIPS_API
719722
int vips_magicksave(VipsImage *in, const char *filename, ...)
720723
G_GNUC_NULL_TERMINATED;
721724
VIPS_API

libvips/module/magick.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,10 @@ g_module_check_init(GModule *module)
6060

6161
extern GType vips_foreign_load_magick_file_get_type(void);
6262
extern GType vips_foreign_load_magick_buffer_get_type(void);
63+
extern GType vips_foreign_load_magick_source_get_type(void);
6364
extern GType vips_foreign_load_magick7_file_get_type(void);
6465
extern GType vips_foreign_load_magick7_buffer_get_type(void);
66+
extern GType vips_foreign_load_magick7_source_get_type(void);
6567
extern GType vips_foreign_save_magick_file_get_type(void);
6668
extern GType vips_foreign_save_magick_bmp_file_get_type(void);
6769
extern GType vips_foreign_save_magick_buffer_get_type(void);
@@ -71,11 +73,13 @@ g_module_check_init(GModule *module)
7173
#ifdef HAVE_MAGICK6
7274
vips_foreign_load_magick_file_get_type();
7375
vips_foreign_load_magick_buffer_get_type();
76+
vips_foreign_load_magick_source_get_type();
7477
#endif /*HAVE_MAGICK6*/
7578

7679
#ifdef HAVE_MAGICK7
7780
vips_foreign_load_magick7_file_get_type();
7881
vips_foreign_load_magick7_buffer_get_type();
82+
vips_foreign_load_magick7_source_get_type();
7983
#endif /*HAVE_MAGICK7*/
8084
#endif /*ENABLE_MAGICKLOAD*/
8185

test/test-suite/test_foreign.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -806,6 +806,9 @@ def bmp_valid(im):
806806

807807
self.file_loader("magickload", BMP_FILE, bmp_valid)
808808
self.buffer_loader("magickload_buffer", BMP_FILE, bmp_valid)
809+
source = pyvips.Source.new_from_file(BMP_FILE)
810+
x = pyvips.Image.new_from_source(source, "")
811+
bmp_valid(x)
809812

810813
# we should have rgb or rgba for svg files ... different versions of
811814
# IM handle this differently. GM even gives 1 band.
@@ -877,11 +880,12 @@ def bmp_valid(im):
877880
assert im.width == 433
878881
assert im.height == 433
879882

880-
881883
# load should see metadata like eg. icc profiles
882884
im = pyvips.Image.magickload(JPEG_FILE)
883885
assert len(im.get("icc-profile-data")) == 564
884886

887+
im = pyvips.Image.magickload(JPEG_FILE)
888+
885889
# added in 8.7
886890
@skip_if_no("magicksave")
887891
def test_magicksave(self):

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy