From: Dan Fandrich Date: Fri, 22 Feb 2019 15:17:01 +0000 (+0100) Subject: Added test-extract.c and a new regression test extract-parse.sh. X-Git-Tag: libexif-0_6_22-release~63 X-Git-Url: http://review.tizen.org/git/?p=platform%2Fupstream%2Flibexif.git;a=commitdiff_plain;h=a37d5d3b613cfbcc9d7d28529f70e8b44041b3a1 Added test-extract.c and a new regression test extract-parse.sh. This extracts the EXIF tags from an image then compares the parsed value of the extracted tags with those of the original file. This ensures that the tags are written properly, without change in tag data. The MakerNote tag sometimes has a harmless, slight difference in size because of padding being removed. However, in developing this test, I found that the Olympus variant 4 MakerNote has a huge size difference. This might be harmless (there might just be a lot of padding removed) but it's also possible that these MakerNotes aren't being properly parsed. This discrepancy should be investigated. The exif_data_save_data() function is also returning some JPEG markers at the end of the buffer which I wasn't expecting. This also should be investigated. The test is enabled anyway in the meantime to reduce the chance of regressions in the remaining tags. --- diff --git a/test/Makefile.am b/test/Makefile.am index 4083e50..04ad079 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -12,19 +12,19 @@ SUBDIRS = nls # here yet. TESTS = test-mem test-value test-integers test-parse test-tagtable test-sorted \ - test-fuzzer parse-regression.sh swap-byte-order.sh + test-fuzzer parse-regression.sh swap-byte-order.sh extract-parse.sh if USE_FAILMALLOC TESTS += check-failmalloc.sh endif check_PROGRAMS = test-mem test-mnote test-value test-integers test-parse \ - test-tagtable test-sorted test-fuzzer + test-tagtable test-sorted test-fuzzer test-extract LDADD = $(top_builddir)/libexif/libexif.la $(LTLIBINTL) EXTRA_DIST = check-vars.sh.in parse-regression.sh swap-byte-order.sh \ - check-failmalloc.sh \ + extract-parse.sh check-failmalloc.sh \ testdata/canon_makernote_variant_1.jpg \ testdata/canon_makernote_variant_1.jpg.parsed \ testdata/fuji_makernote_variant_1.jpg \ diff --git a/test/extract-parse.sh b/test/extract-parse.sh new file mode 100755 index 0000000..3bcfe33 --- /dev/null +++ b/test/extract-parse.sh @@ -0,0 +1,39 @@ +#!/bin/sh +# Compares the parsed EXIF data extracted from test images with the parsed EXIF +# data in the original images. This tests that the tag parsing and writing +# round-trip produces an EXIF structure with the same meaning as the original. +srcdir="${srcdir:-.}" +TMPORIGINAL="$(mktemp)" +TMPEXTRACTED="$(mktemp)" +TMPDATA="$(mktemp)" +trap 'rm -f "${TMPORIGINAL}" "${TMPEXTRACTED}" "${TMPDATA}"' 0 + +# Remove the file name, which is a harmless difference between the two outputs. +# Also delete the size of the MakerNote. Since the MakerNote is parsed +# internally and rewritten, it can sometimes have slightly different padding +# and therefore slightly different size, which is a semantically meaningless +# difference. +# FIXME: Not all MakerNote differences are harmless. For example, +# olympus_makernote_variant_4.jpg has a huge size difference, probably because +# of a parsing bug in libexif. This should be investigated. Ideally, this would +# ignore small differences in size but trigger on larger differences. +parse_canonicalize () { + sed \ + -e '/^File /d' \ + -e '/MakerNote (Undefined)$/{N;N;d}' +} + +# Ensure that names are untranslated +LANG= +LANGUAGE= +LC_ALL=C +export LANG LANGUAGE LC_ALL +for fn in "${srcdir}"/testdata/*.jpg ; do + ./test-parse "${fn}" | parse_canonicalize > "${TMPORIGINAL}" + ./test-extract -o "${TMPDATA}" "${fn}" + ./test-parse "${TMPDATA}" | parse_canonicalize > "${TMPEXTRACTED}" + if ! diff "${TMPORIGINAL}" "${TMPEXTRACTED}"; then + echo Error parsing "$fn" + exit 1 + fi +done diff --git a/test/test-extract.c b/test/test-extract.c new file mode 100644 index 0000000..0c82d73 --- /dev/null +++ b/test/test-extract.c @@ -0,0 +1,102 @@ +/** \file test-extract.c + * \brief Extract EXIF data from a file and write it to another file. + * + * Copyright (C) 2019 Dan Fandrich + * + * This library 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 library 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 library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + */ + +#include "libexif/exif-data.h" + +#include +#include +#include + + +static const unsigned char header[4] = {'\xff', '\xd8', '\xff', '\xe1'}; + +int main(const int argc, const char *argv[]) +{ + int first = 1; + const char *fn = "input.jpg"; + const char *outfn = "output.exif"; + ExifData *d; + unsigned char *buf; + unsigned int len; + FILE *f; + unsigned char lenbuf[2]; + + if (argc > 1 && !strcmp(argv[1], "-o")) { + outfn = argv[2]; + first += 2; + } + if (argc > first) { + fn = argv[first]; + ++first; + } + if (argc > first) { + fprintf (stderr, "Too many arguments\n"); + return 1; + } + + d = exif_data_new_from_file(fn); + if (!d) { + fprintf (stderr, "Could not load data from '%s'!\n", fn); + return 1; + } + + exif_data_save_data(d, &buf, &len); + exif_data_unref(d); + + if (!buf) { + fprintf (stderr, "Could not extract EXIF data!\n"); + return 2; + } + + f = fopen(outfn, "wb"); + if (!f) { + fprintf (stderr, "Could not open '%s' for writing!\n", outfn); + return 1; + } + /* Write EXIF with headers and length. */ + if (fwrite(header, 1, sizeof(header), f) != sizeof(header)) { + fprintf (stderr, "Could not write to '%s'!\n", outfn); + return 3; + } + /* + * FIXME: The buffer from exif_data_save_data() seems to contain extra 0xffd8 + * 0xffd9 JPEG markers at the end that I wasn't expecting, making the length + * seem too long. Should those markers really be included? + */ + exif_set_short(lenbuf, EXIF_BYTE_ORDER_MOTOROLA, len); + if (fwrite(lenbuf, 1, 2, f) != 2) { + fprintf (stderr, "Could not write to '%s'!\n", outfn); + return 3; + } + if (fwrite(buf, 1, len, f) != len) { + fprintf (stderr, "Could not write to '%s'!\n", outfn); + return 3; + } + if (fclose(f) != 0) { + fprintf (stderr, "Could not close '%s'!\n", outfn); + return 3; + } + free(buf); + fprintf (stderr, "Wrote EXIF data to '%s'\n", outfn); + + return 0; +}