start revising heifload

not quite working
This commit is contained in:
John Cupitt 2020-02-28 14:41:00 +00:00
parent 175408733f
commit 7ea34382a3
1 changed files with 160 additions and 118 deletions

View File

@ -152,37 +152,42 @@ typedef struct _VipsForeignLoadHeif {
int stride;
const uint8_t *data;
/* Set from subclasses.
*/
VipsSource *source;
/* The reader struct. We use this to attach to our VipsSource. This
* has to be alloced rather than in our struct, since it may change
* size in libheif API versions.
*/
struct heif_reader *reader;
/* When we see EOF from read(), record the source length here.
*/
gint64 length;
} VipsForeignLoadHeif;
typedef struct _VipsForeignLoadHeifClass {
VipsForeignLoadClass parent_class;
/* Open the reader, eg. call heif_context_read_from_memory() etc. This
* has to be a vfunc so generate can restart after minimise.
*/
int (*open)( VipsForeignLoadHeif *heif );
} VipsForeignLoadHeifClass;
G_DEFINE_ABSTRACT_TYPE( VipsForeignLoadHeif, vips_foreign_load_heif,
VIPS_TYPE_FOREIGN_LOAD );
static void
vips_foreign_load_heif_close( VipsForeignLoadHeif *heif )
{
VIPS_FREEF( heif_image_release, heif->img );
heif->data = NULL;
VIPS_FREEF( heif_image_handle_release, heif->handle );
VIPS_FREEF( heif_context_free, heif->ctx );
}
static void
vips_foreign_load_heif_dispose( GObject *gobject )
{
VipsForeignLoadHeif *heif = (VipsForeignLoadHeif *) gobject;
vips_foreign_load_heif_close( heif );
heif->data = NULL;
VIPS_FREEF( heif_image_release, heif->img );
VIPS_FREEF( heif_image_handle_release, heif->handle );
VIPS_FREEF( heif_context_free, heif->ctx );
VIPS_FREE( heif->id );
VIPS_FREE( heif->reader );
VIPS_UNREF( heif->source );
G_OBJECT_CLASS( vips_foreign_load_heif_parent_class )->
dispose( gobject );
@ -196,6 +201,31 @@ vips__heif_error( struct heif_error *error )
error->subcode );
}
static int
vips_foreign_load_heif_build( VipsObject *object )
{
VipsForeignLoadHeif *heif = (VipsForeignLoadHeif *) object;
if( !heif->ctx ) {
struct heif_error error;
heif->ctx = heif_context_alloc();
error = heif_context_read_from_reader( heif->ctx,
heif->reader, heif, NULL );
if( error.code ) {
vips__heif_error( &error );
return( -1 );
}
}
if( VIPS_OBJECT_CLASS( vips_foreign_load_heif_parent_class )->
build( object ) )
return( -1 );
return( 0 );
}
static const char *heif_magic[] = {
"ftypheic", /* A regular heif image */
"ftypheix", /* Extended range (>8 bit) image */
@ -308,6 +338,8 @@ vips_foreign_load_heif_set_page( VipsForeignLoadHeif *heif,
static int
vips_foreign_load_heif_set_header( VipsForeignLoadHeif *heif, VipsImage *out )
{
VipsForeignLoad *load = (VipsForeignLoad *) heif;
int bands;
int i;
/* Surely, 16 metadata items will be enough for anyone.
@ -464,6 +496,9 @@ vips_foreign_load_heif_set_header( VipsForeignLoadHeif *heif, VipsImage *out )
VIPS_FORMAT_UCHAR, VIPS_CODING_NONE, VIPS_INTERPRETATION_sRGB,
1.0, 1.0 );
VIPS_SETSTR( load->out->filename,
vips_connection_filename( VIPS_CONNECTION( heif->source ) ) );
return( 0 );
}
@ -506,16 +541,11 @@ vips_foreign_load_heif_header( VipsForeignLoad *load )
{
VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( load );
VipsForeignLoadHeif *heif = (VipsForeignLoadHeif *) load;
VipsForeignLoadHeifClass *heif_class =
VIPS_FOREIGN_LOAD_HEIF_GET_CLASS( heif );
struct heif_error error;
heif_item_id primary_id;
int i;
if( heif_class->open( heif ) )
return( -1 );
heif->n_top = heif_context_get_number_of_top_level_images( heif->ctx );
heif->id = VIPS_ARRAY( NULL, heif->n_top, heif_item_id );
heif_context_get_list_of_top_level_image_IDs( heif->ctx,
@ -645,7 +675,7 @@ vips_foreign_load_heif_header( VipsForeignLoad *load )
if( vips_foreign_load_heif_set_header( heif, load->out ) )
return( -1 );
vips_foreign_load_heif_close( heif );
vips_source_minimise( heif->source );
return( 0 );
}
@ -656,8 +686,6 @@ vips_foreign_load_heif_generate( VipsRegion *or,
{
VipsForeignLoadHeif *heif = (VipsForeignLoadHeif *) a;
VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( heif );
VipsForeignLoadHeifClass *heif_class =
VIPS_FOREIGN_LOAD_HEIF_GET_CLASS( heif );
VipsRect *r = &or->valid;
int page = r->top / heif->page_height + heif->page;
@ -669,9 +697,6 @@ vips_foreign_load_heif_generate( VipsRegion *or,
g_assert( r->height == 1 );
if( heif_class->open( heif ) )
return( -1 );
if( vips_foreign_load_heif_set_page( heif, page, heif->thumbnail ) )
return( -1 );
@ -779,15 +804,13 @@ vips_foreign_load_heif_generate( VipsRegion *or,
static void
vips_foreign_load_heif_minimise( VipsObject *object, VipsForeignLoadHeif *heif )
{
vips_foreign_load_heif_close( heif );
vips_source_minimise( heif->source );
}
static int
vips_foreign_load_heif_load( VipsForeignLoad *load )
{
VipsForeignLoadHeif *heif = (VipsForeignLoadHeif *) load;
VipsForeignLoadHeifClass *class =
VIPS_FOREIGN_LOAD_HEIF_GET_CLASS( heif );
VipsImage **t = (VipsImage **)
vips_object_local_array( VIPS_OBJECT( load ), 3 );
@ -796,9 +819,6 @@ vips_foreign_load_heif_load( VipsForeignLoad *load )
printf( "vips_foreign_load_heif_load: loading image\n" );
#endif /*DEBUG*/
if( class->open( heif ) )
return( -1 );
t[0] = vips_image_new();
if( vips_foreign_load_heif_set_header( heif, t[0] ) )
return( -1 );
@ -817,20 +837,12 @@ vips_foreign_load_heif_load( VipsForeignLoad *load )
return( 0 );
}
static int
vips_foreign_load_heif_open( VipsForeignLoadHeif *heif )
{
return( 0 );
}
static void
vips_foreign_load_heif_class_init( VipsForeignLoadHeifClass *class )
{
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
VipsObjectClass *object_class = (VipsObjectClass *) class;
VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class;
VipsForeignLoadHeifClass *heif_class =
(VipsForeignLoadHeifClass *) class;
gobject_class->dispose = vips_foreign_load_heif_dispose;
gobject_class->set_property = vips_object_set_property;
@ -838,13 +850,12 @@ vips_foreign_load_heif_class_init( VipsForeignLoadHeifClass *class )
object_class->nickname = "heifload_base";
object_class->description = _( "load a HEIF image" );
object_class->build = vips_foreign_load_heif_build;
load_class->get_flags = vips_foreign_load_heif_get_flags;
load_class->header = vips_foreign_load_heif_header;
load_class->load = vips_foreign_load_heif_load;
heif_class->open = vips_foreign_load_heif_open;
VIPS_ARG_INT( class, "page", 2,
_( "Page" ),
_( "Load this page from the file" ),
@ -875,10 +886,77 @@ vips_foreign_load_heif_class_init( VipsForeignLoadHeifClass *class )
}
static gint64
vips_foreign_load_heif_get_position( void *userdata )
{
VipsForeignLoadHeif *heif = (VipsForeignLoadHeif *) userdata;
return( vips_source_seek( heif->source, 0L, SEEK_CUR ) );
}
static int
vips_foreign_load_heif_read( void *data, size_t size, void *userdata )
{
VipsForeignLoadHeif *heif = (VipsForeignLoadHeif *) userdata;
int result;
result = vips_source_read( heif->source, data, size );
if( result == 0 ) {
printf( "vips_foreign_load_heif_read: seen EOF\n" );
heif->length = vips_source_seek( heif->source, 0L, SEEK_CUR );
}
if( result < 0 )
return( -1 );
return( 0 );
}
static int
vips_foreign_load_heif_seek( gint64 position, void *userdata )
{
VipsForeignLoadHeif *heif = (VipsForeignLoadHeif *) userdata;
vips_source_seek( heif->source, position, SEEK_SET );
return( 0 );
}
static enum heif_reader_grow_status
vips_foreign_load_heif_wait_for_file_size( gint64 target_size, void *userdata )
{
VipsForeignLoadHeif *heif = (VipsForeignLoadHeif *) userdata;
return( heif_reader_grow_status_size_reached );
if( heif->length == -1 ||
target_size < heif->length )
/* We've not seen EOF yet (so seeking to any point is fine), OR
* we've seen EOF, and this target is less than that.
*/
return( heif_reader_grow_status_size_reached );
else
/* We've seen EOF, we know the length, and this is too far.
*/
return( heif_reader_grow_status_size_beyond_eof );
}
static void
vips_foreign_load_heif_init( VipsForeignLoadHeif *heif )
{
heif->n = 1;
heif->length = -1;
heif->reader = VIPS_ARRAY( NULL, 1, struct heif_reader );
/* The first version to support heif_reader.
*/
heif->reader->reader_api_version = 1.3;
heif->reader->get_position = vips_foreign_load_heif_get_position;
heif->reader->read = vips_foreign_load_heif_read;
heif->reader->seek = vips_foreign_load_heif_seek;
heif->reader->wait_for_file_size =
vips_foreign_load_heif_wait_for_file_size;
}
typedef struct _VipsForeignLoadHeifFile {
@ -895,6 +973,24 @@ typedef VipsForeignLoadHeifClass VipsForeignLoadHeifFileClass;
G_DEFINE_TYPE( VipsForeignLoadHeifFile, vips_foreign_load_heif_file,
vips_foreign_load_heif_get_type() );
static int
vips_foreign_load_heif_file_build( VipsObject *object )
{
VipsForeignLoadHeifFile *file = (VipsForeignLoadHeifFile *) object;
VipsForeignLoadHeif *heif = (VipsForeignLoadHeif *) object;
if( file->filename )
if( !(heif->source =
vips_source_new_from_file( file->filename )) )
return( -1 );
if( VIPS_OBJECT_CLASS( vips_foreign_load_heif_file_parent_class )->
build( object ) )
return( -1 );
return( 0 );
}
static int
vips_foreign_load_heif_file_is_a( const char *filename )
{
@ -906,25 +1002,6 @@ vips_foreign_load_heif_file_is_a( const char *filename )
return( vips_foreign_load_heif_is_a( buf, 12 ) );
}
static int
vips_foreign_load_heif_file_header( VipsForeignLoad *load )
{
VipsForeignLoadHeif *heif = (VipsForeignLoadHeif *) load;
VipsForeignLoadHeifFile *file = (VipsForeignLoadHeifFile *) load;
if( VIPS_FOREIGN_LOAD_CLASS(
vips_foreign_load_heif_file_parent_class )->header( load ) ) {
/* Close early if our base class fails to read.
*/
vips_foreign_load_heif_close( heif );
return( -1 );
}
VIPS_SETSTR( load->out->filename, file->filename );
return( 0 );
}
const char *vips__heif_suffs[] = {
".heic",
".heif",
@ -932,31 +1009,6 @@ const char *vips__heif_suffs[] = {
NULL
};
static int
vips_foreign_load_heif_file_open( VipsForeignLoadHeif *heif )
{
VipsForeignLoadHeifFile *file = (VipsForeignLoadHeifFile *) heif;
if( !heif->ctx ) {
struct heif_error error;
heif->ctx = heif_context_alloc();
error = heif_context_read_from_file( heif->ctx,
file->filename, NULL );
if( error.code ) {
/* Make we close the fd as soon as we can on error.
*/
vips_foreign_load_heif_close( heif );
vips__heif_error( &error );
return( -1 );
}
}
return( VIPS_FOREIGN_LOAD_HEIF_CLASS(
vips_foreign_load_heif_file_parent_class )->open( heif ) );
}
static void
vips_foreign_load_heif_file_class_init( VipsForeignLoadHeifFileClass *class )
{
@ -964,20 +1016,16 @@ vips_foreign_load_heif_file_class_init( VipsForeignLoadHeifFileClass *class )
VipsObjectClass *object_class = (VipsObjectClass *) class;
VipsForeignClass *foreign_class = (VipsForeignClass *) class;
VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class;
VipsForeignLoadHeifClass *heif_class =
(VipsForeignLoadHeifClass *) class;
gobject_class->set_property = vips_object_set_property;
gobject_class->get_property = vips_object_get_property;
object_class->nickname = "heifload";
object_class->build = vips_foreign_load_heif_file_build;
foreign_class->suffs = vips__heif_suffs;
load_class->is_a = vips_foreign_load_heif_file_is_a;
load_class->header = vips_foreign_load_heif_file_header;
heif_class->open = vips_foreign_load_heif_file_open;
VIPS_ARG_STRING( class, "filename", 1,
_( "Filename" ),
@ -1007,35 +1055,32 @@ typedef VipsForeignLoadHeifClass VipsForeignLoadHeifBufferClass;
G_DEFINE_TYPE( VipsForeignLoadHeifBuffer, vips_foreign_load_heif_buffer,
vips_foreign_load_heif_get_type() );
static int
vips_foreign_load_heif_buffer_build( VipsObject *object )
{
VipsForeignLoadHeifBuffer *buffer =
(VipsForeignLoadHeifBuffer *) object;
VipsForeignLoadHeif *heif = (VipsForeignLoadHeif *) object;
if( buffer->buf )
if( !(heif->source = vips_source_new_from_memory(
VIPS_AREA( buffer->buf )->data,
VIPS_AREA( buffer->buf )->length )) )
return( -1 );
if( VIPS_OBJECT_CLASS( vips_foreign_load_heif_file_parent_class )->
build( object ) )
return( -1 );
return( 0 );
}
static gboolean
vips_foreign_load_heif_buffer_is_a( const void *buf, size_t len )
{
return( vips_foreign_load_heif_is_a( buf, len ) );
}
static int
vips_foreign_load_heif_buffer_open( VipsForeignLoadHeif *heif )
{
VipsForeignLoadHeifBuffer *buffer = (VipsForeignLoadHeifBuffer *) heif;
VIPS_DEBUG_MSG( "vips_foreign_load_heif_buffer_open:\n" );
if( !heif->ctx ) {
struct heif_error error;
heif->ctx = heif_context_alloc();
error = heif_context_read_from_memory( heif->ctx,
buffer->buf->data, buffer->buf->length, NULL );
if( error.code ) {
vips__heif_error( &error );
return( -1 );
}
}
return( VIPS_FOREIGN_LOAD_HEIF_CLASS(
vips_foreign_load_heif_buffer_parent_class )->open( heif ) );
}
static void
vips_foreign_load_heif_buffer_class_init(
VipsForeignLoadHeifBufferClass *class )
@ -1043,18 +1088,15 @@ vips_foreign_load_heif_buffer_class_init(
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
VipsObjectClass *object_class = (VipsObjectClass *) class;
VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class;
VipsForeignLoadHeifClass *heif_class =
(VipsForeignLoadHeifClass *) class;
gobject_class->set_property = vips_object_set_property;
gobject_class->get_property = vips_object_get_property;
object_class->nickname = "heifload_buffer";
object_class->build = vips_foreign_load_heif_buffer_build;
load_class->is_a_buffer = vips_foreign_load_heif_buffer_is_a;
heif_class->open = vips_foreign_load_heif_buffer_open;
VIPS_ARG_BOXED( class, "buffer", 1,
_( "Buffer" ),
_( "Buffer to load from" ),