From 463058c149cdca7a9dc9b4eea317c9e012907144 Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Tue, 7 Aug 2012 14:10:19 +0100 Subject: [PATCH 1/4] note and use res unit on jpg load/save previously, jpeg save always used pixels/inch and jpeg load converted to vips pixels/mm now on jpg load the image's res unit is recorded in VIPS_META_RESOLUTION_UNIT, and on jpg save the res unit is set from VIPS_META_RESOLUTION_UNIT (or defaults to inches). you can now copy a cm-preferring tiff to a jpg and the unit is preserved --- ChangeLog | 1 + libvips/foreign/jpeg2vips.c | 6 ++++++ libvips/foreign/vips2jpeg.c | 28 +++++++++++++++++++++++++--- 3 files changed, 32 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index 42ca4b7b..60c67162 100644 --- a/ChangeLog +++ b/ChangeLog @@ -6,6 +6,7 @@ - so affinei and affinei_all appear in Python - be more cautious enabling YCbCr mode in tiff write - add "DEPRECATED" flag to arguments +- jpeg load/save note and use the preferred resolution unit 20/7/12 started 7.30.0 - support "rs" mode in vips7 diff --git a/libvips/foreign/jpeg2vips.c b/libvips/foreign/jpeg2vips.c index 6166dad6..9a105d74 100644 --- a/libvips/foreign/jpeg2vips.c +++ b/libvips/foreign/jpeg2vips.c @@ -45,6 +45,8 @@ * - read jfif resolution as well as exif * 19/2/12 * - switch to lazy reading + * 7/8/12 + * - note EXIF resolution unit in VIPS_META_RESOLUTION_UNIT */ /* @@ -493,6 +495,8 @@ set_vips_resolution( VipsImage *im, ExifData *ed ) */ xres /= 25.4; yres /= 25.4; + vips_image_set_string( im, + VIPS_META_RESOLUTION_UNIT, "in" ); break; case 3: @@ -500,6 +504,8 @@ set_vips_resolution( VipsImage *im, ExifData *ed ) */ xres /= 10.0; yres /= 10.0; + vips_image_set_string( im, + VIPS_META_RESOLUTION_UNIT, "cm" ); break; default: diff --git a/libvips/foreign/vips2jpeg.c b/libvips/foreign/vips2jpeg.c index 33f5f49b..06398901 100644 --- a/libvips/foreign/vips2jpeg.c +++ b/libvips/foreign/vips2jpeg.c @@ -48,6 +48,8 @@ * - rebuild exif tags from coded metadata values * 24/11/11 * - turn into a set of write fns ready to be called from a class + * 7/8/12 + * - use VIPS_META_RESOLUTION_UNIT to select resoltuion unit */ /* @@ -345,13 +347,33 @@ static int set_exif_resolution( ExifData *ed, VipsImage *im ) { double xres, yres; + char *p; int unit; - /* Always save as inches - more progs support it for read. + /* Default to inches, more progs support it. */ - xres = im->Xres * 25.4; - yres = im->Yres * 25.4; unit = 2; + if( vips_image_get_typeof( im, VIPS_META_RESOLUTION_UNIT ) && + !vips_image_get_string( im, VIPS_META_RESOLUTION_UNIT, &p ) && + vips_isprefix( "cm", p ) ) + unit = 3; + + switch( unit ) { + case 2: + xres = im->Xres * 25.4; + yres = im->Yres * 25.4; + break; + + case 3: + xres = im->Xres * 10.0; + yres = im->Yres * 10.0; + break; + + default: + vips_warn( "VipsJpeg", + "%s", _( "unknown EXIF resolution unit" ) ); + return; + } if( write_tag( ed, EXIF_TAG_X_RESOLUTION, EXIF_FORMAT_RATIONAL, vips_exif_set_double, (void *) &xres ) || From 1abac4018a0defb13da3098c8debe49a1ecf4b28 Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Fri, 10 Aug 2012 13:54:42 +0100 Subject: [PATCH 2/4] better enum arg error message you now get something like: $ vips tiffsave k2.jpg x.tif --compression poop tiffsave: enum 'VipsForeignTiffCompression' has no member 'poop', should be one of: none, jpeg, deflate, packbits, ccittfax4, lzw --- ChangeLog | 1 + libvips/conversion/sequential.c | 3 +-- libvips/iofuncs/object.c | 27 ++++++++++++++++++++++++--- 3 files changed, 26 insertions(+), 5 deletions(-) diff --git a/ChangeLog b/ChangeLog index 60c67162..02c50963 100644 --- a/ChangeLog +++ b/ChangeLog @@ -7,6 +7,7 @@ - be more cautious enabling YCbCr mode in tiff write - add "DEPRECATED" flag to arguments - jpeg load/save note and use the preferred resolution unit +- better error msgs for enum args 20/7/12 started 7.30.0 - support "rs" mode in vips7 diff --git a/libvips/conversion/sequential.c b/libvips/conversion/sequential.c index f259e0cd..f3cc416d 100644 --- a/libvips/conversion/sequential.c +++ b/libvips/conversion/sequential.c @@ -80,8 +80,7 @@ vips_sequential_generate( VipsRegion *or, */ if( r->top < sequential->y_pos ) { vips_error( "VipsSequential", - _( "non-sequential read --- " - "at position %d in file, but position %d requested" ), + _( "at line %d in file, but line %d requested" ), sequential->y_pos, r->top ); return( -1 ); } diff --git a/libvips/iofuncs/object.c b/libvips/iofuncs/object.c index a9693e14..2c6cf72a 100644 --- a/libvips/iofuncs/object.c +++ b/libvips/iofuncs/object.c @@ -1438,6 +1438,29 @@ vips_object_class_install_argument( VipsObjectClass *object_class, #endif /*DEBUG*/ } +/* Make a bad-enum error. A common and fiddly case. + */ +static void +vips_enum_error( VipsObjectClass *class, GType otype, const char *value ) +{ + GEnumClass *genum = G_ENUM_CLASS( g_type_class_ref( otype ) ); + int i; + char str[1000]; + VipsBuf buf = VIPS_BUF_STATIC( str ); + + /* -1 since we always have a "last" member. + */ + for( i = 0; i < genum->n_values - 1; i++ ) { + if( i > 0 ) + vips_buf_appends( &buf, ", " ); + vips_buf_appends( &buf, genum->values[i].value_nick ); + } + + vips_error( class->nickname, _( "enum '%s' has no member '%s', " + "should be one of: %s" ), + g_type_name( otype ), value, vips_buf_all( &buf ) ); +} + /* Set a named arg from a string. */ int @@ -1578,9 +1601,7 @@ vips_object_set_argument_from_string( VipsObject *object, g_type_class_ref( otype ), value )) ) { if( !(enum_value = g_enum_get_value_by_nick( g_type_class_ref( otype ), value )) ) { - vips_error( class->nickname, - _( "enum '%s' has no member '%s'" ), - g_type_name( otype ), value ); + vips_enum_error( class, otype, value ); return( -1 ); } } From bc736e4f5ccc031969f8a6dd612ec53ef945d369 Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Fri, 10 Aug 2012 15:19:45 +0100 Subject: [PATCH 3/4] better precision for --vips-progress times does 3sf of float time now --- libvips/conversion/sequential.c | 27 ++++++++++++++++++++++++++- libvips/iofuncs/image.c | 5 +++-- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/libvips/conversion/sequential.c b/libvips/conversion/sequential.c index f3cc416d..50853cd1 100644 --- a/libvips/conversion/sequential.c +++ b/libvips/conversion/sequential.c @@ -7,6 +7,8 @@ * - from VipsForeignLoad * 14/7/12 * - support skip forwards as well, so we can do extract/insert + * 10/8/12 + * - add @trace option */ /* @@ -60,6 +62,7 @@ typedef struct _VipsSequential { VipsImage *in; int y_pos; + gboolean trace; } VipsSequential; typedef VipsConversionClass VipsSequentialClass; @@ -74,7 +77,9 @@ vips_sequential_generate( VipsRegion *or, VipsRect *r = &or->valid; VipsRegion *ir = (VipsRegion *) seq; - VIPS_DEBUG_MSG( "vips_sequential_generate %d\n", r->top ); + if( sequential->trace ) + vips_diag( "VipsSequential", + "%d lines, starting at line %d", r->height, r->top ); /* We can't go backwards, but we can skip forwards. */ @@ -106,6 +111,10 @@ vips_sequential_generate( VipsRegion *or, return( -1 ); sequential->y_pos += rect.height; + + if( sequential->trace ) + vips_diag( "VipsSequential", + "skipping %d lines", rect.height ); } g_assert( sequential->y_pos == r->top ); @@ -168,11 +177,19 @@ vips_sequential_class_init( VipsSequentialClass *class ) _( "Input image" ), VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET( VipsSequential, in ) ); + + VIPS_ARG_BOOL( class, "trace", 2, + _( "trace" ), + _( "trace pixel requests" ), + VIPS_ARGUMENT_OPTIONAL_INPUT, + G_STRUCT_OFFSET( VipsSequential, trace ), + TRUE ); } static void vips_sequential_init( VipsSequential *sequential ) { + sequential->trace = FALSE; } /** @@ -181,6 +198,10 @@ vips_sequential_init( VipsSequential *sequential ) * @out: output image * @...: %NULL-terminated list of optional named arguments * + * Optional arguments: + * + * @trace: trace requests + * * This operation behaves rather like vips_copy() between images * @in and @out, except that it checks that pixels are only requested * top-to-bottom. If an out of order request is made, it throws an exception. @@ -188,6 +209,10 @@ vips_sequential_init( VipsSequential *sequential ) * This operation is handy with tilecache for loading file formats which are * strictly top-to-bottom, like PNG. * + * If @trace is true, the operation will print diagnostic messages for each + * block of pixels which are processed. This can help find the cause of + * non-sequential accesses. + * * See also: vips_image_cache(). * * Returns: 0 on success, -1 on error. diff --git a/libvips/iofuncs/image.c b/libvips/iofuncs/image.c index f2920cca..c3039fb9 100644 --- a/libvips/iofuncs/image.c +++ b/libvips/iofuncs/image.c @@ -556,8 +556,9 @@ vips_image_posteval_cb( VipsImage *image, VipsProgress *progress ) { /* Spaces at end help to erase the %complete message we overwrite. */ - printf( _( "%s %s: done in %ds \n" ), - g_get_prgname(), image->filename, progress->run ); + printf( _( "%s %s: done in %.3gs \n" ), + g_get_prgname(), image->filename, + g_timer_elapsed( progress->start, NULL ) ); return( 0 ); } From 368d3c2b8f8c63d24306f68ceee93ca279e2aa02 Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Tue, 14 Aug 2012 11:00:23 +0100 Subject: [PATCH 4/4] test for gtk-doc in bootstrap --- .gitignore | 1 + ChangeLog | 1 + TODO | 7 ++ bootstrap.sh | 8 ++- gtk-doc.make | 177 --------------------------------------------------- 5 files changed, 16 insertions(+), 178 deletions(-) delete mode 100644 gtk-doc.make diff --git a/.gitignore b/.gitignore index 2df3bc79..b29fab20 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ vips-*.tar.gz +gtk-doc.make libvips-scan libvips-scan.c Makefile.in diff --git a/ChangeLog b/ChangeLog index 02c50963..3f327877 100644 --- a/ChangeLog +++ b/ChangeLog @@ -8,6 +8,7 @@ - add "DEPRECATED" flag to arguments - jpeg load/save note and use the preferred resolution unit - better error msgs for enum args +- test for gtk-doc in bootstrap 20/7/12 started 7.30.0 - support "rs" mode in vips7 diff --git a/TODO b/TODO index e4e24aca..b5188656 100644 --- a/TODO +++ b/TODO @@ -1,3 +1,10 @@ +carrierwave-vips-benchmark seems to fail for 200x200 images with a non-seq +error + +see also the gist comparing oil and vips + +stop compile warnings for production build + blocking bugs ============= diff --git a/bootstrap.sh b/bootstrap.sh index 547924fb..0be480be 100755 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -28,7 +28,13 @@ cp $ACDIR/lcmessage.m4 m4 cp $ACDIR/progtest.m4 m4 cp $ACDIR/introspection.m4 m4 -gtkdocize --copy --docdir doc/reference --flavour no-tmpl || exit 1 +# some systems struggle to install gtk-doc ... test for it first +if gtkdocize --version >/dev/null 2>&1; then + echo setting up gtk-doc ... + gtkdocize --copy --docdir doc/reference --flavour no-tmpl +else + echo no gtk-doc found -- disabling +fi # some systems need libtoolize, some glibtoolize ... how annoying echo testing for glibtoolize ... diff --git a/gtk-doc.make b/gtk-doc.make deleted file mode 100644 index ed29f94d..00000000 --- a/gtk-doc.make +++ /dev/null @@ -1,177 +0,0 @@ -# -*- mode: makefile -*- - -#################################### -# Everything below here is generic # -#################################### - -if GTK_DOC_USE_LIBTOOL -GTKDOC_CC = $(LIBTOOL) --mode=compile $(CC) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -GTKDOC_LD = $(LIBTOOL) --mode=link $(CC) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -GTKDOC_RUN = $(LIBTOOL) --mode=execute -else -GTKDOC_CC = $(CC) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -GTKDOC_LD = $(CC) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -GTKDOC_RUN = sh -c -endif - -# We set GPATH here; this gives us semantics for GNU make -# which are more like other make's VPATH, when it comes to -# whether a source that is a target of one rule is then -# searched for in VPATH/GPATH. -# -GPATH = $(srcdir) - -TARGET_DIR=$(HTML_DIR)/$(DOC_MODULE) - -EXTRA_DIST = \ - $(content_files) \ - $(HTML_IMAGES) \ - $(DOC_MAIN_SGML_FILE) \ - $(DOC_MODULE)-sections.txt \ - $(DOC_MODULE)-overrides.txt - -DOC_STAMPS=scan-build.stamp sgml-build.stamp html-build.stamp \ - $(srcdir)/sgml.stamp $(srcdir)/html.stamp - -SCANOBJ_FILES = \ - $(DOC_MODULE).args \ - $(DOC_MODULE).hierarchy \ - $(DOC_MODULE).interfaces \ - $(DOC_MODULE).prerequisites \ - $(DOC_MODULE).signals - -REPORT_FILES = \ - $(DOC_MODULE)-undocumented.txt \ - $(DOC_MODULE)-undeclared.txt \ - $(DOC_MODULE)-unused.txt - -CLEANFILES = $(SCANOBJ_FILES) $(REPORT_FILES) $(DOC_STAMPS) - -if ENABLE_GTK_DOC -all-local: html-build.stamp -else -all-local: -endif - -docs: html-build.stamp - -$(REPORT_FILES): sgml-build.stamp - -#### scan #### - -scan-build.stamp: $(HFILE_GLOB) $(CFILE_GLOB) - @echo 'gtk-doc: Scanning header files' - @-chmod -R u+w $(srcdir) - cd $(srcdir) && \ - gtkdoc-scan --module=$(DOC_MODULE) --source-dir=$(DOC_SOURCE_DIR) --ignore-headers="$(IGNORE_HFILES)" $(SCAN_OPTIONS) $(EXTRA_HFILES) - if grep -l '^..*$$' $(srcdir)/$(DOC_MODULE).types > /dev/null 2>&1 ; then \ - CC="$(GTKDOC_CC)" LD="$(GTKDOC_LD)" RUN="$(GTKDOC_RUN)" CFLAGS="$(GTKDOC_CFLAGS) $(CFLAGS)" LDFLAGS="$(GTKDOC_LIBS) $(LDFLAGS)" gtkdoc-scangobj $(SCANGOBJ_OPTIONS) --module=$(DOC_MODULE) --output-dir=$(srcdir) ; \ - else \ - cd $(srcdir) ; \ - for i in $(SCANOBJ_FILES) ; do \ - test -f $$i || touch $$i ; \ - done \ - fi - touch scan-build.stamp - -$(DOC_MODULE)-decl.txt $(SCANOBJ_FILES) $(DOC_MODULE)-sections.txt $(DOC_MODULE)-overrides.txt: scan-build.stamp - @true - -#### xml #### - -sgml-build.stamp: $(DOC_MODULE)-decl.txt $(SCANOBJ_FILES) $(DOC_MODULE)-sections.txt $(DOC_MODULE)-overrides.txt $(expand_content_files) - @echo 'gtk-doc: Building XML' - @-chmod -R u+w $(srcdir) - cd $(srcdir) && \ - gtkdoc-mkdb --module=$(DOC_MODULE) --source-dir=$(DOC_SOURCE_DIR) --output-format=xml --expand-content-files="$(expand_content_files)" --main-sgml-file=$(DOC_MAIN_SGML_FILE) $(MKDB_OPTIONS) - touch sgml-build.stamp - -sgml.stamp: sgml-build.stamp - @true - -#### html #### - -html-build.stamp: sgml.stamp $(DOC_MAIN_SGML_FILE) $(content_files) - @echo 'gtk-doc: Building HTML' - @-chmod -R u+w $(srcdir) - rm -rf $(srcdir)/html - mkdir $(srcdir)/html - mkhtml_options=""; \ - gtkdoc-mkhtml 2>&1 --help | grep >/dev/null "\-\-path"; \ - if test "$(?)" = "0"; then \ - mkhtml_options=--path="$(srcdir)"; \ - fi - cd $(srcdir)/html && gtkdoc-mkhtml $(mkhtml_options) $(MKHTML_OPTIONS) $(DOC_MODULE) ../$(DOC_MAIN_SGML_FILE) - test "x$(HTML_IMAGES)" = "x" || ( cd $(srcdir) && cp $(HTML_IMAGES) html ) - @echo 'gtk-doc: Fixing cross-references' - cd $(srcdir) && gtkdoc-fixxref --module-dir=html --html-dir=$(HTML_DIR) $(FIXXREF_OPTIONS) - touch html-build.stamp - -############## - -clean-local: - rm -f *~ *.bak - rm -rf .libs - -distclean-local: - cd $(srcdir) && \ - rm -rf xml $(REPORT_FILES) \ - $(DOC_MODULE)-decl-list.txt $(DOC_MODULE)-decl.txt - -maintainer-clean-local: clean - cd $(srcdir) && rm -rf html - -install-data-local: - installfiles=`echo $(srcdir)/html/*`; \ - if test "$$installfiles" = '$(srcdir)/html/*'; \ - then echo '-- Nothing to install' ; \ - else \ - if test -n "$(DOC_MODULE_VERSION)"; then \ - installdir="$(DESTDIR)$(TARGET_DIR)-$(DOC_MODULE_VERSION)"; \ - else \ - installdir="$(DESTDIR)$(TARGET_DIR)"; \ - fi; \ - $(mkinstalldirs) $${installdir} ; \ - for i in $$installfiles; do \ - echo '-- Installing '$$i ; \ - $(INSTALL_DATA) $$i $${installdir}; \ - done; \ - if test -n "$(DOC_MODULE_VERSION)"; then \ - mv -f $${installdir}/$(DOC_MODULE).devhelp2 \ - $${installdir}/$(DOC_MODULE)-$(DOC_MODULE_VERSION).devhelp2; \ - mv -f $${installdir}/$(DOC_MODULE).devhelp \ - $${installdir}/$(DOC_MODULE)-$(DOC_MODULE_VERSION).devhelp; \ - fi; \ - ! which gtkdoc-rebase >/dev/null 2>&1 || \ - gtkdoc-rebase --relative --dest-dir=$(DESTDIR) --html-dir=$${installdir} ; \ - fi - -uninstall-local: - if test -n "$(DOC_MODULE_VERSION)"; then \ - installdir="$(DESTDIR)$(TARGET_DIR)-$(DOC_MODULE_VERSION)"; \ - else \ - installdir="$(DESTDIR)$(TARGET_DIR)"; \ - fi; \ - rm -rf $${installdir} - -# -# Require gtk-doc when making dist -# -if ENABLE_GTK_DOC -dist-check-gtkdoc: -else -dist-check-gtkdoc: - @echo "*** gtk-doc must be installed and enabled in order to make dist" - @false -endif - -dist-hook: dist-check-gtkdoc dist-hook-local - mkdir $(distdir)/html - cp $(srcdir)/html/* $(distdir)/html - -cp $(srcdir)/$(DOC_MODULE).types $(distdir)/ - -cp $(srcdir)/$(DOC_MODULE)-sections.txt $(distdir)/ - cd $(distdir) && rm -f $(DISTCLEANFILES) - ! which gtkdoc-rebase >/dev/null 2>&1 || \ - gtkdoc-rebase --online --relative --html-dir=$(distdir)/html - -.PHONY : dist-hook-local docs