mirror of
https://github.com/lucaspalomodevelop/meshlab.git
synced 2026-03-13 08:09:39 +00:00
libjhead removed
This commit is contained in:
parent
5937c52762
commit
dac26808bd
@ -17,93 +17,95 @@ win32-g++:DLLDESTDIR = $$MESHLAB_DISTRIB_DIRECTORY/lib
|
||||
linux:CONFIG += dll
|
||||
|
||||
INCLUDEPATH *= \
|
||||
../.. \
|
||||
$$VCGDIR \
|
||||
$$EIGENDIR \
|
||||
$$EXIF_DIR
|
||||
../.. \
|
||||
$$$$MESHLAB_EXTERNAL_DIRECTORY/easyexif \
|
||||
$$VCGDIR \
|
||||
$$EIGENDIR \
|
||||
$$EXIF_DIR
|
||||
|
||||
!CONFIG(system_glew) {
|
||||
INCLUDEPATH *= $$GLEWDIR/include
|
||||
GLEWCODE = $$GLEWDIR/src/glew.c
|
||||
INCLUDEPATH *= $$GLEWDIR/include
|
||||
GLEWCODE = $$GLEWDIR/src/glew.c
|
||||
}
|
||||
|
||||
!CONFIG(system_glew) {
|
||||
SOURCES += $$GLEWCODE
|
||||
DEFINES += GLEW_STATIC
|
||||
SOURCES += $$GLEWCODE
|
||||
DEFINES += GLEW_STATIC
|
||||
}
|
||||
|
||||
# defining meshlab version
|
||||
exists(../../ML_VERSION){
|
||||
MESHLAB_VERSION = $$cat(../../ML_VERSION)
|
||||
message(MeshLab Version: $$MESHLAB_VERSION)
|
||||
DEFINES += "MESHLAB_VERSION=$$MESHLAB_VERSION"
|
||||
MESHLAB_VERSION = $$cat(../../ML_VERSION)
|
||||
message(MeshLab Version: $$MESHLAB_VERSION)
|
||||
DEFINES += "MESHLAB_VERSION=$$MESHLAB_VERSION"
|
||||
}
|
||||
|
||||
# Input
|
||||
HEADERS += \
|
||||
GLExtensionsManager.h \
|
||||
filter_parameter/rich_parameter_list.h \
|
||||
filter_parameter/value.h \
|
||||
filter_parameter/rich_parameter.h \
|
||||
filterscript.h \
|
||||
GLLogStream.h \
|
||||
interfaces/decorate_plugin_interface.h \
|
||||
interfaces/edit_plugin_interface.h \
|
||||
interfaces/filter_plugin_interface.h \
|
||||
interfaces/io_plugin_interface.h \
|
||||
interfaces/mainwindow_interface.h \
|
||||
interfaces/plugin_interface.h \
|
||||
interfaces/render_plugin_interface.h \
|
||||
ml_mesh_type.h \
|
||||
meshmodel.h \
|
||||
pluginmanager.h \
|
||||
mlexception.h \
|
||||
mlapplication.h \
|
||||
meshlabdocumentxml.h \
|
||||
ml_shared_data_context.h \
|
||||
ml_selection_buffers.h \
|
||||
meshlabdocumentxml.h
|
||||
GLExtensionsManager.h \
|
||||
filter_parameter/rich_parameter_list.h \
|
||||
filter_parameter/value.h \
|
||||
filter_parameter/rich_parameter.h \
|
||||
filterscript.h \
|
||||
GLLogStream.h \
|
||||
interfaces/decorate_plugin_interface.h \
|
||||
interfaces/edit_plugin_interface.h \
|
||||
interfaces/filter_plugin_interface.h \
|
||||
interfaces/io_plugin_interface.h \
|
||||
interfaces/mainwindow_interface.h \
|
||||
interfaces/plugin_interface.h \
|
||||
interfaces/render_plugin_interface.h \
|
||||
ml_mesh_type.h \
|
||||
meshmodel.h \
|
||||
pluginmanager.h \
|
||||
mlexception.h \
|
||||
mlapplication.h \
|
||||
meshlabdocumentxml.h \
|
||||
ml_shared_data_context.h \
|
||||
ml_selection_buffers.h \
|
||||
meshlabdocumentxml.h
|
||||
|
||||
SOURCES += \
|
||||
GLExtensionsManager.cpp \
|
||||
filter_parameter/rich_parameter.cpp \
|
||||
filter_parameter/rich_parameter_list.cpp \
|
||||
filter_parameter/value.cpp \
|
||||
filterscript.cpp \
|
||||
GLLogStream.cpp \
|
||||
interfaces/decorate_plugin_interface.cpp \
|
||||
interfaces/filter_plugin_interface.cpp \
|
||||
interfaces/plugin_interface.cpp \
|
||||
meshmodel.cpp \
|
||||
pluginmanager.cpp \
|
||||
mlapplication.cpp \
|
||||
searcher.cpp \
|
||||
meshlabdocumentxml.cpp \
|
||||
meshlabdocumentbundler.cpp \
|
||||
ml_shared_data_context.cpp \
|
||||
ml_selection_buffers.cpp
|
||||
GLExtensionsManager.cpp \
|
||||
filter_parameter/rich_parameter.cpp \
|
||||
filter_parameter/rich_parameter_list.cpp \
|
||||
filter_parameter/value.cpp \
|
||||
filterscript.cpp \
|
||||
GLLogStream.cpp \
|
||||
interfaces/decorate_plugin_interface.cpp \
|
||||
interfaces/filter_plugin_interface.cpp \
|
||||
interfaces/plugin_interface.cpp \
|
||||
meshmodel.cpp \
|
||||
pluginmanager.cpp \
|
||||
mlapplication.cpp \
|
||||
searcher.cpp \
|
||||
meshlabdocumentxml.cpp \
|
||||
meshlabdocumentbundler.cpp \
|
||||
ml_shared_data_context.cpp \
|
||||
ml_selection_buffers.cpp \
|
||||
$$MESHLAB_EXTERNAL_DIRECTORY/easyexif/exif.cpp
|
||||
|
||||
macx:QMAKE_POST_LINK = "\
|
||||
if [ -d $$MESHLAB_DISTRIB_DIRECTORY/meshlab.app/Contents/Frameworks/ ]; \
|
||||
then \
|
||||
echo "Copying"; \
|
||||
else \
|
||||
mkdir -p $$MESHLAB_DISTRIB_DIRECTORY/meshlab.app/Contents/Frameworks; \
|
||||
fi; \
|
||||
cp $$MESHLAB_DISTRIB_DIRECTORY/lib/libmeshlab-common.* $$MESHLAB_DISTRIB_DIRECTORY/meshlab.app/Contents/Frameworks/ ;\
|
||||
# if [ -d ../external/ ];\
|
||||
# then \
|
||||
# echo "ok external dir exists"; \
|
||||
# else \
|
||||
# ln -s ../../meshlab/src/external ../external;\
|
||||
# echo "linked external dir"; \
|
||||
# fi;\
|
||||
# if [ -d $$MESHLAB_DISTRIB_DIRECTORY/shaders/ ];\
|
||||
# then \
|
||||
# echo "ok shader dir exists"; \
|
||||
# else \
|
||||
# ln -s ../../../meshlab/src/distrib/shaders ../distrib/shaders ;\
|
||||
# echo "linked shader dir"; \
|
||||
# fi;\
|
||||
"
|
||||
if [ -d $$MESHLAB_DISTRIB_DIRECTORY/meshlab.app/Contents/Frameworks/ ]; \
|
||||
then \
|
||||
echo "Copying"; \
|
||||
else \
|
||||
mkdir -p $$MESHLAB_DISTRIB_DIRECTORY/meshlab.app/Contents/Frameworks; \
|
||||
fi; \
|
||||
cp $$MESHLAB_DISTRIB_DIRECTORY/lib/libmeshlab-common.* $$MESHLAB_DISTRIB_DIRECTORY/meshlab.app/Contents/Frameworks/ ;\
|
||||
# if [ -d ../external/ ];\
|
||||
# then \
|
||||
# echo "ok external dir exists"; \
|
||||
# else \
|
||||
# ln -s ../../meshlab/src/external ../external;\
|
||||
# echo "linked external dir"; \
|
||||
# fi;\
|
||||
# if [ -d $$MESHLAB_DISTRIB_DIRECTORY/shaders/ ];\
|
||||
# then \
|
||||
# echo "ok shader dir exists"; \
|
||||
# else \
|
||||
# ln -s ../../../meshlab/src/distrib/shaders ../distrib/shaders ;\
|
||||
# echo "linked shader dir"; \
|
||||
# fi;\
|
||||
"
|
||||
|
||||
|
||||
4
src/external/external.pro
vendored
4
src/external/external.pro
vendored
@ -2,10 +2,6 @@ config += debug_and_release
|
||||
|
||||
TEMPLATE = subdirs
|
||||
|
||||
#just jhead needs to be compiled if the config is meshlab_mini
|
||||
SUBDIRS = \
|
||||
jhead-3.04/jhead-3.04.pro
|
||||
|
||||
!meshlab_mini {
|
||||
SUBDIRS += \
|
||||
levmar-2.3/levmar-2.3.pro \
|
||||
|
||||
444
src/external/jhead-3.04/changes.txt
vendored
444
src/external/jhead-3.04/changes.txt
vendored
@ -1,444 +0,0 @@
|
||||
****************************************************
|
||||
***** Detailed change log - since version 1.2 *****
|
||||
***** In cronological order, oldest to newest *****
|
||||
****************************************************
|
||||
|
||||
Jun 3 2001:
|
||||
Added -dc option for deleting all comments
|
||||
|
||||
Jun 5 2001:
|
||||
No longer clip comment length at 200 characters on display
|
||||
|
||||
Jul 16 2001
|
||||
Follow TIFF link correctly
|
||||
Save thumbnail option added
|
||||
(Thanks Michal D Hughes for his help mdh(a)logcabin.woods.bridge.com)
|
||||
|
||||
Aug 8 & 9 2001
|
||||
Transfer exif header option added.
|
||||
Moved relative path & discard all but jpeg stuff in separate functions
|
||||
Changed ISO heuristic to deal with ISo < 80 better
|
||||
(Thanks Harry TsaiHarryTsai(a)alum.mit.edu)
|
||||
|
||||
Agust 12 2001
|
||||
Testing under Linux, minor fixups.
|
||||
|
||||
-------Released version 1.3-------
|
||||
|
||||
August 26 2001
|
||||
Fixed problem where thumbnails in big endian files were not saved right.
|
||||
(thanks Joe Steele [joe(a)madewell.com])
|
||||
|
||||
Sept 1 2001
|
||||
Added command line option to remove exif section entirely.
|
||||
Added time / time-zone adjust option.
|
||||
|
||||
Sept 9 2001
|
||||
Avoid renaming file with right name again with -n option
|
||||
Change name of SetFileTime variable to not conflict with windows.
|
||||
|
||||
Oct 9 2001
|
||||
Added option to set exif timestamp to absolute time
|
||||
Added option to save thumbnail to stdout (unix only)
|
||||
(thanks Nathan Schmidt [mailto:nathan(a)cs.stanford.edu])
|
||||
Fixed bug in parsing truncated exif headers
|
||||
(thanks Joachim.Geyer(a)djh-freeweb.de)
|
||||
Got rid of strnprintf (not avilable on FreeBSD 4.4)
|
||||
|
||||
-------Released version 1.4-------
|
||||
|
||||
Oct 10 2001
|
||||
More improved handling of truncated exif headers - as may be produced
|
||||
by -dt option in older versions of this program.
|
||||
|
||||
Oct 18 2001
|
||||
Fixed bug in -ts option where '-' causes scanf to treat parms as negative.
|
||||
(thanks Pete Ashdon [mailto:pashdown(a)xmission.com])
|
||||
|
||||
Oct 25 2001
|
||||
Added -ce option
|
||||
|
||||
-------Released version 1.5-------
|
||||
|
||||
Dec 26 2001
|
||||
Added -V (version) option
|
||||
Added -exonly (exif only) option
|
||||
|
||||
|
||||
Jan 2 2002:
|
||||
Fixed lots of typos (Thanks, David Baker [mailto:dave(a)dsb3.com])
|
||||
|
||||
Jan 12: 2002
|
||||
Use EDITOR environment variable to pick which editor (Instead of notpead or VI)
|
||||
|
||||
Jan 13: 2002
|
||||
Improved thumbnail deletion feature - now not just shortens the header, but
|
||||
also removes pointers to the thumbnail form the exif header.
|
||||
|
||||
|
||||
-------Released version 1.6-------
|
||||
|
||||
Jan 29 2002
|
||||
Use adjusted date instead of original date when -ta is used in combination
|
||||
with -ft or -n options
|
||||
|
||||
Feb 25 2002
|
||||
Added image orientation display to summary
|
||||
|
||||
April 22 2002
|
||||
Changed 35mm equivalent focal calculation to use 36mm instead of 35mm for 35mm
|
||||
negative width (35 mm negative frames are 36 mm wide)
|
||||
|
||||
April 28 2002
|
||||
Split jhead.c int jhead.c and jpgfile.c. Jpgfile.c contains jpeg manipulation
|
||||
code that is reusable outside of jhead, while jhead.c contains code specific
|
||||
to jhead (command line parsing, display)
|
||||
|
||||
May 11 2002
|
||||
Fix bug in -dt option that rears its ugly head if the directories are in the
|
||||
exif header out of order.
|
||||
|
||||
-------Released version 1.7-------
|
||||
|
||||
June 3 2002
|
||||
Ignore undefined bits of "flash used" tag, as cannon sets them nonzero, causing
|
||||
jhead to indicate flash used when it wasn't with some Canon models.
|
||||
|
||||
Jul 7 2002
|
||||
-------Released version 1.8-------
|
||||
|
||||
Sept 8 2002
|
||||
makehtml now also lists .avi files as video clips
|
||||
|
||||
Sept 11 2002
|
||||
Handle first IFD offset != 8, as comes out of Pentax Optio 230 camera.
|
||||
|
||||
Sept 13 2002
|
||||
Show 4 digits of past decimal if exposrure time is less than 0.01 sec.
|
||||
|
||||
Sept 25 2002
|
||||
Integrate patch from James R Van Zandt to allow inclusion of original name
|
||||
when '%f' is part of rename format string.
|
||||
|
||||
Dec 11 2002
|
||||
-------Released version 1.9-------
|
||||
|
||||
Oct 8 2002
|
||||
Minor changes where newlines are printed.
|
||||
Added check to warn about wiping out the originals with the -st option.
|
||||
|
||||
Oct 9 2002
|
||||
Fixed display of "flash used=no" for exif headers generated by photoshop.
|
||||
|
||||
Oct 13 2002
|
||||
Added -ci and -cs options.
|
||||
|
||||
March 3 2003
|
||||
Limit directory recursion depth to avoid crashing on circularly linked
|
||||
directories within the Exif header.
|
||||
|
||||
April 6 2003
|
||||
Added automatic rottion (-autorotate) to right-up images that contain
|
||||
a rotation tag from the camera.
|
||||
|
||||
*Finally* wrote a nice MAN page for jhead.
|
||||
|
||||
-------Released version 2.0 -- April 2003 -------
|
||||
|
||||
Dec ?? 2003
|
||||
Set all copies of the date to same value when setting or modifying.
|
||||
(I intentionally only set one, but too may people considered this a bug)
|
||||
|
||||
Dec 28 2003
|
||||
fixed unix makefile
|
||||
|
||||
Dec 29 2003
|
||||
added -cl (insert comment literal) option
|
||||
|
||||
Jan 8 2004
|
||||
Added -norot (zero out rotation tag) option
|
||||
|
||||
-------Released version 2.1 -- Jan 2004 -------
|
||||
|
||||
Jan 12
|
||||
Added handling of explicit 35mm equivalent tag
|
||||
fixed inconsistency in computing 35 mm equivalent focal lengths between
|
||||
concise and regular output.
|
||||
|
||||
Jan 17
|
||||
Impelemented optoin to supress file date display, for regression tests.
|
||||
|
||||
Feb 1
|
||||
Better indentatin of verbose option, rudementary canon maker not parsing
|
||||
|
||||
March
|
||||
Various spelling errors fixed in output strings, and
|
||||
jpeg --> JPEG, exif --> Exif
|
||||
|
||||
April 13
|
||||
Use '-outfile' command line option of jpegtran when launching jpegtran to
|
||||
do rotation so that syntax of launched command is same on Windows and Unix.
|
||||
|
||||
April 19
|
||||
Various spelling fixes in manapge.
|
||||
|
||||
Jun 20
|
||||
Added ability to do sequencial renaming ('%i' in format string for -n option)
|
||||
|
||||
-------Released version 2.2 -- Jun 2004 ----------
|
||||
|
||||
Handle some oddities - like '/' separators in date fields, or images with
|
||||
an orientation tag for the thumbnail.
|
||||
|
||||
Increase maximum number of jpeg sections to 40 from 20
|
||||
|
||||
Dec 3
|
||||
Don't try to write to readonly files.
|
||||
Use changed copy of date/time for rename and file time set operations
|
||||
|
||||
Dec 25
|
||||
Added -purejpg and -du options
|
||||
|
||||
Dec 28
|
||||
More details on flash usage.
|
||||
Show digital zoom ratio
|
||||
Don't show jpeg process if it's baseline (almost always is)
|
||||
|
||||
-------Released version 2.3 -- Jan 2005 ----------
|
||||
|
||||
Jan 14 2005
|
||||
Display GPS info if included in image
|
||||
|
||||
Feb 27 2004
|
||||
Fix some time reference confusion bugs relating to -ta option
|
||||
|
||||
May 29 2005
|
||||
Added -da option for easier adjusting of date/time by large amounts.
|
||||
|
||||
-------Released version 2.4 -- May 2005 ----------
|
||||
|
||||
Jun 06 2005
|
||||
Fix -da option
|
||||
|
||||
-------Released version 2.4-1 -- Jun 09 2005 --------
|
||||
|
||||
Jun 10 2005
|
||||
Removed some debug printf I accidentally left in!
|
||||
|
||||
-------Released version 2.4-2 -- Jun 10 2005 --------
|
||||
|
||||
August 8 2005
|
||||
Avoid duplicating exif header on some commands
|
||||
|
||||
Sept 11 2005
|
||||
Fix up return codes.
|
||||
|
||||
Oct 8 2005
|
||||
Preserve file permissions and time when files are modified.
|
||||
|
||||
Oct 29 2005
|
||||
Read ISO euqivalnt and white balance from canon makernote
|
||||
|
||||
Nov 5 2005
|
||||
Added -rt (replace thumbnail) feature, and rotate the thumbnail also
|
||||
when using the -autorot feature
|
||||
|
||||
Dec 28 2005
|
||||
Added -rgt (regenerate thumbnail) feature.
|
||||
Added -orp and -orl options
|
||||
|
||||
-------Released version 2.5 -- Jan 8 2006 --------
|
||||
Jan 28 2006
|
||||
Fix typecast issue run itno with GCC 4
|
||||
|
||||
Feb 17 2006
|
||||
Fix shutter speed display in '-c' mode for very long shutter speeds
|
||||
|
||||
Feb 26 2006
|
||||
Fix some nitpicks from Debian folks
|
||||
|
||||
Mar 6 2006
|
||||
Fix a bug in autorot when rotating filenames with spaces in them.
|
||||
|
||||
April 2 2006
|
||||
Improved handling of corrupt exif linkages in exif header
|
||||
|
||||
April 3 2006
|
||||
Added -a (rename associated files) options
|
||||
|
||||
-------Released version 2.6 -- April 29 2006 --------
|
||||
|
||||
Sept 9 2006
|
||||
Remove maximum jpeg sections limit
|
||||
|
||||
Sept 10 2006
|
||||
Added -ds option
|
||||
|
||||
Oct 18 2006
|
||||
On clearing rotation, clear the image and the optinoal thumbnail rotation tags.
|
||||
(some viewers use the wrong tag)
|
||||
|
||||
Dec 29 2006
|
||||
Add -mkexif option to make a new exif header.
|
||||
|
||||
-------Released version 2.7 -- Jan 11 2007 --------
|
||||
|
||||
Feb 10 2007
|
||||
Added IPTC handling
|
||||
|
||||
Feb 11 2007
|
||||
Added -q option
|
||||
|
||||
Feb 17 2007
|
||||
Fix handling of corrupted GPS directory.
|
||||
|
||||
Feb 18 2007
|
||||
Extract focus distance from canon makernote.
|
||||
|
||||
Jun 3 2007
|
||||
Extract subject range (pentax and fuji cameras)
|
||||
|
||||
-------Released version 2.8 -- Nov 13 2007 --------
|
||||
|
||||
Feb 14 2008
|
||||
Fix it so it no longer deletex XMP sections
|
||||
Improve IPTC handling a little
|
||||
|
||||
March 3 2008
|
||||
Change how date is encoded with -mkexif section to make it more compatible.
|
||||
Make jhead aware of XMP data and not delete it.
|
||||
|
||||
-------Released version 2.82 -- Apr 03 2008 --------
|
||||
|
||||
May 8 2008
|
||||
Decode more exif tags for '-v' mode.
|
||||
|
||||
Sep 23 2008
|
||||
Fix a bunch of potential string overflows
|
||||
|
||||
Oct 1 2008
|
||||
Fix bug where IPTC sction was not deleted by -purejpg
|
||||
Fix GPS altitude decode bug
|
||||
|
||||
-------Released version 2.84 -- Oct 4 2008 --------
|
||||
|
||||
Jan 15 2008
|
||||
Fix bug with -ce introduced as a result of putting all the security
|
||||
checks the debian people wanted.
|
||||
|
||||
Feb 2 2008
|
||||
Added the ability to move files with the -n option. (makes directories if necessary)
|
||||
|
||||
Various minor typo and documentation fixes.
|
||||
|
||||
-------Released version 2.86 -- Feb 14 2009 --------
|
||||
|
||||
Fixed an #ifdef that I had defined the wrong way, causing the -ce option to fail.
|
||||
|
||||
-------Released version 2.87 -- Mar 03 2009 --------
|
||||
|
||||
May 2009:
|
||||
A few more tags recognized with jhead -v
|
||||
Accept strange date encoding of LG VX-9700
|
||||
Fix metering mode display
|
||||
Fix crash bug on corrupted jpeg
|
||||
Deal better with extra padding bytes between jpeg markers
|
||||
|
||||
Nov 3 2009:
|
||||
Now preserve resoltuion units of jfif header, or set them with info from exif header.
|
||||
|
||||
-------Released version 2.88 -- Nov 6 2009 --------
|
||||
|
||||
Dec 16 2009:
|
||||
Handle slightly different signature in IPTC as well.
|
||||
|
||||
Jan 25 2010:
|
||||
Handle mixted-endian-ness files from newer Canon point ant shoot cameras.
|
||||
|
||||
Jan 26 2010:
|
||||
More handling of IPTC variants.
|
||||
|
||||
-------Released version 2.90 -- Feb 5 2010 --------
|
||||
May 7 2010:
|
||||
Fix a compiler warning
|
||||
|
||||
Dec 29 2010:
|
||||
Make -n behave like -nf, and get rid of that option.
|
||||
|
||||
Dec 2 2011:
|
||||
Handle IPTC in UTF8 (as per photoshop CS5)
|
||||
|
||||
-------Released version 2.93 -- Dec 3 2011 --------
|
||||
|
||||
Jan 24 2011:
|
||||
Fixed bug in jhead -cmd that caused metatdata to be deleted.
|
||||
|
||||
-------Released version 2.94 -- Jan 24 2012 --------
|
||||
|
||||
Mar 3 2011:
|
||||
Handle very large unsigned rational numbers in exif header
|
||||
|
||||
-------Released version 2.95 -- Mar 16 2012 --------
|
||||
|
||||
Jun 18 2012:
|
||||
Fix printing file info when -ft option is used
|
||||
Do not skip readonle files with -st option
|
||||
|
||||
-------Released version 2.96 -- Jun 22 2012 --------
|
||||
|
||||
Jul 9 2012:
|
||||
Make it compile clean with visual studio 10
|
||||
|
||||
Jul 28 2012:
|
||||
Various cleanups from debian folks.
|
||||
|
||||
Oct 19 2012:
|
||||
Add feature to show quality of jpeg, (by Andy Spiegel)
|
||||
|
||||
Dec 27 2012:
|
||||
Fix crash on some corrupt files bug, clarify time adjustment syntax in help
|
||||
|
||||
|
||||
-------Released version 2.97 -- Jan 30 2013 --------
|
||||
Jun 10 2013:
|
||||
Make max comment size 16000
|
||||
|
||||
Oct 25 2013:
|
||||
Added "-zt" option to trim 32k of trailing zeroes from Nikon 1 J2 and J3 images.
|
||||
|
||||
Sep 28 2014:
|
||||
Add ability to reset invalid rotation tag (from Moultrie game cameras)
|
||||
|
||||
-------Released version 3.0 -- Feb 2 2015 --------
|
||||
Ma4 5 2015:
|
||||
Add option to set exif date from date from another file.
|
||||
|
||||
Jul 28 2015:
|
||||
Remove some unnecessary warnings with some types of GPS data
|
||||
|
||||
Aug 4 2015:
|
||||
Remove multiple copies of the same type of section when deleting section types
|
||||
|
||||
Aug 11 2011:
|
||||
Bug fixes relating to fuzz testing.
|
||||
|
||||
Aug 1 2017:
|
||||
Fix bug when no orientation tag is present
|
||||
|
||||
Aug 12 2018:
|
||||
Fix bug of not clearing exif information when processing images with an without
|
||||
exif data in one invocation.
|
||||
|
||||
-------Released version 3.02 -- Dec 11 2018 --------
|
||||
|
||||
Dec 21 2018:
|
||||
Fix bug where thumbnail replacement DID NOT WORK.
|
||||
(broke while fixing compiler warnings for 3.02 release)
|
||||
|
||||
-------Released version 3.03 -- Dec 31 2018 --------
|
||||
|
||||
Nov 20 2019:
|
||||
Apply a whole bunch of patches from Debian.
|
||||
Spell check and fuzz test stuff from Debian, nothing useful to human users.
|
||||
|
||||
-------Released version 3.04 -- Nov 22 2019 --------
|
||||
1604
src/external/jhead-3.04/exif.c
vendored
1604
src/external/jhead-3.04/exif.c
vendored
File diff suppressed because it is too large
Load Diff
218
src/external/jhead-3.04/gpsinfo.c
vendored
218
src/external/jhead-3.04/gpsinfo.c
vendored
@ -1,218 +0,0 @@
|
||||
//--------------------------------------------------------------------------
|
||||
// Parsing of GPS info from exif header.
|
||||
//
|
||||
// Matthias Wandel, Dec 1999 - Dec 2002
|
||||
//--------------------------------------------------------------------------
|
||||
#include "jhead.h"
|
||||
|
||||
#define MAX_GPS_TAG 0x1e
|
||||
|
||||
|
||||
#define TAG_GPS_LAT_REF 1
|
||||
#define TAG_GPS_LAT 2
|
||||
#define TAG_GPS_LONG_REF 3
|
||||
#define TAG_GPS_LONG 4
|
||||
#define TAG_GPS_ALT_REF 5
|
||||
#define TAG_GPS_ALT 6
|
||||
|
||||
|
||||
static const char * GpsTags[MAX_GPS_TAG+1]= {
|
||||
"VersionID ",//0x00
|
||||
"LatitudeRef ",//0x01
|
||||
"Latitude ",//0x02
|
||||
"LongitudeRef ",//0x03
|
||||
"Longitude ",//0x04
|
||||
"AltitudeRef ",//0x05
|
||||
"Altitude ",//0x06
|
||||
"TimeStamp ",//0x07
|
||||
"Satellites ",//0x08
|
||||
"Status ",//0x09
|
||||
"MeasureMode ",//0x0A
|
||||
"DOP ",//0x0B
|
||||
"SpeedRef ",//0x0C
|
||||
"Speed ",//0x0D
|
||||
"TrackRef ",//0x0E
|
||||
"Track ",//0x0F
|
||||
"ImgDirectionRef ",//0x10
|
||||
"ImgDirection ",//0x11
|
||||
"MapDatum ",//0x12
|
||||
"DestLatitudeRef ",//0x13
|
||||
"DestLatitude ",//0x14
|
||||
"DestLongitudeRef",//0x15
|
||||
"DestLongitude ",//0x16
|
||||
"DestBearingRef ",//0x17
|
||||
"DestBearing ",//0x18
|
||||
"DestDistanceRef ",//0x19
|
||||
"DestDistance ",//0x1A
|
||||
"ProcessingMethod",//0x1B
|
||||
"AreaInformation ",//0x1C
|
||||
"DateStamp ",//0x1D
|
||||
"Differential ",//0x1E
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Process GPS info directory
|
||||
//--------------------------------------------------------------------------
|
||||
void ProcessGpsInfo(unsigned char * DirStart, unsigned char * OffsetBase, unsigned ExifLength)
|
||||
{
|
||||
int de;
|
||||
unsigned a;
|
||||
int NumDirEntries;
|
||||
|
||||
NumDirEntries = Get16u(DirStart);
|
||||
#define DIR_ENTRY_ADDR(Start, Entry) (Start+2+12*(Entry))
|
||||
|
||||
if (ShowTags){
|
||||
printf("(dir has %d entries)\n",NumDirEntries);
|
||||
}
|
||||
|
||||
ImageInfo.GpsInfoPresent = TRUE;
|
||||
strcpy(ImageInfo.GpsLat, "? ?");
|
||||
strcpy(ImageInfo.GpsLong, "? ?");
|
||||
ImageInfo.GpsAlt[0] = 0;
|
||||
|
||||
for (de=0;de<NumDirEntries;de++){
|
||||
unsigned Tag, Format, Components;
|
||||
unsigned char * ValuePtr;
|
||||
int ComponentSize;
|
||||
unsigned ByteCount;
|
||||
unsigned char * DirEntry;
|
||||
DirEntry = DIR_ENTRY_ADDR(DirStart, de);
|
||||
|
||||
if (DirEntry+12 > OffsetBase+ExifLength){
|
||||
ErrNonfatal("GPS info directory goes past end of exif",0,0);
|
||||
return;
|
||||
}
|
||||
|
||||
Tag = Get16u(DirEntry);
|
||||
Format = Get16u(DirEntry+2);
|
||||
Components = Get32u(DirEntry+4);
|
||||
|
||||
if ((Format-1) >= NUM_FORMATS) {
|
||||
// (-1) catches illegal zero case as unsigned underflows to positive large.
|
||||
ErrNonfatal("Illegal number format %d for Exif gps tag %04x", Format, Tag);
|
||||
continue;
|
||||
}
|
||||
|
||||
ComponentSize = BytesPerFormat[Format];
|
||||
ByteCount = Components * ComponentSize;
|
||||
|
||||
if (ByteCount > 4){
|
||||
unsigned OffsetVal;
|
||||
OffsetVal = Get32u(DirEntry+8);
|
||||
// If its bigger than 4 bytes, the dir entry contains an offset.
|
||||
if (OffsetVal > 0x1000000 || OffsetVal+ByteCount > ExifLength){
|
||||
// Max exif in jpeg is 64k, so any offset bigger than that is bogus.
|
||||
// Bogus pointer offset and / or bytecount value
|
||||
ErrNonfatal("Illegal value pointer for Exif gps tag %04x", Tag,0);
|
||||
continue;
|
||||
}
|
||||
ValuePtr = OffsetBase+OffsetVal;
|
||||
}else{
|
||||
// 4 bytes or less and value is in the dir entry itself
|
||||
ValuePtr = DirEntry+8;
|
||||
}
|
||||
|
||||
switch(Tag){
|
||||
char FmtString[21];
|
||||
char TempString[50];
|
||||
double Values[3];
|
||||
|
||||
case TAG_GPS_LAT_REF:
|
||||
ImageInfo.GpsLat[0] = ValuePtr[0];
|
||||
break;
|
||||
|
||||
case TAG_GPS_LONG_REF:
|
||||
ImageInfo.GpsLong[0] = ValuePtr[0];
|
||||
break;
|
||||
|
||||
case TAG_GPS_LAT:
|
||||
case TAG_GPS_LONG:
|
||||
if (Format != FMT_URATIONAL){
|
||||
ErrNonfatal("Inappropriate format (%d) for Exif GPS coordinates!", Format, 0);
|
||||
}
|
||||
strcpy(FmtString, "%0.0fd %0.0fm %0.0fs");
|
||||
for (a=0;a<3;a++){
|
||||
int den, digits;
|
||||
|
||||
den = Get32s(ValuePtr+4+a*ComponentSize);
|
||||
digits = 0;
|
||||
while (den > 1 && digits <= 6){
|
||||
den = den / 10;
|
||||
digits += 1;
|
||||
}
|
||||
if (digits > 6) digits = 6;
|
||||
FmtString[1+a*7] = (char)('2'+digits+(digits ? 1 : 0));
|
||||
FmtString[3+a*7] = (char)('0'+digits);
|
||||
|
||||
Values[a] = ConvertAnyFormat(ValuePtr+a*ComponentSize, Format);
|
||||
}
|
||||
|
||||
snprintf(TempString, sizeof(TempString), FmtString, Values[0], Values[1], Values[2]);
|
||||
|
||||
if (Tag == TAG_GPS_LAT){
|
||||
strncpy(ImageInfo.GpsLat+2, TempString, 29);
|
||||
}else{
|
||||
strncpy(ImageInfo.GpsLong+2, TempString, 29);
|
||||
}
|
||||
break;
|
||||
|
||||
case TAG_GPS_ALT_REF:
|
||||
ImageInfo.GpsAlt[0] = (char)(ValuePtr[0] ? '-' : ' ');
|
||||
break;
|
||||
|
||||
case TAG_GPS_ALT:
|
||||
snprintf(ImageInfo.GpsAlt+1, sizeof(ImageInfo.GpsAlt)-1,
|
||||
"%.2fm", ConvertAnyFormat(ValuePtr, Format));
|
||||
break;
|
||||
}
|
||||
|
||||
if (ShowTags){
|
||||
// Show tag value.
|
||||
if (Tag < MAX_GPS_TAG){
|
||||
printf(" GPS%s =", GpsTags[Tag]);
|
||||
}else{
|
||||
// Show unknown tag
|
||||
printf(" Illegal GPS tag %04x=", Tag);
|
||||
}
|
||||
|
||||
switch(Format){
|
||||
case FMT_UNDEFINED:
|
||||
// Undefined is typically an ascii string.
|
||||
|
||||
case FMT_STRING:
|
||||
// String arrays printed without function call (different from int arrays)
|
||||
{
|
||||
printf("\"");
|
||||
for (a=0;a<ByteCount;a++){
|
||||
int ZeroSkipped = 0;
|
||||
if (ValuePtr[a] >= 32){
|
||||
if (ZeroSkipped){
|
||||
printf("?");
|
||||
ZeroSkipped = 0;
|
||||
}
|
||||
putchar(ValuePtr[a]);
|
||||
}else{
|
||||
if (ValuePtr[a] == 0){
|
||||
ZeroSkipped = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("\"\n");
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
// Handle arrays of numbers later (will there ever be?)
|
||||
for (a=0;;){
|
||||
PrintFormatNumber(ValuePtr+a*ComponentSize, Format, ByteCount);
|
||||
if (++a >= Components) break;
|
||||
printf(", ");
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
220
src/external/jhead-3.04/iptc.c
vendored
220
src/external/jhead-3.04/iptc.c
vendored
@ -1,220 +0,0 @@
|
||||
//--------------------------------------------------------------------------
|
||||
// Process IPTC data and XMP data.
|
||||
//--------------------------------------------------------------------------
|
||||
#include "jhead.h"
|
||||
|
||||
// IPTC entry types known to Jhead (there's many more defined)
|
||||
#define IPTC_RECORD_VERSION 0x00
|
||||
#define IPTC_SUPLEMENTAL_CATEGORIES 0x14
|
||||
#define IPTC_KEYWORDS 0x19
|
||||
#define IPTC_CAPTION 0x78
|
||||
#define IPTC_AUTHOR 0x7A
|
||||
#define IPTC_HEADLINE 0x69
|
||||
#define IPTC_SPECIAL_INSTRUCTIONS 0x28
|
||||
#define IPTC_CATEGORY 0x0F
|
||||
#define IPTC_BYLINE 0x50
|
||||
#define IPTC_BYLINE_TITLE 0x55
|
||||
#define IPTC_CREDIT 0x6E
|
||||
#define IPTC_SOURCE 0x73
|
||||
#define IPTC_COPYRIGHT_NOTICE 0x74
|
||||
#define IPTC_OBJECT_NAME 0x05
|
||||
#define IPTC_CITY 0x5A
|
||||
#define IPTC_STATE 0x5F
|
||||
#define IPTC_COUNTRY 0x65
|
||||
#define IPTC_TRANSMISSION_REFERENCE 0x67
|
||||
#define IPTC_DATE 0x37
|
||||
#define IPTC_COPYRIGHT 0x0A
|
||||
#define IPTC_COUNTRY_CODE 0x64
|
||||
#define IPTC_REFERENCE_SERVICE 0x2D
|
||||
#define IPTC_TIME_CREATED 0x3C
|
||||
#define IPTC_SUB_LOCATION 0x5C
|
||||
#define IPTC_IMAGE_TYPE 0x82
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Process and display IPTC marker.
|
||||
//
|
||||
// IPTC block consists of:
|
||||
// - Marker: 1 byte (0xED)
|
||||
// - Block length: 2 bytes
|
||||
// - IPTC Signature: 14 bytes ("Photoshop 3.0\0")
|
||||
// - 8BIM Signature 4 bytes ("8BIM")
|
||||
// - IPTC Block start 2 bytes (0x04, 0x04)
|
||||
// - IPTC Header length 1 byte
|
||||
// - IPTC header Header is padded to even length, counting the length byte
|
||||
// - Length 4 bytes
|
||||
// - IPTC Data which consists of a number of entries, each of which has the following format:
|
||||
// - Signature 2 bytes (0x1C02)
|
||||
// - Entry type 1 byte (for defined entry types, see #defines above)
|
||||
// - entry length 2 bytes
|
||||
// - entry data 'entry length' bytes
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
void show_IPTC (unsigned char* Data, unsigned int itemlen)
|
||||
{
|
||||
const char IptcSig1[] = "Photoshop 3.0";
|
||||
const char IptcSig2[] = "8BIM";
|
||||
const char IptcSig3[] = {0x04, 0x04};
|
||||
|
||||
unsigned char * pos = Data + sizeof(short); // position data pointer after length field
|
||||
unsigned char * maxpos = Data+itemlen;
|
||||
unsigned char headerLen = 0;
|
||||
unsigned char dataLen = 0;
|
||||
|
||||
if (itemlen < 25) goto corrupt;
|
||||
|
||||
// Check IPTC signatures
|
||||
if (memcmp(pos, IptcSig1, sizeof(IptcSig1)-1) != 0) goto badsig;
|
||||
pos += sizeof(IptcSig1); // move data pointer to the next field
|
||||
|
||||
if (memcmp(pos, IptcSig2, sizeof(IptcSig2)-1) != 0) goto badsig;
|
||||
pos += sizeof(IptcSig2)-1; // move data pointer to the next field
|
||||
|
||||
|
||||
while (memcmp(pos, IptcSig3, sizeof(IptcSig3)) != 0) { // loop on valid Photoshop blocks
|
||||
|
||||
pos += sizeof(IptcSig3); // move data pointer to the Header Length
|
||||
// Skip header
|
||||
headerLen = *pos; // get header length and move data pointer to the next field
|
||||
pos += (headerLen & 0xfe) + 2; // move data pointer to the next field (Header is padded to even length, counting the length byte)
|
||||
|
||||
pos += 3; // move data pointer to length, assume only one byte, TODO: use all 4 bytes
|
||||
|
||||
dataLen = *pos++;
|
||||
pos += dataLen; // skip data section
|
||||
|
||||
if (memcmp(pos, IptcSig2, sizeof(IptcSig2) - 1) != 0) {
|
||||
badsig: if (ShowTags) {
|
||||
ErrNonfatal("IPTC type signature mismatch\n", 0, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
pos += sizeof(IptcSig2) - 1; // move data pointer to the next field
|
||||
}
|
||||
|
||||
pos += sizeof(IptcSig3); // move data pointer to the next field
|
||||
|
||||
if (pos >= maxpos) goto corrupt;
|
||||
|
||||
// IPTC section found
|
||||
|
||||
// Skip header
|
||||
headerLen = *pos++; // get header length and move data pointer to the next field
|
||||
pos += headerLen + 1 - (headerLen % 2); // move data pointer to the next field (Header is padded to even length, counting the length byte)
|
||||
|
||||
if (pos+4 >= maxpos) goto corrupt;
|
||||
|
||||
// Get length (from motorola format)
|
||||
//length = (*pos << 24) | (*(pos+1) << 16) | (*(pos+2) << 8) | *(pos+3);
|
||||
|
||||
pos += 4; // move data pointer to the next field
|
||||
|
||||
printf("======= IPTC data: =======\n");
|
||||
|
||||
// Now read IPTC data
|
||||
while (pos < (Data + itemlen-5)) {
|
||||
short signature;
|
||||
unsigned char type = 0;
|
||||
short length = 0;
|
||||
const char * description = NULL;
|
||||
|
||||
if (pos+5 > maxpos) goto corrupt;
|
||||
|
||||
signature = (*pos << 8) + (*(pos+1));
|
||||
pos += 2;
|
||||
|
||||
if (signature != 0x1C01 && signature != 0x1c02) break;
|
||||
|
||||
type = *pos++;
|
||||
length = (*pos << 8) + (*(pos+1));
|
||||
if (length < 1) goto corrupt;
|
||||
pos += 2; // Skip tag length
|
||||
|
||||
if (pos+length > maxpos) goto corrupt;
|
||||
// Process tag here
|
||||
switch (type) {
|
||||
case IPTC_RECORD_VERSION:
|
||||
printf("Record vers. : %d\n", (*pos << 8) + (*(pos+1)));
|
||||
break;
|
||||
|
||||
case IPTC_SUPLEMENTAL_CATEGORIES: description = "SuplementalCategories"; break;
|
||||
case IPTC_KEYWORDS: description = "Keywords"; break;
|
||||
case IPTC_CAPTION: description = "Caption"; break;
|
||||
case IPTC_AUTHOR: description = "Author"; break;
|
||||
case IPTC_HEADLINE: description = "Headline"; break;
|
||||
case IPTC_SPECIAL_INSTRUCTIONS: description = "Spec. Instr."; break;
|
||||
case IPTC_CATEGORY: description = "Category"; break;
|
||||
case IPTC_BYLINE: description = "Byline"; break;
|
||||
case IPTC_BYLINE_TITLE: description = "Byline Title"; break;
|
||||
case IPTC_CREDIT: description = "Credit"; break;
|
||||
case IPTC_SOURCE: description = "Source"; break;
|
||||
case IPTC_COPYRIGHT_NOTICE: description = "(C)Notice"; break;
|
||||
case IPTC_OBJECT_NAME: description = "Object Name"; break;
|
||||
case IPTC_CITY: description = "City"; break;
|
||||
case IPTC_STATE: description = "State"; break;
|
||||
case IPTC_COUNTRY: description = "Country"; break;
|
||||
case IPTC_TRANSMISSION_REFERENCE: description = "OriginalTransmissionReference"; break;
|
||||
case IPTC_DATE: description = "DateCreated"; break;
|
||||
case IPTC_COPYRIGHT: description = "(C)Flag"; break;
|
||||
case IPTC_REFERENCE_SERVICE: description = "Country Code"; break;
|
||||
case IPTC_COUNTRY_CODE: description = "Ref. Service"; break;
|
||||
case IPTC_TIME_CREATED: description = "Time Created"; break;
|
||||
case IPTC_SUB_LOCATION: description = "Sub Location"; break;
|
||||
case IPTC_IMAGE_TYPE: description = "Image type"; break;
|
||||
|
||||
default:
|
||||
if (ShowTags){
|
||||
printf("Unrecognised IPTC tag: %d\n", type );
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (description != NULL) {
|
||||
char TempBuf[32];
|
||||
memset(TempBuf, 0, sizeof(TempBuf));
|
||||
memset(TempBuf, ' ', 14);
|
||||
memcpy(TempBuf, description, strlen(description));
|
||||
strcat(TempBuf, ":");
|
||||
printf("%s %*.*s\n", TempBuf, length, length, pos);
|
||||
}
|
||||
pos += length;
|
||||
}
|
||||
return;
|
||||
corrupt:
|
||||
ErrNonfatal("Pointer corruption in IPTC\n",0,0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Dump contents of XMP section
|
||||
//--------------------------------------------------------------------------
|
||||
void ShowXmp(Section_t XmpSection)
|
||||
{
|
||||
unsigned char * Data;
|
||||
char OutLine[101];
|
||||
int OutLineChars;
|
||||
int NonBlank;
|
||||
unsigned a;
|
||||
NonBlank = 0;
|
||||
Data = XmpSection.Data;
|
||||
OutLineChars = 0;
|
||||
|
||||
|
||||
for (a=0;a<XmpSection.Size;a++){
|
||||
if (Data[a] >= 32 && Data[a] < 128){
|
||||
OutLine[OutLineChars++] = Data[a];
|
||||
if (Data[a] != ' ') NonBlank |= 1;
|
||||
}else{
|
||||
if (Data[a] != '\n'){
|
||||
OutLine[OutLineChars++] = '?';
|
||||
}
|
||||
}
|
||||
if (Data[a] == '\n' || OutLineChars >= 100){
|
||||
OutLine[OutLineChars] = 0;
|
||||
if (NonBlank){
|
||||
puts(OutLine);
|
||||
}
|
||||
NonBlank = (NonBlank & 1) << 1;
|
||||
OutLineChars = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
23
src/external/jhead-3.04/jhead-3.04.pro
vendored
23
src/external/jhead-3.04/jhead-3.04.pro
vendored
@ -1,23 +0,0 @@
|
||||
include(../ext_common.pri)
|
||||
TEMPLATE = lib
|
||||
TARGET = jhead
|
||||
CONFIG += staticlib
|
||||
DEPENDPATH += .
|
||||
INCLUDEPATH += .
|
||||
|
||||
# Input
|
||||
HEADERS += jhead.h
|
||||
|
||||
SOURCES += \
|
||||
jpgfile.c \
|
||||
jpgqguess.c \
|
||||
jhead.c \
|
||||
paths.c \
|
||||
exif.c \
|
||||
iptc.c \
|
||||
gpsinfo.c \
|
||||
makernote.c
|
||||
|
||||
win32:SOURCES += myglob.c
|
||||
|
||||
DEFINES += main="jhead_main"
|
||||
427
src/external/jhead-3.04/jhead.1
vendored
427
src/external/jhead-3.04/jhead.1
vendored
@ -1,427 +0,0 @@
|
||||
.TH JHEAD 1 "22 Nov 2019" "jhead 3.04"
|
||||
.SH NAME
|
||||
jhead \- Digicam JPEG Exif header manipulation tool
|
||||
.SH SYNOPSIS
|
||||
.B jhead
|
||||
[
|
||||
.I options
|
||||
]
|
||||
[
|
||||
.I file\.\.\.
|
||||
]
|
||||
|
||||
.LP
|
||||
.SH DESCRIPTION
|
||||
.LP
|
||||
.B jhead
|
||||
is used to display and manipulate data contained in the Exif header of JPEG
|
||||
images from digital cameras. By default, jhead displays the more useful
|
||||
camera settings from the file in a user-friendly format.
|
||||
.PP
|
||||
.B jhead
|
||||
can also be used to manipulate some aspects of the image relating to JPEG and
|
||||
Exif headers, such as changing the internal timestamps, removing the thumbnail,
|
||||
or transferring Exif headers back into edited images after graphical editors
|
||||
deleted the Exif header.
|
||||
.B jhead
|
||||
can also be used to launch other programs, similar in style to the UNIX
|
||||
.B find
|
||||
command, but much simpler.
|
||||
|
||||
|
||||
.SH GENERAL METADATA OPTIONS
|
||||
.TP
|
||||
.BI \-\^te \ file
|
||||
Transplant Exif header from a JPEG (with Exif header) in
|
||||
.I file
|
||||
into the image that is manipulated. This option is useful if you like
|
||||
to edit the photos but still want the Exif header on your photos. As
|
||||
most photo editing programs will wipe out the Exif header, this option
|
||||
can be used to re-copy them back from original copies after editing the
|
||||
photos.
|
||||
|
||||
|
||||
This feature has an interesting 'relative path' option for specifying
|
||||
the thumbnail name. Whenever the <name> contains the characters '&i',
|
||||
will substitute the original filename for this name. This allows
|
||||
creating a jhead 'relative name' when doing a whole batch of files. For
|
||||
example, the incantation:
|
||||
|
||||
.I jhead \-te """originals/&i"" *.jpg
|
||||
|
||||
would transfer the exif header for each .jpg file in the originals
|
||||
directory by the same name, Both Win32 and most Unix shells treat the '&'
|
||||
character in a special way, so you have to put quotes around that
|
||||
command line option for the '&' to even be passed to the program.
|
||||
|
||||
.TP
|
||||
.B \-dc
|
||||
Delete comment field from the JPEG header. Note that the comment
|
||||
is not part of the Exif header.
|
||||
.TP
|
||||
.B \-de
|
||||
Delete the Exif header entirely. Leaves other metadata sections intact.
|
||||
.TP
|
||||
.B \-di
|
||||
Delete the IPTC section, if present. Leaves other metadata sections intact.
|
||||
.TP
|
||||
.B \-dx
|
||||
Delete the XMP section, if present. Leaves other metadata sections intact.
|
||||
.TP
|
||||
.B \-du
|
||||
Delete sections of jpeg that are not Exif, not comment, and otherwise not
|
||||
contributing to the image either - such as data that photoshop might leave in the image.
|
||||
.TP
|
||||
.B \-purejpg
|
||||
Delete all JPEG sections that aren't necessary for rendering the image.
|
||||
Strips any metadata that various applications may have left in the
|
||||
image. A combination of the \-de \-dc and \-du options.
|
||||
.TP
|
||||
.B \-mkexif
|
||||
Creates minimal exif header. Exif header contains date/time, and empty
|
||||
thumbnail fields only. Date/time set to file time by default. Use with
|
||||
\-rgt option if you want the exif header to contain a thumbnail. Note
|
||||
that exif header creation is very limited at this time, and no other
|
||||
fields can be added to the exif header this way.
|
||||
.TP
|
||||
.B \-ce
|
||||
Edit the JPEG header comment field (note, this comment field is outside
|
||||
the Exif structure and can be part of Exif and non Exif style JPEG
|
||||
images).
|
||||
|
||||
A temporary file containing the comment is created and a text editor is
|
||||
launched to edit the file. The editor is specified in the EDITOR
|
||||
environment variable. If none is specified notepad or vi are used under
|
||||
Windows and Unix respectively. After the editor exits, the data is
|
||||
transferred back into the image, and the temporary file deleted.
|
||||
.TP
|
||||
.BI \-\^cs \ file
|
||||
Save comment section to a
|
||||
.I file
|
||||
.TP
|
||||
.BI \-\^ci \ file
|
||||
Replace comment with text from
|
||||
.I file
|
||||
.TP
|
||||
.BI \-\^cl \ string
|
||||
Replace comment with specified string from command line
|
||||
|
||||
.SH DATE / TIME MANIPULATION OPTIONS
|
||||
|
||||
.TP
|
||||
.B \-ft
|
||||
Sets the file's system time stamp to what is stored in the Exif header.
|
||||
.TP
|
||||
.B \-dsft
|
||||
Sets the Exif timestamp to the file's timestamp. Requires an Exif header to
|
||||
pre-exist. Use \-mkexif option to create one if needed.
|
||||
.TP
|
||||
.BI \-\^n [format_string]
|
||||
This option causes files to be renamed and/ or mmoved using the date
|
||||
information from the Exif header "DateTimeOriginal" field. If the file
|
||||
is not an Exif file, or the DateTimeOriginal does not contain a valid
|
||||
value, the file date is used. If the new name contains a '/',
|
||||
this will be interpreted as a new path, and the file will be moved
|
||||
accordingly.
|
||||
|
||||
If the
|
||||
.I format_string
|
||||
is omitted, the file will be renamed to MMDD-HHMMSS. Note that this
|
||||
scheme doesn't include the year (I never have photos from different
|
||||
years together anyway).
|
||||
|
||||
If a
|
||||
.I format_string
|
||||
is provided, it will be passed to the strftime function as the format
|
||||
string. In addition, if the format string contains '%f', this will
|
||||
substitute the original name of the file (minus extension). '%i' will
|
||||
substitute a sequence number. Leading zeros can be specified like with
|
||||
printf - i.e. '%04i' pads the number to 4 digits using leading zeros.
|
||||
|
||||
If the name includes '/', this is interpreted as a new path for the file.
|
||||
If the new path does not exist, the path will be created.
|
||||
|
||||
If the target name already exists, the name will be appended with "a",
|
||||
"b", "c", etc, unless the name ends with a letter, in which case it will
|
||||
be appended with "0", "1", "2", etc.
|
||||
|
||||
This feature is especially useful if more than one digital camera was
|
||||
used to take pictures of an event. By renaming them to a scheme
|
||||
according to date, they will automatically appear in order of taking in
|
||||
most directory listings and image browsers. Alternatively, if your
|
||||
image browser supports listing by file time, you can use the \-ft option
|
||||
to set the file time to the time the photo was taken.
|
||||
|
||||
Some of the more useful arguments for strftime are:
|
||||
|
||||
.BR %H \ Hour\ in\ 24-hour\ format\ (00\ -\ 23)
|
||||
.br
|
||||
.BR %j \ Day\ of\ year\ as\ decimal\ number\ (001\ -\ 366)
|
||||
.br
|
||||
.BR %m \ Month\ as\ decimal\ number\ (01\ -\ 12)
|
||||
.br
|
||||
.BR %M \ Minute\ as\ decimal\ number\ (00\ -\ 59)
|
||||
.br
|
||||
.BR %S \ Second\ as\ decimal\ number\ (00\ -\ 59)
|
||||
.br
|
||||
.BR %w \ Weekday\ as\ decimal\ number\ (0\ -\ 6;\ Sunday\ is\ 0)
|
||||
.br
|
||||
.BR %y \ Year\ without\ century,\ as\ decimal\ number\ (00\ -\ 99)
|
||||
.br
|
||||
.BR %Y \ Year\ with\ century,\ as\ decimal\ number
|
||||
|
||||
Example:
|
||||
|
||||
.I jhead \-n%Y%m%d\-%H%M%S *.jpg
|
||||
|
||||
This will rename files matched by *.jpg in the format YYYYMMDD\-HHMMSS
|
||||
|
||||
For a full listing of strftime arguments, look up the strftime in them
|
||||
man pages. Note that some arguments to the strftime function (not
|
||||
listed here) produce strings with characters such as ':' that may not be
|
||||
valid as part of a filename on some systems.
|
||||
|
||||
.TP
|
||||
.B \-ta<+|\-><timediff>
|
||||
Adjust time stored in the Exif header by h:mm forwards or backwards.
|
||||
Useful when having taken pictures with the wrong time set on the camera,
|
||||
such as after travelling across time zones, or when daylight savings
|
||||
time has changed.
|
||||
|
||||
Examples:
|
||||
|
||||
Add 1 hourand 5 minutes to the time
|
||||
.br
|
||||
jhead \-ta+1:05
|
||||
|
||||
Decrease time by one second:
|
||||
.br
|
||||
jhead \-ta-0:0:1
|
||||
|
||||
|
||||
This option changes all Date/time fields in the exif header, including
|
||||
"DateTimeOriginal" (tag 0x9003) and "DateTimeDigitized" (tag 0x9004).
|
||||
.TP
|
||||
.B \-da<newdate>\-<olddate>
|
||||
|
||||
Works like \-ta, but for specifying large date offsets, to be used when
|
||||
fixing dates from cameras where the date was set incorrectly, such as
|
||||
having date and time reset by battery removal on some cameras
|
||||
|
||||
Because different months and years have different numbers of days in
|
||||
them, a simple offset for months, days, years would lead to unexpected
|
||||
results at times. The time offset is thus specified as a difference
|
||||
between two dates, so that jhead can figure out exactly how many days
|
||||
the timestamp needs to be adjusted by, including leap years and daylight
|
||||
savings time changes. The dates are specified as yyyy:mm:dd. For
|
||||
sub-day adjustments, a time of day can also be included, by specifying
|
||||
yyyy:nn:dd/hh:mm or yyyy:mm:dd/hh:mm:ss
|
||||
|
||||
Examples:
|
||||
|
||||
Year on camera was set to 2005 instead of 2004 for pictures taken in April
|
||||
.br
|
||||
jhead \-da2004:03:01\-2005:03:01
|
||||
|
||||
Default camera date is 2002:01:01, and date was reset on 2005:05:29 at 11:21 am
|
||||
.br
|
||||
jhead \-da2005:05:29/11:21\-2002:01:01
|
||||
.TP
|
||||
.B \-ts
|
||||
Sets the time stored in the Exif header to what is specified on the
|
||||
command line.
|
||||
Time must be specified as:
|
||||
.I yyyy:mm:dd\-hh:mm:ss
|
||||
.TP
|
||||
.B \-ds
|
||||
Sets the date stored in the Exif header to what is specified on the
|
||||
command line.
|
||||
Can be used to set date, just year and month, or just year.
|
||||
Date is specified as:
|
||||
.I yyyy:mm:dd, yyyy:mm, or yyyy
|
||||
|
||||
.SH THUMBNAIL MANIPULATION OPTIONS
|
||||
|
||||
.TP
|
||||
.B \-dt
|
||||
Delete thumbnails from the Exif header, but leave the interesting parts
|
||||
intact. This option truncates the thumbnail from the Exif header,
|
||||
provided that the thumbnail is the last part of the Exif header (which
|
||||
so far as I know is always the case). Exif headers have a built-in
|
||||
thumbnail, which typically occupies around 10k of space. This thumbnail
|
||||
is used by digital cameras. Windows XP may also use this thumbnail if
|
||||
present (but it doesn't need it). The thumbnails are too small to use
|
||||
even full screen on the digicam's LCD. I have not encountered any
|
||||
adverse side effects of deleting the thumbnails, even from the software
|
||||
provided with my old Olympus digicam. Use with caution.
|
||||
|
||||
.TP
|
||||
.BI \-\^st \ file
|
||||
Save the integral thumbnail to
|
||||
.I file
|
||||
The thumbnail lives inside the Exif header, and is a very low-res JPEG
|
||||
image. Note that making any changes to a photo, except for with some
|
||||
programs, generally wipes out the Exif header and with it the thumbnail.
|
||||
|
||||
The thumbnail is too low res to really use for very much.
|
||||
|
||||
This feature has an interesting 'relative path' option for specifying
|
||||
the thumbnail name. Whenever the name for
|
||||
.I file
|
||||
contains the characters '&i',
|
||||
.B jhead
|
||||
will substitute the original filename for this name. This allows
|
||||
creating a 'relative name' when doing a whole batch of files. For
|
||||
example, the incantation:
|
||||
|
||||
.I jhead \-st """thumbnails/&i"" *.jpg
|
||||
|
||||
would create a thumbnail for each .jpg file in the thumbnails directory
|
||||
by the same name, (provided that the thumbnails directory exists, of
|
||||
course). Both Win32 and UNIX shells treat the '&'character in a special
|
||||
way, so you have to put quotes around that command line option for the '&'
|
||||
to even be passed to the program.
|
||||
|
||||
If a '\-' is specified for the output file, the thumbnail is sent to
|
||||
stdout. (UNIX build only)
|
||||
|
||||
.TP
|
||||
.B \-rt
|
||||
Replace thumbnails from the Exif header. This only works if the exif
|
||||
header already contains a thumbnail, and the thumbnail is at the end of
|
||||
the header (both always the case if the photo came from a digital
|
||||
camera)
|
||||
.TP
|
||||
.BI \-\^rgt \ size
|
||||
Regenerate exif thumbnail. 'size' specifies maximum height or width of
|
||||
thumbnail. Relies on 'mogrify' program (from ImageMagick) to regenerate
|
||||
the thumbnail. This only works if the image already contains a
|
||||
thumbnail.
|
||||
|
||||
.SH ROTATION OPTIONS
|
||||
.TP
|
||||
.B \-autorot
|
||||
Using the 'Orientation' tag of the Exif header, rotate the image so that
|
||||
it is upright. The program
|
||||
.B jpegtran
|
||||
is used to perform the rotation. This program is present in most Linux
|
||||
distributions. For windows, you need to get a copy of it. After
|
||||
rotation, the orientation tag of the Exif header is set to '1' (normal
|
||||
orientation). The thumbnail is also rotated. Other fields of the Exif
|
||||
header, including dimensions are untouched, but the JPEG height/width
|
||||
are adjusted. This feature is especially useful with newer Canon
|
||||
cameras, that set the orientation tag automatically using a gravity
|
||||
sensor.
|
||||
.TP
|
||||
.B \-norot
|
||||
Clears the rotation field in the Exif header without altering the image.
|
||||
Useful if the images were previously rotated without clearing the Exif
|
||||
rotation tag, as some image browsers will auto rotate images when the
|
||||
rotation tag is set. Sometimes, thumbnails and rotation tags can get
|
||||
very out of sync from manipulation with various tools. To reset it all
|
||||
use \-norot with \-rgt to clear this out.
|
||||
|
||||
.SH OUTPUT VERBOSITY CONTROL
|
||||
.TP
|
||||
.B \-h
|
||||
Displays summary of command line options.
|
||||
.TP
|
||||
.B \-v
|
||||
Makes the program even more verbose than it already is. Like DOS
|
||||
programs, and unlike UNIX programs, Jhead gives feedback as to what it
|
||||
is doing, even when nothing goes wrong. Windows user that I am, when
|
||||
something doesn't give me feedback for 20 seconds, I assume its crashed.
|
||||
.TP
|
||||
.B \-q
|
||||
No output on success, more like Unix programs.
|
||||
.TP
|
||||
.B \-V
|
||||
Print version info and compilation date.
|
||||
.B \-exifmap
|
||||
Show a map of the bytes in the exif header. Useful when analyzing
|
||||
strange exif headers, not of much use to non software developers.
|
||||
.TP
|
||||
.B \-se
|
||||
Suppress error messages relating to corrupt Exif header structure.
|
||||
.TP
|
||||
.B \-c
|
||||
Concise output. This causes picture info to be summarized on one line
|
||||
instead of several. Useful for grep-ing through images, as well as
|
||||
importing into spread sheets (data is space delimited with quotes as
|
||||
text qualifier).
|
||||
|
||||
.SH FILE MATCHING OPTIONS
|
||||
.TP
|
||||
.B \-model
|
||||
Restricts processing of files to those whose camera model, as indicated
|
||||
by the Exif image information, contains the substring specified in the
|
||||
argument after '\-model'. For example, the following command will list
|
||||
only images that are from an S100 camera:
|
||||
|
||||
.I jhead \-model S100 *.jpg
|
||||
|
||||
I use this option to restrict my JPEG recompensing to those images that
|
||||
came from my Canon S100 digicam, (see the \-cmd option).
|
||||
.TP
|
||||
.B \-exonly
|
||||
Skip all files that don't have an Exif header. Photos straight from a
|
||||
digital camera have an Exif header, whereas many photo manipulation
|
||||
tools discard the Exif header.
|
||||
.TP
|
||||
.B \-cmd
|
||||
Executes the specified command on each JPEG file to be processed.
|
||||
|
||||
The Exif section of each file is read before running the command, and
|
||||
reinserted after the command finishes.
|
||||
|
||||
The specified command invoked separately for each JPEG that is
|
||||
processed, even if multiple files are specified (explicitly or by wild
|
||||
card).
|
||||
|
||||
Example use:
|
||||
|
||||
Having a whole directory of photos from my S100, I run the following commands:
|
||||
|
||||
.I jhead \-cmd """mogrify \-quality 80 &i"" \-model S100 *.jpg
|
||||
.br
|
||||
.I jhead \-cmd """jpegtran \-progressive &i > &o"" *.jpg
|
||||
|
||||
The first command mogrifies all JPEGs in the tree that indicate that
|
||||
they are from a Canon S100 in their Exif header to 80% quality at the
|
||||
same resolution. This is a 'lossy' process, so I only run it on files
|
||||
that are from the Canon, and only run it once. The next command then
|
||||
takes a JPEGs and converts them to progressive JPEGs. The result is the
|
||||
same images, with no discernible differences, stored in half the space.
|
||||
This produces substantial savings on some cameras.
|
||||
|
||||
.SH SEE ALSO
|
||||
.BR jpegtran (1),
|
||||
.BR mogrify (1),
|
||||
.BR rdjpgcom (1),
|
||||
.BR wrjpgcom (1)
|
||||
.SH AUTHOR
|
||||
Matthias Wandel
|
||||
.SH BUGS
|
||||
After jhead runs a program to rotate or resize an image, the image
|
||||
dimensions and thumbnail in the Exif header are not adjusted.
|
||||
.PP
|
||||
Modifying of Exif header data is very limited, as Jhead internally only
|
||||
has a read only implementation of the file system contained in the Exif
|
||||
header. For example, there is no way to replace the thumbnail or edit
|
||||
the Exif comment in the Exif header. There is also no way to create
|
||||
minimal exif headers.
|
||||
.PP
|
||||
Some Canon digital SLR cameras fail to adjust the effective sensor
|
||||
resolution when shooting at less than full resolution, causing jhead to
|
||||
incorrectly miscalculate the sensor width and 35mm equivalent focal
|
||||
length. The same can result from resizing photos with Photoshop, which
|
||||
will manipulate parts of the exif header. This is often reported as a
|
||||
bug in Jhead, but Jhead can't do much about incorrect data.
|
||||
.PP
|
||||
Send bug reports to mwandel at sentex dot net.
|
||||
|
||||
.SH COPYING PERMISSIONS
|
||||
Jhead is 'public domain'. You may freely copy jhead, and reuse part or
|
||||
all of its code in free or proprietary programs. I do however request
|
||||
that you do not post my e-mail address in ways that spam robots can
|
||||
harvest it.
|
||||
1771
src/external/jhead-3.04/jhead.c
vendored
1771
src/external/jhead-3.04/jhead.c
vendored
File diff suppressed because it is too large
Load Diff
271
src/external/jhead-3.04/jhead.h
vendored
271
src/external/jhead-3.04/jhead.h
vendored
@ -1,271 +0,0 @@
|
||||
//--------------------------------------------------------------------------
|
||||
// Include file for jhead program.
|
||||
//
|
||||
// This include file only defines stuff that goes across modules.
|
||||
// I like to keep the definitions for macros and structures as close to
|
||||
// where they get used as possible, so include files only get stuff that
|
||||
// gets used in more than one file.
|
||||
//--------------------------------------------------------------------------
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <sys/utime.h>
|
||||
|
||||
// Make the Microsoft Visual c 10 deprecate warnings go away.
|
||||
// The _CRT_SECURE_NO_DEPRECATE doesn't do the trick like it should.
|
||||
#define unlink _unlink
|
||||
#define chmod _chmod
|
||||
#define access _access
|
||||
#define mktemp _mktemp
|
||||
|
||||
#if _MSC_VER && _MSC_VER <= 1500
|
||||
// The 2007 vintage compiler I use on windows doesn't have snprintf
|
||||
#define snprintf(dest, len, format,...) sprintf (dest, format, __VA_ARGS__)
|
||||
#endif
|
||||
#else
|
||||
#include <utime.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#endif
|
||||
|
||||
|
||||
typedef unsigned char uchar;
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
#define MAX_COMMENT_SIZE 16000
|
||||
|
||||
#ifdef _WIN32
|
||||
#define PATH_MAX _MAX_PATH
|
||||
#define SLASH '\\'
|
||||
#else
|
||||
#ifndef PATH_MAX
|
||||
#define PATH_MAX 1024
|
||||
#endif
|
||||
#define SLASH '/'
|
||||
#endif
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// This structure is used to store jpeg file sections in memory.
|
||||
typedef struct {
|
||||
uchar * Data;
|
||||
int Type;
|
||||
unsigned Size;
|
||||
}Section_t;
|
||||
|
||||
extern int ExifSectionIndex;
|
||||
|
||||
extern int DumpExifMap;
|
||||
|
||||
#define MAX_DATE_COPIES 10
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// This structure stores Exif header image elements in a simple manner
|
||||
// Used to store camera data as extracted from the various ways that it can be
|
||||
// stored in an exif header
|
||||
typedef struct {
|
||||
char FileName [PATH_MAX+1];
|
||||
time_t FileDateTime;
|
||||
|
||||
struct {
|
||||
// Info in the jfif header.
|
||||
// This info is not used much - jhead used to just replace it with default
|
||||
// values, and over 10 years, only two people pointed this out.
|
||||
char Present;
|
||||
char ResolutionUnits;
|
||||
short XDensity;
|
||||
short YDensity;
|
||||
}JfifHeader;
|
||||
|
||||
unsigned FileSize;
|
||||
char CameraMake [32];
|
||||
char CameraModel [40];
|
||||
char DateTime [20];
|
||||
unsigned Height, Width;
|
||||
int Orientation;
|
||||
int IsColor;
|
||||
int Process;
|
||||
int FlashUsed;
|
||||
float FocalLength;
|
||||
float ExposureTime;
|
||||
float ApertureFNumber;
|
||||
float Distance;
|
||||
float CCDWidth;
|
||||
float ExposureBias;
|
||||
float DigitalZoomRatio;
|
||||
int FocalLength35mmEquiv; // Exif 2.2 tag - usually not present.
|
||||
int Whitebalance;
|
||||
int MeteringMode;
|
||||
int ExposureProgram;
|
||||
int ExposureMode;
|
||||
int ISOequivalent;
|
||||
int LightSource;
|
||||
int DistanceRange;
|
||||
|
||||
float xResolution;
|
||||
float yResolution;
|
||||
int ResolutionUnit;
|
||||
|
||||
char Comments[MAX_COMMENT_SIZE];
|
||||
int CommentWidthchars; // If nonzero, widechar comment, indicates number of chars.
|
||||
|
||||
int ThumbnailOffset; // Exif offset to thumbnail
|
||||
int ThumbnailSize; // Size of thumbnail.
|
||||
int LargestExifOffset; // Last exif data referenced (to check if thumbnail is at end)
|
||||
|
||||
char ThumbnailAtEnd; // Exif header ends with the thumbnail
|
||||
// (we can only modify the thumbnail if its at the end)
|
||||
int ThumbnailSizeOffset;
|
||||
|
||||
int DateTimeOffsets[MAX_DATE_COPIES];
|
||||
int numDateTimeTags;
|
||||
|
||||
int GpsInfoPresent;
|
||||
char GpsLat[31];
|
||||
char GpsLong[31];
|
||||
char GpsAlt[20];
|
||||
|
||||
int QualityGuess;
|
||||
}ImageInfo_t;
|
||||
|
||||
|
||||
#ifndef EXIT_FAILURE
|
||||
#define EXIT_FAILURE 1
|
||||
#endif
|
||||
#define EXIT_SUCCESS 0
|
||||
|
||||
// jpgfile.c functions
|
||||
typedef enum {
|
||||
READ_METADATA = 1,
|
||||
READ_IMAGE = 2,
|
||||
READ_ALL = 3,
|
||||
READ_ANY = 5 // Don't abort on non-jpeg files.
|
||||
}ReadMode_t;
|
||||
|
||||
|
||||
// prototypes for jhead.c functions
|
||||
void ErrFatal(const char * msg);
|
||||
void ErrNonfatal(const char * msg, int a1, int a2);
|
||||
void FileTimeAsString(char * TimeStr);
|
||||
|
||||
// Prototypes for exif.c functions.
|
||||
int Exif2tm(struct tm * timeptr, char * ExifTime);
|
||||
void Clear_EXIF();
|
||||
void process_EXIF (unsigned char * CharBuf, int length);
|
||||
void ShowImageInfo(int ShowFileInfo);
|
||||
void ShowConciseImageInfo(void);
|
||||
const char * ClearOrientation(void);
|
||||
void PrintFormatNumber(void * ValuePtr, int Format, int ByteCount);
|
||||
double ConvertAnyFormat(void * ValuePtr, int Format);
|
||||
int Get16u(void * Short);
|
||||
unsigned Get32u(void * Long);
|
||||
int Get32s(void * Long);
|
||||
void Put32u(void * Value, unsigned PutValue);
|
||||
void create_EXIF(void);
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Exif format descriptor stuff
|
||||
extern const int BytesPerFormat[];
|
||||
#define NUM_FORMATS 12
|
||||
|
||||
#define FMT_BYTE 1
|
||||
#define FMT_STRING 2
|
||||
#define FMT_USHORT 3
|
||||
#define FMT_ULONG 4
|
||||
#define FMT_URATIONAL 5
|
||||
#define FMT_SBYTE 6
|
||||
#define FMT_UNDEFINED 7
|
||||
#define FMT_SSHORT 8
|
||||
#define FMT_SLONG 9
|
||||
#define FMT_SRATIONAL 10
|
||||
#define FMT_SINGLE 11
|
||||
#define FMT_DOUBLE 12
|
||||
|
||||
|
||||
// makernote.c prototypes
|
||||
extern void ProcessMakerNote(unsigned char * DirStart, int ByteCount,
|
||||
unsigned char * OffsetBase, unsigned ExifLength);
|
||||
|
||||
// gpsinfo.c prototypes
|
||||
void ProcessGpsInfo(unsigned char * ValuePtr,
|
||||
unsigned char * OffsetBase, unsigned ExifLength);
|
||||
|
||||
// iptc.c prototpyes
|
||||
void show_IPTC (unsigned char * CharBuf, unsigned int length);
|
||||
void ShowXmp(Section_t XmpSection);
|
||||
|
||||
// Prototypes for myglob.c module
|
||||
#ifdef _WIN32
|
||||
void MyGlob(const char * Pattern , void (*FileFuncParm)(const char * FileName));
|
||||
void SlashToNative(char * Path);
|
||||
#endif
|
||||
|
||||
// Prototypes for paths.c module
|
||||
int EnsurePathExists(const char * FileName);
|
||||
void CatPath(char * BasePath, const char * FilePath);
|
||||
|
||||
// Prototypes from jpgfile.c
|
||||
int ReadJpegSections (FILE * infile, ReadMode_t ReadMode);
|
||||
void DiscardData(void);
|
||||
void DiscardAllButExif(void);
|
||||
int ReadJpegFile(const char * FileName, ReadMode_t ReadMode);
|
||||
int ReplaceThumbnail(const char * ThumbFileName);
|
||||
int SaveThumbnail(char * ThumbFileName);
|
||||
int RemoveSectionType(int SectionType);
|
||||
int RemoveUnknownSections(void);
|
||||
void WriteJpegFile(const char * FileName);
|
||||
Section_t * FindSection(int SectionType);
|
||||
Section_t * CreateSection(int SectionType, unsigned char * Data, int size);
|
||||
void ResetJpgfile(void);
|
||||
|
||||
// Prototypes from jpgqguess.c
|
||||
void process_DQT (const uchar * Data, int length);
|
||||
void process_DHT (const uchar * Data, int length);
|
||||
|
||||
// Variables from jhead.c used by exif.c
|
||||
extern ImageInfo_t ImageInfo;
|
||||
extern int ShowTags;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// JPEG markers consist of one or more 0xFF bytes, followed by a marker
|
||||
// code byte (which is not an FF). Here are the marker codes of interest
|
||||
// in this program. (See jdmarker.c for a more complete list.)
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
#define M_SOF0 0xC0 // Start Of Frame N
|
||||
#define M_SOF1 0xC1 // N indicates which compression process
|
||||
#define M_SOF2 0xC2 // Only SOF0-SOF2 are now in common use
|
||||
#define M_SOF3 0xC3
|
||||
#define M_SOF5 0xC5 // NB: codes C4 and CC are NOT SOF markers
|
||||
#define M_SOF6 0xC6
|
||||
#define M_SOF7 0xC7
|
||||
#define M_SOF9 0xC9
|
||||
#define M_SOF10 0xCA
|
||||
#define M_SOF11 0xCB
|
||||
#define M_SOF13 0xCD
|
||||
#define M_SOF14 0xCE
|
||||
#define M_SOF15 0xCF
|
||||
#define M_SOI 0xD8 // Start Of Image (beginning of datastream)
|
||||
#define M_EOI 0xD9 // End Of Image (end of datastream)
|
||||
#define M_SOS 0xDA // Start Of Scan (begins compressed data)
|
||||
#define M_JFIF 0xE0 // Jfif marker
|
||||
#define M_EXIF 0xE1 // Exif marker. Also used for XMP data!
|
||||
#define M_XMP 0x10E1 // Not a real tag (same value in file as Exif!)
|
||||
#define M_COM 0xFE // COMment
|
||||
#define M_DQT 0xDB // Define Quantization Table
|
||||
#define M_DHT 0xC4 // Define Huffmann Table
|
||||
#define M_DRI 0xDD
|
||||
#define M_IPTC 0xED // IPTC marker
|
||||
775
src/external/jhead-3.04/jpgfile.c
vendored
775
src/external/jhead-3.04/jpgfile.c
vendored
@ -1,775 +0,0 @@
|
||||
//--------------------------------------------------------------------------
|
||||
// Program to pull the information out of various types of EXIF digital
|
||||
// camera files and show it in a reasonably consistent way
|
||||
//
|
||||
// This module handles basic Jpeg file handling
|
||||
//
|
||||
// Matthias Wandel
|
||||
//--------------------------------------------------------------------------
|
||||
#include "jhead.h"
|
||||
|
||||
// Storage for simplified info extracted from file.
|
||||
ImageInfo_t ImageInfo;
|
||||
|
||||
|
||||
static Section_t * Sections = NULL;
|
||||
static int SectionsAllocated;
|
||||
static int SectionsRead;
|
||||
static int HaveAll;
|
||||
|
||||
|
||||
|
||||
#define PSEUDO_IMAGE_MARKER 0x123; // Extra value.
|
||||
//--------------------------------------------------------------------------
|
||||
// Get 16 bits motorola order (always) for jpeg header stuff.
|
||||
//--------------------------------------------------------------------------
|
||||
static int Get16m(const void * Short)
|
||||
{
|
||||
return (((uchar *)Short)[0] << 8) | ((uchar *)Short)[1];
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Process a COM marker.
|
||||
// We want to print out the marker contents as legible text;
|
||||
// we must guard against random junk and varying newline representations.
|
||||
//--------------------------------------------------------------------------
|
||||
static void process_COM (const uchar * Data, int length)
|
||||
{
|
||||
int ch;
|
||||
char Comment[MAX_COMMENT_SIZE+1];
|
||||
int nch;
|
||||
int a;
|
||||
|
||||
nch = 0;
|
||||
|
||||
if (length > MAX_COMMENT_SIZE) length = MAX_COMMENT_SIZE; // Truncate if it won't fit in our structure.
|
||||
|
||||
for (a=2;a<length;a++){
|
||||
ch = Data[a];
|
||||
|
||||
if (ch == '\r' && Data[a+1] == '\n') continue; // Remove cr followed by lf.
|
||||
|
||||
if (ch >= 32 || ch == '\n' || ch == '\t'){
|
||||
Comment[nch++] = (char)ch;
|
||||
}else{
|
||||
Comment[nch++] = '?';
|
||||
}
|
||||
}
|
||||
|
||||
Comment[nch] = '\0'; // Null terminate
|
||||
|
||||
if (ShowTags){
|
||||
printf("COM marker comment: %s\n",Comment);
|
||||
}
|
||||
|
||||
strcpy(ImageInfo.Comments,Comment);
|
||||
ImageInfo.CommentWidthchars = 0;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Process a SOFn marker. This is useful for the image dimensions
|
||||
//--------------------------------------------------------------------------
|
||||
static void process_SOFn (const uchar * Data, int marker)
|
||||
{
|
||||
int data_precision, num_components;
|
||||
|
||||
data_precision = Data[2];
|
||||
ImageInfo.Height = Get16m(Data+3);
|
||||
ImageInfo.Width = Get16m(Data+5);
|
||||
num_components = Data[7];
|
||||
|
||||
if (num_components == 3){
|
||||
ImageInfo.IsColor = 1;
|
||||
}else{
|
||||
ImageInfo.IsColor = 0;
|
||||
}
|
||||
|
||||
ImageInfo.Process = marker;
|
||||
|
||||
if (ShowTags){
|
||||
printf("JPEG image is %uw * %uh, %d color components, %d bits per sample\n",
|
||||
ImageInfo.Width, ImageInfo.Height, num_components, data_precision);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Check sections array to see if it needs to be increased in size.
|
||||
//--------------------------------------------------------------------------
|
||||
static void CheckSectionsAllocated(void)
|
||||
{
|
||||
if (SectionsRead > SectionsAllocated){
|
||||
ErrFatal("allocation screwup");
|
||||
}
|
||||
if (SectionsRead >= SectionsAllocated){
|
||||
SectionsAllocated += SectionsAllocated/2;
|
||||
Sections = (Section_t *)realloc(Sections, sizeof(Section_t)*SectionsAllocated);
|
||||
if (Sections == NULL){
|
||||
ErrFatal("could not allocate data for entire image");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Parse the marker stream until SOS or EOI is seen;
|
||||
//--------------------------------------------------------------------------
|
||||
int ReadJpegSections (FILE * infile, ReadMode_t ReadMode)
|
||||
{
|
||||
int a;
|
||||
int HaveCom = FALSE;
|
||||
|
||||
a = fgetc(infile);
|
||||
|
||||
if (a != 0xff || fgetc(infile) != M_SOI){
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ImageInfo.JfifHeader.XDensity = ImageInfo.JfifHeader.YDensity = 300;
|
||||
ImageInfo.JfifHeader.ResolutionUnits = 1;
|
||||
|
||||
for(;;){
|
||||
int itemlen;
|
||||
int prev;
|
||||
int marker = 0;
|
||||
int ll,lh, got;
|
||||
uchar * Data;
|
||||
|
||||
CheckSectionsAllocated();
|
||||
|
||||
prev = 0;
|
||||
for (a=0;;a++){
|
||||
marker = fgetc(infile);
|
||||
if (marker != 0xff && prev == 0xff) break;
|
||||
if (marker == EOF){
|
||||
ErrFatal("Unexpected end of file");
|
||||
}
|
||||
prev = marker;
|
||||
}
|
||||
|
||||
if (a > 10){
|
||||
ErrNonfatal("Extraneous %d padding bytes before section %02X",a-1,marker);
|
||||
}
|
||||
|
||||
Sections[SectionsRead].Type = marker;
|
||||
|
||||
// Read the length of the section.
|
||||
lh = fgetc(infile);
|
||||
ll = fgetc(infile);
|
||||
if (lh == EOF || ll == EOF){
|
||||
ErrFatal("Unexpected end of file");
|
||||
}
|
||||
|
||||
itemlen = (lh << 8) | ll;
|
||||
|
||||
if (itemlen < 2){
|
||||
ErrFatal("invalid marker");
|
||||
}
|
||||
|
||||
Sections[SectionsRead].Size = itemlen;
|
||||
|
||||
Data = (uchar *)malloc(itemlen);
|
||||
if (Data == NULL){
|
||||
ErrFatal("Could not allocate memory");
|
||||
}
|
||||
Sections[SectionsRead].Data = Data;
|
||||
|
||||
// Store first two pre-read bytes.
|
||||
Data[0] = (uchar)lh;
|
||||
Data[1] = (uchar)ll;
|
||||
|
||||
got = fread(Data+2, 1, itemlen-2, infile); // Read the whole section.
|
||||
if (got != itemlen-2){
|
||||
ErrFatal("Premature end of file?");
|
||||
}
|
||||
SectionsRead += 1;
|
||||
|
||||
switch(marker){
|
||||
|
||||
case M_SOS: // stop before hitting compressed data
|
||||
// If reading entire image is requested, read the rest of the data.
|
||||
if (ReadMode & READ_IMAGE){
|
||||
int cp, ep, size;
|
||||
// Determine how much file is left.
|
||||
cp = ftell(infile);
|
||||
fseek(infile, 0, SEEK_END);
|
||||
ep = ftell(infile);
|
||||
fseek(infile, cp, SEEK_SET);
|
||||
|
||||
size = ep-cp;
|
||||
Data = (uchar *)malloc(size);
|
||||
if (Data == NULL){
|
||||
ErrFatal("could not allocate data for entire image");
|
||||
}
|
||||
|
||||
got = fread(Data, 1, size, infile);
|
||||
if (got != size){
|
||||
ErrFatal("could not read the rest of the image");
|
||||
}
|
||||
|
||||
CheckSectionsAllocated();
|
||||
Sections[SectionsRead].Data = Data;
|
||||
Sections[SectionsRead].Size = size;
|
||||
Sections[SectionsRead].Type = PSEUDO_IMAGE_MARKER;
|
||||
SectionsRead ++;
|
||||
HaveAll = 1;
|
||||
}
|
||||
return TRUE;
|
||||
|
||||
case M_DQT:
|
||||
// Use for jpeg quality guessing
|
||||
process_DQT(Data, itemlen);
|
||||
break;
|
||||
|
||||
case M_DHT:
|
||||
// Use for jpeg quality guessing
|
||||
process_DHT(Data, itemlen);
|
||||
break;
|
||||
|
||||
|
||||
case M_EOI: // in case it's a tables-only JPEG stream
|
||||
fprintf(stderr,"No image in jpeg!\n");
|
||||
return FALSE;
|
||||
|
||||
case M_COM: // Comment section
|
||||
if (HaveCom || ((ReadMode & READ_METADATA) == 0)){
|
||||
// Discard this section.
|
||||
free(Sections[--SectionsRead].Data);
|
||||
}else{
|
||||
process_COM(Data, itemlen);
|
||||
HaveCom = TRUE;
|
||||
}
|
||||
break;
|
||||
|
||||
case M_JFIF:
|
||||
// Regular jpegs always have this tag, exif images have the exif
|
||||
// marker instead, althogh ACDsee will write images with both markers.
|
||||
// this program will re-create this marker on absence of exif marker.
|
||||
// hence no need to keep the copy from the file.
|
||||
if (itemlen < 16){
|
||||
fprintf(stderr,"Jfif header too short\n");
|
||||
goto ignore;
|
||||
}
|
||||
if (memcmp(Data+2, "JFIF\0",5)){
|
||||
fprintf(stderr,"Header missing JFIF marker\n");
|
||||
}
|
||||
|
||||
ImageInfo.JfifHeader.Present = TRUE;
|
||||
ImageInfo.JfifHeader.ResolutionUnits = Data[9];
|
||||
ImageInfo.JfifHeader.XDensity = (Data[10]<<8) | Data[11];
|
||||
ImageInfo.JfifHeader.YDensity = (Data[12]<<8) | Data[13];
|
||||
if (ShowTags){
|
||||
printf("JFIF SOI marker: Units: %d ",ImageInfo.JfifHeader.ResolutionUnits);
|
||||
switch(ImageInfo.JfifHeader.ResolutionUnits){
|
||||
case 0: printf("(aspect ratio)"); break;
|
||||
case 1: printf("(dots per inch)"); break;
|
||||
case 2: printf("(dots per cm)"); break;
|
||||
default: printf("(unknown)"); break;
|
||||
}
|
||||
printf(" X-density=%d Y-density=%d\n",ImageInfo.JfifHeader.XDensity, ImageInfo.JfifHeader.YDensity);
|
||||
|
||||
if (Data[14] || Data[15]){
|
||||
fprintf(stderr,"Ignoring jfif header thumbnail\n");
|
||||
}
|
||||
}
|
||||
|
||||
ignore:
|
||||
|
||||
free(Sections[--SectionsRead].Data);
|
||||
break;
|
||||
|
||||
case M_EXIF:
|
||||
// There can be different section using the same marker.
|
||||
if (ReadMode & READ_METADATA){
|
||||
if (memcmp(Data+2, "Exif", 4) == 0){
|
||||
process_EXIF(Data, itemlen);
|
||||
break;
|
||||
}else if (memcmp(Data+2, "http:", 5) == 0){
|
||||
Sections[SectionsRead-1].Type = M_XMP; // Change tag for internal purposes.
|
||||
if (ShowTags){
|
||||
printf("Image contains XMP section, %d bytes long\n", itemlen);
|
||||
if (ShowTags){
|
||||
ShowXmp(Sections[SectionsRead-1]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Oterwise, discard this section.
|
||||
free(Sections[--SectionsRead].Data);
|
||||
break;
|
||||
|
||||
case M_IPTC:
|
||||
if (ReadMode & READ_METADATA){
|
||||
if (ShowTags){
|
||||
printf("Image contains IPTC section, %d bytes long\n", itemlen);
|
||||
}
|
||||
// Note: We just store the IPTC section. Its relatively straightforward
|
||||
// and we don't act on any part of it, so just display it at parse time.
|
||||
}else{
|
||||
free(Sections[--SectionsRead].Data);
|
||||
}
|
||||
break;
|
||||
|
||||
case M_SOF0:
|
||||
case M_SOF1:
|
||||
case M_SOF2:
|
||||
case M_SOF3:
|
||||
case M_SOF5:
|
||||
case M_SOF6:
|
||||
case M_SOF7:
|
||||
case M_SOF9:
|
||||
case M_SOF10:
|
||||
case M_SOF11:
|
||||
case M_SOF13:
|
||||
case M_SOF14:
|
||||
case M_SOF15:
|
||||
if (itemlen < 8){
|
||||
fprintf(stderr,"Section too short\n");
|
||||
break;
|
||||
}
|
||||
process_SOFn(Data, marker);
|
||||
break;
|
||||
default:
|
||||
// Skip any other sections.
|
||||
if (ShowTags){
|
||||
printf("Jpeg section marker 0x%02x size %d\n",marker, itemlen);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Discard read data.
|
||||
//--------------------------------------------------------------------------
|
||||
void DiscardData(void)
|
||||
{
|
||||
int a;
|
||||
|
||||
for (a=0;a<SectionsRead;a++){
|
||||
free(Sections[a].Data);
|
||||
}
|
||||
|
||||
memset(&ImageInfo, 0, sizeof(ImageInfo));
|
||||
SectionsRead = 0;
|
||||
HaveAll = 0;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Read image data.
|
||||
//--------------------------------------------------------------------------
|
||||
int ReadJpegFile(const char * FileName, ReadMode_t ReadMode)
|
||||
{
|
||||
FILE * infile;
|
||||
int ret;
|
||||
|
||||
infile = fopen(FileName, "rb"); // Unix ignores 'b', windows needs it.
|
||||
|
||||
if (infile == NULL) {
|
||||
fprintf(stderr, "can't open '%s'\n", FileName);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
// Scan the JPEG headers.
|
||||
ret = ReadJpegSections(infile, ReadMode);
|
||||
if (!ret){
|
||||
if (ReadMode == READ_ANY){
|
||||
// Process any files mode. Ignore the fact that it's not
|
||||
// a jpeg file.
|
||||
ret = TRUE;
|
||||
}else{
|
||||
fprintf(stderr,"Not JPEG: %s\n",FileName);
|
||||
}
|
||||
}
|
||||
|
||||
fclose(infile);
|
||||
|
||||
if (ret == FALSE){
|
||||
DiscardData();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Replace or remove exif thumbnail
|
||||
//--------------------------------------------------------------------------
|
||||
int SaveThumbnail(char * ThumbFileName)
|
||||
{
|
||||
FILE * ThumbnailFile;
|
||||
|
||||
if (ImageInfo.ThumbnailOffset == 0 || ImageInfo.ThumbnailSize == 0){
|
||||
fprintf(stderr,"Image contains no thumbnail\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (strcmp(ThumbFileName, "-") == 0){
|
||||
// A filename of '-' indicates thumbnail goes to stdout.
|
||||
// This doesn't make much sense under Windows, so this feature is unix only.
|
||||
ThumbnailFile = stdout;
|
||||
}else{
|
||||
ThumbnailFile = fopen(ThumbFileName,"wb");
|
||||
}
|
||||
|
||||
if (ThumbnailFile){
|
||||
uchar * ThumbnailPointer;
|
||||
Section_t * ExifSection;
|
||||
ExifSection = FindSection(M_EXIF);
|
||||
ThumbnailPointer = ExifSection->Data+ImageInfo.ThumbnailOffset+8;
|
||||
|
||||
fwrite(ThumbnailPointer, ImageInfo.ThumbnailSize ,1, ThumbnailFile);
|
||||
fclose(ThumbnailFile);
|
||||
return TRUE;
|
||||
}else{
|
||||
ErrFatal("Could not write thumbnail file");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Replace or remove exif thumbnail
|
||||
//--------------------------------------------------------------------------
|
||||
int ReplaceThumbnail(const char * ThumbFileName)
|
||||
{
|
||||
FILE * ThumbnailFile;
|
||||
int ThumbLen, NewExifSize;
|
||||
Section_t * ExifSection;
|
||||
uchar * ThumbnailPointer;
|
||||
|
||||
if (ImageInfo.ThumbnailOffset == 0 || ImageInfo.ThumbnailAtEnd == FALSE){
|
||||
if (ThumbFileName == NULL){
|
||||
// Delete of nonexistent thumbnail (not even pointers present)
|
||||
// No action, no error.
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Adding or removing of thumbnail is not possible - that would require rearranging
|
||||
// of the exif header, which is risky, and jhad doesn't know how to do.
|
||||
fprintf(stderr,"Image contains no thumbnail to replace - add is not possible\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (ThumbFileName){
|
||||
ThumbnailFile = fopen(ThumbFileName,"rb");
|
||||
|
||||
if (ThumbnailFile == NULL){
|
||||
noread:
|
||||
ErrFatal("Could not read thumbnail file");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// get length
|
||||
fseek(ThumbnailFile, 0, SEEK_END);
|
||||
|
||||
ThumbLen = ftell(ThumbnailFile);
|
||||
fseek(ThumbnailFile, 0, SEEK_SET);
|
||||
|
||||
if (ThumbLen + ImageInfo.ThumbnailOffset > 0x10000-20){
|
||||
ErrFatal("Thumbnail is too large to insert into exif header");
|
||||
}
|
||||
}else{
|
||||
if (ImageInfo.ThumbnailSize == 0){
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ThumbLen = 0;
|
||||
ThumbnailFile = NULL;
|
||||
}
|
||||
|
||||
ExifSection = FindSection(M_EXIF);
|
||||
|
||||
NewExifSize = ImageInfo.ThumbnailOffset+8+ThumbLen;
|
||||
ExifSection->Data = (uchar *)realloc(ExifSection->Data, NewExifSize);
|
||||
|
||||
ThumbnailPointer = ExifSection->Data+ImageInfo.ThumbnailOffset+8;
|
||||
|
||||
if (ThumbnailFile){
|
||||
if (fread(ThumbnailPointer, 1, ThumbLen, ThumbnailFile) != ThumbLen){
|
||||
goto noread;
|
||||
}
|
||||
fclose(ThumbnailFile);
|
||||
}
|
||||
|
||||
ImageInfo.ThumbnailSize = ThumbLen;
|
||||
|
||||
Put32u(ExifSection->Data+ImageInfo.ThumbnailSizeOffset+8, ThumbLen);
|
||||
|
||||
ExifSection->Data[0] = (uchar)(NewExifSize >> 8);
|
||||
ExifSection->Data[1] = (uchar)NewExifSize;
|
||||
ExifSection->Size = NewExifSize;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Discard everything but the exif and comment sections.
|
||||
//--------------------------------------------------------------------------
|
||||
void DiscardAllButExif(void)
|
||||
{
|
||||
Section_t ExifKeeper;
|
||||
Section_t CommentKeeper;
|
||||
Section_t IptcKeeper;
|
||||
Section_t XmpKeeper;
|
||||
int a;
|
||||
|
||||
memset(&ExifKeeper, 0, sizeof(ExifKeeper));
|
||||
memset(&CommentKeeper, 0, sizeof(CommentKeeper));
|
||||
memset(&IptcKeeper, 0, sizeof(IptcKeeper));
|
||||
memset(&XmpKeeper, 0, sizeof(IptcKeeper));
|
||||
|
||||
for (a=0;a<SectionsRead;a++){
|
||||
if (Sections[a].Type == M_EXIF && ExifKeeper.Type == 0){
|
||||
ExifKeeper = Sections[a];
|
||||
}else if (Sections[a].Type == M_XMP && XmpKeeper.Type == 0){
|
||||
XmpKeeper = Sections[a];
|
||||
}else if (Sections[a].Type == M_COM && CommentKeeper.Type == 0){
|
||||
CommentKeeper = Sections[a];
|
||||
}else if (Sections[a].Type == M_IPTC && IptcKeeper.Type == 0){
|
||||
IptcKeeper = Sections[a];
|
||||
}else{
|
||||
free(Sections[a].Data);
|
||||
}
|
||||
}
|
||||
SectionsRead = 0;
|
||||
if (ExifKeeper.Type){
|
||||
CheckSectionsAllocated();
|
||||
Sections[SectionsRead++] = ExifKeeper;
|
||||
}
|
||||
if (CommentKeeper.Type){
|
||||
CheckSectionsAllocated();
|
||||
Sections[SectionsRead++] = CommentKeeper;
|
||||
}
|
||||
if (IptcKeeper.Type){
|
||||
CheckSectionsAllocated();
|
||||
Sections[SectionsRead++] = IptcKeeper;
|
||||
}
|
||||
|
||||
if (XmpKeeper.Type){
|
||||
CheckSectionsAllocated();
|
||||
Sections[SectionsRead++] = XmpKeeper;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Write image data back to disk.
|
||||
//--------------------------------------------------------------------------
|
||||
void WriteJpegFile(const char * FileName)
|
||||
{
|
||||
FILE * outfile;
|
||||
int a;
|
||||
|
||||
if (!HaveAll){
|
||||
ErrFatal("Can't write back - didn't read all");
|
||||
}
|
||||
|
||||
outfile = fopen(FileName,"wb");
|
||||
if (outfile == NULL){
|
||||
ErrFatal("Could not open file for write");
|
||||
}
|
||||
|
||||
// Initial static jpeg marker.
|
||||
fputc(0xff,outfile);
|
||||
fputc(0xd8,outfile);
|
||||
|
||||
if (Sections[0].Type != M_EXIF && Sections[0].Type != M_JFIF){
|
||||
// The image must start with an exif or jfif marker. If we threw those away, create one.
|
||||
static uchar JfifHead[18] = {
|
||||
0xff, M_JFIF,
|
||||
0x00, 0x10, 'J' , 'F' , 'I' , 'F' , 0x00, 0x01,
|
||||
0x01, 0x01, 0x01, 0x2C, 0x01, 0x2C, 0x00, 0x00
|
||||
};
|
||||
|
||||
if (ImageInfo.ResolutionUnit == 2 || ImageInfo.ResolutionUnit == 3){
|
||||
// Use the exif resolution info to fill out the jfif header.
|
||||
// Usually, for exif images, there's no jfif header, so if wediscard
|
||||
// the exif header, use info from the exif header for the jfif header.
|
||||
|
||||
ImageInfo.JfifHeader.ResolutionUnits = (char)(ImageInfo.ResolutionUnit-1);
|
||||
// Jfif is 1 and 2, Exif is 2 and 3 for In and cm respecively
|
||||
ImageInfo.JfifHeader.XDensity = (int)ImageInfo.xResolution;
|
||||
ImageInfo.JfifHeader.YDensity = (int)ImageInfo.yResolution;
|
||||
}
|
||||
|
||||
JfifHead[11] = ImageInfo.JfifHeader.ResolutionUnits;
|
||||
JfifHead[12] = (uchar)(ImageInfo.JfifHeader.XDensity >> 8);
|
||||
JfifHead[13] = (uchar)ImageInfo.JfifHeader.XDensity;
|
||||
JfifHead[14] = (uchar)(ImageInfo.JfifHeader.YDensity >> 8);
|
||||
JfifHead[15] = (uchar)ImageInfo.JfifHeader.YDensity;
|
||||
|
||||
|
||||
fwrite(JfifHead, 18, 1, outfile);
|
||||
|
||||
// use the values from the exif data for the jfif header, if we have found values
|
||||
if (ImageInfo.ResolutionUnit != 0) {
|
||||
// JFIF.ResolutionUnit is {1,2}, EXIF.ResolutionUnit is {2,3}
|
||||
JfifHead[11] = (uchar)ImageInfo.ResolutionUnit - 1;
|
||||
}
|
||||
if (ImageInfo.xResolution > 0.0 && ImageInfo.yResolution > 0.0) {
|
||||
JfifHead[12] = (uchar)((int)ImageInfo.xResolution>>8);
|
||||
JfifHead[13] = (uchar)((int)ImageInfo.xResolution);
|
||||
|
||||
JfifHead[14] = (uchar)((int)ImageInfo.yResolution>>8);
|
||||
JfifHead[15] = (uchar)((int)ImageInfo.yResolution);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Write all the misc sections
|
||||
for (a=0;a<SectionsRead-1;a++){
|
||||
fputc(0xff,outfile);
|
||||
fputc((unsigned char)Sections[a].Type, outfile);
|
||||
fwrite(Sections[a].Data, Sections[a].Size, 1, outfile);
|
||||
}
|
||||
|
||||
// Write the remaining image data.
|
||||
fwrite(Sections[a].Data, Sections[a].Size, 1, outfile);
|
||||
|
||||
fclose(outfile);
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Check if image has exif header.
|
||||
//--------------------------------------------------------------------------
|
||||
Section_t * FindSection(int SectionType)
|
||||
{
|
||||
int a;
|
||||
|
||||
for (a=0;a<SectionsRead;a++){
|
||||
if (Sections[a].Type == SectionType){
|
||||
return &Sections[a];
|
||||
}
|
||||
}
|
||||
// Could not be found.
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Remove a certain type of section.
|
||||
//--------------------------------------------------------------------------
|
||||
int RemoveSectionType(int SectionType)
|
||||
{
|
||||
int a;
|
||||
int retval = FALSE;
|
||||
for (a=0;a<SectionsRead-1;a++){
|
||||
if (Sections[a].Type == SectionType){
|
||||
// Free up this section
|
||||
free (Sections[a].Data);
|
||||
// Move succeding sections back by one to close space in array.
|
||||
memmove(Sections+a, Sections+a+1, sizeof(Section_t) * (SectionsRead-a));
|
||||
SectionsRead -= 1;
|
||||
a -= 1;
|
||||
retval = TRUE;
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Remove sectons not part of image and not exif or comment sections.
|
||||
//--------------------------------------------------------------------------
|
||||
int RemoveUnknownSections(void)
|
||||
{
|
||||
int a;
|
||||
int Modified = FALSE;
|
||||
for (a=0;a<SectionsRead-1;){
|
||||
switch(Sections[a].Type){
|
||||
case M_SOF0:
|
||||
case M_SOF1:
|
||||
case M_SOF2:
|
||||
case M_SOF3:
|
||||
case M_SOF5:
|
||||
case M_SOF6:
|
||||
case M_SOF7:
|
||||
case M_SOF9:
|
||||
case M_SOF10:
|
||||
case M_SOF11:
|
||||
case M_SOF13:
|
||||
case M_SOF14:
|
||||
case M_SOF15:
|
||||
case M_SOI:
|
||||
case M_EOI:
|
||||
case M_SOS:
|
||||
case M_JFIF:
|
||||
case M_EXIF:
|
||||
case M_XMP:
|
||||
case M_COM:
|
||||
case M_DQT:
|
||||
case M_DHT:
|
||||
case M_DRI:
|
||||
case M_IPTC:
|
||||
// keep.
|
||||
a++;
|
||||
break;
|
||||
default:
|
||||
// Unknown. Delete.
|
||||
free (Sections[a].Data);
|
||||
// Move succeding sections back by one to close space in array.
|
||||
memmove(Sections+a, Sections+a+1, sizeof(Section_t) * (SectionsRead-a));
|
||||
SectionsRead -= 1;
|
||||
Modified = TRUE;
|
||||
}
|
||||
}
|
||||
return Modified;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Add a section (assume it doesn't already exist) - used for
|
||||
// adding comment sections and exif sections
|
||||
//--------------------------------------------------------------------------
|
||||
Section_t * CreateSection(int SectionType, unsigned char * Data, int Size)
|
||||
{
|
||||
Section_t * NewSection;
|
||||
int a;
|
||||
int NewIndex;
|
||||
|
||||
NewIndex = 0; // Figure out where to put the comment section.
|
||||
if (SectionType == M_EXIF){
|
||||
// Exif alwas goes first!
|
||||
}else{
|
||||
for (;NewIndex < 3;NewIndex++){ // Maximum fourth position (just for the heck of it)
|
||||
if (Sections[NewIndex].Type == M_JFIF) continue; // Put it after Jfif
|
||||
if (Sections[NewIndex].Type == M_EXIF) continue; // Put it after Exif
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (SectionsRead < NewIndex){
|
||||
ErrFatal("Too few sections!");
|
||||
}
|
||||
|
||||
CheckSectionsAllocated();
|
||||
for (a=SectionsRead;a>NewIndex;a--){
|
||||
Sections[a] = Sections[a-1];
|
||||
}
|
||||
SectionsRead += 1;
|
||||
|
||||
NewSection = Sections+NewIndex;
|
||||
|
||||
NewSection->Type = SectionType;
|
||||
NewSection->Size = Size;
|
||||
NewSection->Data = Data;
|
||||
|
||||
return NewSection;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Initialisation.
|
||||
//--------------------------------------------------------------------------
|
||||
void ResetJpgfile(void)
|
||||
{
|
||||
if (Sections == NULL){
|
||||
Sections = (Section_t *)malloc(sizeof(Section_t)*5);
|
||||
SectionsAllocated = 5;
|
||||
}
|
||||
|
||||
SectionsRead = 0;
|
||||
HaveAll = 0;
|
||||
}
|
||||
214
src/external/jhead-3.04/jpgqguess.c
vendored
214
src/external/jhead-3.04/jpgqguess.c
vendored
@ -1,214 +0,0 @@
|
||||
//--------------------------------------------------------------------------
|
||||
// Program to pull the information out of various types of EXIF digital
|
||||
// camera files and show it in a reasonably consistent way
|
||||
//
|
||||
// This module handles guessing of jpeg quality from quantization table
|
||||
//
|
||||
// Using code from Andy Spiegl
|
||||
//--------------------------------------------------------------------------
|
||||
#include "jhead.h"
|
||||
|
||||
// for the DQT marker -- start --
|
||||
// Sample quantization tables from JPEG spec --- only needed for
|
||||
// guesstimate of quality factor. Note these are in zigzag order.
|
||||
|
||||
static int std_luminance_quant_tbl[64] = {
|
||||
16, 11, 12, 14, 12, 10, 16, 14,
|
||||
13, 14, 18, 17, 16, 19, 24, 40,
|
||||
26, 24, 22, 22, 24, 49, 35, 37,
|
||||
29, 40, 58, 51, 61, 60, 57, 51,
|
||||
56, 55, 64, 72, 92, 78, 64, 68,
|
||||
87, 69, 55, 56, 80, 109, 81, 87,
|
||||
95, 98, 103, 104, 103, 62, 77, 113,
|
||||
121, 112, 100, 120, 92, 101, 103, 99
|
||||
};
|
||||
|
||||
static int std_chrominance_quant_tbl[64] = {
|
||||
17, 18, 18, 24, 21, 24, 47, 26,
|
||||
26, 47, 99, 66, 56, 66, 99, 99,
|
||||
99, 99, 99, 99, 99, 99, 99, 99,
|
||||
99, 99, 99, 99, 99, 99, 99, 99,
|
||||
99, 99, 99, 99, 99, 99, 99, 99,
|
||||
99, 99, 99, 99, 99, 99, 99, 99,
|
||||
99, 99, 99, 99, 99, 99, 99, 99,
|
||||
99, 99, 99, 99, 99, 99, 99, 99
|
||||
};
|
||||
|
||||
static int *deftabs[2] =
|
||||
{ std_luminance_quant_tbl, std_chrominance_quant_tbl };
|
||||
|
||||
// jpeg_zigzag_order[i] is the zigzag-order position of the i'th element
|
||||
// of a DCT block read in natural order (left to right, top to bottom).
|
||||
|
||||
static int jpeg_zigzag_order[64] = {
|
||||
0, 1, 5, 6, 14, 15, 27, 28,
|
||||
2, 4, 7, 13, 16, 26, 29, 42,
|
||||
3, 8, 12, 17, 25, 30, 41, 43,
|
||||
9, 11, 18, 24, 31, 40, 44, 53,
|
||||
10, 19, 23, 32, 39, 45, 52, 54,
|
||||
20, 22, 33, 38, 46, 51, 55, 60,
|
||||
21, 34, 37, 47, 50, 56, 59, 61,
|
||||
35, 36, 48, 49, 57, 58, 62, 63
|
||||
};
|
||||
// for the DQT marker -- end --
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Process an DQT (Define Quantization Table) marker.
|
||||
//
|
||||
// Code mostly "stolen" from jpegdump:
|
||||
// Copyright (c) 1992 Handmade Software, Inc.
|
||||
// by Allan N. Hessenflow
|
||||
//
|
||||
// We want to print out the "Approximate quality factor"
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// The numbers printed in the `Approximate quality factor' line are as follows:
|
||||
// Quality: an estimate of the quality factor used when cjpeg was run.
|
||||
// Scaling factor (scale): mean ratio between quantization table entries
|
||||
// and JPEG sample table entries, times 100.
|
||||
// Variance (var): squared standard deviation of the above ratio.
|
||||
// If this is larger than about 2, then the table is not a simple
|
||||
// multiple of the standard's sample table, so the file was NOT
|
||||
// generated by cjpeg and the quality estimate is dubious.
|
||||
//--------------------------------------------------------------------------
|
||||
void process_DQT (const uchar * Data, int length)
|
||||
{
|
||||
int a;
|
||||
int c;
|
||||
int tableindex, coefindex, row, col;
|
||||
unsigned int table[64];
|
||||
int *reftable = NULL;
|
||||
double cumsf = 0.0, cumsf2 = 0.0;
|
||||
int allones = 1;
|
||||
|
||||
a=2; // first two bytes is length
|
||||
while (a<length)
|
||||
{
|
||||
c = Data[a++];
|
||||
tableindex = c & 0x0f;
|
||||
if (ShowTags>1){
|
||||
printf("DQT: table %d precision %d\n", tableindex, (c>>4) ? 16 : 8);
|
||||
}
|
||||
if (tableindex < 2){
|
||||
reftable = deftabs[tableindex];
|
||||
}
|
||||
|
||||
// Read in the table, compute statistics relative to reference table
|
||||
if (a+64 > length) {
|
||||
ErrNonfatal("DQT section too short",0,0);
|
||||
return;
|
||||
}
|
||||
for (coefindex = 0; coefindex < 64; coefindex++) {
|
||||
unsigned int val;
|
||||
if (c>>4) {
|
||||
register unsigned int temp;
|
||||
temp=(unsigned int) (Data[a++]);
|
||||
temp *= 256;
|
||||
val=(unsigned int) Data[a++] + temp;
|
||||
} else {
|
||||
val=(unsigned int) Data[a++];
|
||||
}
|
||||
table[coefindex] = val;
|
||||
if (reftable) {
|
||||
double x;
|
||||
// scaling factor in percent
|
||||
x = 100.0 * (double)val / (double)reftable[coefindex];
|
||||
cumsf += x;
|
||||
cumsf2 += x * x;
|
||||
// separate check for all-ones table (Q 100)
|
||||
if (val != 1) allones = 0;
|
||||
}
|
||||
}
|
||||
// If requested, print table in normal array order
|
||||
if (ShowTags>2){
|
||||
for (row=0; row<8; row++) {
|
||||
printf(" ");
|
||||
for (col=0; col<8; col++) {
|
||||
printf("%5u ", table[jpeg_zigzag_order[row*8+col]]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
// Print summary stats
|
||||
if (reftable) { // terse output includes quality
|
||||
double qual, var;
|
||||
cumsf /= 64.0; // mean scale factor
|
||||
cumsf2 /= 64.0;
|
||||
var = cumsf2 - (cumsf * cumsf); // variance
|
||||
if (allones){ // special case for all-ones table
|
||||
qual = 100.0;
|
||||
}else if (cumsf <= 100.0){
|
||||
qual = (200.0 - cumsf) / 2.0;
|
||||
}else{
|
||||
qual = 5000.0 / cumsf;
|
||||
}
|
||||
if (ShowTags>1) printf(" ");
|
||||
|
||||
if (ShowTags){
|
||||
printf("Approximate quality factor for qtable %d: %.0f (scale %.2f, var %.2f)\n",
|
||||
tableindex, qual, cumsf, var);
|
||||
}
|
||||
if (tableindex == 0){
|
||||
ImageInfo.QualityGuess = (int)(qual+0.5);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Process an DHT (Define Huffmann Tables) marker.
|
||||
//
|
||||
// Code mostly "stolen" from jpegdump:
|
||||
// Copyright (c) 1992 Handmade Software, Inc.
|
||||
// by Allan N. Hessenflow
|
||||
//--------------------------------------------------------------------------
|
||||
void process_DHT (const uchar * Data, int length)
|
||||
{
|
||||
int a, i;
|
||||
int c, c2;
|
||||
unsigned char huff[16];
|
||||
if (ShowTags>1){
|
||||
printf("DHT (length %d bytes)\n", length);
|
||||
}
|
||||
|
||||
a=2; // first two bytes is length
|
||||
while (a<length)
|
||||
{
|
||||
c = Data[a++];
|
||||
if (ShowTags>1){
|
||||
printf(" table %d\n", c);
|
||||
}
|
||||
if (a+16 > length){
|
||||
tooshort:
|
||||
ErrFatal("Huff table too short");
|
||||
}
|
||||
|
||||
for (i=0; i<16; i++) {
|
||||
huff[i]=(unsigned char) Data[a++];
|
||||
}
|
||||
for (i=0; i<16; i++) {
|
||||
if (ShowTags>2){
|
||||
printf(" bits %2d (codes=%3u) ", i+1, (unsigned int) huff[i]);
|
||||
}
|
||||
if (a+huff[i] > length){
|
||||
goto tooshort;
|
||||
}
|
||||
while (huff[i]--) {
|
||||
c2 = Data[a++];
|
||||
if (ShowTags>2){
|
||||
printf(" $%02x ", c2);
|
||||
}
|
||||
}
|
||||
if (ShowTags>2){
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
191
src/external/jhead-3.04/makernote.c
vendored
191
src/external/jhead-3.04/makernote.c
vendored
@ -1,191 +0,0 @@
|
||||
//--------------------------------------------------------------------------
|
||||
// Parse some maker specific onformation.
|
||||
// (Very limited right now - add maker specific stuff to this module)
|
||||
//--------------------------------------------------------------------------
|
||||
#include "jhead.h"
|
||||
|
||||
extern int MotorolaOrder;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Process exif format directory, as used by Cannon maker note
|
||||
//--------------------------------------------------------------------------
|
||||
static void ProcessCanonMakerNoteDir(unsigned char * DirStart, unsigned char * OffsetBase,
|
||||
unsigned ExifLength)
|
||||
{
|
||||
int de;
|
||||
int a;
|
||||
int NumDirEntries;
|
||||
|
||||
NumDirEntries = Get16u(DirStart);
|
||||
#define DIR_ENTRY_ADDR(Start, Entry) (Start+2+12*(Entry))
|
||||
|
||||
{
|
||||
unsigned char * DirEnd;
|
||||
DirEnd = DIR_ENTRY_ADDR(DirStart, NumDirEntries);
|
||||
if (DirEnd > (OffsetBase+ExifLength)){
|
||||
ErrNonfatal("Illegally sized Exif makernote subdir (%d entries)",NumDirEntries,0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (DumpExifMap){
|
||||
printf("Map: %05u-%05u: Directory (makernote)\n",(int)(DirStart-OffsetBase), (int)(DirEnd-OffsetBase));
|
||||
}
|
||||
}
|
||||
|
||||
if (ShowTags){
|
||||
printf("(dir has %d entries)\n",NumDirEntries);
|
||||
}
|
||||
|
||||
for (de=0;de<NumDirEntries;de++){
|
||||
int Tag, Format, Components;
|
||||
unsigned char * ValuePtr;
|
||||
int ByteCount;
|
||||
unsigned char * DirEntry;
|
||||
DirEntry = DIR_ENTRY_ADDR(DirStart, de);
|
||||
|
||||
Tag = Get16u(DirEntry);
|
||||
Format = Get16u(DirEntry+2);
|
||||
Components = Get32u(DirEntry+4);
|
||||
|
||||
if ((Format-1) >= NUM_FORMATS) {
|
||||
// (-1) catches illegal zero case as unsigned underflows to positive large.
|
||||
ErrNonfatal("Illegal Exif number format %d for maker tag %04x", Format, Tag);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((unsigned)Components > 0x10000){
|
||||
ErrNonfatal("Too many components (%d) for Exif maker tag %04x", Components, Tag);
|
||||
continue;
|
||||
}
|
||||
|
||||
ByteCount = Components * BytesPerFormat[Format];
|
||||
|
||||
if (ByteCount > 4){
|
||||
unsigned OffsetVal;
|
||||
OffsetVal = Get32u(DirEntry+8);
|
||||
// If its bigger than 4 bytes, the dir entry contains an offset.
|
||||
if (OffsetVal+ByteCount > ExifLength){
|
||||
// Bogus pointer offset and / or bytecount value
|
||||
ErrNonfatal("Illegal value pointer for Exif maker tag %04x", Tag,0);
|
||||
continue;
|
||||
}
|
||||
ValuePtr = OffsetBase+OffsetVal;
|
||||
|
||||
if (DumpExifMap){
|
||||
printf("Map: %05d-%05d: Data for makernote tag %04x\n",OffsetVal, OffsetVal+ByteCount, Tag);
|
||||
}
|
||||
}else{
|
||||
// 4 bytes or less and value is in the dir entry itself
|
||||
ValuePtr = DirEntry+8;
|
||||
}
|
||||
|
||||
if (ShowTags){
|
||||
// Show tag name
|
||||
printf(" Canon maker tag %04x Value = ", Tag);
|
||||
}
|
||||
|
||||
// Show tag value.
|
||||
switch(Format){
|
||||
|
||||
case FMT_UNDEFINED:
|
||||
// Undefined is typically an ascii string.
|
||||
|
||||
case FMT_STRING:
|
||||
// String arrays printed without function call (different from int arrays)
|
||||
if (ShowTags){
|
||||
printf("\"");
|
||||
for (a=0;a<ByteCount;a++){
|
||||
int ZeroSkipped = 0;
|
||||
if (ValuePtr[a] >= 32){
|
||||
if (ZeroSkipped){
|
||||
printf("?");
|
||||
ZeroSkipped = 0;
|
||||
}
|
||||
putchar(ValuePtr[a]);
|
||||
}else{
|
||||
if (ValuePtr[a] == 0){
|
||||
ZeroSkipped = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("\"\n");
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if (ShowTags){
|
||||
PrintFormatNumber(ValuePtr, Format, ByteCount);
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
if (Tag == 1 && Components > 16){
|
||||
int IsoCode = Get16u(ValuePtr + 16*sizeof(unsigned short));
|
||||
if (IsoCode >= 16 && IsoCode <= 24){
|
||||
ImageInfo.ISOequivalent = 50 << (IsoCode-16);
|
||||
}
|
||||
}
|
||||
|
||||
if (Tag == 4 && Format == FMT_USHORT){
|
||||
if (Components > 7){
|
||||
int WhiteBalance = Get16u(ValuePtr + 7*sizeof(unsigned short));
|
||||
switch(WhiteBalance){
|
||||
// 0=Auto, 6=Custom
|
||||
case 1: ImageInfo.LightSource = 1; break; // Sunny
|
||||
case 2: ImageInfo.LightSource = 1; break; // Cloudy
|
||||
case 3: ImageInfo.LightSource = 3; break; // Thungsten
|
||||
case 4: ImageInfo.LightSource = 2; break; // Fourescent
|
||||
case 5: ImageInfo.LightSource = 4; break; // Flash
|
||||
}
|
||||
}
|
||||
if (Components > 19 && ImageInfo.Distance <= 0) {
|
||||
// Indicates the distance the autofocus camera is focused to.
|
||||
// Tends to be less accurate as distance increases.
|
||||
int temp_dist = Get16u(ValuePtr + 19*sizeof(unsigned short));
|
||||
if (temp_dist != 65535){
|
||||
ImageInfo.Distance = (float)temp_dist/100;
|
||||
}else{
|
||||
ImageInfo.Distance = -1 /* infinity */;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Show generic maker note - just hex bytes.
|
||||
//--------------------------------------------------------------------------
|
||||
static void ShowMakerNoteGeneric(unsigned char * ValuePtr, int ByteCount)
|
||||
{
|
||||
int a;
|
||||
for (a=0;a<ByteCount;a++){
|
||||
if (a > 10){
|
||||
printf("...");
|
||||
break;
|
||||
}
|
||||
printf(" %02x",ValuePtr[a]);
|
||||
}
|
||||
printf(" (%d bytes)", ByteCount);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Process maker note - to the limited extent that its supported.
|
||||
//--------------------------------------------------------------------------
|
||||
void ProcessMakerNote(unsigned char * ValuePtr, int ByteCount,
|
||||
unsigned char * OffsetBase, unsigned ExifLength)
|
||||
{
|
||||
if (strstr(ImageInfo.CameraMake, "Canon")){
|
||||
// So it turns out that some canons cameras use big endian, others use little
|
||||
// endian in the main exif header. But the maker note is always little endian.
|
||||
static int MotorolaOrderSave;
|
||||
MotorolaOrderSave = MotorolaOrder;
|
||||
MotorolaOrder = 0; // Temporarily switch to little endian.
|
||||
ProcessCanonMakerNoteDir(ValuePtr, OffsetBase, ExifLength);
|
||||
MotorolaOrder = MotorolaOrderSave;
|
||||
}else{
|
||||
if (ShowTags){
|
||||
ShowMakerNoteGeneric(ValuePtr, ByteCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
304
src/external/jhead-3.04/myglob.c
vendored
304
src/external/jhead-3.04/myglob.c
vendored
@ -1,304 +0,0 @@
|
||||
//--------------------------------------------------------------------------------
|
||||
// Module to do recursive directory file matching under windows.
|
||||
//
|
||||
// Tries to do pattern matching to produce similar results as Unix, but using
|
||||
// the Windows _findfirst to do all the pattern matching.
|
||||
//
|
||||
// Also hadles recursive directories - "**" path component expands into
|
||||
// any levels of subdirectores (ie c:\**\*.c matches ALL .c files on drive c:)
|
||||
//
|
||||
// Matthias Wandel Nov 5 2000
|
||||
//--------------------------------------------------------------------------------
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
#include <io.h>
|
||||
#include "jhead.h"
|
||||
|
||||
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
|
||||
//#define DEBUGGING
|
||||
|
||||
typedef struct {
|
||||
char * Name;
|
||||
int attrib;
|
||||
}FileEntry;
|
||||
|
||||
|
||||
#ifdef DEBUGGING
|
||||
//--------------------------------------------------------------------------------
|
||||
// Dummy function to show operation.
|
||||
//--------------------------------------------------------------------------------
|
||||
void ShowName(const char * FileName)
|
||||
{
|
||||
printf(" %s\n",FileName);
|
||||
}
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
// Simple path splicing (assumes no '\' in either part)
|
||||
//--------------------------------------------------------------------------------
|
||||
static void SplicePath(char * dest, const char * p1, const char * p2)
|
||||
{
|
||||
int l;
|
||||
l = strlen(p1);
|
||||
if (!l){
|
||||
strcpy(dest, p2);
|
||||
}else{
|
||||
if (l+strlen(p2) > _MAX_PATH-2){
|
||||
fprintf(stderr,"Path too long\n");
|
||||
exit(-1);
|
||||
}
|
||||
memcpy(dest, p1, l+1);
|
||||
if (dest[l-1] != '\\' && dest[l-1] != ':'){
|
||||
dest[l++] = '\\';
|
||||
}
|
||||
strcpy(dest+l, p2);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
// Qsort compare function
|
||||
//--------------------------------------------------------------------------------
|
||||
int CompareFunc(const void * f1, const void * f2)
|
||||
{
|
||||
return strcmp(((FileEntry *)f1)->Name,((FileEntry *)f2)->Name);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
// Decide how a particular pattern should be handled, and call function for each.
|
||||
//--------------------------------------------------------------------------------
|
||||
void MyGlob(const char * Pattern , void (*FileFuncParm)(const char * FileName))
|
||||
{
|
||||
char BasePattern[_MAX_PATH];
|
||||
char MatchPattern[_MAX_PATH];
|
||||
char PatCopy[_MAX_PATH*2+1];
|
||||
|
||||
int a;
|
||||
|
||||
int MatchFiles, MatchDirs;
|
||||
int BaseEnd, PatternEnd;
|
||||
int SawPat;
|
||||
int RecurseAt;
|
||||
|
||||
strcpy(PatCopy, Pattern);
|
||||
|
||||
#ifdef DEBUGGING
|
||||
printf("Called with '%s'\n",Pattern);
|
||||
#endif
|
||||
|
||||
DoRecursion:
|
||||
MatchFiles = FALSE;
|
||||
MatchDirs = TRUE;
|
||||
BaseEnd = 0;
|
||||
PatternEnd = 0;
|
||||
|
||||
SawPat = FALSE;
|
||||
RecurseAt = -1;
|
||||
|
||||
// Split the path into base path and pattern to match against using findfirst.
|
||||
for (a=0;;a++){
|
||||
if (PatCopy[a] == '*' || PatCopy[a] == '?'){
|
||||
SawPat = TRUE;
|
||||
}
|
||||
|
||||
if (PatCopy[a] == '*' && PatCopy[a+1] == '*'){
|
||||
if (a == 0 || PatCopy[a-1] == '\\' || PatCopy[a-1] == ':'){
|
||||
if (PatCopy[a+2] == '\\' || PatCopy[a+2] == '\0'){
|
||||
// x\**\y ---> x\y x\*\**\y
|
||||
RecurseAt = a;
|
||||
if (PatCopy[a+2]){
|
||||
memcpy(PatCopy+a, PatCopy+a+3, strlen(PatCopy)-a-1);
|
||||
}else{
|
||||
PatCopy[a+1] = '\0';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (PatCopy[a] == '\\' || (PatCopy[a] == ':' && PatCopy[a+1] != '\\')){
|
||||
PatternEnd = a;
|
||||
if (SawPat) break; // Findfirst can only match one level of wildcard at a time.
|
||||
BaseEnd = a+1;
|
||||
}
|
||||
if (PatCopy[a] == '\0'){
|
||||
PatternEnd = a;
|
||||
MatchFiles = TRUE;
|
||||
MatchDirs = FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!SawPat){
|
||||
// No pattern. This should refer to a file.
|
||||
FileFuncParm(PatCopy);
|
||||
return;
|
||||
}
|
||||
|
||||
strncpy(BasePattern, PatCopy, BaseEnd);
|
||||
BasePattern[BaseEnd] = 0;
|
||||
|
||||
strncpy(MatchPattern, PatCopy, PatternEnd);
|
||||
MatchPattern[PatternEnd] = 0;
|
||||
|
||||
#ifdef DEBUGGING
|
||||
printf("Base:%s Pattern:%s Files:%d dirs:%d\n",BasePattern, MatchPattern, MatchFiles, MatchDirs);
|
||||
#endif
|
||||
|
||||
{
|
||||
FileEntry * FileList = NULL;
|
||||
int NumAllocated = 0;
|
||||
int NumHave = 0;
|
||||
|
||||
struct _finddata_t finddata;
|
||||
long find_handle;
|
||||
|
||||
find_handle = _findfirst(MatchPattern, &finddata);
|
||||
|
||||
for (;;){
|
||||
if (find_handle == -1) break;
|
||||
|
||||
// Eliminate the obvious patterns.
|
||||
if (!memcmp(finddata.name, ".",2)) goto next_file;
|
||||
if (!memcmp(finddata.name, "..",3)) goto next_file;
|
||||
|
||||
if (finddata.attrib & _A_SUBDIR){
|
||||
if (!MatchDirs) goto next_file;
|
||||
}else{
|
||||
if (!MatchFiles) goto next_file;
|
||||
}
|
||||
|
||||
// Add it to the list.
|
||||
if (NumAllocated <= NumHave){
|
||||
NumAllocated = NumAllocated+10+NumAllocated/2;
|
||||
FileList = realloc(FileList, NumAllocated * sizeof(FileEntry));
|
||||
if (FileList == NULL) goto nomem;
|
||||
}
|
||||
a = strlen(finddata.name);
|
||||
FileList[NumHave].Name = malloc(a+1);
|
||||
if (FileList[NumHave].Name == NULL){
|
||||
nomem:
|
||||
printf("malloc failure\n");
|
||||
exit(-1);
|
||||
}
|
||||
memcpy(FileList[NumHave].Name, finddata.name, a+1);
|
||||
FileList[NumHave].attrib = finddata.attrib;
|
||||
NumHave++;
|
||||
|
||||
next_file:
|
||||
if (_findnext(find_handle, &finddata) != 0) break;
|
||||
}
|
||||
_findclose(find_handle);
|
||||
|
||||
// Sort the list...
|
||||
qsort(FileList, NumHave, sizeof(FileEntry), CompareFunc);
|
||||
|
||||
|
||||
// Use the list.
|
||||
for (a=0;a<NumHave;a++){
|
||||
char CombinedName[_MAX_PATH*2+1];
|
||||
if (FileList[a].attrib & _A_SUBDIR){
|
||||
if (MatchDirs){
|
||||
// Need more directories.
|
||||
SplicePath(CombinedName, BasePattern, FileList[a].Name);
|
||||
strncat(CombinedName, PatCopy+PatternEnd, _MAX_PATH*2-strlen(CombinedName));
|
||||
MyGlob(CombinedName,FileFuncParm);
|
||||
}
|
||||
}else{
|
||||
if (MatchFiles){
|
||||
// We need files at this level.
|
||||
SplicePath(CombinedName, BasePattern, FileList[a].Name);
|
||||
FileFuncParm(CombinedName);
|
||||
}
|
||||
}
|
||||
free(FileList[a].Name);
|
||||
}
|
||||
free(FileList);
|
||||
}
|
||||
|
||||
if(RecurseAt >= 0){
|
||||
strcpy(MatchPattern, PatCopy+RecurseAt);
|
||||
PatCopy[RecurseAt] = 0;
|
||||
strncpy(PatCopy+RecurseAt, "*\\**\\", _MAX_PATH*2-RecurseAt);
|
||||
strncat(PatCopy, MatchPattern, _MAX_PATH*2-strlen(PatCopy));
|
||||
|
||||
#ifdef DEBUGGING
|
||||
printf("Recurse with '%s'\n",PatCopy);
|
||||
#endif
|
||||
|
||||
// As this function context is no longer needed, we can just goto back
|
||||
// to the top of it to avoid adding another context on the stack.
|
||||
goto DoRecursion;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
// Flip slashes to native OS representation (for Windows)
|
||||
//--------------------------------------------------------------------------------
|
||||
void SlashToNative(char * Path)
|
||||
{
|
||||
int a;
|
||||
for (a=0;Path[a];a++){
|
||||
if (Path[a] == '/') Path[a] = SLASH;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef DEBUGGING
|
||||
//--------------------------------------------------------------------------------
|
||||
// The main program.
|
||||
//--------------------------------------------------------------------------------
|
||||
int main (int argc, char **argv)
|
||||
{
|
||||
int argn;
|
||||
char * arg;
|
||||
|
||||
for (argn=1;argn<argc;argn++){
|
||||
arg = argv[argn];
|
||||
if (arg[0] != '-') break; // Filenames from here on.
|
||||
if (!strcmp(arg,"-r")){
|
||||
printf("do recursive\n");
|
||||
}else{
|
||||
fprintf(stderr, "Argument '%s' not understood\n",arg);
|
||||
}
|
||||
}
|
||||
if (argn == argc){
|
||||
fprintf(stderr,"Error: Must supply a file name\n");
|
||||
}
|
||||
|
||||
for (;argn<argc;argn++){
|
||||
MyGlob(argv[argn], ShowName);
|
||||
}
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
||||
non-recursive test cases:
|
||||
|
||||
e:\make*\*
|
||||
\make*\*
|
||||
e:*\*.c
|
||||
\*\*.c
|
||||
\*
|
||||
c:*.c
|
||||
c:\*
|
||||
..\*.c
|
||||
|
||||
|
||||
recursive test cases:
|
||||
**
|
||||
**\*.c
|
||||
c:\**\*.c
|
||||
c:**\*.c
|
||||
.\**
|
||||
..\**
|
||||
|
||||
*/
|
||||
|
||||
|
||||
140
src/external/jhead-3.04/paths.c
vendored
140
src/external/jhead-3.04/paths.c
vendored
@ -1,140 +0,0 @@
|
||||
//--------------------------------------------------------------------------------
|
||||
// Module to do path manipulation for file moving of jhead.
|
||||
//
|
||||
// Matthias Wandel Feb 2 2009
|
||||
//--------------------------------------------------------------------------------
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/stat.h>
|
||||
#ifdef _WIN32
|
||||
#include <direct.h> // for mkdir under windows.
|
||||
#define mkdir(dir,mode) _mkdir(dir)
|
||||
#define S_ISDIR(a) (a & _S_IFDIR)
|
||||
#endif
|
||||
|
||||
#include "jhead.h"
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
// Ensure that a path exists
|
||||
//--------------------------------------------------------------------------------
|
||||
int EnsurePathExists(const char * FileName)
|
||||
{
|
||||
char NewPath[PATH_MAX*2];
|
||||
int a;
|
||||
int LastSlash = 0;
|
||||
|
||||
//printf("\nEnsure exists:%s\n",FileName);
|
||||
|
||||
// Extract the path component of the file name.
|
||||
strcpy(NewPath, FileName);
|
||||
a = strlen(NewPath);
|
||||
for (;;){
|
||||
a--;
|
||||
if (a == 0){
|
||||
NewPath[0] = 0;
|
||||
break;
|
||||
}
|
||||
if (NewPath[a] == SLASH){
|
||||
struct stat dummy;
|
||||
NewPath[a] = 0;
|
||||
if (stat(NewPath, &dummy) == 0){
|
||||
if (S_ISDIR(dummy.st_mode)){
|
||||
// Break out of loop, and go forward along path making
|
||||
// the directories.
|
||||
if (LastSlash == 0){
|
||||
// Full path exists. No need to create any directories.
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
}else{
|
||||
// Its a file.
|
||||
fprintf(stderr,"Can't create path '%s' due to file conflict\n",NewPath);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (LastSlash == 0) LastSlash = a;
|
||||
}
|
||||
}
|
||||
|
||||
// Now work forward.
|
||||
//printf("Existing First dir: '%s' a = %d\n",NewPath,a);
|
||||
|
||||
for(;FileName[a];a++){
|
||||
if (FileName[a] == SLASH || a == 0){
|
||||
if (a == LastSlash) break;
|
||||
NewPath[a] = FileName[a];
|
||||
//printf("make dir '%s'\n",NewPath);
|
||||
#ifdef _WIN32
|
||||
if (NewPath[1] == ':' && strlen(NewPath) == 2) continue;
|
||||
#endif
|
||||
if (mkdir(NewPath,0777)){
|
||||
fprintf(stderr,"Could not create directory '%s'\n",NewPath);
|
||||
// Failed to create directory.
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
// Make a new path out of a base path, and a filename.
|
||||
// Basepath is the base path, and FilePath is a filename, or path + filename.
|
||||
//--------------------------------------------------------------------------------
|
||||
void CatPath(char * BasePath, const char * FilePath)
|
||||
{
|
||||
int l;
|
||||
l = strlen(BasePath);
|
||||
|
||||
if (FilePath[1] == ':'){
|
||||
// Its a windows absolute path.
|
||||
l = 0;
|
||||
}
|
||||
|
||||
if (FilePath[0] == SLASH || FilePath[0] == '.' || l == 0){
|
||||
// Its an absolute path, or there was no base path.
|
||||
strcpy(BasePath, FilePath);
|
||||
return;
|
||||
}
|
||||
|
||||
if (BasePath[l-1] != SLASH){
|
||||
BasePath[l++] = SLASH;
|
||||
BasePath[l] = 0;
|
||||
}
|
||||
|
||||
strcat(BasePath, FilePath);
|
||||
|
||||
// Note that the combined path may contains things like "foo/../bar". We assume
|
||||
// that the filesystem will take care of these.
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
char Path1[] = "ztest\\cdir\\foo.jpg";
|
||||
char Path2[] = "zxtest\\cdir\\foo.jpg";
|
||||
char Path3[] = "\\tzest\\cdir\\foo.jpg";
|
||||
|
||||
char BasePath[100];
|
||||
|
||||
main()
|
||||
{
|
||||
EnsurePathExists(Path1);
|
||||
EnsurePathExists(Path2);
|
||||
EnsurePathExists(Path3);
|
||||
|
||||
|
||||
|
||||
|
||||
CatPath(BasePath, "hello.txt");
|
||||
CatPath(BasePath, "world\\hello.txt");
|
||||
CatPath(BasePath, "\\hello.txt");
|
||||
CatPath(BasePath, "c:\\hello.txt");
|
||||
CatPath(BasePath, "c:\\world\\hello.txt");
|
||||
CatPath(BasePath, "c:\\abresl\\hello.txt");
|
||||
|
||||
}
|
||||
*/
|
||||
60
src/external/jhead-3.04/readme.txt
vendored
60
src/external/jhead-3.04/readme.txt
vendored
@ -1,60 +0,0 @@
|
||||
|
||||
Some notes:
|
||||
|
||||
When I first wrote Jhead back in 1999, there wasn't much software around
|
||||
for looking inside Exif headers, so I wrote jhead for that task. Since
|
||||
then, a lot of much more sophisticated programs for looking inside Exif
|
||||
headers have been written, many with GUIs, and features that Jhead lacks.
|
||||
|
||||
Seeing that Jhead does everything I need it to do, My goal is not to have
|
||||
every feature imaginable. Rather, I want Jhead to be a small, simple,
|
||||
easy to understand program. My goal is that if you need to understand
|
||||
Exif internals, or add Exif capability to your program, Jhead is the
|
||||
place to cut and paste code from.
|
||||
|
||||
As a result, Jhead may not have your pet feature. Feel free to add your
|
||||
pet feature to Jhead - its meant to be hacked. If you send me your
|
||||
changes, I might integrate it, but only if its simple.
|
||||
|
||||
If you find that it dies on a certain jpeg file, send it to me, and I
|
||||
will look at it.
|
||||
|
||||
|
||||
Compiling:
|
||||
|
||||
Windows:
|
||||
|
||||
Make sure visual C is on your path (I use version 6 from 1998,
|
||||
but it shouldn't matter much).
|
||||
Run the batch file make.bat
|
||||
|
||||
Linux & Unices:
|
||||
|
||||
type 'make'.
|
||||
|
||||
Portability:
|
||||
|
||||
Although I have never done so myself, people tell me it compiles
|
||||
under platforms as diverse as such as Mac OS-X, or NetBSD on Mac68k.
|
||||
Jhead doesn't care about the endian-ness of your CPU, and should not
|
||||
have problems with processors that do not handle unaligned data,
|
||||
such as ARM or Alpha. The main portability problem is the use
|
||||
of C++ style '//' comments. This is intentional, and won't change.
|
||||
|
||||
Jhead has also made its way into various Linux distributions and ports
|
||||
trees, so you might already have it on your system without knowing.
|
||||
Note that I am a windows weenie myself.
|
||||
|
||||
License:
|
||||
|
||||
Jhead is public domain software - that is, you can do whatever you want
|
||||
with it, and include it software that is licensed under the GNU or the
|
||||
BSD license, or whatever other licence you chose, including proprietary
|
||||
closed source licenses. Although not part of the license, I do expect
|
||||
common courtesy, please.
|
||||
|
||||
If you do integrate the code into some software of yours, I'd appreciate
|
||||
knowing about it though.
|
||||
|
||||
Matthias Wandel
|
||||
|
||||
478
src/external/jhead-3.04/usage.html
vendored
478
src/external/jhead-3.04/usage.html
vendored
@ -1,478 +0,0 @@
|
||||
<html>
|
||||
<span style="font-family: helvetica,arial,sans-serif;">
|
||||
|
||||
<h3>Jhead is a command line driven program for manipulating the non-image parts of Exif flavour
|
||||
JPEG files that most digital cameras produce.</h3><p>
|
||||
|
||||
Windows / Mac users: Jhead has <b>no Graphical User Interface</b>. Clicking on it with the mouse from Windows
|
||||
or Mac OS-X won't do anything for you - you have to <b>use it from the Command prompt</b>
|
||||
|
||||
|
||||
<h3>Jhead v3.03 program Features</h3>
|
||||
<ul>
|
||||
<li>Extracting camera settings from Exif image files
|
||||
<li>Able to set and/or adjust the Exif time field
|
||||
<li>Manipulation (extract, replace, regenerate) of Exif integral thumbnails
|
||||
<li>Transplant Exif image header from one JPEG to another
|
||||
<li>Edit JPEG comment fields
|
||||
<li>Automatically rotate images upright (using jpegtran) according to "orientation" tag.
|
||||
<li>Manage running programs on large batches of Jpegs and restoring Exif header
|
||||
information afterwards.
|
||||
<li>Display embedded GPS info (if present)
|
||||
</ul>
|
||||
|
||||
|
||||
<h3>General metadata options</h3>
|
||||
<table cellpadding=5>
|
||||
|
||||
<tr valign=top><td><b>-te <name>
|
||||
<td>
|
||||
Transplant Exif header from image <name> into specified image. This option is
|
||||
useful if you like to edit the photos but still want the Exif header on your photos.
|
||||
As most photo editing programs will wipe out the Exif header, this option can be used
|
||||
to re-transplant them back in after editing the photos.
|
||||
<br>
|
||||
This feature has an interesting 'relative path' option for specifying the thumbnail name.
|
||||
Whenever the <name> contains the characters '&i', jhead will substitute the original
|
||||
filename for this name. This allows creating a 'relative name' when doing a whole
|
||||
batch of files. For example, the incantation:
|
||||
<ul>jhead -te "originals\&i" *.jpg</ul>
|
||||
would transfer the Exif header for each .jpg file in the originals directory by the same name,
|
||||
Both Win32 and most UNIX shells treat the '&' character in a special way, so you have to
|
||||
put quotes around that command line option for the '&' to even be passed to the program.
|
||||
|
||||
|
||||
<tr valign=top><td><b>-dc
|
||||
<td>Delete comment field from the JPEG header. Note that the comment
|
||||
is not part of the Exif header.
|
||||
|
||||
<tr valign=top><td><b>-de
|
||||
<td>Delete the Exif header entirely. This leaves other sections (IPTC, XMP, comment) intact
|
||||
|
||||
<tr valign=top><td><b>-di
|
||||
<td>Delete IPTC section (if present). Leaves other sections intact.
|
||||
|
||||
<tr valign=top><td><b>-dx
|
||||
<td>Delete XMP section (if present). Leaves other sections intact.
|
||||
|
||||
<tr valign=top><td><b>-du
|
||||
<td>Delete any sections that jhead doesn't know about. Leaves Exif, XMP, IPTC and comment
|
||||
sections intact.
|
||||
|
||||
<tr valign=top><td><b>-purejpg
|
||||
<td>Delete all JPEG sections that aren't necessary for rendering the image. Strips any
|
||||
metadata that various applications may have left in the image. A combination of
|
||||
the -de -dc and -du options.
|
||||
|
||||
<tr valign=top><td><b>-mkexif
|
||||
<td>Creates minimal Exif header. Exif header contains date/time, and empty thumbnail
|
||||
fields only. Date/time set to file time by default.
|
||||
use with -rgt option if you want the Exif header to contain a thumbnail.
|
||||
Note that Exif header creation is very limited at this time, and no other fields
|
||||
can be added to the Exif header this way.
|
||||
|
||||
<tr valign=top><td><b>-ce
|
||||
<td>Edit the JPEG header comment field (note, this comment field is outside the Exif structure
|
||||
and can be part of Exif and non Exif style JPEG images).
|
||||
<br>
|
||||
A temporary file containing the comment is created and a text editor is launched to edit
|
||||
the file. The editor is specified in the EDITOR environment variable. If none is specified
|
||||
notepad or vi are used under Windows and UNIX respectively. After the editor exits,
|
||||
the data is transferred back into the image, and the temporary file deleted.
|
||||
|
||||
<tr valign=top><td><b>-cs <name>
|
||||
<td>Save comment section to a file
|
||||
|
||||
<tr valign=top><td><b>-ci <name>
|
||||
<td>Replace comment with text from file.
|
||||
|
||||
<tr valign=top><td><b>-cl <comment>
|
||||
<td>Replace comment with comment from command line.
|
||||
</table>
|
||||
|
||||
|
||||
<h3>Date / Time manipulation options</h3>
|
||||
<table cellpadding=5>
|
||||
|
||||
<tr valign=top><td><b>-ft
|
||||
<td>Sets the file's system time stamp to what is stored in the Exif header.
|
||||
|
||||
<tr valign=top><td><b>-dsft
|
||||
<td>Sets the Exif timestamp to the file's timestamp. Requires an Exif header to pre-exist.
|
||||
Use -mkexif option to create one if needed.
|
||||
|
||||
<tr valign=top><td><b>-n[<fmt-string>]
|
||||
<td>This option causes files to be renamed and/or moved according to the Exif header "DateTimeOriginal" field.
|
||||
If the file is not an Exif file, or the DateTimeOriginal does not contain a valid value,
|
||||
the file date is used.
|
||||
<p>
|
||||
If the name includes '/' or '\' (under windows), this is interpreted as a new path for
|
||||
the file. If the new path does not exist, the path will be created.
|
||||
<p>
|
||||
If the [fmt-string] is omitted, the file will be renamed to MMDD-HHMMSS.
|
||||
<br>
|
||||
If a [fmt-string] is provided, the fmt-string will be passed to the
|
||||
strftime function for formatting. In addition, if the format string contains '%f', this will
|
||||
substitute the original name of the file (minus extension).
|
||||
<br>
|
||||
A sequence number may also be included by including '%i' in the format string. Leading
|
||||
zeros can be specified. '%03i' for example will pad the numbers to '001', '002'...
|
||||
this works just like printf in C, but with '%i' instead of '%d'.
|
||||
<br>
|
||||
If the target name already exists, the name will be appended with "a", "b", "c", etc,
|
||||
unless the name ends with a letter, in which case it will be appended with "0", "1", "2", etc.
|
||||
<br>
|
||||
This feature is especially useful if more than one digital camera was used to take pictures
|
||||
of an event. By renaming them to a scheme according to date, they will automatically
|
||||
appear in order of taking when viewed with some sort of viewer like Xnview or AcdSee, and
|
||||
sorted by name. Or you could use the -ft option and view the images sorted by date.
|
||||
Typically, one of the camera's date will be set not quite right, in which case you may have
|
||||
to use the -ta or -da options on those files first.
|
||||
<p>
|
||||
<b>Some of the more useful arguments for strftime are:</b>
|
||||
|
||||
<table>
|
||||
<tr><td>%d   </td><td>Day of month as decimal number (01 – 31)
|
||||
<tr><td>%H</td><td>Hour in 24-hour format (00 – 23)
|
||||
<tr><td>%j</td><td>Day of year as decimal number (001 – 366)
|
||||
<tr><td>%m</td><td>Month as decimal number (01 – 12)
|
||||
<tr><td>%M</td><td>Minute as decimal number (00 – 59)
|
||||
<tr><td>%S</td><td>Second as decimal number (00 – 59)
|
||||
<tr><td>%U</td><td>Week of year as decimal number, with Sunday as first day of week (00 – 53)
|
||||
<tr><td>%w</td><td>Weekday as decimal number (0 – 6; Sunday is 0)
|
||||
<tr><td>%y</td><td>Year without century, as decimal number (00 – 99)
|
||||
<tr><td>%Y</td><td>Year with century, as decimal number
|
||||
</table>
|
||||
<p>
|
||||
Example:<br>
|
||||
    jhead -n%Y%m%d-%H%M%S *.jpg<p>
|
||||
This will rename files matched by *.jpg according to YYYYMMDD-HHMMSS
|
||||
<p>
|
||||
Note to Windows batch file users: '%' is used to deliminate macros in Windows batch files. You must
|
||||
use %% to get one % passed to the program. So from a batch file, you would have to write "jhead -n%%Y%%m%%d-%%H%%M%%S *.jpg"
|
||||
<p>
|
||||
For a full listing of strftime arguments, look up the strftime function. Note that some arguments
|
||||
to the strftime function (not listed here) produce strings with characters such as '/' and ':' that
|
||||
may not be valid as part of a filename on various systems.
|
||||
|
||||
<tr valign=top><td><b>-a
|
||||
<td>(Windows only option). Rename files with the same name but different extension as well.
|
||||
This is useful for renaming .AVI files based on Exif file in .THM, or to rename sound annotation
|
||||
files or raw files with jpeg files. Use together with '-n' option.
|
||||
|
||||
<tr valign=top><td><b>-ta<timediff>
|
||||
<td>Adjust time stored in the Exif header by h:mm forwards or backwards. Useful when having
|
||||
taken pictures with the wrong time set on the camera, such as after travelling across
|
||||
time zones, or when daylight savings time has changed.
|
||||
This option uses the time from the "DateTimeOriginal" (tag 0x9003) field, but sets
|
||||
all the time fields in the Exif header to the new value.
|
||||
<p>
|
||||
Examples:<br>
|
||||
Adjust time one hour forward (you would use this after you forgot to set daylight savings
|
||||
time on the camera)<br>
|
||||
<ul>jhead -ta+1:00 *.jpg</ul>
|
||||
Adjust time back by 23 seconds (you would use this to get the timestamps from two cameras
|
||||
in sync after you found that they didn't quite align)
|
||||
<ul>jhead -ta-0:00:23 *.jpg</ul>
|
||||
Adjust time forward by 2 days and 1 hour (49 hours)
|
||||
<ul>jhead -ta+49 *.jpg</ul>
|
||||
|
||||
<tr valign=top><td><b>-da<date>-<date>
|
||||
<td>Works like -ta, but for specifying large date offsets, to be used when fixing dates from
|
||||
cameras where the date was set incorrectly, such as having date and time reset by battery
|
||||
removal on some cameras. This feature is best for adjusting dates on pictures taken
|
||||
over a large range of dates. For pictures all taken the same date, the "-ds" option
|
||||
is often easier to use.
|
||||
<p>
|
||||
Because different months and years have different numbers of days in them, a simple offset
|
||||
for months, days, years would lead to unexpected results at times. The time offset is
|
||||
thus specified as a difference between two dates, so that jhead can figure out exactly
|
||||
how many days the timestamp needs to be adjusted by, including leap years and daylight
|
||||
savings time changes.
|
||||
The dates are specified as yyyy:mm:dd. For sub-day adjustments, a time of day can also
|
||||
be included, by specifying yyyy:nn:dd/hh:mm or yyyy:mm:dd/hh:mm:ss
|
||||
<p>
|
||||
Examples:<br>
|
||||
Year on camera was set to 2004 instead of 2005 for pictures taken in April
|
||||
<ul>jhead -da2005:03:01-2004:03:01</ul>
|
||||
Default camera date is 2002:01:01, and date was reset on 2005:05:29 at 11:21 am
|
||||
<ul>jhead -da2005:05:29/11:21-2002:01:01</ul>
|
||||
|
||||
<tr valign=top><td><b>-ts<date-time>
|
||||
<td>Sets the date and time stored in the Exif header to what is specified on the command line.
|
||||
This option changes all the date fields in the Exif header.
|
||||
Time must be specified as:<br>
|
||||
<font face=courier>     yyyy:mm:dd-hh:mm:ss</font><p>
|
||||
|
||||
<tr valign=top><td><b>-tf <filename>
|
||||
<td>Sets the date stored in the Exif header to the modification time from a file.
|
||||
This option changes all the date fields in the Exif header.
|
||||
|
||||
<tr valign=top><td><b>-ds<date-time>
|
||||
<td>Sets the date stored in the Exif header to what is specified on the command line.
|
||||
Can be used to set date, just year and month, or just year.
|
||||
Date is specified as:<br>
|
||||
<font face=courier>     yyyy:mm:dd, yyyy:mm, or yyyy</font><p>
|
||||
|
||||
</table>
|
||||
<h3>Thumbnail manipulation options</h3>
|
||||
<table cellpadding=5>
|
||||
<tr valign=top><td><b>-dt
|
||||
<td>Delete thumbnails from the Exif header, but leave the
|
||||
interesting parts intact. This option truncates the thumbnail from the Exif header, provided
|
||||
that the thumbnail is the last part of the Exif header (which so far as I know is always the case).
|
||||
Exif headers have a built-in thumbnail, which is typically 240x160 and 10k in size.
|
||||
This thumbnail is used by digital cameras. Windows XP, as well
|
||||
as various photo viewing software may also use this thumbnail if present, but work just fine
|
||||
if it isn't.
|
||||
|
||||
<tr valign=top><td><b>-st <name>
|
||||
<td>Save the built in thumbnail from Jpegs that came from a digital camera. The thumbnail lives
|
||||
inside the Exif header, and is a very low-res JPEG image. Note that making
|
||||
any changes to a photo, except for with some programs, generally wipes out the Exif header
|
||||
and with it the thumbnail.
|
||||
<br>
|
||||
I implemented this option because I kept getting asked about having such an option.
|
||||
I don't consider the
|
||||
built in thumbnails to be all that useful - too low res. However, now you can see for
|
||||
yourself. I always generate my thumbnails using ImageMagick (see end of this page).
|
||||
<br>
|
||||
Like the '-te' option, this feature has the 'relative path' option for specifying the
|
||||
thumbnail name.
|
||||
Whenever the <name> contains the characters '&i', jhead will substitute the original
|
||||
filename for this name. This allows creating a 'relative name' when doing a whole
|
||||
batch of files. For example, the incantation:
|
||||
<ul>jhead -st "thumbnails\&i" *.jpg</ul>
|
||||
would create a thumbnail for each .jpg file in the thumbnails directory by the same name,
|
||||
(provided that the thumbnails directory exists, of course).
|
||||
Both Win32 and most UNIX shells treat the '&' character in a special way, so you have to
|
||||
put quotes around that command line option for the '&' to even be passed to the program.
|
||||
<p>
|
||||
If a '-' is specified for the output file, the thumbnail is sent to stdout. (UNIX build only)
|
||||
|
||||
<tr valign=top><td><b>-rt <name>
|
||||
<td>Replace thumbnails from the Exif header.
|
||||
This only works if the Exif header already contains an Exif header a thumbnail.
|
||||
|
||||
<tr valign=top><td><b>-rgt[size]
|
||||
<td>Regenerate Exif thumbnail.
|
||||
'size' specifies maximum height or width of thumbnail.
|
||||
I added this option because I had a lot of images that I had rotated with various tools that don't
|
||||
update the Exif header. But newer image browsers such as XnView make use of the Exif thumbnail,
|
||||
and so the thumbnails would be different from the image itself. Note that the rotation tag also
|
||||
needed to be cleared (-norot option).
|
||||
<br>
|
||||
Typically, only images that are shot in portrait orientation are afflicted with this. You can use
|
||||
the -orp option to tell jhead to only operate on images that are upright.
|
||||
<p>
|
||||
|
||||
This option relies on 'mogrify' program (from ImageMagick) to regenerate the thumbnail.
|
||||
Linux users often already have this tool pre-installed. Windows users have to go and download it.
|
||||
This option only works if the image already contains a thumbnail.
|
||||
</table>
|
||||
|
||||
<h3>Rotation tag manipulation</h3>
|
||||
<table cellpadding=5>
|
||||
<tr valign=top>
|
||||
<td><b>-autorot
|
||||
<td>
|
||||
Using the 'Orientation' tag of the Exif header, rotate the image so that it is upright.
|
||||
The program 'jpegtran' is used to perform the rotation. This program is present in most
|
||||
Linux distributions. For windows, you need to get a copy of it.
|
||||
After rotation, the orientation tag of the Exif header is set to '1' (normal orientation).
|
||||
The Exif thumbnail is also rotated. Other fields of the Exif header,
|
||||
including dimensions are untouched, but the JPEG height/width are adjusted.<br>
|
||||
This feature is especially useful with newer digital cameras, which set the orientation
|
||||
field in the Exif header automatically using a built in orientation sensor in the camera.
|
||||
|
||||
<tr valign=top>
|
||||
<td><b>-norot
|
||||
<td>
|
||||
Clears the Exif header rotation tag without altering the image.
|
||||
You may find that your images have rotation tags in them from your camera, but you already
|
||||
rotated them with some lossless tool without clearing the rotation tag.
|
||||
Now your friendly browser rotates the images on you again because the image rotation
|
||||
tag still indicates the image should be rotated. Use this option to fix this problem.
|
||||
You may also want to regenerate the thumbnail using the -rgt option.
|
||||
</table>
|
||||
|
||||
|
||||
<h3>Output verbosity control</h3>
|
||||
<table cellpadding=5>
|
||||
|
||||
|
||||
<tr valign=top><td><b>-h
|
||||
<td>Displays summary of command line options.
|
||||
|
||||
<tr valign=top><td><b>-v
|
||||
<td>Makes the program even more verbose than it already is. Like DOS programs, and unlike
|
||||
UNIX programs, Jhead gives feedback as to what it is doing, even when nothing goes wrong.
|
||||
Windows user that I am, when something doesn't give me feedback for 20 seconds, I assume
|
||||
its crashed.
|
||||
|
||||
<tr valign=top><td><b>-q
|
||||
<td>Makes the program not spit out messages on success - more like the "Silence is golden" Unix way. its crashed.
|
||||
|
||||
<tr valign=top><td><b>-V
|
||||
<td>Print version info and compilation date.
|
||||
|
||||
<tr valign=top><td><b>-exifmap
|
||||
<td>Show a map of the bytes in the Exif header. Useful when analyzing strange Exif headers,
|
||||
not of much use to non software developers.
|
||||
|
||||
<tr valign=top><td><b>-se
|
||||
<td>Suppress error messages relating to corrupt Exif header structure.
|
||||
|
||||
<tr valign=top><td><b>-c
|
||||
<td>Concise output. This causes picture info to be summarized on one line instead of several.
|
||||
Useful for grep-ing through images, as well as importing into spread sheets (data is space
|
||||
delimited with quotes as text qualifier).
|
||||
|
||||
</table>
|
||||
|
||||
|
||||
<h3>File matching and selection</h3>
|
||||
<table cellpadding=5>
|
||||
|
||||
<tr valign=top><td><b>-model <model>
|
||||
<td>Restricts processing of files to those whose camera model, as indicated by the Exif image
|
||||
information, contains the substring specified in the argument after '-model'.
|
||||
For example, the following command will list only images that are from an S100 camera:
|
||||
<p>
|
||||
jhead -model S100 *.jpg<p>
|
||||
<p>
|
||||
I use this option to restrict my JPEG re-compressing to those images that came from my
|
||||
Cannon S100 camera, (see the -cmd option).
|
||||
|
||||
<tr valign=top><td><b>-quality <nn>
|
||||
<td>Restricts processing of files to those whose estimated quality factor is equal to
|
||||
or higher than the specified number nn.
|
||||
|
||||
<tr valign=top>
|
||||
<td><b>-exonly
|
||||
<td>Skip all files that don't have an Exif header. This skips all files that did not
|
||||
come directly from the digital camera, as most photo editing software does not
|
||||
preserve the Exif header when saving pictures.
|
||||
|
||||
<tr valign=top><td><b>-cmd<command>
|
||||
<td>Executes the specified command on each Jpeg file to be processed.<p>
|
||||
The Exif section of each file is read before running the command, and re-inserted
|
||||
after the command finishes.
|
||||
<p>
|
||||
This is useful for using Jhead's file globbing capability for processing a whole
|
||||
directory tree of files.
|
||||
<p>
|
||||
It's also useful for restoring the exif header after operations that wipe out
|
||||
the Exif metadata. Most programs today however will keep the Exif metadata
|
||||
intact, so this is less important than it used to be.
|
||||
|
||||
<tr valign=top><td><b>-orp, -orl
|
||||
<td>Operate only on images with portrait (-orp) or landscape (-orl) aspect ratio.<br>
|
||||
Please note that this is solely based on jpeg width and height values. Some browsers may auto
|
||||
rotate the image on displaying it based on the Exif orientation tag, so that images shot
|
||||
in portrait mode are displayed as portrait. However, the image itself may not be stored in
|
||||
portrait orientation.
|
||||
The -autorot and -norot options are useful for dealing with rotation issues.
|
||||
|
||||
<tr valign=top><td><b>-r
|
||||
<td>The recursive feature of version 1.0 never worked to my satisfaction, and I replaced it
|
||||
with my recursive file globbing code in the Windows version. See below.
|
||||
|
||||
</table>
|
||||
|
||||
<h3>Bugs and Shortcomings</h3>
|
||||
<ul>
|
||||
After Jhead runs a program to rotate or resize an image, the image dimensions and thumbnail
|
||||
in the Exif header are not adjusted.
|
||||
<p>
|
||||
Modifying of Exif header data is very limited, as Jhead internally only has a read only
|
||||
implementation of the file system contained in the Exif header. For the most part, Exif
|
||||
can only modify pre-existing fixed-length fields in the header.
|
||||
<p>
|
||||
|
||||
Most Canon digital SLR cameras fail to adjust the effective sensor resolution when shooting at less
|
||||
than full resolution, causing Jhead to incorrectly miscalculate the sensor width and 35mm equivalent
|
||||
focal length. The same can result from resizing photos with Photoshop, which will manipulate
|
||||
parts of the Exif header.
|
||||
This is often reported as a bug in Jhead, but Jhead can't do much about incorrect data.
|
||||
</ul>
|
||||
|
||||
<h3>Name globbing and recursive directories under Windows</h3>
|
||||
<ul>
|
||||
Name globbing means matching wildcard patterns to actual file names. If you know what this
|
||||
term means, you are probably annoyed at how programs on Windows typically handle this.
|
||||
The Win32 version of this program goes beyond the pattern matching that Windows provides,
|
||||
and allows you to specify fancy UNIX-like patterns such as:
|
||||
<p>
|
||||
<font size = 2 face="courier">  jhead c:\pix\199*\*\*.jpg</font>
|
||||
<p>
|
||||
This program goes one step beyond beyond that in that "**" as a path component means any
|
||||
level of subdirectories. The invocation
|
||||
<p>
|
||||
<font size = 2 face="courier">  jhead c:\**\*.jpg</font>
|
||||
<p>
|
||||
will find ALL Jpegs files on the c: drive, including those in the root directory.
|
||||
The <font size = 2 face="courier">**</font>
|
||||
only works if it is the only part of that path component. For example, the path
|
||||
<font size = 2 face="courier">'c:\a**\*.jpg'</font>
|
||||
will not recurse.
|
||||
The <font size = 2 face="courier">'**'</font>
|
||||
recursive expansion is ONLY supported on the Windows version. The code is in the module 'myglob.c',
|
||||
if you want to reuse it (I certainly intend to reuse that code for other applications).
|
||||
Under UNIX, the shell's wildcard expansion is
|
||||
pretty decent already, and dealing with the convoluted nature of some UNIX file layouts,
|
||||
doing better would have been much more of a challenge.
|
||||
</ul>
|
||||
|
||||
<h3>Programs I use with Jhead</h3>
|
||||
<b>ImageMagick</b><br>
|
||||
<ul>
|
||||
I use the MOGIRIFY command from ImageMagick to do batch conversions and re-compresses of images.
|
||||
If you use Linux, you probably already have ImageMagick on your system (just type 'mogrify' at the
|
||||
command prompt to see if you have it). For Windows users, you have to download it from:
|
||||
<a href="http://www.imagemagick.org"> http://www.imagemagick.org</a><p>
|
||||
Image Magick is one of those programs that preserves comment and Exif headers, although older
|
||||
versions do not.
|
||||
</ul>
|
||||
<b>JPEGTRAN</b><br>
|
||||
<ul>
|
||||
If you use Linux you probably also already have this program. For windows, it's hard to find a
|
||||
pre-built binary on the web. The <a href="http://www.ijg.org"> Independent JPEG
|
||||
Group</a>'s website only has the source code.<p>
|
||||
There's a fancier version, with pre-built Windows binaries and a lossless cropping feature added at:
|
||||
<a href="http://sylvana.net/jpegcrop"> http://sylvana.net/jpegcrop</a>.
|
||||
</ul>
|
||||
|
||||
<b>XnView</b><br>
|
||||
<ul>
|
||||
<a href="http://www.xnview.com">XnView</a> is an excellent, small, fast, and free graphical image browser.
|
||||
It makes use of jpeg thumbnails for the thumbnail view. On account of Xnview, I added
|
||||
options to fix or regenerate the thumbnails to jhead, so that I could regenerate the thumbnails
|
||||
for images where the thumbnail had gotten out of sync with the image.
|
||||
<br>
|
||||
Mac and Linux versions of XnView are also available.
|
||||
</ul>
|
||||
|
||||
<b>wrjpgcom / rdjpgcom</b><br>
|
||||
<ul>
|
||||
You can use these programs to write and extract COM markers from JPEG images respectively. Although I always
|
||||
use my jhead program for this feature, the wrjpgcom and rdjpgcom programs are extremely simple and very
|
||||
suitable for use with shell scripts to process lots of images. These programs are part of most
|
||||
Linux distributions as part of the libjpg package (along with jpegtran)
|
||||
</ul>
|
||||
<p><br>
|
||||
If you are looking for a feature that Jhead doesn't have, try
|
||||
<a href="http://www.sno.phy.queensu.ca/~phil/exiftool/"><b>Exiftool</b></a>.
|
||||
Exiftool is actively maintained and has a LOT of features. A downside of Exiftool is that
|
||||
it's much bigger and slower.
|
||||
<p>
|
||||
For those who need a programming interface, there are:
|
||||
<b><a href="https://libexif.github.io/">libexif</a></b> and
|
||||
<b><a href="http://www.exiv2.org">exifv2</a></b>.
|
||||
<p>
|
||||
|
||||
Jhead homeage: <a href="http://www.sentex.net/~mwandel/jhead">http://www.sentex.net/~mwandel/jhead</a><br>
|
||||
Last Updated: Dec 31 2018<p>
|
||||
|
||||
|
||||
|
||||
@ -653,7 +653,7 @@ private:
|
||||
|
||||
/*
|
||||
Given a shot "from" and a trackball "track", updates "track" with "from" extrinsics.
|
||||
A traslation involving cameraDistance is included. This is necessary to compensate a trasformation that OpenGL performs
|
||||
A traslation involving cameraDistance is included. This is necessary to compensate a transformation that OpenGL performs
|
||||
at the end of the graphic pipeline.
|
||||
*/
|
||||
template <class T>
|
||||
|
||||
@ -54,7 +54,7 @@
|
||||
#include "rich_parameter_gui/richparameterlistdialog.h"
|
||||
|
||||
#include <wrap/io_trimesh/alnParser.h>
|
||||
#include "../external/easyexif/exif.h"
|
||||
#include <exif.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace vcg;
|
||||
@ -327,10 +327,10 @@ void MainWindow::updateLayerDialog()
|
||||
layerDialog->updateDecoratorParsView();
|
||||
MLRenderingData dt;
|
||||
if (meshDoc()->mm() != NULL)
|
||||
{
|
||||
{
|
||||
MLSceneGLSharedDataContext::PerMeshRenderingDataMap::iterator it = dtf.find(meshDoc()->mm()->id());
|
||||
if (it != dtf.end())
|
||||
layerDialog->updateRenderingParametersTab(meshDoc()->mm()->id(),*it);
|
||||
layerDialog->updateRenderingParametersTab(meshDoc()->mm()->id(),*it);
|
||||
}
|
||||
if (globrendtoolbar != NULL)
|
||||
{
|
||||
@ -943,7 +943,7 @@ void MainWindow::startFilter()
|
||||
{
|
||||
QString enstr = missingPreconditions.join(",");
|
||||
QMessageBox::warning(this, tr("PreConditions' Failure"), QString("Warning the filter <font color=red>'" + iFilter->filterName(action) + "'</font> has not been applied.<br>"
|
||||
"Current mesh does not have <i>" + enstr + "</i>."));
|
||||
"Current mesh does not have <i>" + enstr + "</i>."));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1012,25 +1012,25 @@ void MainWindow::updateSharedContextDataAfterFilterExecution(int postcondmask,in
|
||||
int updatemask = MeshModel::MM_NONE;
|
||||
bool connectivitychanged = false;
|
||||
if (((unsigned int)mm->cm.VN() != existit->_nvert) || ((unsigned int)mm->cm.FN() != existit->_nface) ||
|
||||
bool(postcondmask & MeshModel::MM_UNKNOWN) || bool(postcondmask & MeshModel::MM_VERTNUMBER) ||
|
||||
bool(postcondmask & MeshModel::MM_FACENUMBER) || bool(postcondmask & MeshModel::MM_FACEVERT) ||
|
||||
bool(postcondmask & MeshModel::MM_VERTFACETOPO) || bool(postcondmask & MeshModel::MM_FACEFACETOPO))
|
||||
{
|
||||
bool(postcondmask & MeshModel::MM_UNKNOWN) || bool(postcondmask & MeshModel::MM_VERTNUMBER) ||
|
||||
bool(postcondmask & MeshModel::MM_FACENUMBER) || bool(postcondmask & MeshModel::MM_FACEVERT) ||
|
||||
bool(postcondmask & MeshModel::MM_VERTFACETOPO) || bool(postcondmask & MeshModel::MM_FACEFACETOPO))
|
||||
{
|
||||
updatemask = MeshModel::MM_ALL;
|
||||
connectivitychanged = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
//masks differences bitwise operator (^) -> remove the attributes that didn't apparently change + the ones that for sure changed according to the postCondition function
|
||||
//this operation has been introduced in order to minimize problems with filters that didn't declared properly the postCondition mask
|
||||
//this operation has been introduced in order to minimize problems with filters that didn't declared properly the postCondition mask
|
||||
updatemask = (existit->_mask ^ mm->dataMask()) | postcondmask;
|
||||
connectivitychanged = false;
|
||||
}
|
||||
|
||||
MLRenderingData::RendAtts dttoupdate;
|
||||
//1) we convert the meshmodel updating mask to a RendAtts structure
|
||||
//1) we convert the meshmodel updating mask to a RendAtts structure
|
||||
MLPoliciesStandAloneFunctions::fromMeshModelMaskToMLRenderingAtts(updatemask,dttoupdate);
|
||||
//2) The correspondent bos to the updated rendering attributes are set to invalid
|
||||
//2) The correspondent bos to the updated rendering attributes are set to invalid
|
||||
shared->meshAttributesUpdated(mm->id(),connectivitychanged,dttoupdate);
|
||||
|
||||
//3) we took the current rendering modality for the mesh in the active gla
|
||||
@ -1095,7 +1095,7 @@ void MainWindow::updateSharedContextDataAfterFilterExecution(int postcondmask,in
|
||||
|
||||
shared->setRenderingDataPerMeshView(mm->id(),GLA()->context(),curr);
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
//A new mesh has been created by the filter. I have to add it in the shared context data structure
|
||||
newmeshcreated = true;
|
||||
@ -1287,7 +1287,7 @@ void MainWindow::executeFilter(const QAction* action, RichParameterList ¶ms,
|
||||
if (mm != NULL)
|
||||
{
|
||||
// at the end for filters that change the color, or selection set the appropriate rendering mode
|
||||
if(iFilter->getClass(action) & FilterPluginInterface::FaceColoring )
|
||||
if(iFilter->getClass(action) & FilterPluginInterface::FaceColoring )
|
||||
mm->updateDataMask(MeshModel::MM_FACECOLOR);
|
||||
|
||||
if(iFilter->getClass(action) & FilterPluginInterface::VertexColoring )
|
||||
@ -1314,9 +1314,10 @@ void MainWindow::executeFilter(const QAction* action, RichParameterList ¶ms,
|
||||
{
|
||||
meshDoc()->setBusy(false);
|
||||
qApp->restoreOverrideCursor();
|
||||
QMessageBox::warning(this, tr("Filter Failure"),
|
||||
QString("Operating system was not able to allocate the requested memory.<br><b>"
|
||||
"Failure of filter <font color=red>: '%1'</font><br>").arg(action->text())+bdall.what()); // text
|
||||
QMessageBox::warning(
|
||||
this, tr("Filter Failure"),
|
||||
QString("Operating system was not able to allocate the requested memory.<br><b>"
|
||||
"Failure of filter <font color=red>: '%1'</font><br>").arg(action->text())+bdall.what()); // text
|
||||
MainWindow::globalStatusBar()->showMessage("Filter failed...",2000);
|
||||
}
|
||||
qb->reset();
|
||||
@ -1626,7 +1627,7 @@ bool MainWindow::openProject(QString fileName)
|
||||
{
|
||||
QString relativeToProj = fi.absoluteDir().absolutePath() + "/" + (*ir).filename.c_str();
|
||||
meshDoc()->addNewMesh(relativeToProj,relativeToProj);
|
||||
openRes = loadMeshWithStandardParams(relativeToProj,this->meshDoc()->mm(),ir->trasformation);
|
||||
openRes = loadMeshWithStandardParams(relativeToProj,this->meshDoc()->mm(),ir->transformation);
|
||||
if(!openRes)
|
||||
meshDoc()->delMesh(meshDoc()->mm());
|
||||
}
|
||||
@ -1662,10 +1663,10 @@ bool MainWindow::openProject(QString fileName)
|
||||
QString model_filename;
|
||||
|
||||
image_list_filename = QFileDialog::getOpenFileName(
|
||||
this , tr("Open image list file"),
|
||||
QFileInfo(fileName).absolutePath(),
|
||||
tr("Bundler images list file (*.txt)")
|
||||
);
|
||||
this,
|
||||
tr("Open image list file"),
|
||||
QFileInfo(fileName).absolutePath(),
|
||||
tr("Bundler images list file (*.txt)"));
|
||||
if(image_list_filename.isEmpty())
|
||||
return false;
|
||||
|
||||
@ -1767,7 +1768,7 @@ bool MainWindow::appendProject(QString fileName)
|
||||
{
|
||||
QString relativeToProj = fi.absoluteDir().absolutePath() + "/" + (*ir).filename.c_str();
|
||||
meshDoc()->addNewMesh(relativeToProj,relativeToProj);
|
||||
if(!loadMeshWithStandardParams(relativeToProj,this->meshDoc()->mm(),(*ir).trasformation))
|
||||
if(!loadMeshWithStandardParams(relativeToProj,this->meshDoc()->mm(),(*ir).transformation))
|
||||
meshDoc()->delMesh(meshDoc()->mm());
|
||||
}
|
||||
}
|
||||
@ -1802,10 +1803,10 @@ bool MainWindow::appendProject(QString fileName)
|
||||
QString model_filename;
|
||||
|
||||
image_list_filename = QFileDialog::getOpenFileName(
|
||||
this, tr("Open image list file"),
|
||||
QFileInfo(fileName).absolutePath(),
|
||||
tr("Bundler images list file (*.txt)")
|
||||
);
|
||||
this,
|
||||
tr("Open image list file"),
|
||||
QFileInfo(fileName).absolutePath(),
|
||||
tr("Bundler images list file (*.txt)"));
|
||||
if (image_list_filename.isEmpty())
|
||||
return false;
|
||||
|
||||
@ -2014,50 +2015,51 @@ bool MainWindow::importRaster(const QString& fileImg)
|
||||
/// If no CCD Width value is provided, the intrinsics are extracted using the Equivalent 35mm focal
|
||||
/// If no or invalid EXIF info is found, the Intrinsics are initialized as a "plausible" 35mm sensor, with 50mm focal
|
||||
|
||||
// Read the JPEG file into a buffer
|
||||
FILE *fp = fopen(qUtf8Printable(fileName), "rb");
|
||||
if (fp) {
|
||||
QString errorMsgFormat = "Exif Parsing: Unable to open file:\n\"%1\"\n\nError details: file %1 is not readable.";
|
||||
QMessageBox::critical(this, tr("Meshlab Opening Error"), errorMsgFormat.arg(fileName));
|
||||
return false;
|
||||
}
|
||||
fseek(fp, 0, SEEK_END);
|
||||
unsigned long fsize = ftell(fp);
|
||||
rewind(fp);
|
||||
unsigned char *buf = new unsigned char[fsize];
|
||||
if (fread(buf, 1, fsize, fp) != fsize) {
|
||||
QString errorMsgFormat = "Exif Parsing: Unable to read the content of the opened file:\n\"%1\"\n\nError details: file %1 is not readable.";
|
||||
QMessageBox::critical(this, tr("Meshlab Opening Error"), errorMsgFormat.arg(fileName));
|
||||
delete[] buf;
|
||||
return false;
|
||||
}
|
||||
fclose(fp);
|
||||
|
||||
// Parse EXIF
|
||||
easyexif::EXIFInfo ImageInfo;
|
||||
int code = ImageInfo.parseFrom(buf, fsize);
|
||||
delete[] buf;
|
||||
if (code) {
|
||||
GLA()->Logf(0,"Warning unable to parse exif for file %s",qPrintable(fileName) );
|
||||
}
|
||||
|
||||
if (code || ImageInfo.FocalLengthIn35mm==0.0f)
|
||||
{
|
||||
rm->shot.Intrinsics.ViewportPx = vcg::Point2i(rm->currentPlane->image.width(), rm->currentPlane->image.height());
|
||||
rm->shot.Intrinsics.CenterPx = Point2m(float(rm->currentPlane->image.width()/2.0), float(rm->currentPlane->image.width()/2.0));
|
||||
rm->shot.Intrinsics.PixelSizeMm[0]=36.0f/(float)rm->currentPlane->image.width();
|
||||
rm->shot.Intrinsics.PixelSizeMm[1]=rm->shot.Intrinsics.PixelSizeMm[0];
|
||||
rm->shot.Intrinsics.FocalMm = 50.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
rm->shot.Intrinsics.ViewportPx = vcg::Point2i(ImageInfo.ImageWidth, ImageInfo.ImageHeight);
|
||||
rm->shot.Intrinsics.CenterPx = Point2m(float(ImageInfo.ImageWidth/2.0), float(ImageInfo.ImageHeight/2.0));
|
||||
float ratioFocal=ImageInfo.FocalLength/ImageInfo.FocalLengthIn35mm;
|
||||
rm->shot.Intrinsics.PixelSizeMm[0]=(36.0f*ratioFocal)/(float)ImageInfo.ImageWidth;
|
||||
rm->shot.Intrinsics.PixelSizeMm[1]=(24.0f*ratioFocal)/(float)ImageInfo.ImageHeight;
|
||||
rm->shot.Intrinsics.FocalMm = ImageInfo.FocalLength;
|
||||
}
|
||||
// Read the JPEG file into a buffer
|
||||
FILE *fp = fopen(qUtf8Printable(fileName), "rb");
|
||||
if (!fp) {
|
||||
QString errorMsgFormat = "Exif Parsing: Unable to open file:\n\"%1\"\n\nError details: file %1 is not readable.";
|
||||
QMessageBox::critical(this, tr("Meshlab Opening Error"), errorMsgFormat.arg(fileName));
|
||||
return false;
|
||||
}
|
||||
fseek(fp, 0, SEEK_END);
|
||||
unsigned long fsize = ftell(fp);
|
||||
rewind(fp);
|
||||
unsigned char *buf = new unsigned char[fsize];
|
||||
if (fread(buf, 1, fsize, fp) != fsize) {
|
||||
QString errorMsgFormat = "Exif Parsing: Unable to read the content of the opened file:\n\"%1\"\n\nError details: file %1 is not readable.";
|
||||
QMessageBox::critical(this, tr("Meshlab Opening Error"), errorMsgFormat.arg(fileName));
|
||||
delete[] buf;
|
||||
fclose(fp);
|
||||
return false;
|
||||
}
|
||||
fclose(fp);
|
||||
|
||||
// Parse EXIF
|
||||
easyexif::EXIFInfo ImageInfo;
|
||||
int code = ImageInfo.parseFrom(buf, fsize);
|
||||
delete[] buf;
|
||||
if (code) {
|
||||
GLA()->Logf(0,"Warning unable to parse exif for file %s",qPrintable(fileName) );
|
||||
}
|
||||
|
||||
if (code || ImageInfo.FocalLengthIn35mm==0.0f)
|
||||
{
|
||||
rm->shot.Intrinsics.ViewportPx = vcg::Point2i(rm->currentPlane->image.width(), rm->currentPlane->image.height());
|
||||
rm->shot.Intrinsics.CenterPx = Point2m(float(rm->currentPlane->image.width()/2.0), float(rm->currentPlane->image.width()/2.0));
|
||||
rm->shot.Intrinsics.PixelSizeMm[0]=36.0f/(float)rm->currentPlane->image.width();
|
||||
rm->shot.Intrinsics.PixelSizeMm[1]=rm->shot.Intrinsics.PixelSizeMm[0];
|
||||
rm->shot.Intrinsics.FocalMm = 50.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
rm->shot.Intrinsics.ViewportPx = vcg::Point2i(ImageInfo.ImageWidth, ImageInfo.ImageHeight);
|
||||
rm->shot.Intrinsics.CenterPx = Point2m(float(ImageInfo.ImageWidth/2.0), float(ImageInfo.ImageHeight/2.0));
|
||||
float ratioFocal=ImageInfo.FocalLength/ImageInfo.FocalLengthIn35mm;
|
||||
rm->shot.Intrinsics.PixelSizeMm[0]=(36.0f*ratioFocal)/(float)ImageInfo.ImageWidth;
|
||||
rm->shot.Intrinsics.PixelSizeMm[1]=(24.0f*ratioFocal)/(float)ImageInfo.ImageHeight;
|
||||
rm->shot.Intrinsics.FocalMm = ImageInfo.FocalLength;
|
||||
}
|
||||
// End of EXIF reading
|
||||
|
||||
//// Since no extrinsic are available, the current trackball is reset (except for the FOV) and assigned to the raster
|
||||
@ -2761,7 +2763,7 @@ bool MainWindow::QCallBack(const int pos, const char * str)
|
||||
void MainWindow::updateTexture(int meshid)
|
||||
{
|
||||
MultiViewer_Container* mvc = currentViewContainer();
|
||||
if ((mvc == NULL) || (meshDoc() == NULL))
|
||||
if ((mvc == NULL) || (meshDoc() == NULL))
|
||||
return;
|
||||
|
||||
MLSceneGLSharedDataContext* shared = mvc->sharedDataContext();
|
||||
@ -3220,7 +3222,7 @@ void MainWindow::updateRenderingDataAccordingToActionToAllVisibleLayers(MLRender
|
||||
|
||||
void MainWindow::updateRenderingDataAccordingToActions(QList<MLRenderingGlobalAction*> actlist)
|
||||
{
|
||||
if (meshDoc() == NULL)
|
||||
if (meshDoc() == NULL)
|
||||
return;
|
||||
|
||||
for (int ii = 0; ii < meshDoc()->meshList.size(); ++ii)
|
||||
@ -3329,7 +3331,7 @@ void MainWindow::switchCurrentContainer(QMdiSubWindow * subwin)
|
||||
if (_currviewcontainer != NULL)
|
||||
{
|
||||
updateLayerDialog();
|
||||
updateMenus();
|
||||
updateMenus();
|
||||
updateStdDialog();
|
||||
}
|
||||
}
|
||||
|
||||
@ -15,6 +15,7 @@ INCLUDEPATH *= \
|
||||
. \
|
||||
.. \
|
||||
../.. \
|
||||
$$MESHLAB_EXTERNAL_DIRECTORY/easyexif \
|
||||
$$VCGDIR \
|
||||
$$EIGENDIR
|
||||
|
||||
@ -76,8 +77,7 @@ SOURCES += \
|
||||
glarea_setting.cpp \
|
||||
rich_parameter_gui/richparameterlistdialog.cpp \
|
||||
rich_parameter_gui/richparameterlistframe.cpp \
|
||||
rich_parameter_gui/richparameterwidgets.cpp \
|
||||
../external/easyexif/exif.cpp
|
||||
rich_parameter_gui/richparameterwidgets.cpp
|
||||
|
||||
FORMS += \
|
||||
ui/layerDialog.ui \
|
||||
|
||||
@ -244,8 +244,8 @@ void DecorateBasePlugin::decorateMesh(const QAction* a, MeshModel &m, const Rich
|
||||
|
||||
case DP_SHOW_BOX_CORNERS:
|
||||
{
|
||||
bool untrasformed = rm->getBool(this->BBAbsParam());
|
||||
DrawBBoxCorner(m, untrasformed);
|
||||
bool untransformed = rm->getBool(this->BBAbsParam());
|
||||
DrawBBoxCorner(m, untransformed);
|
||||
|
||||
Point3m bmin, bmax;
|
||||
bmin = m.cm.bbox.min;
|
||||
@ -1083,7 +1083,7 @@ switch(ID(action))
|
||||
{
|
||||
case DP_SHOW_BOX_CORNERS :
|
||||
{
|
||||
parset.addParam(RichBool(this->BBAbsParam(), false, "Draw Untrasformed","If true the bbox is drawn in the original, untrasformed position "
|
||||
parset.addParam(RichBool(this->BBAbsParam(), false, "Draw Untransformed","If true the bbox is drawn in the original, untransformed position "
|
||||
"(instead of the position obtained by transforming it using the matrix associated to the current Layer)"));
|
||||
} break;
|
||||
|
||||
|
||||
@ -84,7 +84,7 @@ public:
|
||||
vcg::Point2<ScalarType> UVDiam;
|
||||
///transform to diamond coordinates
|
||||
isoParam->GE1(I0,dest,DiamIndex,UVDiam);
|
||||
///trasform back to I,alpha,beta
|
||||
///transform back to I,alpha,beta
|
||||
isoParam->inv_GE1(DiamIndex,UVDiam,I1,bary1);
|
||||
domain=1;
|
||||
return true;
|
||||
@ -104,7 +104,7 @@ public:
|
||||
vcg::Point2<ScalarType> UVHstar;
|
||||
///transform to UV
|
||||
bool found=isoParam->GE0(I0,dest,StarIndex,UVHstar);
|
||||
///trasform back to I,alpha,beta
|
||||
///transform back to I,alpha,beta
|
||||
if (!found)
|
||||
return false;
|
||||
found=isoParam->inv_GE0(StarIndex,UVHstar,I1,bary1);
|
||||
|
||||
@ -103,7 +103,7 @@ QString QhullPlugin::pluginName() const
|
||||
case FP_QHULL_VISIBLE_POINTS: return QString("Select the <b>visible points</b> in a point cloud, as viewed from a given viewpoint.<br>"
|
||||
"It uses the Qhull library (http://www.qhull.org/ <br><br>"
|
||||
"The algorithm used (Katz, Tal and Basri 2007) determines visibility without reconstructing a surface or estimating normals."
|
||||
"A point is considered visible if its transformed point lies on the convex hull of a trasformed points cloud from the original mesh points.");
|
||||
"A point is considered visible if its transformed point lies on the convex hull of a transformed points cloud from the original mesh points.");
|
||||
default : assert(0);
|
||||
}
|
||||
return QString("Error: Unknown Filter");
|
||||
|
||||
@ -683,7 +683,7 @@ bool compute_alpha_shapes(int dim, int numpoints, MeshModel &m, MeshModel &pm, d
|
||||
Select the visible points in a point cloud, as viewed from a given viewpoint.
|
||||
It uses the Qhull library (http://www.qhull.org/.
|
||||
The algorithm used (Katz, Tal and Basri 2007) determines visibility without reconstructing a surface or estimating normals.
|
||||
A point is considered visible if its transformed point lies on the convex hull of a trasformed points cloud from the original mesh points.
|
||||
A point is considered visible if its transformed point lies on the convex hull of a transformed points cloud from the original mesh points.
|
||||
|
||||
returns
|
||||
the number of visible points if no errors occurred;
|
||||
|
||||
@ -144,7 +144,7 @@ namespace io {
|
||||
{
|
||||
QDomElement lod = lodNodes.at(ln).toElement();
|
||||
QDomNode parent = lod.parentNode();
|
||||
//Create a traslation Trasform node from attribute 'center'
|
||||
//Create a traslation Transform node from attribute 'center'
|
||||
QString center = lod.attribute("center");
|
||||
QDomElement transform = doc->createElement("Transform");
|
||||
transform.setAttribute("traslation", center);
|
||||
@ -2023,7 +2023,7 @@ namespace io {
|
||||
|
||||
|
||||
//Create the transformation matrix for texture coordinate from TextureTransform node
|
||||
inline static vcg::Matrix33f createTextureTrasformMatrix(QDomElement elem)
|
||||
inline static vcg::Matrix33f createTextureTransformMatrix(QDomElement elem)
|
||||
{
|
||||
vcg::Matrix33f matrix, tmp;
|
||||
matrix.SetIdentity();
|
||||
@ -2073,7 +2073,7 @@ namespace io {
|
||||
}
|
||||
|
||||
|
||||
//Create the transformation matrix from Trasform node
|
||||
//Create the transformation matrix from Transform node
|
||||
inline static vcg::Matrix44<ScalarType> createTransformMatrix(QDomElement root, vcg::Matrix44<ScalarType> tMatrix)
|
||||
{
|
||||
vcg::Matrix44<ScalarType> t, tmp;
|
||||
@ -2396,7 +2396,7 @@ namespace io {
|
||||
point = vcg::Point3f(0, 0, 1.0);
|
||||
textCoord.N() = -1;
|
||||
}
|
||||
//Apply trasform
|
||||
//Apply transform
|
||||
point = textInfo.textureTransform * point;
|
||||
//Apply clamb and repeat
|
||||
if (!textInfo.repeatS)
|
||||
@ -2567,7 +2567,7 @@ namespace io {
|
||||
textureInfo[j].isCoordGenerator = true;
|
||||
}
|
||||
if ( i < (size_t)textureTransformList.size())
|
||||
textureInfo[j].textureTransform = createTextureTrasformMatrix(textureTransformList.at(i).toElement());
|
||||
textureInfo[j].textureTransform = createTextureTransformMatrix(textureTransformList.at(i).toElement());
|
||||
j++;
|
||||
}
|
||||
i++;
|
||||
@ -2582,7 +2582,7 @@ namespace io {
|
||||
if (textureInfo[0].textureCoordList.isEmpty())
|
||||
textureInfo[0].isValid = false;
|
||||
if (textureTransformList.size() > 0)
|
||||
textureInfo[0].textureTransform = createTextureTrasformMatrix(textureTransformList.at(0).toElement());
|
||||
textureInfo[0].textureTransform = createTextureTransformMatrix(textureTransformList.at(0).toElement());
|
||||
}
|
||||
}
|
||||
else if (textureCoord.tagName() == "TextureCoordinateGenerator")
|
||||
@ -2595,7 +2595,7 @@ namespace io {
|
||||
textureInfo[0].isValid = (mode == "COORD") || (mode == "SPHERE");
|
||||
textureInfo[0].isCoordGenerator = true;
|
||||
if (textureTransformList.size() > 0)
|
||||
textureInfo[0].textureTransform = createTextureTrasformMatrix(textureTransformList.at(0).toElement());
|
||||
textureInfo[0].textureTransform = createTextureTransformMatrix(textureTransformList.at(0).toElement());
|
||||
}
|
||||
}
|
||||
else if (validTexture.size() == 1 && validTexture.at(0))
|
||||
|
||||
@ -452,7 +452,7 @@ public:
|
||||
{
|
||||
QString relativeToProj = fi.absoluteDir().absolutePath() + "/" + (*ir).filename.c_str();
|
||||
md.addNewMesh(relativeToProj,relativeToProj);
|
||||
openRes = loadMeshWithStandardParams(relativeToProj,md.mm(),ir->trasformation, &md);
|
||||
openRes = loadMeshWithStandardParams(relativeToProj,md.mm(),ir->transformation, &md);
|
||||
if(!openRes)
|
||||
md.delMesh(md.mm());
|
||||
}
|
||||
|
||||
2
vcglib
2
vcglib
@ -1 +1 @@
|
||||
Subproject commit f38172157ab001ba219c5df13d2548d259025c97
|
||||
Subproject commit dd8c26474dfa3ee2cde2e4c39366fe9df41e667d
|
||||
Loading…
x
Reference in New Issue
Block a user