Merge branch 'master' into revise-heifload

This commit is contained in:
John Cupitt 2020-03-14 13:06:23 +00:00
commit 1deada5aad
56 changed files with 816 additions and 610 deletions

View File

@ -6,18 +6,22 @@
- tiffsave has a "depth" param to set max pyr depth
- libtiff LOGLUV images load and save as libvips XYZ
- add gifload_source, csvload_source, csvsave_target, matrixload_source,
matrixsave_source
matrixsave_source, pdfload_source
- revise vipsthumbnail flags
- add VIPS_LEAK env var
- add vips_pipe_read_limit_set(), --vips-pipe-read-limit,
VIPS_PIPE_READ_LIMIT
- revise gifload to fix BACKGROUND and PREVIOUS dispose [alon-ne]
- add subsample_mode, deprecate no_subsample in jpegsave [Elad-Laufer]
- add vips_isdirf()
- add PAGENUMBER support to tiff write [jclavoie-jive]
31/1/19 started 8.9.2
- fix a deadlock with --vips-leak [DarthSim]
- better gifload behaviour for DISPOSAL_UNSPECIFIED [DarthSim]
- ban ppm max_value < 0
- add fuzz corpus to dist
- detect read errors correctly in source_sniff
20/6/19 started 8.9.1
- don't use the new source loaders for new_from_file or new_from_buffer, it

View File

@ -61,4 +61,6 @@ autoheader
$LIBTOOLIZE --copy --force --automake
automake --add-missing --copy
./configure $*
if test -z "$NOCONFIGURE"; then
./configure $*
fi

View File

@ -450,8 +450,8 @@ AC_CHECK_LIB(m,cbrt,[AC_DEFINE(HAVE_CBRT,1,[have cbrt() in libm.])])
AC_CHECK_LIB(m,hypot,[AC_DEFINE(HAVE_HYPOT,1,[have hypot() in libm.])])
AC_CHECK_LIB(m,atan2,[AC_DEFINE(HAVE_ATAN2,1,[have atan2() in libm.])])
# have to have these
# need glib 2.6 for GOption
# have to have these parts of glib ... we need glib 2.6 for GOption
# gio is optional, see below
PKG_CHECK_MODULES(REQUIRED, glib-2.0 >= 2.6 gmodule-2.0 gobject-2.0)
PACKAGES_USED="$PACKAGES_USED glib-2.0 gmodule-2.0 gobject-2.0"
@ -480,6 +480,7 @@ PKG_CHECK_MODULES(GIO, glib-2.0 >= 2.15,
[AC_DEFINE(HAVE_GIO,1,
[define if your glib has GIO.]
)
PACKAGES_USED="$PACKAGES_USED gio-2.0"
],
[:
]
@ -1326,14 +1327,14 @@ fi
# Gather all up for VIPS_CFLAGS, VIPS_INCLUDES, VIPS_LIBS
# sort includes to get longer, more specific dirs first
# helps, for example, selecting graphicsmagick over imagemagick
VIPS_CFLAGS=`for i in $VIPS_CFLAGS $GTHREAD_CFLAGS $REQUIRED_CFLAGS $EXPAT_CFLAGS $ZLIB_CFLAGS $PANGOFT2_CFLAGS $GSF_CFLAGS $FFTW_CFLAGS $MAGICK_CFLAGS $JPEG_CFLAGS $PNG_CFLAGS $IMAGEQUANT_CFLAGS $EXIF_CFLAGS $MATIO_CFLAGS $CFITSIO_CFLAGS $LIBWEBP_CFLAGS $LIBWEBPMUX_CFLAGS $GIFLIB_INCLUDES $RSVG_CFLAGS $PDFIUM_INCLUDES $POPPLER_CFLAGS $OPENEXR_CFLAGS $OPENSLIDE_CFLAGS $ORC_CFLAGS $TIFF_CFLAGS $LCMS_CFLAGS $HEIF_CFLAGS
VIPS_CFLAGS=`for i in $VIPS_CFLAGS $GTHREAD_CFLAGS $GIO_CFLAGS $REQUIRED_CFLAGS $EXPAT_CFLAGS $ZLIB_CFLAGS $PANGOFT2_CFLAGS $GSF_CFLAGS $FFTW_CFLAGS $MAGICK_CFLAGS $JPEG_CFLAGS $PNG_CFLAGS $IMAGEQUANT_CFLAGS $EXIF_CFLAGS $MATIO_CFLAGS $CFITSIO_CFLAGS $LIBWEBP_CFLAGS $LIBWEBPMUX_CFLAGS $GIFLIB_INCLUDES $RSVG_CFLAGS $PDFIUM_INCLUDES $POPPLER_CFLAGS $OPENEXR_CFLAGS $OPENSLIDE_CFLAGS $ORC_CFLAGS $TIFF_CFLAGS $LCMS_CFLAGS $HEIF_CFLAGS
do
echo $i
done | sort -ru`
VIPS_CFLAGS=`echo $VIPS_CFLAGS`
VIPS_CFLAGS="$VIPS_DEBUG_FLAGS $VIPS_CFLAGS"
VIPS_INCLUDES="$ZLIB_INCLUDES $PNG_INCLUDES $TIFF_INCLUDES $JPEG_INCLUDES $NIFTI_INCLUDES"
VIPS_LIBS="$ZLIB_LIBS $HEIF_LIBS $MAGICK_LIBS $PNG_LIBS $IMAGEQUANT_LIBS $TIFF_LIBS $JPEG_LIBS $GTHREAD_LIBS $REQUIRED_LIBS $EXPAT_LIBS $PANGOFT2_LIBS $GSF_LIBS $FFTW_LIBS $ORC_LIBS $LCMS_LIBS $GIFLIB_LIBS $RSVG_LIBS $NIFTI_LIBS $PDFIUM_LIBS $POPPLER_LIBS $OPENEXR_LIBS $OPENSLIDE_LIBS $CFITSIO_LIBS $LIBWEBP_LIBS $LIBWEBPMUX_LIBS $MATIO_LIBS $EXIF_LIBS -lm"
VIPS_LIBS="$ZLIB_LIBS $HEIF_LIBS $MAGICK_LIBS $PNG_LIBS $IMAGEQUANT_LIBS $TIFF_LIBS $JPEG_LIBS $GTHREAD_LIBS $GIO_LIBS $REQUIRED_LIBS $EXPAT_LIBS $PANGOFT2_LIBS $GSF_LIBS $FFTW_LIBS $ORC_LIBS $LCMS_LIBS $GIFLIB_LIBS $RSVG_LIBS $NIFTI_LIBS $PDFIUM_LIBS $POPPLER_LIBS $OPENEXR_LIBS $OPENSLIDE_LIBS $CFITSIO_LIBS $LIBWEBP_LIBS $LIBWEBPMUX_LIBS $MATIO_LIBS $EXIF_LIBS -lm"
AC_SUBST(VIPS_LIBDIR)

View File

@ -16,7 +16,7 @@
<para>
This page tries to explain what the different strategies are and when each is used. If you are running into unexpected memory, disc or CPU use, this might be helpful. <literal>vips_image_new_from_file()</literal> has the official documentation.
</para>
<refsect3 id="direct-access">
<section xml:id="direct-access">
<title>Direct access</title>
<para>
This is the fastest and simplest one. The file is mapped directly into the processs address space and can be read with ordinary pointer access. Small files are completely mapped; large files are mapped in a series of small windows that are shared and which scroll about as pixels are read. Files which are accessed like this can be read by many threads at once, making them especially quick. They also interact well with the computers operating system: your OS will use spare memory to cache recently used chunks of the file.
@ -25,10 +25,10 @@
For this to be possible, the file format needs to be a simple dump of a memory array. libvips supports direct access for vips, 8-bit binary ppm/pbm/pnm, analyse and raw.
</para>
<para>
libvips has a special direct write mode where pixels can be written directly to the file image. This is used for the <ulink url="libvips-draw.html">draw operators</ulink>.
libvips has a special direct write mode where pixels can be written directly to the file image. This is used for the <link xlink:href="libvips-draw.html">draw operators</link>.
</para>
</refsect3>
<refsect3 id="random-access-via-load-library">
</section>
<section xml:id="random-access-via-load-library">
<title>Random access via load library</title>
<para>
Some image file formats have libraries which allow true random access to image pixels. For example, libtiff lets you read any tile out of a tiled tiff image very quickly. Because the libraries allow true random access, libvips can simply hook the image load library up to the input of the operation pipeline.
@ -39,8 +39,8 @@
<para>
libvips can load tiled tiff, tiled OpenEXR, FITS and OpenSlide images in this manner.
</para>
</refsect3>
<refsect3 id="full-decompression">
</section>
<section xml:id="full-decompression">
<title>Full decompression</title>
<para>
Many image load libraries do not support random access. In order to use images of this type as inputs to pipelines, libvips has to convert them to a random access format first.
@ -54,8 +54,8 @@
<para>
This is the slowest and most memory-hungry way to read files, but its unavoidable for many file formats. Unless you can use the next one!
</para>
</refsect3>
<refsect3 id="sequential-access">
</section>
<section xml:id="sequential-access">
<title>Sequential access</title>
<para>
This a fairly recent addition to libvips and is a hybrid of the previous two.
@ -90,7 +90,7 @@ $ vips shrink fred.png jim.png 10 10
<para>
This is done automatically in command-line operation. In programs, you need to set <literal>access</literal> to #VIPS_ACCESS_SEQUENTIAL in calls to functions like vips_image_new_from_file().
</para>
</refsect3>
</section>
</refentry>

View File

@ -21,7 +21,7 @@ $filename = &quot;image.jpg&quot;;
$image = Vips\Image::thumbnail($filename, 200, [&quot;height&quot; =&gt; 200]);
$image-&gt;writeToFile(&quot;my-thumbnail.jpg&quot;);
</programlisting>
<refsect3 id="libvips-options">
<section xml:id="libvips-options">
<title>libvips options</title>
<para>
<literal>vipsthumbnail</literal> supports the usual range of vips command-line options. A few of them are useful:
@ -38,8 +38,8 @@ $image-&gt;writeToFile(&quot;my-thumbnail.jpg&quot;);
<para>
<literal>--vips-info</literal> shows a higher level view of the operations that <literal>vipsthumbnail</literal> is running. 
</para>
</refsect3>
<refsect3 id="looping">
</section>
<section xml:id="looping">
<title>Looping</title>
<para>
<literal>vipsthumbnail</literal> can process many images in one command. For example:
@ -56,8 +56,8 @@ $ vipsthumbnail *.jpg
<programlisting>
$ parallel vipsthumbnail ::: *.jpg
</programlisting>
</refsect3>
<refsect3 id="thumbnail-size">
</section>
<section xml:id="thumbnail-size">
<title>Thumbnail size</title>
<para>
You can set the bounding box of the generated thumbnail with the <literal>--size</literal> option. For example:
@ -80,8 +80,8 @@ $ vipsthumbnail shark.jpg --size 200x
<para>
You can append <literal>!</literal> to force a resize to the exact target size, breaking the aspect ratio.
</para>
</refsect3>
<refsect3 id="cropping">
</section>
<section xml:id="cropping">
<title>Cropping</title>
<para>
<literal>vipsthumbnail</literal> normally shrinks images to fit within the box set by <literal>--size</literal>. You can use the <literal>--smartcrop</literal> option to crop to fill the box instead. Excess pixels are trimmed away using the strategy you set. For example:
@ -92,30 +92,28 @@ $ vipsthumbnail owl.jpg --smartcrop attention -s 128
<para>
Where <literal>owl.jpg</literal> is an off-centre composition:
</para>
<figure>
<mediaobject>
<para>
<inlinemediaobject>
<imageobject>
<imagedata fileref="owl.jpg" />
</imageobject>
<textobject><phrase></phrase></textobject>
</mediaobject>
</figure>
</inlinemediaobject>
</para>
<para>
Gives this result:
</para>
<figure>
<mediaobject>
<para>
<inlinemediaobject>
<imageobject>
<imagedata fileref="tn_owl.jpg" />
</imageobject>
<textobject><phrase></phrase></textobject>
</mediaobject>
</figure>
</inlinemediaobject>
</para>
<para>
First it shrinks the image to get the vertical axis to 128 pixels, then crops down to 128 pixels across using the <literal>attention</literal> strategy. This one searches the image for features which might catch a human eye, see <literal>vips_smartcrop()</literal> for details.
</para>
</refsect3>
<refsect3 id="linear-light">
</section>
<section xml:id="linear-light">
<title>Linear light</title>
<para>
Shrinking images involves combining many pixels into one. Arithmetic averaging really ought to be in terms of the number of photons, but (for historical reasons) the values stored in image files are usually related to the voltage that should be applied to the electron gun in a CRT display.
@ -142,8 +140,8 @@ real 0m4.660s
user 0m4.640s
sys 0m0.016s
</programlisting>
</refsect3>
<refsect3 id="output-directory">
</section>
<section xml:id="output-directory">
<title>Output directory</title>
<para>
You set the thumbnail write parameters with the <literal>-o</literal> option. This is a pattern which the input filename is pasted into to produce the output filename. For example:
@ -172,8 +170,8 @@ $ vipsthumbnail fred.jpg ../jim.tif -o mythumbs/tn_%s.jpg
<para>
Now both input files will have thumbnails written to a subdirectory of their current directory.
</para>
</refsect3>
<refsect3 id="output-format-and-options">
</section>
<section xml:id="output-format-and-options">
<title>Output format and options</title>
<para>
You can use <literal>-o</literal> to specify the thumbnail image format too. For example: 
@ -247,8 +245,8 @@ $ vipsthumbnail 42-32157534.jpg -o x.jpg[optimize_coding,strip]
$ ls -l x.jpg
-rw-rr 1 john john 3600 Nov 12 21:27 x.jpg
</programlisting>
</refsect3>
<refsect3 id="colour-management">
</section>
<section xml:id="colour-management">
<title>Colour management</title>
<para>
<literal>vipsthumbnail</literal> will optionally put images through LittleCMS for you. You can use this to move all thumbnails to the same colour space. All web browsers assume that images without an ICC profile are in sRGB colourspace, so if you move your thumbnails to sRGB, you can strip all the embedded profiles. This can save several kb per thumbnail.
@ -265,12 +263,15 @@ $ ls -l tn_shark.jpg
Now encode with sRGB and delete any embedded profile:
</para>
<programlisting>
$ vipsthumbnail shark.jpg --eprofile /usr/share/color/icc/sRGB.icc --delete
$ vipsthumbnail shark.jpg --eprofile srgb --delete
$ ls -l tn_shark.jpg
-rw-rr 1 john john 4229 Nov  9 14:33 tn_shark.jpg
</programlisting>
<para>
Itll look identical to a user, but be almost half the size.
(You can use the filename of any RGB profile. The magic string <literal>srgb</literal> selects a high-quality sRGB profile thats built into libvips.)
</para>
<para>
<literal>tn_shark.jpg</literal> will look identical to a user, but its almost half the size.
</para>
<para>
You can also specify a fallback input profile to use if the image has no embedded one. This can often happen with CMYK images, producing an error message like:
@ -284,28 +285,13 @@ vips_colourspace: no known route from 'cmyk' to 'srgb'
If you supply a CMYK profile, it will be able to convert the image, for example:
</para>
<programlisting>
$ vipsthumbnail kgdev.jpg --iprofile /usr/share/color/icc/colord/FOGRA28L_webcoated.icc
$ vipsthumbnail kgdev.jpg --iprofile cmyk
</programlisting>
<para>
Ive had good results with this profile:
(As before, the magic string <literal>cmyk</literal> selects a high-quality CMYK profile thats built into libvips, but you can use any CMYK profile you like.)
</para>
<para>
https://github.com/libvips/nip2/blob/master/share/nip2/data/cmyk.icm
</para>
<para>
It makes nice-looking images from most CMYK files, and is completely free.
</para>
</refsect3>
<refsect3 id="auto-rotate">
<title>Auto-rotate</title>
<para>
Many JPEG files have a hint set in the header giving the image orientation. If you strip out the metadata, this hint will be lost, and the image will appear to be rotated.
</para>
<para>
If you use the <literal>--rotate</literal> option, <literal>vipsthumbnail</literal> examines the image header and if theres an orientation tag, applies and removes it.
</para>
</refsect3>
<refsect3 id="final-suggestion">
</section>
<section xml:id="final-suggestion">
<title>Final suggestion</title>
<para>
Putting all this together, I suggest this as a sensible set of options:
@ -314,10 +300,9 @@ $ vipsthumbnail kgdev.jpg --iprofile /usr/share/color/icc/colord/FOGRA28L_webcoa
$ vipsthumbnail fred.jpg \
--size 128 \
-o tn_%s.jpg[optimize_coding,strip] \
--eprofile /usr/share/color/icc/sRGB.icc \
--rotate
--eprofile srgb
</programlisting>
</refsect3>
</section>
</refentry>

View File

@ -25,4 +25,6 @@ libstandaloneengine_a_SOURCES = StandaloneFuzzTargetMain.c
check_PROGRAMS = $(FUZZPROGS)
noinst_LIBRARIES = $(FUZZLIBS)
EXTRA_DIST = $(TESTS)
EXTRA_DIST = \
$(TESTS) \
common_fuzzer_corpus

View File

@ -1,15 +0,0 @@
P2
#vips2ppm - Fri Aug 23 12:48:07 2019
10 10
255
96 101 113 118 124 130 136 141 147 150
81 87 98 101 107 112 117 123 130 135
73 78 85 90 95 99 103 110 118 124
46 51 60 67 73 81 87 94 103 109
34 35 40 48 60 69 77 81 85 88
28 26 31 36 45 54 59 64 69 72
32 31 41 39 39 40 45 52 61 66
38 38 47 42 38 36 38 43 49 53
37 38 39 39 37 37 37 36 34 32
36 36 38 36 35 34 35 32 28 25

View File

@ -1,10 +0,0 @@
96 101 113 118 124 130 136 141 147 150
81 87 98 101 107 112 117 123 130 135
73 78 85 90 95 99 103 110 118 124
46 51 60 67 73 81 87 94 103 109
34 35 40 48 60 69 77 81 85 88
28 26 31 36 45 54 59 64 69 72
32 31 41 39 39 40 45 52 61 66
38 38 47 42 38 36 38 43 49 53
37 38 39 39 37 37 37 36 34 32
36 36 38 36 35 34 35 32 28 25
1 96 101 113 118 124 130 136 141 147 150
2 81 87 98 101 107 112 117 123 130 135
3 73 78 85 90 95 99 103 110 118 124
4 46 51 60 67 73 81 87 94 103 109
5 34 35 40 48 60 69 77 81 85 88
6 28 26 31 36 45 54 59 64 69 72
7 32 31 41 39 39 40 45 52 61 66
8 38 38 47 42 38 36 38 43 49 53
9 37 38 39 39 37 37 37 36 34 32
10 36 36 38 36 35 34 35 32 28 25

View File

@ -1,11 +0,0 @@
10 10
96 101 113 118 124 130 136 141 147 150
81 87 98 101 107 112 117 123 130 135
73 78 85 90 95 99 103 110 118 124
46 51 60 67 73 81 87 94 103 109
34 35 40 48 60 69 77 81 85 88
28 26 31 36 45 54 59 64 69 72
32 31 41 39 39 40 45 52 61 66
38 38 47 42 38 36 38 43 49 53
37 38 39 39 37 37 37 36 34 32
36 36 38 36 35 34 35 32 28 25

View File

@ -1,6 +0,0 @@
P5
#vips2ppm - Fri Aug 23 12:47:38 2019
10 10
255
`eqv|ˆ<E2809A>QWbekpu{‡INUZ_cgnv|.3<CIQW^gm"#(0<EMQUX$-6;@EH )''(-4=B&&/*&$&+15%&''%%%$" $$&$#"# 

View File

@ -1,6 +0,0 @@
P6
#vips2ppm - Fri Aug 23 12:47:50 2019
10 10
255
g[ilaoxm{{s€<73>yˆ<E280A0>Œ…—<E280A6>œ•<C593>¤˜”¥\K[`Rai]klaophwtm}yr„wŒ„•‰…TBRYHX^P_aUcf[kh_plcvrjzr‰€y:(6=-:E7DJ>LQDUWL]\SfcZolbzri|.(/)3#.9+8E7FM@QSHYVM`ZQf]Tg' %*$- *6(5=1?C6HG;OL@VOCW,!)!3$+2",0#-1#05(9</AE8LJ=Q1"%/#%7+/3&-/"+- */!04&7:+>>/B.""/##0$&/#'.!(.!*. --.+.)-," ,"!/##-!#,&+'-*+*'(#%

View File

@ -562,7 +562,7 @@ vips_boolean_const_init( VipsBooleanConst *boolean_const )
static int
vips_boolean_constv( VipsImage *in, VipsImage **out,
VipsOperationBoolean operation, double *c, int n, va_list ap )
VipsOperationBoolean operation, const double *c, int n, va_list ap )
{
VipsArea *area_c;
double *array;
@ -609,7 +609,7 @@ vips_boolean_constv( VipsImage *in, VipsImage **out,
*/
int
vips_boolean_const( VipsImage *in, VipsImage **out,
VipsOperationBoolean boolean, double *c, int n, ... )
VipsOperationBoolean boolean, const double *c, int n, ... )
{
va_list ap;
int result;
@ -637,7 +637,8 @@ vips_boolean_const( VipsImage *in, VipsImage **out,
* Returns: 0 on success, -1 on error
*/
int
vips_andimage_const( VipsImage *in, VipsImage **out, double *c, int n, ... )
vips_andimage_const( VipsImage *in, VipsImage **out,
const double *c, int n, ... )
{
va_list ap;
int result;
@ -666,7 +667,8 @@ vips_andimage_const( VipsImage *in, VipsImage **out, double *c, int n, ... )
* Returns: 0 on success, -1 on error
*/
int
vips_orimage_const( VipsImage *in, VipsImage **out, double *c, int n, ... )
vips_orimage_const( VipsImage *in, VipsImage **out,
const double *c, int n, ... )
{
va_list ap;
int result;
@ -695,7 +697,8 @@ vips_orimage_const( VipsImage *in, VipsImage **out, double *c, int n, ... )
* Returns: 0 on success, -1 on error
*/
int
vips_eorimage_const( VipsImage *in, VipsImage **out, double *c, int n, ... )
vips_eorimage_const( VipsImage *in, VipsImage **out,
const double *c, int n, ... )
{
va_list ap;
int result;
@ -724,7 +727,7 @@ vips_eorimage_const( VipsImage *in, VipsImage **out, double *c, int n, ... )
* Returns: 0 on success, -1 on error
*/
int
vips_lshift_const( VipsImage *in, VipsImage **out, double *c, int n, ... )
vips_lshift_const( VipsImage *in, VipsImage **out, const double *c, int n, ... )
{
va_list ap;
int result;
@ -753,7 +756,7 @@ vips_lshift_const( VipsImage *in, VipsImage **out, double *c, int n, ... )
* Returns: 0 on success, -1 on error
*/
int
vips_rshift_const( VipsImage *in, VipsImage **out, double *c, int n, ... )
vips_rshift_const( VipsImage *in, VipsImage **out, const double *c, int n, ... )
{
va_list ap;
int result;

View File

@ -453,7 +453,7 @@ vips_linear_init( VipsLinear *linear )
static int
vips_linearv( VipsImage *in, VipsImage **out,
double *a, double *b, int n, va_list ap )
const double *a, const double *b, int n, va_list ap )
{
VipsArea *area_a;
VipsArea *area_b;
@ -500,7 +500,8 @@ vips_linearv( VipsImage *in, VipsImage **out,
* Returns: 0 on success, -1 on error
*/
int
vips_linear( VipsImage *in, VipsImage **out, double *a, double *b, int n, ... )
vips_linear( VipsImage *in, VipsImage **out,
const double *a, const double *b, int n, ... )
{
va_list ap;
int result;

View File

@ -420,7 +420,7 @@ vips_math2_const_init( VipsMath2Const *math2_const )
static int
vips_math2_constv( VipsImage *in, VipsImage **out,
VipsOperationMath2 math2, double *c, int n, va_list ap )
VipsOperationMath2 math2, const double *c, int n, va_list ap )
{
VipsArea *area_c;
double *array;
@ -470,7 +470,7 @@ vips_math2_constv( VipsImage *in, VipsImage **out,
*/
int
vips_math2_const( VipsImage *in, VipsImage **out,
VipsOperationMath2 math2, double *c, int n, ... )
VipsOperationMath2 math2, const double *c, int n, ... )
{
va_list ap;
int result;
@ -496,7 +496,7 @@ vips_math2_const( VipsImage *in, VipsImage **out,
* Returns: 0 on success, -1 on error
*/
int
vips_pow_const( VipsImage *in, VipsImage **out, double *c, int n, ... )
vips_pow_const( VipsImage *in, VipsImage **out, const double *c, int n, ... )
{
va_list ap;
int result;
@ -523,7 +523,7 @@ vips_pow_const( VipsImage *in, VipsImage **out, double *c, int n, ... )
* Returns: 0 on success, -1 on error
*/
int
vips_wop_const( VipsImage *in, VipsImage **out, double *c, int n, ... )
vips_wop_const( VipsImage *in, VipsImage **out, const double *c, int n, ... )
{
va_list ap;
int result;

View File

@ -598,7 +598,7 @@ vips_relational_const_init( VipsRelationalConst *relational_const )
static int
vips_relational_constv( VipsImage *in, VipsImage **out,
VipsOperationRelational relational, double *c, int n, va_list ap )
VipsOperationRelational relational, const double *c, int n, va_list ap )
{
VipsArea *area_c;
double *array;
@ -645,7 +645,7 @@ vips_relational_constv( VipsImage *in, VipsImage **out,
*/
int
vips_relational_const( VipsImage *in, VipsImage **out,
VipsOperationRelational relational, double *c, int n, ... )
VipsOperationRelational relational, const double *c, int n, ... )
{
va_list ap;
int result;
@ -671,7 +671,7 @@ vips_relational_const( VipsImage *in, VipsImage **out,
* Returns: 0 on success, -1 on error
*/
int
vips_equal_const( VipsImage *in, VipsImage **out, double *c, int n, ... )
vips_equal_const( VipsImage *in, VipsImage **out, const double *c, int n, ... )
{
va_list ap;
int result;
@ -698,7 +698,8 @@ vips_equal_const( VipsImage *in, VipsImage **out, double *c, int n, ... )
* Returns: 0 on success, -1 on error
*/
int
vips_notequal_const( VipsImage *in, VipsImage **out, double *c, int n, ... )
vips_notequal_const( VipsImage *in, VipsImage **out,
const double *c, int n, ... )
{
va_list ap;
int result;
@ -725,7 +726,7 @@ vips_notequal_const( VipsImage *in, VipsImage **out, double *c, int n, ... )
* Returns: 0 on success, -1 on error
*/
int
vips_less_const( VipsImage *in, VipsImage **out, double *c, int n, ... )
vips_less_const( VipsImage *in, VipsImage **out, const double *c, int n, ... )
{
va_list ap;
int result;
@ -752,7 +753,7 @@ vips_less_const( VipsImage *in, VipsImage **out, double *c, int n, ... )
* Returns: 0 on success, -1 on error
*/
int
vips_lesseq_const( VipsImage *in, VipsImage **out, double *c, int n, ... )
vips_lesseq_const( VipsImage *in, VipsImage **out, const double *c, int n, ... )
{
va_list ap;
int result;
@ -779,7 +780,7 @@ vips_lesseq_const( VipsImage *in, VipsImage **out, double *c, int n, ... )
* Returns: 0 on success, -1 on error
*/
int
vips_more_const( VipsImage *in, VipsImage **out, double *c, int n, ... )
vips_more_const( VipsImage *in, VipsImage **out, const double *c, int n, ... )
{
va_list ap;
int result;
@ -806,7 +807,7 @@ vips_more_const( VipsImage *in, VipsImage **out, double *c, int n, ... )
* Returns: 0 on success, -1 on error
*/
int
vips_moreeq_const( VipsImage *in, VipsImage **out, double *c, int n, ... )
vips_moreeq_const( VipsImage *in, VipsImage **out, const double *c, int n, ... )
{
va_list ap;
int result;

View File

@ -333,7 +333,7 @@ vips_remainder_const_init( VipsRemainderConst *remainder_const )
static int
vips_remainder_constv( VipsImage *in, VipsImage **out,
double *c, int n, va_list ap )
const double *c, int n, va_list ap )
{
VipsArea *area_c;
double *array;
@ -379,7 +379,8 @@ vips_remainder_constv( VipsImage *in, VipsImage **out,
* Returns: 0 on success, -1 on error
*/
int
vips_remainder_const( VipsImage *in, VipsImage **out, double *c, int n, ... )
vips_remainder_const( VipsImage *in, VipsImage **out,
const double *c, int n, ... )
{
va_list ap;
int result;

View File

@ -621,7 +621,7 @@ vips_composite_base_blend( VipsCompositeBase *composite,
case VIPS_BLEND_MODE_DIFFERENCE:
for( int b = 0; b < bands; b++ )
f[b] = abs( B[b] - A[b] );
f[b] = fabs( B[b] - A[b] );
break;
case VIPS_BLEND_MODE_EXCLUSION:

View File

@ -176,7 +176,7 @@ im_isvips( const char *filename )
{
unsigned char buf[4];
if( im__get_bytes( filename, buf, 4 ) ) {
if( im__get_bytes( filename, buf, 4 ) == 4 ) {
if( buf[0] == 0x08 && buf[1] == 0xf2 &&
buf[2] == 0xa6 && buf[3] == 0xb6 )
/* SPARC-order VIPS image.
@ -212,7 +212,7 @@ vips_flags( const char *filename )
flags = VIPS_FORMAT_PARTIAL;
if( im__get_bytes( filename, buf, 4 ) &&
if( im__get_bytes( filename, buf, 4 ) == 4 &&
buf[0] == 0x08 &&
buf[1] == 0xf2 &&
buf[2] == 0xa6 &&

View File

@ -311,10 +311,8 @@ vips_foreign_load_csv_read_double( VipsForeignLoadCsv *csv, double *out )
/* If it's a separator, we have to step over it.
*/
if( csv->sepmap[ch] ) {
if( csv->sepmap[ch] )
(void) VIPS_SBUF_GETC( csv->sbuf );
csv->colno += 1;
}
return( ch );
}
@ -348,9 +346,10 @@ vips_foreign_load_csv_header( VipsForeignLoad *load )
/* Parse the first line to get the number of columns.
*/
csv->colno = 1;
csv->lineno = csv->skip;
csv->lineno = csv->skip + 1;
csv->colno = 0;
do {
csv->colno += 1;
ch = vips_foreign_load_csv_read_double( csv, &value );
} while( ch != '\n' &&
ch != EOF );
@ -410,13 +409,14 @@ vips_foreign_load_csv_load( VipsForeignLoad *load )
VIPS_FORMAT_DOUBLE,
VIPS_CODING_NONE, VIPS_INTERPRETATION_B_W, 1.0, 1.0 );
csv->lineno = csv->skip;
csv->lineno = csv->skip + 1;
for( y = 0; y < load->real->Ysize; y++ ) {
csv->colno = 1;
csv->colno = 0;
for( x = 0; x < load->real->Xsize; x++ ) {
double value;
csv->colno += 1;
ch = vips_foreign_load_csv_read_double( csv, &value );
if( ch == EOF ) {
vips_error( class->nickname,

View File

@ -61,7 +61,7 @@ typedef struct _VipsForeignSaveCsv {
typedef VipsForeignSaveClass VipsForeignSaveCsvClass;
G_DEFINE_TYPE( VipsForeignSaveCsv, vips_foreign_save_csv,
G_DEFINE_ABSTRACT_TYPE( VipsForeignSaveCsv, vips_foreign_save_csv,
VIPS_TYPE_FOREIGN_SAVE );
static void
@ -182,11 +182,17 @@ vips_foreign_save_csv_build( VipsObject *object )
return( 0 );
}
static const char *vips_foreign_save_csv_suffs[] = {
".csv",
NULL
};
static void
vips_foreign_save_csv_class_init( VipsForeignSaveCsvClass *class )
{
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
VipsObjectClass *object_class = (VipsObjectClass *) class;
VipsForeignClass *foreign_class = (VipsForeignClass *) class;
VipsForeignSaveClass *save_class = (VipsForeignSaveClass *) class;
gobject_class->dispose = vips_foreign_save_csv_dispose;
@ -197,6 +203,8 @@ vips_foreign_save_csv_class_init( VipsForeignSaveCsvClass *class )
object_class->description = _( "save image to csv" );
object_class->build = vips_foreign_save_csv_build;
foreign_class->suffs = vips_foreign_save_csv_suffs;
save_class->saveable = VIPS_SAVEABLE_MONO;
VIPS_ARG_STRING( class, "separator", 13,
@ -238,17 +246,11 @@ vips_foreign_save_csv_file_build( VipsObject *object )
build( object ) );
}
static const char *vips_foreign_save_csv_file_suffs[] = {
".csv",
NULL
};
static void
vips_foreign_save_csv_file_class_init( VipsForeignSaveCsvFileClass *class )
{
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
VipsObjectClass *object_class = (VipsObjectClass *) class;
VipsForeignClass *foreign_class = (VipsForeignClass *) class;
gobject_class->set_property = vips_object_set_property;
gobject_class->get_property = vips_object_get_property;
@ -256,8 +258,6 @@ vips_foreign_save_csv_file_class_init( VipsForeignSaveCsvFileClass *class )
object_class->nickname = "csvsave";
object_class->build = vips_foreign_save_csv_file_build;
foreign_class->suffs = vips_foreign_save_csv_file_suffs;
VIPS_ARG_STRING( class, "filename", 1,
_( "Filename" ),
_( "Filename to save to" ),

View File

@ -535,7 +535,12 @@ vips_foreign_find_load( const char *name )
*/
if( !vips_existsf( "%s", filename ) ) {
vips_error( "VipsForeignLoad",
_( "file \"%s\" not found" ), name );
_( "file \"%s\" does not exist" ), name );
return( NULL );
}
if( vips_isdirf( "%s", filename ) ) {
vips_error( "VipsForeignLoad",
_( "\"%s\" is a directory" ), name );
return( NULL );
}
@ -1763,16 +1768,17 @@ vips_foreign_find_save_sub( VipsForeignSaveClass *save_class,
VipsObjectClass *object_class = VIPS_OBJECT_CLASS( save_class );
VipsForeignClass *class = VIPS_FOREIGN_CLASS( save_class );
/* The suffs might be defined on an abstract base class, make sure we
* don't pick that.
*
* Suffs can be defined on buffer and target writers too. Make sure
* it's not one of those.
/* All concrete savers needs suffs, since we use the suff to pick the
* saver.
*/
if( !G_TYPE_IS_ABSTRACT( G_TYPE_FROM_CLASS( class ) ) &&
!class->suffs )
g_warning( "no suffix defined for %s", object_class->nickname );
if( !G_TYPE_IS_ABSTRACT( G_TYPE_FROM_CLASS( class ) ) &&
class->suffs &&
!vips_ispostfix( object_class->nickname, "_buffer" ) &&
!vips_ispostfix( object_class->nickname, "_target" ) &&
class->suffs &&
vips_filename_suffix_match( filename, class->suffs ) )
return( save_class );
@ -1918,7 +1924,15 @@ vips_foreign_find_save_target_sub( VipsForeignSaveClass *save_class,
VipsObjectClass *object_class = VIPS_OBJECT_CLASS( save_class );
VipsForeignClass *class = VIPS_FOREIGN_CLASS( save_class );
if( class->suffs &&
/* All concrete savers needs suffs, since we use the suff to pick the
* saver.
*/
if( !G_TYPE_IS_ABSTRACT( G_TYPE_FROM_CLASS( class ) ) &&
!class->suffs )
g_warning( "no suffix defined for %s", object_class->nickname );
if( !G_TYPE_IS_ABSTRACT( G_TYPE_FROM_CLASS( class ) ) &&
class->suffs &&
vips_ispostfix( object_class->nickname, "_target" ) &&
vips_filename_suffix_match( suffix, class->suffs ) )
return( save_class );
@ -1968,7 +1982,15 @@ vips_foreign_find_save_buffer_sub( VipsForeignSaveClass *save_class,
VipsObjectClass *object_class = VIPS_OBJECT_CLASS( save_class );
VipsForeignClass *class = VIPS_FOREIGN_CLASS( save_class );
if( class->suffs &&
/* All concrete savers needs suffs, since we use the suff to pick the
* saver.
*/
if( !G_TYPE_IS_ABSTRACT( G_TYPE_FROM_CLASS( class ) ) &&
!class->suffs )
g_warning( "no suffix defined for %s", object_class->nickname );
if( !G_TYPE_IS_ABSTRACT( G_TYPE_FROM_CLASS( class ) ) &&
class->suffs &&
vips_ispostfix( object_class->nickname, "_buffer" ) &&
vips_filename_suffix_match( suffix, class->suffs ) )
return( save_class );
@ -2092,9 +2114,9 @@ vips_foreign_operation_init( void )
extern GType vips_foreign_save_webp_buffer_get_type( void );
extern GType vips_foreign_save_webp_target_get_type( void );
extern GType vips_foreign_load_pdf_get_type( void );
extern GType vips_foreign_load_pdf_file_get_type( void );
extern GType vips_foreign_load_pdf_buffer_get_type( void );
extern GType vips_foreign_load_pdf_source_get_type( void );
extern GType vips_foreign_load_svg_file_get_type( void );
extern GType vips_foreign_load_svg_buffer_get_type( void );
@ -2146,14 +2168,13 @@ vips_foreign_operation_init( void )
vips_foreign_save_rad_target_get_type();
#endif /*HAVE_RADIANCE*/
#ifdef HAVE_POPPLER
vips_foreign_load_pdf_get_type();
#if defined(HAVE_POPPLER) && defined(HAVE_GIO)
vips_foreign_load_pdf_file_get_type();
vips_foreign_load_pdf_buffer_get_type();
vips_foreign_load_pdf_source_get_type();
#endif /*HAVE_POPPLER*/
#ifdef HAVE_PDFIUM
vips_foreign_load_pdf_get_type();
vips_foreign_load_pdf_file_get_type();
vips_foreign_load_pdf_buffer_get_type();
#endif /*HAVE_PDFIUM*/

View File

@ -44,10 +44,10 @@
*/
/*
*/
#define DEBUG_VERBOSE
#define VIPS_DEBUG
#define DEBUG
*/
#ifdef HAVE_CONFIG_H
#include <config.h>

View File

@ -751,15 +751,13 @@ G_DEFINE_TYPE( VipsForeignLoadMagick7File, vips_foreign_load_magick7_file,
static gboolean
ismagick7( const char *filename )
{
/* Fetch the first 100 bytes. Hopefully that'll be enough.
/* Fetch up to the first 100 bytes. Hopefully that'll be enough.
*/
unsigned char buf[100];
int len;
/* Files shorter than 100 bytes will leave nonsense at the end of buf,
* but it shouldn't matter.
*/
return( vips__get_bytes( filename, buf, 100 ) &&
magick_ismagick( buf, 100 ) );
return( (len = vips__get_bytes( filename, buf, 100 )) > 10 &&
magick_ismagick( buf, len ) );
}
static int

View File

@ -173,15 +173,13 @@ G_DEFINE_TYPE( VipsForeignLoadMagickFile, vips_foreign_load_magick_file,
static gboolean
ismagick( const char *filename )
{
/* Fetch the first 100 bytes. Hopefully that'll be enough.
/* Fetch up to the first 100 bytes. Hopefully that'll be enough.
*/
unsigned char buf[100];
int len;
/* Files shorter than 100 bytes will leave nonsense at the end of buf,
* but it shouldn't matter.
*/
return( vips__get_bytes( filename, buf, 100 ) &&
magick_ismagick( buf, 100 ) );
return( (len = vips__get_bytes( filename, buf, 100 )) > 10 &&
magick_ismagick( buf, len ) );
}
/* Unfortunately, libMagick does not support header-only reads very well. See

View File

@ -61,7 +61,7 @@ typedef struct _VipsForeignSaveMatrix {
typedef VipsForeignSaveClass VipsForeignSaveMatrixClass;
G_DEFINE_TYPE( VipsForeignSaveMatrix, vips_foreign_save_matrix,
G_DEFINE_ABSTRACT_TYPE( VipsForeignSaveMatrix, vips_foreign_save_matrix,
VIPS_TYPE_FOREIGN_SAVE );
static void
@ -157,11 +157,17 @@ static int bandfmt_matrix[10] = {
D, D, D, D, D, D, D, D, D, D
};
static const char *vips_foreign_save_matrix_suffs[] = {
".mat",
NULL
};
static void
vips_foreign_save_matrix_class_init( VipsForeignSaveMatrixClass *class )
{
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
VipsObjectClass *object_class = (VipsObjectClass *) class;
VipsForeignClass *foreign_class = (VipsForeignClass *) class;
VipsForeignSaveClass *save_class = (VipsForeignSaveClass *) class;
gobject_class->dispose = vips_foreign_save_matrix_dispose;
@ -170,6 +176,8 @@ vips_foreign_save_matrix_class_init( VipsForeignSaveMatrixClass *class )
object_class->description = _( "save image to matrix" );
object_class->build = vips_foreign_save_matrix_build;
foreign_class->suffs = vips_foreign_save_matrix_suffs;
save_class->saveable = VIPS_SAVEABLE_MONO;
save_class->format_table = bandfmt_matrix;
@ -205,17 +213,12 @@ vips_foreign_save_matrix_file_build( VipsObject *object )
vips_foreign_save_matrix_file_parent_class )->build( object ) );
}
static const char *vips_foreign_save_matrix_file_suffs[] = {
".mat",
NULL
};
static void
vips_foreign_save_matrix_file_class_init( VipsForeignSaveMatrixFileClass *class )
vips_foreign_save_matrix_file_class_init(
VipsForeignSaveMatrixFileClass *class )
{
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
VipsObjectClass *object_class = (VipsObjectClass *) class;
VipsForeignClass *foreign_class = (VipsForeignClass *) class;
gobject_class->set_property = vips_object_set_property;
gobject_class->get_property = vips_object_get_property;
@ -223,8 +226,6 @@ vips_foreign_save_matrix_file_class_init( VipsForeignSaveMatrixFileClass *class
object_class->nickname = "matrixsave";
object_class->build = vips_foreign_save_matrix_file_build;
foreign_class->suffs = vips_foreign_save_matrix_file_suffs;
VIPS_ARG_STRING( class, "filename", 1,
_( "Filename" ),
_( "Filename to save to" ),

View File

@ -14,6 +14,8 @@
* - shut down the input file as soon as we can
* 19/9/19
* - reopen the input if we minimised too early
* 11/3/20
* - move on top of VipsSource
*/
/*
@ -63,7 +65,10 @@
#include "pforeign.h"
#ifdef HAVE_POPPLER
/* TODO ... put minimise support back in.
*/
#if defined(HAVE_POPPLER) && defined(HAVE_GIO)
#include <cairo.h>
#include <poppler.h>
@ -86,6 +91,12 @@
typedef struct _VipsForeignLoadPdf {
VipsForeignLoad parent_object;
/* The VipsSource we load from, and the GInputStream we wrap around
* it. Set from subclasses.
*/
VipsSource *source;
GInputStream *stream;
/* Load this page.
*/
int page_no;
@ -133,9 +144,6 @@ typedef struct _VipsForeignLoadPdf {
typedef struct _VipsForeignLoadPdfClass {
VipsForeignLoadClass parent_class;
int (*open)( VipsForeignLoadPdf *pdf );
void (*close)( VipsForeignLoadPdf *pdf );
} VipsForeignLoadPdfClass;
G_DEFINE_ABSTRACT_TYPE( VipsForeignLoadPdf, vips_foreign_load_pdf,
@ -145,9 +153,11 @@ static void
vips_foreign_load_pdf_dispose( GObject *gobject )
{
VipsForeignLoadPdf *pdf = VIPS_FOREIGN_LOAD_PDF( gobject );
VipsForeignLoadPdfClass *class = VIPS_FOREIGN_LOAD_PDF_GET_CLASS( pdf );
class->close( pdf );
VIPS_UNREF( pdf->page );
VIPS_UNREF( pdf->doc );
VIPS_UNREF( pdf->source );
VIPS_UNREF( pdf->stream );
G_OBJECT_CLASS( vips_foreign_load_pdf_parent_class )->
dispose( gobject );
@ -158,9 +168,18 @@ vips_foreign_load_pdf_build( VipsObject *object )
{
VipsForeignLoadPdf *pdf = VIPS_FOREIGN_LOAD_PDF( object );
GError *error = NULL;
if( !vips_object_argument_isset( object, "scale" ) )
pdf->scale = pdf->dpi / 72.0;
pdf->stream = vips_g_input_stream_new_from_source( pdf->source );
if( !(pdf->doc = poppler_document_new_from_stream( pdf->stream,
vips_source_length( pdf->source ), NULL, NULL, &error )) ) {
vips_g_error( &error );
return( -1 );
}
if( VIPS_OBJECT_CLASS( vips_foreign_load_pdf_parent_class )->
build( object ) )
return( -1 );
@ -274,8 +293,6 @@ vips_foreign_load_pdf_header( VipsForeignLoad *load )
{
VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( load );
VipsForeignLoadPdf *pdf = VIPS_FOREIGN_LOAD_PDF( load );
VipsForeignLoadPdfClass *pdf_class =
VIPS_FOREIGN_LOAD_PDF_GET_CLASS( pdf );
int top;
int i;
@ -284,9 +301,6 @@ vips_foreign_load_pdf_header( VipsForeignLoad *load )
printf( "vips_foreign_load_pdf_header: %p\n", pdf );
#endif /*DEBUG*/
if( pdf_class->open( pdf ) )
return( -1 );
pdf->n_pages = poppler_document_get_n_pages( pdf->doc );
/* @n == -1 means until the end of the doc.
@ -357,7 +371,7 @@ vips_foreign_load_pdf_header( VipsForeignLoad *load )
VIPS_AREA( pdf->background )->n )) )
return( -1 );
pdf_class->close( pdf );
vips_source_minimise( pdf->source );
return( 0 );
}
@ -367,7 +381,6 @@ vips_foreign_load_pdf_generate( VipsRegion *or,
void *seq, void *a, void *b, gboolean *stop )
{
VipsForeignLoadPdf *pdf = VIPS_FOREIGN_LOAD_PDF( a );
VipsForeignLoadPdfClass *class = VIPS_FOREIGN_LOAD_PDF_GET_CLASS( pdf );
VipsRect *r = &or->valid;
int top;
@ -380,11 +393,6 @@ vips_foreign_load_pdf_generate( VipsRegion *or,
r->left, r->top, r->width, r->height );
*/
/* We may have been minimised. Make sure the doc is open.
*/
if( class->open( pdf ) )
return( -1 );
/* Poppler won't always paint the background.
*/
vips_region_paint_pel( or, r, pdf->ink );
@ -445,7 +453,6 @@ static int
vips_foreign_load_pdf_load( VipsForeignLoad *load )
{
VipsForeignLoadPdf *pdf = VIPS_FOREIGN_LOAD_PDF( load );
VipsForeignLoadPdfClass *class = VIPS_FOREIGN_LOAD_PDF_GET_CLASS( pdf );
VipsImage **t = (VipsImage **)
vips_object_local_array( (VipsObject *) load, 2 );
@ -453,9 +460,6 @@ vips_foreign_load_pdf_load( VipsForeignLoad *load )
printf( "vips_foreign_load_pdf_load: %p\n", pdf );
#endif /*DEBUG*/
if( class->open( pdf ) )
return( -1 );
/* Read to this image, then cache to out, see below.
*/
t[0] = vips_image_new();
@ -484,23 +488,6 @@ vips_foreign_load_pdf_load( VipsForeignLoad *load )
return( 0 );
}
static int
vips_foreign_load_pdf_open( VipsForeignLoadPdf *pdf )
{
return( 0 );
}
static void
vips_foreign_load_pdf_close( VipsForeignLoadPdf *pdf )
{
#ifdef DEBUG
printf( "vips_foreign_load_pdf_file_close:\n" );
#endif /*DEBUG*/
VIPS_UNREF( pdf->page );
VIPS_UNREF( pdf->doc );
}
static void
vips_foreign_load_pdf_class_init( VipsForeignLoadPdfClass *class )
{
@ -522,9 +509,6 @@ vips_foreign_load_pdf_class_init( VipsForeignLoadPdfClass *class )
load_class->header = vips_foreign_load_pdf_header;
load_class->load = vips_foreign_load_pdf_load;
class->open = vips_foreign_load_pdf_open;
class->close = vips_foreign_load_pdf_close;
VIPS_ARG_INT( class, "page", 20,
_( "Page" ),
_( "Load this page from the file" ),
@ -617,19 +601,18 @@ static const char *vips_foreign_pdf_suffs[] = {
};
static int
vips_foreign_load_pdf_file_open( VipsForeignLoadPdf *pdf )
vips_foreign_load_pdf_file_build( VipsObject *object )
{
VipsForeignLoadPdf *pdf = VIPS_FOREIGN_LOAD_PDF( object );
VipsForeignLoadPdfFile *file = (VipsForeignLoadPdfFile *) pdf;
GError *error = NULL;
#ifdef DEBUG
printf( "vips_foreign_load_pdf_file_open: %s\n", file->filename );
printf( "vips_foreign_load_pdf_file_build: %s\n", file->filename );
#endif /*DEBUG*/
if( !file->uri &&
file->filename ) {
if( file->filename ) {
char *path;
GError *error = NULL;
/* We need an absolute path for a URI.
*/
@ -640,18 +623,15 @@ vips_foreign_load_pdf_file_open( VipsForeignLoadPdf *pdf )
return( -1 );
}
g_free( path );
if( !(pdf->source =
vips_source_new_from_file( file->filename )) )
return( -1 );
}
if( !pdf->doc &&
file->uri &&
!(pdf->doc = poppler_document_new_from_file(
file->uri, NULL, &error )) ) {
vips_g_error( &error );
return( -1 );
}
return( VIPS_FOREIGN_LOAD_PDF_CLASS(
vips_foreign_load_pdf_file_parent_class )->open( pdf ) );
return( VIPS_OBJECT_CLASS( vips_foreign_load_pdf_file_parent_class )->
build( object ) );
}
static void
@ -668,14 +648,14 @@ vips_foreign_load_pdf_file_class_init(
gobject_class->get_property = vips_object_get_property;
object_class->nickname = "pdfload";
object_class->description = _( "load PDF from file" );
object_class->build = vips_foreign_load_pdf_file_build;
foreign_class->suffs = vips_foreign_pdf_suffs;
load_class->is_a = vips_foreign_load_pdf_is_a;
load_class->header = vips_foreign_load_pdf_file_header;
class->open = vips_foreign_load_pdf_file_open;
VIPS_ARG_STRING( class, "filename", 1,
_( "Filename" ),
_( "Filename to load from" ),
@ -705,21 +685,19 @@ G_DEFINE_TYPE( VipsForeignLoadPdfBuffer, vips_foreign_load_pdf_buffer,
vips_foreign_load_pdf_get_type() );
static int
vips_foreign_load_pdf_buffer_open( VipsForeignLoadPdf *pdf )
vips_foreign_load_pdf_buffer_build( VipsObject *object )
{
VipsForeignLoadPdf *pdf = VIPS_FOREIGN_LOAD_PDF( object );
VipsForeignLoadPdfBuffer *buffer = (VipsForeignLoadPdfBuffer *) pdf;
GError *error = NULL;
if( buffer->buf &&
!(pdf->source = vips_source_new_from_memory(
VIPS_AREA( buffer->buf )->data,
VIPS_AREA( buffer->buf )->length )) )
return( -1 );
if( !pdf->doc &&
!(pdf->doc = poppler_document_new_from_data(
buffer->buf->data, buffer->buf->length, NULL, &error )) ) {
vips_g_error( &error );
return( -1 );
}
return( VIPS_FOREIGN_LOAD_PDF_CLASS(
vips_foreign_load_pdf_buffer_parent_class )->open( pdf ) );
return( VIPS_OBJECT_CLASS( vips_foreign_load_pdf_buffer_parent_class )->
build( object ) );
}
static void
@ -734,11 +712,11 @@ vips_foreign_load_pdf_buffer_class_init(
gobject_class->get_property = vips_object_get_property;
object_class->nickname = "pdfload_buffer";
object_class->description = _( "load PDF from buffer" );
object_class->build = vips_foreign_load_pdf_buffer_build;
load_class->is_a_buffer = vips_foreign_load_pdf_is_a_buffer;
class->open = vips_foreign_load_pdf_buffer_open;
VIPS_ARG_BOXED( class, "buffer", 1,
_( "Buffer" ),
_( "Buffer to load from" ),
@ -753,7 +731,77 @@ vips_foreign_load_pdf_buffer_init( VipsForeignLoadPdfBuffer *buffer )
{
}
#endif /*HAVE_POPPLER*/
typedef struct _VipsForeignLoadPdfSource {
VipsForeignLoadPdf parent_object;
VipsSource *source;
} VipsForeignLoadPdfSource;
typedef VipsForeignLoadPdfClass VipsForeignLoadPdfSourceClass;
G_DEFINE_TYPE( VipsForeignLoadPdfSource, vips_foreign_load_pdf_source,
vips_foreign_load_pdf_get_type() );
static int
vips_foreign_load_pdf_source_build( VipsObject *object )
{
VipsForeignLoadPdf *pdf = VIPS_FOREIGN_LOAD_PDF( object );
VipsForeignLoadPdfSource *source = (VipsForeignLoadPdfSource *) pdf;
if( source->source ) {
pdf->source = source->source;
g_object_ref( pdf->source );
}
return( VIPS_OBJECT_CLASS( vips_foreign_load_pdf_source_parent_class )->
build( object ) );
}
static gboolean
vips_foreign_load_pdf_source_is_a_source( VipsSource *source )
{
const unsigned char *p;
return( (p = vips_source_sniff( source, 4 )) &&
p[0] == '%' &&
p[1] == 'P' &&
p[2] == 'D' &&
p[3] == 'F' );
}
static void
vips_foreign_load_pdf_source_class_init(
VipsForeignLoadPdfSourceClass *class )
{
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
VipsObjectClass *object_class = (VipsObjectClass *) class;
VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class;
gobject_class->set_property = vips_object_set_property;
gobject_class->get_property = vips_object_get_property;
object_class->nickname = "pdfload_source";
object_class->description = _( "load PDF from source" );
object_class->build = vips_foreign_load_pdf_source_build;
load_class->is_a_source = vips_foreign_load_pdf_source_is_a_source;
VIPS_ARG_OBJECT( class, "source", 1,
_( "Source" ),
_( "Source to load from" ),
VIPS_ARGUMENT_REQUIRED_INPUT,
G_STRUCT_OFFSET( VipsForeignLoadPdfSource, source ),
VIPS_TYPE_SOURCE );
}
static void
vips_foreign_load_pdf_source_init( VipsForeignLoadPdfSource *source )
{
}
#endif /*defined(HAVE_POPPLER) && defined(HAVE_GIO)*/
/* Also used by the pdfium loader.
*/
@ -889,3 +937,36 @@ vips_pdfload_buffer( void *buf, size_t len, VipsImage **out, ... )
return( result );
}
/**
* vips_pdfload_source:
* @source: source to load from
* @out: (out): image to write
* @...: %NULL-terminated list of optional named arguments
*
* Optional arguments:
*
* * @page: %gint, load this page, numbered from zero
* * @n: %gint, load this many pages
* * @dpi: %gdouble, render at this DPI
* * @scale: %gdouble, scale render by this factor
* * @background: #VipsArrayDouble background colour
*
* Exactly as vips_pdfload(), but read from a source.
*
* See also: vips_pdfload()
*
* Returns: 0 on success, -1 on error.
*/
int
vips_pdfload_source( VipsSource *source, VipsImage **out, ... )
{
va_list ap;
int result;
va_start( ap, out );
result = vips_call_split( "pdfload_source", ap, source, out );
va_end( ap );
return( result );
}

View File

@ -126,11 +126,17 @@ vips_foreign_save_raw_build( VipsObject *object )
return( 0 );
}
static const char *vips_foreign_save_raw_suffs[] = {
".raw",
NULL
};
static void
vips_foreign_save_raw_class_init( VipsForeignSaveRawClass *class )
{
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
VipsObjectClass *object_class = (VipsObjectClass *) class;
VipsForeignClass *foreign_class = (VipsForeignClass *) class;
VipsForeignSaveClass *save_class = (VipsForeignSaveClass *) class;
gobject_class->dispose = vips_foreign_save_raw_dispose;
@ -141,6 +147,8 @@ vips_foreign_save_raw_class_init( VipsForeignSaveRawClass *class )
object_class->description = _( "save image to raw file" );
object_class->build = vips_foreign_save_raw_build;
foreign_class->suffs = vips_foreign_save_raw_suffs;
save_class->saveable = VIPS_SAVEABLE_ANY;
VIPS_ARG_STRING( class, "filename", 1,
@ -238,6 +246,7 @@ vips_foreign_save_raw_fd_class_init( VipsForeignSaveRawFdClass *class )
{
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
VipsObjectClass *object_class = (VipsObjectClass *) class;
VipsForeignClass *foreign_class = (VipsForeignClass *) class;
VipsForeignSaveClass *save_class = (VipsForeignSaveClass *) class;
gobject_class->set_property = vips_object_set_property;
@ -247,6 +256,8 @@ vips_foreign_save_raw_fd_class_init( VipsForeignSaveRawFdClass *class )
object_class->description = _( "write raw image to file descriptor" );
object_class->build = vips_foreign_save_raw_fd_build;
foreign_class->suffs = vips_foreign_save_raw_suffs;
save_class->saveable = VIPS_SAVEABLE_ANY;
VIPS_ARG_INT( class, "fd", 1,

View File

@ -72,293 +72,6 @@
#if defined(HAVE_RSVG) && defined(HAVE_GIO)
#include <gio/gio.h>
/* A GInputStream that's actually a VipsSource under the hood. This lets us
* hook librsvg up to libvips using the GInputStream interface.
*/
#define VIPS_TYPE_G_INPUT_STREAM (vips_g_input_stream_get_type())
#define VIPS_G_INPUT_STREAM( obj ) \
(G_TYPE_CHECK_INSTANCE_CAST( (obj), \
VIPS_TYPE_G_INPUT_STREAM, VipsGInputStream ))
#define VIPS_G_INPUT_STREAM_CLASS( klass ) \
(G_TYPE_CHECK_CLASS_CAST( (klass), \
VIPS_TYPE_G_INPUT_STREAM, VipsGInputStreamClass))
#define VIPS_IS_G_INPUT_STREAM( obj ) \
(G_TYPE_CHECK_INSTANCE_TYPE( (obj), VIPS_TYPE_G_INPUT_STREAM ))
#define VIPS_IS_G_INPUT_STREAM_CLASS( klass ) \
(G_TYPE_CHECK_CLASS_TYPE( (klass), VIPS_TYPE_G_INPUT_STREAM ))
#define VIPS_G_INPUT_STREAM_GET_CLASS( obj ) \
(G_TYPE_INSTANCE_GET_CLASS( (obj), \
VIPS_TYPE_G_INPUT_STREAM, VipsGInputStreamClass ))
/* GInputStream <--> VipsSource
*/
typedef struct _VipsGInputStream {
GInputStream parent_instance;
/*< private >*/
/* The VipsSource we wrap.
*/
VipsSource *source;
} VipsGInputStream;
typedef struct _VipsGInputStreamClass {
GInputStreamClass parent_class;
} VipsGInputStreamClass;
static void vips_g_input_stream_seekable_iface_init( GSeekableIface *iface );
G_DEFINE_TYPE_WITH_CODE( VipsGInputStream, vips_g_input_stream,
G_TYPE_INPUT_STREAM, G_IMPLEMENT_INTERFACE( G_TYPE_SEEKABLE,
vips_g_input_stream_seekable_iface_init ) )
enum {
PROP_0,
PROP_STREAM
};
static void
vips_g_input_stream_get_property( GObject *object, guint prop_id,
GValue *value, GParamSpec *pspec )
{
VipsGInputStream *gstream = VIPS_G_INPUT_STREAM( object );
switch( prop_id ) {
case PROP_STREAM:
g_value_set_object( value, gstream->source );
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID( object, prop_id, pspec );
}
}
static void
vips_g_input_stream_set_property( GObject *object, guint prop_id,
const GValue *value, GParamSpec *pspec )
{
VipsGInputStream *gstream = VIPS_G_INPUT_STREAM( object );
switch( prop_id ) {
case PROP_STREAM:
gstream->source = g_value_dup_object( value );
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID( object, prop_id, pspec );
}
}
static void
vips_g_input_stream_finalize( GObject *object )
{
VipsGInputStream *gstream = VIPS_G_INPUT_STREAM( object );
VIPS_FREEF( g_object_unref, gstream->source );
G_OBJECT_CLASS( vips_g_input_stream_parent_class )->finalize( object );
}
static goffset
vips_g_input_stream_tell( GSeekable *seekable )
{
VipsSource *source = VIPS_G_INPUT_STREAM( seekable )->source;
goffset pos;
VIPS_DEBUG_MSG( "vips_g_input_stream_tell:\n" );
pos = vips_source_seek( source, 0, SEEK_CUR );
if( pos == -1 )
return( 0 );
return( pos );
}
static gboolean
vips_g_input_stream_can_seek( GSeekable *seekable )
{
VipsSource *source = VIPS_G_INPUT_STREAM( seekable )->source;
VIPS_DEBUG_MSG( "vips_g_input_stream_can_seek: %d\n",
!source->is_pipe );
return( !source->is_pipe );
}
static int
seek_type_to_lseek( GSeekType type )
{
switch( type ) {
default:
case G_SEEK_CUR:
return( SEEK_CUR );
case G_SEEK_SET:
return( SEEK_SET );
case G_SEEK_END:
return( SEEK_END );
}
}
static gboolean
vips_g_input_stream_seek( GSeekable *seekable, goffset offset,
GSeekType type, GCancellable *cancellable, GError **error )
{
VipsSource *source = VIPS_G_INPUT_STREAM( seekable )->source;
VIPS_DEBUG_MSG( "vips_g_input_stream_seek: offset = %" G_GINT64_FORMAT
", type = %d\n", offset, type );
if( vips_source_seek( source, offset,
seek_type_to_lseek( type ) ) == -1 ) {
g_set_error( error, G_IO_ERROR,
G_IO_ERROR_FAILED,
_( "Error while seeking: %s" ),
vips_error_buffer() );
return( FALSE );
}
return( TRUE );
}
static gboolean
vips_g_input_stream_can_truncate( GSeekable *seekable )
{
return( FALSE );
}
static gboolean
vips_g_input_stream_truncate( GSeekable *seekable, goffset offset,
GCancellable *cancellable, GError **error )
{
g_set_error_literal( error,
G_IO_ERROR,
G_IO_ERROR_NOT_SUPPORTED,
_( "Cannot truncate VipsGInputStream" ) );
return( FALSE );
}
static gssize
vips_g_input_stream_read( GInputStream *stream, void *buffer, gsize count,
GCancellable *cancellable, GError **error )
{
VipsSource *source;
gssize res;
source = VIPS_G_INPUT_STREAM( stream )->source;
VIPS_DEBUG_MSG( "vips_g_input_stream_read: count: %zd\n", count );
if( g_cancellable_set_error_if_cancelled( cancellable, error ) )
return( -1 );
if( (res = vips_source_read( source, buffer, count )) == -1 )
g_set_error( error, G_IO_ERROR,
G_IO_ERROR_FAILED,
_( "Error while reading: %s" ),
vips_error_buffer() );
return( res );
}
static gssize
vips_g_input_stream_skip( GInputStream *stream, gsize count,
GCancellable *cancellable, GError **error )
{
VipsSource *source;
gssize position;
source = VIPS_G_INPUT_STREAM( stream )->source;
VIPS_DEBUG_MSG( "vips_g_input_stream_skip: count: %zd\n", count );
if( g_cancellable_set_error_if_cancelled( cancellable, error ) )
return( -1 );
position = vips_source_seek( source, count, SEEK_CUR );
if( position == -1 ) {
g_set_error( error, G_IO_ERROR,
G_IO_ERROR_FAILED,
_( "Error while seeking: %s" ),
vips_error_buffer() );
return( -1 );
}
return( position );
}
static gboolean
vips_g_input_stream_close( GInputStream *stream,
GCancellable *cancellable, GError **error )
{
VipsGInputStream *gstream = VIPS_G_INPUT_STREAM( stream );
vips_source_minimise( gstream->source );
return( TRUE );
}
static void
vips_g_input_stream_seekable_iface_init( GSeekableIface *iface )
{
iface->tell = vips_g_input_stream_tell;
iface->can_seek = vips_g_input_stream_can_seek;
iface->seek = vips_g_input_stream_seek;
iface->can_truncate = vips_g_input_stream_can_truncate;
iface->truncate_fn = vips_g_input_stream_truncate;
}
static void
vips_g_input_stream_class_init( VipsGInputStreamClass *class )
{
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
GInputStreamClass *istream_class = G_INPUT_STREAM_CLASS( class );
gobject_class->finalize = vips_g_input_stream_finalize;
gobject_class->get_property = vips_g_input_stream_get_property;
gobject_class->set_property = vips_g_input_stream_set_property;
istream_class->read_fn = vips_g_input_stream_read;
istream_class->skip = vips_g_input_stream_skip;
istream_class->close_fn = vips_g_input_stream_close;
g_object_class_install_property( gobject_class, PROP_STREAM,
g_param_spec_object( "input",
_( "Input" ),
_( "Stream to wrap" ),
VIPS_TYPE_SOURCE, G_PARAM_CONSTRUCT_ONLY |
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS ) );
}
static void
vips_g_input_stream_init( VipsGInputStream *gstream )
{
}
/**
* g_input_stream_new_from_vips:
* @source: stream to wrap
*
* Create a new #GInputStream wrapping a #VipsSource.
*
* Returns: a new #GInputStream
*/
static GInputStream *
g_input_stream_new_from_vips( VipsSource *source )
{
return( g_object_new( VIPS_TYPE_G_INPUT_STREAM,
"input", source,
NULL ) );
}
#include <cairo.h>
#include <librsvg/rsvg.h>
@ -796,7 +509,7 @@ vips_foreign_load_svg_source_header( VipsForeignLoad *load )
if( vips_source_rewind( source->source ) )
return( -1 );
gstream = g_input_stream_new_from_vips( source->source );
gstream = vips_g_input_stream_new_from_source( source->source );
if( !(svg->page = rsvg_handle_new_from_stream_sync(
gstream, NULL, flags, NULL, &error )) ) {
g_object_unref( gstream );

View File

@ -191,6 +191,8 @@
* - add "depth" to set pyr depth
* 27/1/20
* - write XYZ images as logluv
* 7/2/20 [jclavoie-jive]
* - add PAGENUMBER support
*/
/*
@ -334,10 +336,13 @@ struct _Wtiff {
VipsForeignDzDepth depth; /* Pyr depth */
/* True if we've detected a toilet-roll image, plus the page height,
* which has been checked to be a factor of im->Ysize.
* which has been checked to be a factor of im->Ysize. page_number
* starts at zero and ticks up as we write each page.
*/
gboolean toilet_roll;
int page_height;
int page_number;
int n_pages;
/* The height of the TIFF we write. Equal to page_height in toilet
* roll mode.
@ -779,6 +784,15 @@ wtiff_write_header( Wtiff *wtiff, Layer *layer )
*/
TIFFSetField( tif, TIFFTAG_SUBFILETYPE, FILETYPE_REDUCEDIMAGE );
if( wtiff->toilet_roll ) {
/* One page of many.
*/
TIFFSetField( tif, TIFFTAG_SUBFILETYPE, FILETYPE_PAGE );
TIFFSetField( tif, TIFFTAG_PAGENUMBER,
wtiff->page_number, wtiff->n_pages );
}
/* Sample format.
*
* Don't set for logluv: libtiff does this for us.
@ -1052,6 +1066,8 @@ wtiff_new( VipsImage *input, const char *filename,
wtiff->depth = depth;
wtiff->toilet_roll = FALSE;
wtiff->page_height = vips_image_get_page_height( input );
wtiff->page_number = 0;
wtiff->n_pages = 1;
wtiff->image_height = input->Ysize;
/* Any pre-processing on the image.
@ -1079,6 +1095,7 @@ wtiff_new( VipsImage *input, const char *filename,
wtiff->toilet_roll = TRUE;
wtiff->image_height = wtiff->page_height;
wtiff->n_pages = wtiff->ready->Ysize / wtiff->page_height;
/* We can't pyramid toilet roll images.
*/
@ -1738,8 +1755,9 @@ write_strip( VipsRegion *region, VipsRect *area, void *a )
static int
wtiff_copy_tiff( Wtiff *wtiff, TIFF *out, TIFF *in )
{
uint32 i32;
uint16 i16;
uint32 ui32;
uint16 ui16;
uint16 ui16_2;
float f;
tdata_t buf;
ttile_t tile;
@ -1748,25 +1766,28 @@ wtiff_copy_tiff( Wtiff *wtiff, TIFF *out, TIFF *in )
/* All the fields we might have set.
*/
CopyField( TIFFTAG_IMAGEWIDTH, i32 );
CopyField( TIFFTAG_IMAGELENGTH, i32 );
CopyField( TIFFTAG_PLANARCONFIG, i16 );
CopyField( TIFFTAG_ORIENTATION, i16 );
CopyField( TIFFTAG_IMAGEWIDTH, ui32 );
CopyField( TIFFTAG_IMAGELENGTH, ui32 );
CopyField( TIFFTAG_PLANARCONFIG, ui16 );
CopyField( TIFFTAG_ORIENTATION, ui16 );
CopyField( TIFFTAG_XRESOLUTION, f );
CopyField( TIFFTAG_YRESOLUTION, f );
CopyField( TIFFTAG_RESOLUTIONUNIT, i16 );
CopyField( TIFFTAG_COMPRESSION, i16 );
CopyField( TIFFTAG_SAMPLESPERPIXEL, i16 );
CopyField( TIFFTAG_BITSPERSAMPLE, i16 );
CopyField( TIFFTAG_PHOTOMETRIC, i16 );
CopyField( TIFFTAG_ORIENTATION, i16 );
CopyField( TIFFTAG_TILEWIDTH, i32 );
CopyField( TIFFTAG_TILELENGTH, i32 );
CopyField( TIFFTAG_ROWSPERSTRIP, i32 );
CopyField( TIFFTAG_SUBFILETYPE, i32 );
CopyField( TIFFTAG_RESOLUTIONUNIT, ui16 );
CopyField( TIFFTAG_COMPRESSION, ui16 );
CopyField( TIFFTAG_SAMPLESPERPIXEL, ui16 );
CopyField( TIFFTAG_BITSPERSAMPLE, ui16 );
CopyField( TIFFTAG_PHOTOMETRIC, ui16 );
CopyField( TIFFTAG_ORIENTATION, ui16 );
CopyField( TIFFTAG_TILEWIDTH, ui32 );
CopyField( TIFFTAG_TILELENGTH, ui32 );
CopyField( TIFFTAG_ROWSPERSTRIP, ui32 );
CopyField( TIFFTAG_SUBFILETYPE, ui32 );
if( TIFFGetField( in, TIFFTAG_EXTRASAMPLES, &i16, &a ) )
TIFFSetField( out, TIFFTAG_EXTRASAMPLES, i16, a );
if( TIFFGetField( in, TIFFTAG_EXTRASAMPLES, &ui16, &a ) )
TIFFSetField( out, TIFFTAG_EXTRASAMPLES, ui16, a );
if( TIFFGetField( in, TIFFTAG_PAGENUMBER, &ui16, &ui16_2 ) )
TIFFSetField( out, TIFFTAG_PAGENUMBER, ui16, ui16_2 );
/* TIFFTAG_JPEGQUALITY is a pesudo-tag, so we can't copy it.
* Set explicitly from Wtiff.
@ -1912,6 +1933,7 @@ wtiff_write_image( Wtiff *wtiff )
}
g_object_unref( page );
wtiff->page_number += 1;
y += wtiff->page_height;
if( y >= wtiff->ready->Ysize )
break;

View File

@ -346,6 +346,7 @@ vips_hist_local_class_init( VipsHistLocalClass *class )
{
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
VipsObjectClass *object_class = (VipsObjectClass *) class;
VipsOperationClass *operation_class = VIPS_OPERATION_CLASS( class );
gobject_class->set_property = vips_object_set_property;
gobject_class->get_property = vips_object_get_property;
@ -354,6 +355,8 @@ vips_hist_local_class_init( VipsHistLocalClass *class )
object_class->description = _( "local histogram equalisation" );
object_class->build = vips_hist_local_build;
operation_class->flags = VIPS_OPERATION_SEQUENTIAL;
VIPS_ARG_IMAGE( class, "in", 1,
_( "Input" ),
_( "Input image" ),

View File

@ -185,14 +185,14 @@ int vips_multiply( VipsImage *left, VipsImage *right, VipsImage **out, ... )
int vips_divide( VipsImage *left, VipsImage *right, VipsImage **out, ... )
__attribute__((sentinel));
int vips_linear( VipsImage *in, VipsImage **out,
double *a, double *b, int n, ... )
const double *a, const double *b, int n, ... )
__attribute__((sentinel));
int vips_linear1( VipsImage *in, VipsImage **out, double a, double b, ... )
__attribute__((sentinel));
int vips_remainder( VipsImage *left, VipsImage *right, VipsImage **out, ... )
__attribute__((sentinel));
int vips_remainder_const( VipsImage *in, VipsImage **out,
double *c, int n, ... )
const double *c, int n, ... )
__attribute__((sentinel));
int vips_remainder_const1( VipsImage *in, VipsImage **out,
double c, ... )
@ -279,19 +279,25 @@ int vips_more( VipsImage *left, VipsImage *right, VipsImage **out, ... )
int vips_moreeq( VipsImage *left, VipsImage *right, VipsImage **out, ... )
__attribute__((sentinel));
int vips_relational_const( VipsImage *in, VipsImage **out,
VipsOperationRelational relational, double *c, int n, ... )
VipsOperationRelational relational, const double *c, int n, ... )
__attribute__((sentinel));
int vips_equal_const( VipsImage *in, VipsImage **out, double *c, int n, ... )
int vips_equal_const( VipsImage *in, VipsImage **out,
const double *c, int n, ... )
__attribute__((sentinel));
int vips_notequal_const( VipsImage *in, VipsImage **out, double *c, int n, ... )
int vips_notequal_const( VipsImage *in, VipsImage **out,
const double *c, int n, ... )
__attribute__((sentinel));
int vips_less_const( VipsImage *in, VipsImage **out, double *c, int n, ... )
int vips_less_const( VipsImage *in, VipsImage **out,
const double *c, int n, ... )
__attribute__((sentinel));
int vips_lesseq_const( VipsImage *in, VipsImage **out, double *c, int n, ... )
int vips_lesseq_const( VipsImage *in, VipsImage **out,
const double *c, int n, ... )
__attribute__((sentinel));
int vips_more_const( VipsImage *in, VipsImage **out, double *c, int n, ... )
int vips_more_const( VipsImage *in, VipsImage **out,
const double *c, int n, ... )
__attribute__((sentinel));
int vips_moreeq_const( VipsImage *in, VipsImage **out, double *c, int n, ... )
int vips_moreeq_const( VipsImage *in, VipsImage **out,
const double *c, int n, ... )
__attribute__((sentinel));
int vips_relational_const1( VipsImage *in, VipsImage **out,
VipsOperationRelational relational, double c, ... )
@ -324,17 +330,22 @@ int vips_rshift( VipsImage *left, VipsImage *right, VipsImage **out, ... )
__attribute__((sentinel));
int vips_boolean_const( VipsImage *in, VipsImage **out,
VipsOperationBoolean boolean, double *c, int n, ... )
VipsOperationBoolean boolean, const double *c, int n, ... )
__attribute__((sentinel));
int vips_andimage_const( VipsImage *in, VipsImage **out, double *c, int n, ... )
int vips_andimage_const( VipsImage *in, VipsImage **out,
const double *c, int n, ... )
__attribute__((sentinel));
int vips_orimage_const( VipsImage *in, VipsImage **out, double *c, int n, ... )
int vips_orimage_const( VipsImage *in, VipsImage **out,
const double *c, int n, ... )
__attribute__((sentinel));
int vips_eorimage_const( VipsImage *in, VipsImage **out, double *c, int n, ... )
int vips_eorimage_const( VipsImage *in, VipsImage **out,
const double *c, int n, ... )
__attribute__((sentinel));
int vips_lshift_const( VipsImage *in, VipsImage **out, double *c, int n, ... )
int vips_lshift_const( VipsImage *in, VipsImage **out,
const double *c, int n, ... )
__attribute__((sentinel));
int vips_rshift_const( VipsImage *in, VipsImage **out, double *c, int n, ... )
int vips_rshift_const( VipsImage *in, VipsImage **out,
const double *c, int n, ... )
__attribute__((sentinel));
int vips_boolean_const1( VipsImage *in, VipsImage **out,
VipsOperationBoolean boolean, double c, ... )
@ -358,11 +369,13 @@ int vips_pow( VipsImage *left, VipsImage *right, VipsImage **out, ... )
int vips_wop( VipsImage *left, VipsImage *right, VipsImage **out, ... )
__attribute__((sentinel));
int vips_math2_const( VipsImage *in, VipsImage **out,
VipsOperationMath2 math2, double *c, int n, ... )
VipsOperationMath2 math2, const double *c, int n, ... )
__attribute__((sentinel));
int vips_pow_const( VipsImage *in, VipsImage **out, double *c, int n, ... )
int vips_pow_const( VipsImage *in, VipsImage **out,
const double *c, int n, ... )
__attribute__((sentinel));
int vips_wop_const( VipsImage *in, VipsImage **out, double *c, int n, ... )
int vips_wop_const( VipsImage *in, VipsImage **out,
const double *c, int n, ... )
__attribute__((sentinel));
int vips_math2_const1( VipsImage *in, VipsImage **out,
VipsOperationMath2 math2, double c, ... )

View File

@ -222,7 +222,7 @@ const void *vips_source_map( VipsSource *source, size_t *length );
VipsBlob *vips_source_map_blob( VipsSource *source );
gint64 vips_source_seek( VipsSource *source, gint64 offset, int whence );
int vips_source_rewind( VipsSource *source );
size_t vips_source_sniff_at_most( VipsSource *source,
gint64 vips_source_sniff_at_most( VipsSource *source,
unsigned char **data, size_t length );
unsigned char *vips_source_sniff( VipsSource *source, size_t length );
gint64 vips_source_length( VipsSource *source );
@ -265,6 +265,49 @@ typedef struct _VipsSourceCustomClass {
GType vips_source_custom_get_type( void );
VipsSourceCustom *vips_source_custom_new( void );
/* A GInputStream that's actually a VipsSource under the hood. This lets us
* hook librsvg up to libvips using the GInputStream interface.
*/
#ifdef HAVE_GIO
#define VIPS_TYPE_G_INPUT_STREAM (vips_g_input_stream_get_type())
#define VIPS_G_INPUT_STREAM( obj ) \
(G_TYPE_CHECK_INSTANCE_CAST( (obj), \
VIPS_TYPE_G_INPUT_STREAM, VipsGInputStream ))
#define VIPS_G_INPUT_STREAM_CLASS( klass ) \
(G_TYPE_CHECK_CLASS_CAST( (klass), \
VIPS_TYPE_G_INPUT_STREAM, VipsGInputStreamClass))
#define VIPS_IS_G_INPUT_STREAM( obj ) \
(G_TYPE_CHECK_INSTANCE_TYPE( (obj), VIPS_TYPE_G_INPUT_STREAM ))
#define VIPS_IS_G_INPUT_STREAM_CLASS( klass ) \
(G_TYPE_CHECK_CLASS_TYPE( (klass), VIPS_TYPE_G_INPUT_STREAM ))
#define VIPS_G_INPUT_STREAM_GET_CLASS( obj ) \
(G_TYPE_INSTANCE_GET_CLASS( (obj), \
VIPS_TYPE_G_INPUT_STREAM, VipsGInputStreamClass ))
/* GInputStream <--> VipsSource
*/
typedef struct _VipsGInputStream {
GInputStream parent_instance;
/*< private >*/
/* The VipsSource we wrap.
*/
VipsSource *source;
} VipsGInputStream;
typedef struct _VipsGInputStreamClass {
GInputStreamClass parent_class;
} VipsGInputStreamClass;
GInputStream *vips_g_input_stream_new_from_source( VipsSource *source );
#endif /*HAVE_GIO*/
#define VIPS_TYPE_TARGET (vips_target_get_type())
#define VIPS_TARGET( obj ) \
(G_TYPE_CHECK_INSTANCE_CAST( (obj), \

View File

@ -610,6 +610,8 @@ int vips_pdfload( const char *filename, VipsImage **out, ... )
__attribute__((sentinel));
int vips_pdfload_buffer( void *buf, size_t len, VipsImage **out, ... )
__attribute__((sentinel));
int vips_pdfload_source( VipsSource *source, VipsImage **out, ... )
__attribute__((sentinel));
int vips_svgload( const char *filename, VipsImage **out, ... )
__attribute__((sentinel));

View File

@ -266,8 +266,8 @@ char *vips__file_read( FILE *fp, const char *name, size_t *length_out );
char *vips__file_read_name( const char *name, const char *fallback_dir,
size_t *length_out );
int vips__file_write( void *data, size_t size, size_t nmemb, FILE *stream );
guint64 vips__get_bytes( const char *filename,
unsigned char buf[], guint64 len );
gint64 vips__get_bytes( const char *filename,
unsigned char buf[], gint64 len );
int vips__fgetc( FILE *fp );
GValue *vips__gvalue_ref_string_new( const char *text );
@ -281,6 +281,8 @@ gint64 vips__seek( int fd, gint64 pos, int whence );
int vips__ftruncate( int fd, gint64 pos );
int vips_existsf( const char *name, ... )
__attribute__((format(printf, 1, 2)));
int vips_isdirf( const char *name, ... )
__attribute__((format(printf, 1, 2)));
int vips_mkdirf( const char *name, ... )
__attribute__((format(printf, 1, 2)));
int vips_rmdirf( const char *name, ... )

View File

@ -89,6 +89,12 @@ extern "C" {
#include <gmodule.h>
#include <glib-object.h>
/* Needed for VipsGInputStream.
*/
#ifdef HAVE_GIO
#include <gio/gio.h>
#endif /*HAVE_GIO*/
/* If we're being parsed by SWIG, remove gcc attributes.
*/
#ifdef SWIG

View File

@ -1,6 +1,7 @@
noinst_LTLIBRARIES = libiofuncs.la
libiofuncs_la_SOURCES = \
ginputsource.c \
connection.c \
source.c \
sourcecustom.c \

View File

@ -0,0 +1,305 @@
/* A GInputStream that links to a VipsSource under the hood.
*
* 10/11/19 kleisauke
*/
/*
This file is part of VIPS.
VIPS is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
/*
These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
*/
/*
#define DEBUG
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif /*HAVE_CONFIG_H*/
#include <vips/intl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <ctype.h>
#include <vips/vips.h>
#include <vips/internal.h>
#include <vips/debug.h>
#ifdef HAVE_GIO
#include <gio/gio.h>
static void vips_g_input_stream_seekable_iface_init( GSeekableIface *iface );
G_DEFINE_TYPE_WITH_CODE( VipsGInputStream, vips_g_input_stream,
G_TYPE_INPUT_STREAM, G_IMPLEMENT_INTERFACE( G_TYPE_SEEKABLE,
vips_g_input_stream_seekable_iface_init ) )
enum {
PROP_0,
PROP_STREAM
};
static void
vips_g_input_stream_get_property( GObject *object, guint prop_id,
GValue *value, GParamSpec *pspec )
{
VipsGInputStream *gstream = VIPS_G_INPUT_STREAM( object );
switch( prop_id ) {
case PROP_STREAM:
g_value_set_object( value, gstream->source );
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID( object, prop_id, pspec );
}
}
static void
vips_g_input_stream_set_property( GObject *object, guint prop_id,
const GValue *value, GParamSpec *pspec )
{
VipsGInputStream *gstream = VIPS_G_INPUT_STREAM( object );
switch( prop_id ) {
case PROP_STREAM:
gstream->source = g_value_dup_object( value );
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID( object, prop_id, pspec );
}
}
static void
vips_g_input_stream_finalize( GObject *object )
{
VipsGInputStream *gstream = VIPS_G_INPUT_STREAM( object );
VIPS_FREEF( g_object_unref, gstream->source );
G_OBJECT_CLASS( vips_g_input_stream_parent_class )->finalize( object );
}
static goffset
vips_g_input_stream_tell( GSeekable *seekable )
{
VipsSource *source = VIPS_G_INPUT_STREAM( seekable )->source;
goffset pos;
VIPS_DEBUG_MSG( "vips_g_input_stream_tell:\n" );
pos = vips_source_seek( source, 0, SEEK_CUR );
if( pos == -1 )
return( 0 );
return( pos );
}
static gboolean
vips_g_input_stream_can_seek( GSeekable *seekable )
{
VipsSource *source = VIPS_G_INPUT_STREAM( seekable )->source;
VIPS_DEBUG_MSG( "vips_g_input_stream_can_seek: %d\n",
!source->is_pipe );
return( !source->is_pipe );
}
static int
seek_type_to_lseek( GSeekType type )
{
switch( type ) {
default:
case G_SEEK_CUR:
return( SEEK_CUR );
case G_SEEK_SET:
return( SEEK_SET );
case G_SEEK_END:
return( SEEK_END );
}
}
static gboolean
vips_g_input_stream_seek( GSeekable *seekable, goffset offset,
GSeekType type, GCancellable *cancellable, GError **error )
{
VipsSource *source = VIPS_G_INPUT_STREAM( seekable )->source;
VIPS_DEBUG_MSG( "vips_g_input_stream_seek: offset = %" G_GINT64_FORMAT
", type = %d\n", offset, type );
if( vips_source_seek( source, offset,
seek_type_to_lseek( type ) ) == -1 ) {
g_set_error( error, G_IO_ERROR,
G_IO_ERROR_FAILED,
_( "Error while seeking: %s" ),
vips_error_buffer() );
return( FALSE );
}
return( TRUE );
}
static gboolean
vips_g_input_stream_can_truncate( GSeekable *seekable )
{
return( FALSE );
}
static gboolean
vips_g_input_stream_truncate( GSeekable *seekable, goffset offset,
GCancellable *cancellable, GError **error )
{
g_set_error_literal( error,
G_IO_ERROR,
G_IO_ERROR_NOT_SUPPORTED,
_( "Cannot truncate VipsGInputStream" ) );
return( FALSE );
}
static gssize
vips_g_input_stream_read( GInputStream *stream, void *buffer, gsize count,
GCancellable *cancellable, GError **error )
{
VipsSource *source;
gssize res;
source = VIPS_G_INPUT_STREAM( stream )->source;
VIPS_DEBUG_MSG( "vips_g_input_stream_read: count: %zd\n", count );
if( g_cancellable_set_error_if_cancelled( cancellable, error ) )
return( -1 );
if( (res = vips_source_read( source, buffer, count )) == -1 )
g_set_error( error, G_IO_ERROR,
G_IO_ERROR_FAILED,
_( "Error while reading: %s" ),
vips_error_buffer() );
return( res );
}
static gssize
vips_g_input_stream_skip( GInputStream *stream, gsize count,
GCancellable *cancellable, GError **error )
{
VipsSource *source;
gssize position;
source = VIPS_G_INPUT_STREAM( stream )->source;
VIPS_DEBUG_MSG( "vips_g_input_stream_skip: count: %zd\n", count );
if( g_cancellable_set_error_if_cancelled( cancellable, error ) )
return( -1 );
position = vips_source_seek( source, count, SEEK_CUR );
if( position == -1 ) {
g_set_error( error, G_IO_ERROR,
G_IO_ERROR_FAILED,
_( "Error while seeking: %s" ),
vips_error_buffer() );
return( -1 );
}
return( position );
}
static gboolean
vips_g_input_stream_close( GInputStream *stream,
GCancellable *cancellable, GError **error )
{
VipsGInputStream *gstream = VIPS_G_INPUT_STREAM( stream );
vips_source_minimise( gstream->source );
return( TRUE );
}
static void
vips_g_input_stream_seekable_iface_init( GSeekableIface *iface )
{
iface->tell = vips_g_input_stream_tell;
iface->can_seek = vips_g_input_stream_can_seek;
iface->seek = vips_g_input_stream_seek;
iface->can_truncate = vips_g_input_stream_can_truncate;
iface->truncate_fn = vips_g_input_stream_truncate;
}
static void
vips_g_input_stream_class_init( VipsGInputStreamClass *class )
{
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
GInputStreamClass *istream_class = G_INPUT_STREAM_CLASS( class );
gobject_class->finalize = vips_g_input_stream_finalize;
gobject_class->get_property = vips_g_input_stream_get_property;
gobject_class->set_property = vips_g_input_stream_set_property;
istream_class->read_fn = vips_g_input_stream_read;
istream_class->skip = vips_g_input_stream_skip;
istream_class->close_fn = vips_g_input_stream_close;
g_object_class_install_property( gobject_class, PROP_STREAM,
g_param_spec_object( "input",
_( "Input" ),
_( "Stream to wrap" ),
VIPS_TYPE_SOURCE, G_PARAM_CONSTRUCT_ONLY |
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS ) );
}
static void
vips_g_input_stream_init( VipsGInputStream *gstream )
{
}
/**
* vips_g_input_stream_new_from_source:
* @source: vips source to wrap
*
* Create a new #GInputStream wrapping a #VipsSource. This is useful for
* loaders like SVG and PDF which support GInput methods.
*
* Returns: a new #GInputStream
*/
GInputStream *
vips_g_input_stream_new_from_source( VipsSource *source )
{
return( g_object_new( VIPS_TYPE_G_INPUT_STREAM,
"input", source,
NULL ) );
}
#endif /*HAVE_GIO*/

View File

@ -336,6 +336,7 @@ vips_init( const char *argv0 )
extern GType vips_source_custom_get_type( void );
extern GType vips_target_get_type( void );
extern GType vips_target_custom_get_type( void );
extern GType vips_g_input_stream_get_type( void );
static gboolean started = FALSE;
static gboolean done = FALSE;
@ -483,6 +484,9 @@ vips_init( const char *argv0 )
vips_morphology_operation_init();
vips_draw_operation_init();
vips_mosaicing_operation_init();
#ifdef HAVE_GIO
vips_g_input_stream_get_type();
#endif /*HAVE_GIO*/
/* Load any vips8 plugins from the vips libdir. Keep going, even if
* some plugins fail to load.

View File

@ -358,7 +358,7 @@ vips_tracked_malloc( size_t size )
* @flags: flags for open()
* @...: open mode
*
* Exactly as open(2), but the number of files current open via
* Exactly as open(2), but the number of files currently open via
* vips_tracked_open() is available via vips_tracked_get_files(). This is used
* by the vips operation cache to drop cache when the number of files
* available is low.

View File

@ -1191,7 +1191,7 @@ vips_source_length( VipsSource *source )
}
/**
* vips_source_peek:
* vips_source_sniff_at_most:
* @source: peek this source
* @data: return a pointer to the bytes read here
* @length: max number of bytes to read
@ -1203,7 +1203,7 @@ vips_source_length( VipsSource *source )
*
* Returns: number of bytes read, or -1 on error.
*/
size_t
gint64
vips_source_sniff_at_most( VipsSource *source,
unsigned char **data, size_t length )
{
@ -1257,12 +1257,14 @@ unsigned char *
vips_source_sniff( VipsSource *source, size_t length )
{
unsigned char *data;
size_t bytes_read;
gint64 bytes_read;
if( vips_source_test_features( source ) )
return( NULL );
bytes_read = vips_source_sniff_at_most( source, &data, length );
if( bytes_read == -1 )
return( NULL );
if( bytes_read < length )
return( NULL );

View File

@ -634,6 +634,14 @@ vips__open( const char *filename, int flags, ... )
mode = va_arg( ap, int );
va_end( ap );
/* Various bad things happen if you accidentally open a directory as a
* file.
*/
if( g_file_test( filename, G_FILE_TEST_IS_DIR ) ) {
errno = EISDIR;
return( -1 );
}
fd = g_open( filename, flags, mode );
#ifdef OS_WIN32
@ -874,13 +882,13 @@ vips__file_write( void *data, size_t size, size_t nmemb, FILE *stream )
* types, so we must read binary.
*
* Return the number of bytes actually read (the file might be shorter than
* len), or 0 for error.
* len), or -1 for error.
*/
guint64
vips__get_bytes( const char *filename, unsigned char buf[], guint64 len )
gint64
vips__get_bytes( const char *filename, unsigned char buf[], gint64 len )
{
int fd;
guint64 bytes_read;
gint64 bytes_read;
/* File may not even exist (for tmp images for example!)
* so no hasty messages. And the file might be truncated, so no error
@ -1090,6 +1098,10 @@ vips__seek_no_error( int fd, gint64 pos, int whence )
#ifdef OS_WIN32
new_pos = _lseeki64( fd, pos, whence );
#else /*!OS_WIN32*/
/* On error, eg. opening a directory and seeking to the end, lseek()
* on linux seems to return 9223372036854775807 ((1 << 63) - 1)
* rather than (off_t) -1 for reasons I don't understand.
*/
new_pos = lseek( fd, pos, whence );
#endif /*OS_WIN32*/
@ -1145,29 +1157,44 @@ vips__ftruncate( int fd, gint64 pos )
return( 0 );
}
/* TRUE if file exists.
/* TRUE if file exists. True for directories as well.
*/
gboolean
vips_existsf( const char *name, ... )
{
va_list ap;
char *path;
int result;
gboolean result;
va_start( ap, name );
path = g_strdup_vprintf( name, ap );
va_end( ap );
result = g_access( path, R_OK );
result = g_file_test( path, G_FILE_TEST_EXISTS );
g_free( path );
/* access() can fail for various reasons, especially under things
* like selinux. Only return FALSE if we are certain the file does not
* exist.
*/
return( result == 0 ||
errno != ENOENT );
return( result );
}
/* TRUE if file exists and is a directory.
*/
gboolean
vips_isdirf( const char *name, ... )
{
va_list ap;
char *path;
gboolean result;
va_start( ap, name );
path = g_strdup_vprintf( name, ap );
va_end( ap );
result = g_file_test( path, G_FILE_TEST_IS_DIR );
g_free( path );
return( result );
}
#ifdef OS_WIN32

View File

@ -5,6 +5,7 @@
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <vips/vips.h>
typedef struct _MyInput {