add an experimental libspng reader
it compiles, but I've not tried running it yet heh
This commit is contained in:
parent
a5680abbd6
commit
02327b6214
@ -18,6 +18,7 @@
|
|||||||
- add all to smartcrop
|
- add all to smartcrop
|
||||||
- flood fill could stop half-way for some very complex shapes
|
- flood fill could stop half-way for some very complex shapes
|
||||||
- better handling of unaligned reads in multipage tiffs [petoor]
|
- better handling of unaligned reads in multipage tiffs [petoor]
|
||||||
|
- add experimental libspng reader
|
||||||
|
|
||||||
24/4/20 started 8.9.3
|
24/4/20 started 8.9.3
|
||||||
- better iiif tile naming [IllyaMoskvin]
|
- better iiif tile naming [IllyaMoskvin]
|
||||||
|
24
README.md
24
README.md
@ -4,6 +4,30 @@
|
|||||||
[![Fuzzing Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/libvips.svg)](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=2&q=proj:libvips)
|
[![Fuzzing Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/libvips.svg)](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=2&q=proj:libvips)
|
||||||
[![Coverity Status](https://scan.coverity.com/projects/6503/badge.svg)](https://scan.coverity.com/projects/jcupitt-libvips)
|
[![Coverity Status](https://scan.coverity.com/projects/6503/badge.svg)](https://scan.coverity.com/projects/jcupitt-libvips)
|
||||||
|
|
||||||
|
# This branch
|
||||||
|
|
||||||
|
Is for experiemtning with [libspng](https://github.com/randy408/libspng).
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
Build libspng:
|
||||||
|
|
||||||
|
```
|
||||||
|
cd libspng
|
||||||
|
meson build --prefix=/home/john/vips --libdir=/home/john/vips/lib
|
||||||
|
cd build
|
||||||
|
ninja
|
||||||
|
ninja install
|
||||||
|
```
|
||||||
|
|
||||||
|
Installs `spng.pc`.
|
||||||
|
|
||||||
|
Sample code:
|
||||||
|
|
||||||
|
https://github.com/randy408/libspng/blob/master/examples/example.c
|
||||||
|
|
||||||
|
# Introduction
|
||||||
|
|
||||||
libvips is a [demand-driven, horizontally
|
libvips is a [demand-driven, horizontally
|
||||||
threaded](https://github.com/libvips/libvips/wiki/Why-is-libvips-quick)
|
threaded](https://github.com/libvips/libvips/wiki/Why-is-libvips-quick)
|
||||||
image processing library. Compared to similar
|
image processing library. Compared to similar
|
||||||
|
22
configure.ac
22
configure.ac
@ -1175,6 +1175,22 @@ FIND_GIFLIB(
|
|||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Look for libspng first
|
||||||
|
AC_ARG_WITH([spng],
|
||||||
|
AS_HELP_STRING([--without-spng], [build without libspng (default: test)]))
|
||||||
|
|
||||||
|
if test x"$with_spng" != x"no"; then
|
||||||
|
PKG_CHECK_MODULES(SPNG, spng >= 0.6,
|
||||||
|
[AC_DEFINE(HAVE_SPNG,1,[define if you have libspng installed.])
|
||||||
|
with_spng=yes
|
||||||
|
PACKAGES_USED="$PACKAGES_USED spng"
|
||||||
|
with_png=no
|
||||||
|
],
|
||||||
|
[
|
||||||
|
]
|
||||||
|
)
|
||||||
|
fi
|
||||||
|
|
||||||
# look for PNG with pkg-config ... fall back to our tester
|
# look for PNG with pkg-config ... fall back to our tester
|
||||||
AC_ARG_WITH([png],
|
AC_ARG_WITH([png],
|
||||||
AS_HELP_STRING([--without-png], [build without libpng (default: test)]))
|
AS_HELP_STRING([--without-png], [build without libpng (default: test)]))
|
||||||
@ -1298,10 +1314,10 @@ if test x"$LIB_FUZZING_ENGINE" = x; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Gather all up for VIPS_CFLAGS, VIPS_INCLUDES, VIPS_LIBS
|
# Gather all up for VIPS_CFLAGS, VIPS_INCLUDES, VIPS_LIBS
|
||||||
VIPS_CFLAGS="$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"
|
VIPS_CFLAGS="$VIPS_CFLAGS $GTHREAD_CFLAGS $GIO_CFLAGS $REQUIRED_CFLAGS $EXPAT_CFLAGS $ZLIB_CFLAGS $PANGOFT2_CFLAGS $GSF_CFLAGS $FFTW_CFLAGS $MAGICK_CFLAGS $JPEG_CFLAGS $SPNG_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="$VIPS_DEBUG_FLAGS $VIPS_CFLAGS"
|
VIPS_CFLAGS="$VIPS_DEBUG_FLAGS $VIPS_CFLAGS"
|
||||||
VIPS_INCLUDES="$ZLIB_INCLUDES $PNG_INCLUDES $TIFF_INCLUDES $JPEG_INCLUDES $NIFTI_INCLUDES"
|
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 $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"
|
VIPS_LIBS="$ZLIB_LIBS $HEIF_LIBS $MAGICK_LIBS $SPNG_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)
|
AC_SUBST(VIPS_LIBDIR)
|
||||||
|
|
||||||
@ -1397,6 +1413,8 @@ file import with cfitsio: $with_cfitsio
|
|||||||
file import/export with libwebp: $with_libwebp
|
file import/export with libwebp: $with_libwebp
|
||||||
(requires libwebp, libwebpmux, libwebpdemux 0.6.0 or later)
|
(requires libwebp, libwebpmux, libwebpdemux 0.6.0 or later)
|
||||||
text rendering with pangoft2: $with_pangoft2
|
text rendering with pangoft2: $with_pangoft2
|
||||||
|
file import/export with libspng: $with_spng
|
||||||
|
(requires libspng-0.6 or later)
|
||||||
file import/export with libpng: $with_png
|
file import/export with libpng: $with_png
|
||||||
(requires libpng-1.2.9 or later)
|
(requires libpng-1.2.9 or later)
|
||||||
support 8bpp PNG quantisation: $with_imagequant
|
support 8bpp PNG quantisation: $with_imagequant
|
||||||
|
@ -39,6 +39,7 @@ libforeign_la_SOURCES = \
|
|||||||
magickload.c \
|
magickload.c \
|
||||||
magick7load.c \
|
magick7load.c \
|
||||||
magicksave.c \
|
magicksave.c \
|
||||||
|
spngload.c \
|
||||||
pngload.c \
|
pngload.c \
|
||||||
pngsave.c \
|
pngsave.c \
|
||||||
vipspng.c \
|
vipspng.c \
|
||||||
|
674
libvips/foreign/spngload.c
Normal file
674
libvips/foreign/spngload.c
Normal file
@ -0,0 +1,674 @@
|
|||||||
|
/* load PNG with libspng
|
||||||
|
*
|
||||||
|
* 5/12/11
|
||||||
|
* - from pngload.c
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Notes:
|
||||||
|
*
|
||||||
|
* an enum for interlace_method would be nice ... ADAM7 == 1,
|
||||||
|
* no interlace == 0.
|
||||||
|
* an equivalent of png_sig_cmp() from libpng (is_a_png on a memory area)
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
#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 <vips/vips.h>
|
||||||
|
#include <vips/buf.h>
|
||||||
|
#include <vips/internal.h>
|
||||||
|
|
||||||
|
#include "pforeign.h"
|
||||||
|
|
||||||
|
#ifdef HAVE_SPNG
|
||||||
|
|
||||||
|
#include <spng.h>
|
||||||
|
|
||||||
|
typedef struct _VipsForeignLoadPng {
|
||||||
|
VipsForeignLoad parent_object;
|
||||||
|
|
||||||
|
/* Set by subclasses.
|
||||||
|
*/
|
||||||
|
VipsSource *source;
|
||||||
|
|
||||||
|
spng_ctx *ctx;
|
||||||
|
struct spng_ihdr ihdr;
|
||||||
|
enum spng_format fmt;
|
||||||
|
int bands;
|
||||||
|
VipsInterpretation interpretation;
|
||||||
|
VipsBandFormat format;
|
||||||
|
size_t out_size;
|
||||||
|
size_t out_line_size;
|
||||||
|
int y_pos;
|
||||||
|
|
||||||
|
} VipsForeignLoadPng;
|
||||||
|
|
||||||
|
typedef VipsForeignLoadClass VipsForeignLoadPngClass;
|
||||||
|
|
||||||
|
G_DEFINE_ABSTRACT_TYPE( VipsForeignLoadPng, vips_foreign_load_png,
|
||||||
|
VIPS_TYPE_FOREIGN_LOAD );
|
||||||
|
|
||||||
|
static void
|
||||||
|
vips_foreign_load_png_dispose( GObject *gobject )
|
||||||
|
{
|
||||||
|
VipsForeignLoadPng *png = (VipsForeignLoadPng *) gobject;
|
||||||
|
|
||||||
|
VIPS_FREEF( spng_ctx_free, png->ctx );
|
||||||
|
VIPS_UNREF( png->source );
|
||||||
|
|
||||||
|
G_OBJECT_CLASS( vips_foreign_load_png_parent_class )->
|
||||||
|
dispose( gobject );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* libspng read callbacks should copy length bytes to dest and return 0
|
||||||
|
* or SPNG_IO_EOF/SPNG_IO_ERROR on error.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
vips_foreign_load_png_stream( spng_ctx *ctx, void *user,
|
||||||
|
void *dest, size_t length )
|
||||||
|
{
|
||||||
|
VipsSource *source = VIPS_SOURCE( user );
|
||||||
|
|
||||||
|
gint64 bytes_read;
|
||||||
|
|
||||||
|
bytes_read = vips_source_read( source, dest, length );
|
||||||
|
if( bytes_read < 0 )
|
||||||
|
return( SPNG_IO_ERROR );
|
||||||
|
if( bytes_read < length )
|
||||||
|
return( SPNG_IO_EOF);
|
||||||
|
|
||||||
|
return( 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
static VipsForeignFlags
|
||||||
|
vips_foreign_load_png_get_flags_source( VipsSource *source )
|
||||||
|
{
|
||||||
|
spng_ctx *ctx;
|
||||||
|
struct spng_ihdr ihdr;
|
||||||
|
VipsForeignFlags flags;
|
||||||
|
|
||||||
|
ctx = spng_ctx_new( 0 );
|
||||||
|
spng_set_crc_action( ctx, SPNG_CRC_USE, SPNG_CRC_USE );
|
||||||
|
spng_set_png_stream( ctx,
|
||||||
|
vips_foreign_load_png_stream, source );
|
||||||
|
if( spng_get_ihdr( ctx, &ihdr ) ) {
|
||||||
|
spng_ctx_free( ctx );
|
||||||
|
return( 0 );
|
||||||
|
}
|
||||||
|
spng_ctx_free( ctx );
|
||||||
|
|
||||||
|
flags = 0;
|
||||||
|
if( ihdr.interlace_method != 0 )
|
||||||
|
flags |= VIPS_FOREIGN_PARTIAL;
|
||||||
|
else
|
||||||
|
flags |= VIPS_FOREIGN_SEQUENTIAL;
|
||||||
|
|
||||||
|
return( flags );
|
||||||
|
}
|
||||||
|
|
||||||
|
static VipsForeignFlags
|
||||||
|
vips_foreign_load_png_get_flags( VipsForeignLoad *load )
|
||||||
|
{
|
||||||
|
VipsForeignLoadPng *png = (VipsForeignLoadPng *) load;
|
||||||
|
|
||||||
|
return( vips_foreign_load_png_get_flags_source( png->source ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
static VipsForeignFlags
|
||||||
|
vips_foreign_load_png_get_flags_filename( const char *filename )
|
||||||
|
{
|
||||||
|
VipsSource *source;
|
||||||
|
VipsForeignFlags flags;
|
||||||
|
|
||||||
|
if( !(source = vips_source_new_from_file( filename )) )
|
||||||
|
return( 0 );
|
||||||
|
flags = vips_foreign_load_png_get_flags_source( source );
|
||||||
|
VIPS_UNREF( source );
|
||||||
|
|
||||||
|
return( flags );
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
vips_foreign_load_png_set_header( VipsForeignLoadPng *png, VipsImage *image )
|
||||||
|
{
|
||||||
|
vips_image_init_fields( image,
|
||||||
|
png->ihdr.width, png->ihdr.height, png->bands,
|
||||||
|
png->format, VIPS_CODING_NONE, png->interpretation,
|
||||||
|
1.0, 1.0 );
|
||||||
|
VIPS_SETSTR( image->filename,
|
||||||
|
vips_connection_filename( VIPS_CONNECTION( png->source ) ) );
|
||||||
|
|
||||||
|
/* 0 is no interlace.
|
||||||
|
*/
|
||||||
|
if( png->ihdr.interlace_method == 0 )
|
||||||
|
/* Sequential mode needs thinstrip to work with things like
|
||||||
|
* vips_shrink().
|
||||||
|
*/
|
||||||
|
vips_image_pipelinev( image,
|
||||||
|
VIPS_DEMAND_STYLE_THINSTRIP, NULL );
|
||||||
|
else
|
||||||
|
/* Interlaced images are read via a huge memory buffer.
|
||||||
|
*/
|
||||||
|
vips_image_pipelinev( image, VIPS_DEMAND_STYLE_ANY, NULL );
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
vips_foreign_load_png_header( VipsForeignLoad *load )
|
||||||
|
{
|
||||||
|
VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( load );
|
||||||
|
VipsForeignLoadPng *png = (VipsForeignLoadPng *) load;
|
||||||
|
|
||||||
|
int error;
|
||||||
|
|
||||||
|
/* Flags can be eg. SPNG_CTX_IGNORE_ADLER32 to ignore CRC chaekcs in
|
||||||
|
* deflate.
|
||||||
|
*
|
||||||
|
* FIXME ... fail handling
|
||||||
|
*/
|
||||||
|
png->ctx = spng_ctx_new( 0 );
|
||||||
|
spng_set_crc_action( png->ctx, SPNG_CRC_USE, SPNG_CRC_USE );
|
||||||
|
|
||||||
|
spng_set_png_stream( png->ctx,
|
||||||
|
vips_foreign_load_png_stream, png->source );
|
||||||
|
if( (error = spng_get_ihdr( png->ctx, &png->ihdr )) ) {
|
||||||
|
vips_error( class->nickname, "%s", spng_strerror( error ) );
|
||||||
|
return( -1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
printf(" width: %d\nheight: %d\nbit depth: %d\ncolor type: %d\n",
|
||||||
|
png->ihdr.width, png->ihdr.height,
|
||||||
|
png->ihdr.bit_depth, png->ihdr.color_type );
|
||||||
|
printf( "compression method: %d\nfilter method: %d\n"
|
||||||
|
"interlace method: %d\n",
|
||||||
|
png->ihdr.compression_method, png->ihdr.filter_method,
|
||||||
|
png->ihdr.interlace_method );
|
||||||
|
|
||||||
|
switch( png->ihdr.color_type ) {
|
||||||
|
case SPNG_COLOR_TYPE_GRAYSCALE:
|
||||||
|
png->interpretation = VIPS_INTERPRETATION_B_W;
|
||||||
|
png->bands = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SPNG_COLOR_TYPE_GRAYSCALE_ALPHA:
|
||||||
|
png->interpretation = VIPS_INTERPRETATION_B_W;
|
||||||
|
png->bands = 2;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SPNG_COLOR_TYPE_TRUECOLOR:
|
||||||
|
case SPNG_COLOR_TYPE_INDEXED:
|
||||||
|
png->interpretation = VIPS_INTERPRETATION_sRGB;
|
||||||
|
png->bands = 3;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SPNG_COLOR_TYPE_TRUECOLOR_ALPHA:
|
||||||
|
png->interpretation = VIPS_INTERPRETATION_sRGB;
|
||||||
|
png->bands = 4;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
vips_error( class->nickname, "%s", "unknown color_type" );
|
||||||
|
return( -1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( png->ihdr.bit_depth == 16 ) {
|
||||||
|
png->fmt = SPNG_FMT_RGBA16;
|
||||||
|
png->format = VIPS_FORMAT_USHORT;
|
||||||
|
if( png->interpretation == VIPS_INTERPRETATION_B_W )
|
||||||
|
png->interpretation = VIPS_INTERPRETATION_GREY16;
|
||||||
|
if( png->interpretation == VIPS_INTERPRETATION_sRGB )
|
||||||
|
png->interpretation = VIPS_INTERPRETATION_RGB16;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
png->fmt = SPNG_FMT_RGBA8;
|
||||||
|
png->format = VIPS_FORMAT_UCHAR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FIXME ... get resolution.
|
||||||
|
*/
|
||||||
|
|
||||||
|
vips_source_minimise( png->source );
|
||||||
|
|
||||||
|
vips_foreign_load_png_set_header( png, load->out );
|
||||||
|
|
||||||
|
return( 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
vips_foreign_load_png_interlace( VipsForeignLoadPng *png, VipsImage *image )
|
||||||
|
{
|
||||||
|
/* FIXME ... load interlaced PNG to huge memory image.
|
||||||
|
*/
|
||||||
|
|
||||||
|
return( 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
vips_foreign_load_png_generate( VipsRegion *or,
|
||||||
|
void *seq, void *a, void *b, gboolean *stop )
|
||||||
|
{
|
||||||
|
VipsRect *r = &or->valid;
|
||||||
|
VipsForeignLoad *load = VIPS_FOREIGN_LOAD( a );
|
||||||
|
VipsForeignLoadPng *png = (VipsForeignLoadPng *) load;
|
||||||
|
VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( png );
|
||||||
|
|
||||||
|
int y;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
printf( "vips_foreign_load_png_generate: line %d, %d rows\n",
|
||||||
|
r->top, r->height );
|
||||||
|
printf( "vips_foreign_load_png_generate: y_top = %d\n", png->y_pos );
|
||||||
|
#endif /*DEBUG*/
|
||||||
|
|
||||||
|
/* We're inside a tilecache where tiles are the full image width, so
|
||||||
|
* this should always be true.
|
||||||
|
*/
|
||||||
|
g_assert( r->left == 0 );
|
||||||
|
g_assert( r->width == or->im->Xsize );
|
||||||
|
g_assert( VIPS_RECT_BOTTOM( r ) <= or->im->Ysize );
|
||||||
|
|
||||||
|
/* Tiles should always be a strip in height, unless it's the final
|
||||||
|
* strip.
|
||||||
|
*/
|
||||||
|
g_assert( r->height == VIPS_MIN( VIPS__FATSTRIP_HEIGHT,
|
||||||
|
or->im->Ysize - r->top ) );
|
||||||
|
|
||||||
|
/* And check that y_pos is correct. It should be, since we are inside
|
||||||
|
* a vips_sequential().
|
||||||
|
*/
|
||||||
|
if( r->top != png->y_pos ) {
|
||||||
|
vips_error( class->nickname,
|
||||||
|
_( "out of order read at line %d" ), png->y_pos );
|
||||||
|
return( -1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
for( y = 0; y < r->height; y++ ) {
|
||||||
|
error = spng_decode_row( png->ctx,
|
||||||
|
VIPS_REGION_ADDR( or, 0, r->top + y ),
|
||||||
|
VIPS_REGION_SIZEOF_LINE( or ) );
|
||||||
|
|
||||||
|
/* FIXME .. should allow SPNG_EOI here?
|
||||||
|
*/
|
||||||
|
if( error ) {
|
||||||
|
/* We've failed to read some pixels. Knock this
|
||||||
|
* operation out of cache.
|
||||||
|
*/
|
||||||
|
vips_operation_invalidate( VIPS_OPERATION( png ) );
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
printf( "vips_foreign_load_png_generate:\n" );
|
||||||
|
printf( " spng_decode_row() failed, line %d\n",
|
||||||
|
r->top + y );
|
||||||
|
printf( " file %s\n", read->name );
|
||||||
|
printf( " thread %p\n", g_thread_self() );
|
||||||
|
#endif /*DEBUG*/
|
||||||
|
|
||||||
|
/* And bail if fail is on. We have to add an error
|
||||||
|
* message, since the handler we install just does
|
||||||
|
* g_warning().
|
||||||
|
*/
|
||||||
|
if( load->fail ) {
|
||||||
|
vips_error( class->nickname,
|
||||||
|
"%s", _( "libpng read error" ) );
|
||||||
|
return( -1 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
png->y_pos += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return( 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
vips_foreign_load_png_load( VipsForeignLoad *load )
|
||||||
|
{
|
||||||
|
VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( load );
|
||||||
|
VipsForeignLoadPng *png = (VipsForeignLoadPng *) load;
|
||||||
|
VipsImage **t = (VipsImage **)
|
||||||
|
vips_object_local_array( VIPS_OBJECT( load ), 3 );
|
||||||
|
|
||||||
|
int error;
|
||||||
|
|
||||||
|
if( (error = spng_decoded_image_size( png->ctx,
|
||||||
|
png->fmt, &png->out_size )) ) {
|
||||||
|
vips_error( class->nickname, "%s", spng_strerror( error ) );
|
||||||
|
return( -1 );
|
||||||
|
}
|
||||||
|
png->out_line_size = png->out_size / png->ihdr.height;
|
||||||
|
|
||||||
|
/* Initialize for progressive decoding.
|
||||||
|
*/
|
||||||
|
if( (error = spng_decode_image( png->ctx, NULL, 0,
|
||||||
|
png->fmt, SPNG_DECODE_PROGRESSIVE )) ) {
|
||||||
|
vips_error( class->nickname, "%s", spng_strerror( error ) );
|
||||||
|
return( -1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
t[0] = vips_image_new_memory();
|
||||||
|
vips_foreign_load_png_set_header( png, t[0] );
|
||||||
|
if( vips_source_decode( png->source ) )
|
||||||
|
return( -1 );
|
||||||
|
|
||||||
|
if( png->ihdr.interlace_method != 0 ) {
|
||||||
|
/* Arg awful interlaced image. We have to load to a huge mem
|
||||||
|
* buffer, then copy to out.
|
||||||
|
*/
|
||||||
|
if( vips_foreign_load_png_interlace( png, t[0] ) ||
|
||||||
|
vips_image_write( t[0], load->real ) )
|
||||||
|
return( -1 );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if( vips_image_generate( t[0],
|
||||||
|
NULL, vips_foreign_load_png_generate, NULL,
|
||||||
|
read, NULL ) ||
|
||||||
|
vips_sequential( t[0], &t[1],
|
||||||
|
"tile_height", VIPS__FATSTRIP_HEIGHT,
|
||||||
|
NULL ) ||
|
||||||
|
vips_image_write( t[1], load->real ) )
|
||||||
|
return( -1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
return( 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
vips_foreign_load_png_class_init( VipsForeignLoadPngClass *class )
|
||||||
|
{
|
||||||
|
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
|
||||||
|
VipsObjectClass *object_class = (VipsObjectClass *) class;
|
||||||
|
VipsForeignClass *foreign_class = (VipsForeignClass *) class;
|
||||||
|
VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class;
|
||||||
|
|
||||||
|
gobject_class->dispose = vips_foreign_load_png_dispose;
|
||||||
|
|
||||||
|
object_class->nickname = "pngload_base";
|
||||||
|
object_class->description = _( "load png base class" );
|
||||||
|
|
||||||
|
/* We are fast at is_a(), so high priority.
|
||||||
|
*/
|
||||||
|
foreign_class->priority = 200;
|
||||||
|
|
||||||
|
load_class->get_flags_filename =
|
||||||
|
vips_foreign_load_png_get_flags_filename;
|
||||||
|
load_class->get_flags = vips_foreign_load_png_get_flags;
|
||||||
|
load_class->header = vips_foreign_load_png_header;
|
||||||
|
load_class->load = vips_foreign_load_png_load;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
vips_foreign_load_png_init( VipsForeignLoadPng *png )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct _VipsForeignLoadPngSource {
|
||||||
|
VipsForeignLoadPng parent_object;
|
||||||
|
|
||||||
|
/* Load from a source.
|
||||||
|
*/
|
||||||
|
VipsSource *source;
|
||||||
|
|
||||||
|
} VipsForeignLoadPngSource;
|
||||||
|
|
||||||
|
typedef VipsForeignLoadPngClass VipsForeignLoadPngSourceClass;
|
||||||
|
|
||||||
|
G_DEFINE_TYPE( VipsForeignLoadPngSource, vips_foreign_load_png_source,
|
||||||
|
vips_foreign_load_png_get_type() );
|
||||||
|
|
||||||
|
static int
|
||||||
|
vips_foreign_load_png_source_build( VipsObject *object )
|
||||||
|
{
|
||||||
|
VipsForeignLoadPng *png = (VipsForeignLoadPng *) object;
|
||||||
|
VipsForeignLoadPngSource *source = (VipsForeignLoadPngSource *) object;
|
||||||
|
|
||||||
|
if( source->source ) {
|
||||||
|
png->source = source->source;
|
||||||
|
g_object_ref( png->source );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( VIPS_OBJECT_CLASS( vips_foreign_load_png_source_parent_class )->
|
||||||
|
build( object ) )
|
||||||
|
return( -1 );
|
||||||
|
|
||||||
|
return( 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
vips_foreign_load_png_source_is_a_source( VipsSource *source )
|
||||||
|
{
|
||||||
|
static unsigned char signature[8] = { 137, 80, 78, 71, 13, 10, 26, 10 };
|
||||||
|
|
||||||
|
const unsigned char *p;
|
||||||
|
|
||||||
|
if( (p = vips_source_sniff( source, 8 )) &&
|
||||||
|
memcmp( p, signature, 8 ) == 0 )
|
||||||
|
return( TRUE );
|
||||||
|
|
||||||
|
return( FALSE );
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
vips_foreign_load_png_source_class_init( VipsForeignLoadPngSourceClass *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 = "pngload_source";
|
||||||
|
object_class->description = _( "load png from source" );
|
||||||
|
object_class->build = vips_foreign_load_png_source_build;
|
||||||
|
|
||||||
|
load_class->is_a_source = vips_foreign_load_png_source_is_a_source;
|
||||||
|
|
||||||
|
VIPS_ARG_OBJECT( class, "source", 1,
|
||||||
|
_( "Source" ),
|
||||||
|
_( "Source to load from" ),
|
||||||
|
VIPS_ARGUMENT_REQUIRED_INPUT,
|
||||||
|
G_STRUCT_OFFSET( VipsForeignLoadPngSource, source ),
|
||||||
|
VIPS_TYPE_SOURCE );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
vips_foreign_load_png_source_init( VipsForeignLoadPngSource *source )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct _VipsForeignLoadPngFile {
|
||||||
|
VipsForeignLoadPng parent_object;
|
||||||
|
|
||||||
|
/* Filename for load.
|
||||||
|
*/
|
||||||
|
char *filename;
|
||||||
|
|
||||||
|
} VipsForeignLoadPngFile;
|
||||||
|
|
||||||
|
typedef VipsForeignLoadPngClass VipsForeignLoadPngFileClass;
|
||||||
|
|
||||||
|
G_DEFINE_TYPE( VipsForeignLoadPngFile, vips_foreign_load_png_file,
|
||||||
|
vips_foreign_load_png_get_type() );
|
||||||
|
|
||||||
|
static int
|
||||||
|
vips_foreign_load_png_file_build( VipsObject *object )
|
||||||
|
{
|
||||||
|
VipsForeignLoadPng *png = (VipsForeignLoadPng *) object;
|
||||||
|
VipsForeignLoadPngFile *file = (VipsForeignLoadPngFile *) object;
|
||||||
|
|
||||||
|
if( file->filename &&
|
||||||
|
!(png->source = vips_source_new_from_file( file->filename )) )
|
||||||
|
return( -1 );
|
||||||
|
|
||||||
|
if( VIPS_OBJECT_CLASS( vips_foreign_load_png_file_parent_class )->
|
||||||
|
build( object ) )
|
||||||
|
return( -1 );
|
||||||
|
|
||||||
|
return( 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
vips_foreign_load_png_file_is_a( const char *filename )
|
||||||
|
{
|
||||||
|
VipsSource *source;
|
||||||
|
gboolean result;
|
||||||
|
|
||||||
|
if( !(source = vips_source_new_from_file( filename )) )
|
||||||
|
return( FALSE );
|
||||||
|
result = vips_foreign_load_png_source_is_a_source( source );
|
||||||
|
VIPS_UNREF( source );
|
||||||
|
|
||||||
|
return( result );
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *vips_foreign_load_png_file_suffs[] = { ".png", NULL };
|
||||||
|
|
||||||
|
static void
|
||||||
|
vips_foreign_load_png_file_class_init( VipsForeignLoadPngFileClass *class )
|
||||||
|
{
|
||||||
|
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
|
||||||
|
VipsObjectClass *object_class = (VipsObjectClass *) class;
|
||||||
|
VipsForeignClass *foreign_class = (VipsForeignClass *) 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 = "pngload";
|
||||||
|
object_class->description = _( "load png from file" );
|
||||||
|
object_class->build = vips_foreign_load_png_file_build;
|
||||||
|
|
||||||
|
foreign_class->suffs = vips_foreign_load_png_file_suffs;
|
||||||
|
|
||||||
|
load_class->is_a = vips_foreign_load_png_file_is_a;
|
||||||
|
|
||||||
|
VIPS_ARG_STRING( class, "filename", 1,
|
||||||
|
_( "Filename" ),
|
||||||
|
_( "Filename to load from" ),
|
||||||
|
VIPS_ARGUMENT_REQUIRED_INPUT,
|
||||||
|
G_STRUCT_OFFSET( VipsForeignLoadPngFile, filename ),
|
||||||
|
NULL );
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
vips_foreign_load_png_file_init( VipsForeignLoadPngFile *file )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct _VipsForeignLoadPngBuffer {
|
||||||
|
VipsForeignLoadPng parent_object;
|
||||||
|
|
||||||
|
/* Load from a buffer.
|
||||||
|
*/
|
||||||
|
VipsBlob *blob;
|
||||||
|
|
||||||
|
} VipsForeignLoadPngBuffer;
|
||||||
|
|
||||||
|
typedef VipsForeignLoadPngClass VipsForeignLoadPngBufferClass;
|
||||||
|
|
||||||
|
G_DEFINE_TYPE( VipsForeignLoadPngBuffer, vips_foreign_load_png_buffer,
|
||||||
|
vips_foreign_load_png_get_type() );
|
||||||
|
|
||||||
|
static int
|
||||||
|
vips_foreign_load_png_buffer_build( VipsObject *object )
|
||||||
|
{
|
||||||
|
VipsForeignLoadPng *png = (VipsForeignLoadPng *) object;
|
||||||
|
VipsForeignLoadPngBuffer *buffer = (VipsForeignLoadPngBuffer *) object;
|
||||||
|
|
||||||
|
if( buffer->blob &&
|
||||||
|
!(png->source = vips_source_new_from_memory(
|
||||||
|
VIPS_AREA( buffer->blob )->data,
|
||||||
|
VIPS_AREA( buffer->blob )->length )) )
|
||||||
|
return( -1 );
|
||||||
|
|
||||||
|
if( VIPS_OBJECT_CLASS( vips_foreign_load_png_buffer_parent_class )->
|
||||||
|
build( object ) )
|
||||||
|
return( -1 );
|
||||||
|
|
||||||
|
return( 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
vips_foreign_load_png_buffer_is_a_buffer( const void *buf, size_t len )
|
||||||
|
{
|
||||||
|
VipsSource *source;
|
||||||
|
gboolean result;
|
||||||
|
|
||||||
|
if( !(source = vips_source_new_from_memory( buf, len )) )
|
||||||
|
return( FALSE );
|
||||||
|
result = vips_foreign_load_png_source_is_a_source( source );
|
||||||
|
VIPS_UNREF( source );
|
||||||
|
|
||||||
|
return( result );
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
vips_foreign_load_png_buffer_class_init( VipsForeignLoadPngBufferClass *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 = "pngload_buffer";
|
||||||
|
object_class->description = _( "load png from buffer" );
|
||||||
|
object_class->build = vips_foreign_load_png_buffer_build;
|
||||||
|
|
||||||
|
load_class->is_a_buffer = vips_foreign_load_png_buffer_is_a_buffer;
|
||||||
|
|
||||||
|
VIPS_ARG_BOXED( class, "buffer", 1,
|
||||||
|
_( "Buffer" ),
|
||||||
|
_( "Buffer to load from" ),
|
||||||
|
VIPS_ARGUMENT_REQUIRED_INPUT,
|
||||||
|
G_STRUCT_OFFSET( VipsForeignLoadPngBuffer, blob ),
|
||||||
|
VIPS_TYPE_BLOB );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
vips_foreign_load_png_buffer_init( VipsForeignLoadPngBuffer *buffer )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /*HAVE_SPNG*/
|
Loading…
Reference in New Issue
Block a user