diff --git a/ChangeLog.txt b/ChangeLog.txt index 456c5108d..8eb068dc3 100755 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -111,4 +111,5 @@ and command can be executed numerous times. Add a new verify command that will write to a register, read from register, and verify that returned value. - * apps/graphics/tiff: Add a library that can be used to create TIFF files. \ No newline at end of file + * apps/graphics/tiff: Add a library that can be used to create TIFF files. + * apps/examples/tiff: Add a unit test for the TIFF file creation logic diff --git a/examples/README.txt b/examples/README.txt index 027b0a669..5252a40c4 100644 --- a/examples/README.txt +++ b/examples/README.txt @@ -735,10 +735,26 @@ examples/tiff This is a simple unit test for the TIFF creation library at apps/graphic/tiff. It is configured to work in the Linux user-mode simulation and has not been - tested in any other environment. + tested in any other environment. Since the example also depends on some + other logic to mount a file system, currently it will only work as an NSH + built-on, i.e., if the following is defined: - At a miniumum, you would probably have to change the hard-coded pathes to - the TIFF files defined in the example to run in an embedded platform. + CONFIG_NSH_BUILTIN_APPS=y + CONFIG_EXAMPLES_TIFF_BUILTIN=y + + At a miniumum, to run in an embedded environment, you will probably have to + change the configured paths to the TIFF files defined in the example. + + CONFIG_EXAMPLES_TIFF_OUTFILE - Name of the resulting TIFF file. Default is + "/tmp/result.tif" + CONFIG_EXAMPLES_TIFF_TMPFILE1/2 - Names of two temporaries files that + will be used in the file creation. Defaults are "/tmp/tmpfile1.dat" and + "/tmp/tmpfile2.dat" + + The following must also be defined in your appconfig file: + + CONFIGURED_APPS += examples/tiff + CONFIGURED_APPS += graphics/tiff examples/udp ^^^^^^^^^^^^ diff --git a/examples/tiff/Makefile b/examples/tiff/Makefile index bbe168683..045508d14 100644 --- a/examples/tiff/Makefile +++ b/examples/tiff/Makefile @@ -82,7 +82,7 @@ $(COBJS): %$(OBJEXT): %.c @touch .built .context: -ifeq ($(CONFIG_EXAMPLES_USBSTRG_BUILTIN),y) +ifeq ($(CONFIG_EXAMPLES_TIFF_BUILTIN),y) $(call REGISTER,$(APPNAME),$(PRIORITY),$(STACKSIZE),$(APPNAME)_main) @touch $@ endif diff --git a/examples/tiff/tiff_main.c b/examples/tiff/tiff_main.c index 279c9324d..0c8f2bb94 100644 --- a/examples/tiff/tiff_main.c +++ b/examples/tiff/tiff_main.c @@ -48,6 +48,34 @@ /**************************************************************************** * Pre-Processor Definitions ****************************************************************************/ +/* Configuration ************************************************************/ +/* This is a simple unit test for the TIFF creation library at apps/graphic/tiff. + * It is configured to work in the Linux user-mode simulation and has not been + * tested in any other environment. Since the example also depends on some + * other logic to mount a file system, currently it will only work as an NSH + * built-on, i.e., if the following is defined: + * + * CONFIG_NSH_BUILTIN_APPS=y + * CONFIG_EXAMPLES_TIFF_BUILTIN=y + * + * Other configuration options: + * + * CONFIG_EXAMPLES_TIFF_OUTFILE - Name of the resulting TIFF file + * CONFIG_EXAMPLES_TIFF_TMPFILE1/2 - Names of two temporaries files that + * will be used in the file creation. + */ + +#ifndef CONFIG_EXAMPLES_TIFF_OUTFILE +# define CONFIG_EXAMPLES_TIFF_OUTFILE "/tmp/result.tif" +#endif + +#ifndef CONFIG_EXAMPLES_TIFF_TMPFILE1 +# define CONFIG_EXAMPLES_TIFF_TMPFILE1 "/tmp/tmpfile1.dat" +#endif + +#ifndef CONFIG_EXAMPLES_TIFF_TMPFILE2 +# define CONFIG_EXAMPLES_TIFF_TMPFILE2 "/tmp/tmpfile2.dat" +#endif /**************************************************************************** * Private Types @@ -95,9 +123,9 @@ int MAIN_NAME(int argc, char *argv[]) /* Configure the interface structure */ memset(&info, 0, sizeof(struct tiff_info_s)); - info.outfile = "result.tif"; - info.tmpfile1 = "tmpfile1.dat"; - info.tmpfile2 = "tmpfile2.dat"; + info.outfile = CONFIG_EXAMPLES_TIFF_OUTFILE; + info.tmpfile1 = CONFIG_EXAMPLES_TIFF_TMPFILE1; + info.tmpfile2 = CONFIG_EXAMPLES_TIFF_TMPFILE2; info.colorfmt = FB_FMT_RGB24; info.rps = 1; info.imgwidth = 256; @@ -118,6 +146,7 @@ int MAIN_NAME(int argc, char *argv[]) for (green = 0, ptr = strip; green < 256; green++) { + ptr = strip; for (blue = 0; blue < 256; blue++) { *ptr++ = (green + blue) >> 1; @@ -138,7 +167,7 @@ int MAIN_NAME(int argc, char *argv[]) ret = tiff_finalize(&info); if (ret < 0) { - printf("tiff_initialize() failed: %d\n", ret); + printf("tiff_finalize() failed: %d\n", ret); exit(1); } return 0; diff --git a/graphics/tiff/tiff_addstrip.c b/graphics/tiff/tiff_addstrip.c index 165eec5ae..fa2a50e72 100644 --- a/graphics/tiff/tiff_addstrip.c +++ b/graphics/tiff/tiff_addstrip.c @@ -144,7 +144,9 @@ int tiff_convstrip(FAR struct tiff_info_s *info, FAR const uint8_t *strip) /* Flush any buffer data to tmpfile2 */ ret = tiff_write(info->tmp2fd, info->iobuffer, nbytes); - DEBUGASSERT(ntotal == info->bps); +#ifdef CONFIG_DEBUG_GRAPHICS + ASSERT(ntotal == info->bps); +#endif return ret; } diff --git a/graphics/tiff/tiff_finalize.c b/graphics/tiff/tiff_finalize.c index 18aac9765..9526121a5 100644 --- a/graphics/tiff/tiff_finalize.c +++ b/graphics/tiff/tiff_finalize.c @@ -88,18 +88,22 @@ static int tiff_readifdentry(int fd, off_t offset, FAR struct tiff_ifdentry_s *ifdentry) { off_t newoffs; + ssize_t nbytes; /* Seek to the read position */ - newoffs = lseek(fd, SEEK_SET, offset); + newoffs = lseek(fd, offset, SEEK_SET); if (newoffs == (off_t)-1) { return -errno; } - /* Then read the IFD entry */ + /* Then read the IFD entry. Anything returned by tiff_read other than the + * size of the IFD entry would be an error. + */ - return tiff_read(fd, ifdentry, SIZEOF_IFD_ENTRY); + nbytes = tiff_read(fd, ifdentry, SIZEOF_IFD_ENTRY); + return nbytes == SIZEOF_IFD_ENTRY ? OK : -ENOSPC; } /**************************************************************************** @@ -125,7 +129,7 @@ static int tiff_writeifdentry(int fd, off_t offset, /* Seek to the write position */ - newoffs = lseek(fd, SEEK_SET, offset); + newoffs = lseek(fd, offset, SEEK_SET); if (newoffs == (off_t)-1) { return -errno; @@ -247,9 +251,9 @@ int tiff_finalize(FAR struct tiff_info_s *info) goto errout; } - /* Seek to the beginning of tmpfile2 */ + /* Revind to the beginning of tmpfile1 */ - offset = lseek(info->tmp2fd, SEEK_SET, 0); + offset = lseek(info->tmp1fd, 0, SEEK_SET); if (offset == (off_t)-1) { ret = -errno; @@ -258,14 +262,14 @@ int tiff_finalize(FAR struct tiff_info_s *info) /* Seek to the end of the outfile */ - ret = lseek(info->outfd, SEEK_END, 0); + ret = lseek(info->outfd, 0, SEEK_END); if (offset == (off_t)-1) { ret = -errno; goto errout; } - /* Now read strip offset data from tmpfile2, update the offsets, and write + /* Now read strip offset data from tmpfile1, update the offsets, and write * the updated offsets to the outfile. */ @@ -277,6 +281,7 @@ int tiff_finalize(FAR struct tiff_info_s *info) for (i = 0; i < info->nstrips; ) { size_t noffsets; + ssize_t nbytes; /* Read a group of up to 32-bit values */ @@ -286,8 +291,13 @@ int tiff_finalize(FAR struct tiff_info_s *info) noffsets = maxoffsets; } - ret = tiff_read(info->tmp1fd, info->iobuffer, noffsets << 2); - if (ret <= 0) + nbytes = tiff_read(info->tmp1fd, info->iobuffer, noffsets << 2); + + /* If an error occurs or we fail to read exactly this number of + * bytes, then something bad happened. + */ + + if (nbytes != noffsets << 2) { goto errout; } @@ -305,7 +315,7 @@ int tiff_finalize(FAR struct tiff_info_s *info) /* Then write the corrected offsets to the outfile */ - ret = tiff_write(info->outfd, info->iobuffer, noffsets << 2); + ret = tiff_write(info->outfd, info->iobuffer, nbytes); if (ret < 0) { goto errout; @@ -315,14 +325,22 @@ int tiff_finalize(FAR struct tiff_info_s *info) i += noffsets; #ifdef CONFIG_DEBUG_GRAPHICS - total += noffsets << 2; + total += nbytes; #endif - } #ifdef CONFIG_DEBUG_GRAPHICS ASSERT(total == info->tmp1size); #endif + /* Rewind to the beginning of tmpfile2 */ + + offset = lseek(info->tmp2fd, 0, SEEK_SET); + if (offset == (off_t)-1) + { + ret = -errno; + goto errout; + } + /* Finally, copy the tmpfile2 to the end of the outfile */ #ifdef CONFIG_DEBUG_GRAPHICS @@ -335,12 +353,15 @@ int tiff_finalize(FAR struct tiff_info_s *info) /* Read a block of data from tmpfile2 */ nbytes = tiff_read(info->tmp2fd, info->iobuffer, info->iosize); + + /* Check for tead errors and for end-of-file */ + if (nbytes < 0) { ret = (int)nbytes; goto errout; } - else if (ret == 0) + else if (nbytes == 0) { break; } diff --git a/graphics/tiff/tiff_initialize.c b/graphics/tiff/tiff_initialize.c index bc275ebdf..a7194d552 100644 --- a/graphics/tiff/tiff_initialize.c +++ b/graphics/tiff/tiff_initialize.c @@ -635,11 +635,11 @@ int tiff_initialize(FAR struct tiff_info_s *info) if (IMGFLAGS_ISRGB(info->imgflags)) { - val16 = TAG_PMI_BLACK; + val16 = TAG_PMI_RGB; } else { - val16 = TAG_PMI_RGB; + val16 = TAG_PMI_BLACK; } ret = tiff_putifdentry16(info, IFD_TAG_PMI, IFD_FIELD_SHORT, 1, val16); @@ -750,7 +750,6 @@ int tiff_initialize(FAR struct tiff_info_s *info) * RGB: Offset 168 Count, Hard-coded "NuttX" */ - tiff_checkoffs(offset, info->filefmt->sbcifdoffset); ret = tiff_putifdentry(info, IFD_TAG_SOFTWARE, IFD_FIELD_ASCII, TIFF_SOFTWARE_STRLEN, info->filefmt->swoffset); if (ret < 0) { @@ -765,7 +764,6 @@ int tiff_initialize(FAR struct tiff_info_s *info) * RGB: Offset 180 Count, Format "YYYY:MM:DD HH:MM:SS" */ - tiff_checkoffs(offset, info->filefmt->sbcifdoffset); ret = tiff_putifdentry(info, IFD_TAG_DATETIME, IFD_FIELD_ASCII, TIFF_DATETIME_STRLEN, info->filefmt->dateoffset); if (ret < 0) { @@ -830,6 +828,24 @@ int tiff_initialize(FAR struct tiff_info_s *info) } tiff_offset(offset, 8); + /* Write RGB BitsPerSample Data: + * + * Bi-level Images: N/A + * Greyscale: N/A + * RGB: Offset 212 BitsPerSample (8,8,8) + * Offset 218 [2 bytes padding] + */ + + if (IMGFLAGS_ISRGB(info->imgflags)) + { + tiff_checkoffs(offset, TIFF_RGB_BPSOFFSET); + tiff_putint16(info->outfd, 8); + tiff_putint16(info->outfd, 8); + tiff_putint16(info->outfd, 8); + tiff_putint16(info->outfd, 0); + tiff_offset(offset, 8); + } + /* Write the Software string: * * @@ -838,7 +854,7 @@ int tiff_initialize(FAR struct tiff_info_s *info) * RGB: Offset 220, Hard-coded "NuttX" */ - tiff_checkoffs(offset, info->filefmt->xresoffset); + tiff_checkoffs(offset, info->filefmt->swoffset); ret = tiff_putstring(info->outfd, TIFF_SOFTWARE_STRING, TIFF_SOFTWARE_STRLEN); if (ret < 0) { diff --git a/graphics/tiff/tiff_internal.h b/graphics/tiff/tiff_internal.h index bfc2a0253..5596122fa 100644 --- a/graphics/tiff/tiff_internal.h +++ b/graphics/tiff/tiff_internal.h @@ -108,11 +108,12 @@ extern "C" { * count - The number of bytes to write * * Returned Value: - * Zero (OK) on success. A negated errno value on failure. + * On success, then number of bytes read; Zero is returned on EOF. + * Otherwise, a negated errno value on failure. * ****************************************************************************/ -EXTERN int tiff_read(int fd, FAR void *buffer, size_t count); +EXTERN ssize_t tiff_read(int fd, FAR void *buffer, size_t count); /**************************************************************************** * Name: tiff_write diff --git a/graphics/tiff/tiff_utils.c b/graphics/tiff/tiff_utils.c index 264219520..66599db8b 100644 --- a/graphics/tiff/tiff_utils.c +++ b/graphics/tiff/tiff_utils.c @@ -144,12 +144,14 @@ uint32_t tiff_get32(FAR uint8_t *src) * count - The number of bytes to write * * Returned Value: - * Zero (OK) on success. A negated errno value on failure. + * On success, then number of bytes read; Zero is returned on EOF. + * Otherwise, a negated errno value on failure. * ****************************************************************************/ -int tiff_read(int fd, FAR void *buffer, size_t count) +ssize_t tiff_read(int fd, FAR void *buffer, size_t count) { + size_t ntotal; ssize_t nbytes; int errval; @@ -157,11 +159,14 @@ int tiff_read(int fd, FAR void *buffer, size_t count) * or (2) until an irrecoverble error occurs. */ - while (count > 0) + for (ntotal = 0; ntotal < count; ) { - /* Do the read */ + /* Do the read. The number of bytes left to read is the total + * requested size (count) minus the amount that we have alread read + * (ntotal). + */ - nbytes = read(fd, buffer, count); + nbytes = read(fd, buffer, count-ntotal); /* Check for an error */ @@ -180,17 +185,26 @@ int tiff_read(int fd, FAR void *buffer, size_t count) } } - /* What if read returns some number of bytes other than the requested number? */ + /* Zero is a special case and means that the end of file was encountered. */ + + else if (nbytes == 0) + { + break; + } + + /* What if read returns some number of bytes other than the requested number? + * This probably means that the end-of-file will be encountered the next time + * that we call read(). + */ else { - DEBUGASSERT(nbytes < count && nbytes != 0); buffer += nbytes; - count -= nbytes; + ntotal += nbytes; } } - return OK; + return ntotal; } /**************************************************************************** @@ -245,7 +259,7 @@ int tiff_write(int fd, FAR const void *buffer, size_t count) else { - DEBUGASSERT(nbytes < count && nbytes != 0); + DEBUGASSERT(nbytes == count); buffer += nbytes; count -= nbytes; }