Project

General

Profile

RE: Metadata XML? ยป exiv2json.cpp

Robin Mills, 24 Mar 2015 16:38

 
1
// ***************************************************************** -*- C++ -*-
2
// exif2json.cpp, $Id: exif2json.cpp 518 2013-05-10 23:53:00Z robinwmills@gmail.com $
3
// Sample program to print the Exif metadata in JSON format
4

    
5
#include <exiv2/exiv2.hpp>
6
#include <Jzon.h>
7

    
8
#include <iostream>
9
#include <iomanip>
10
#include <cassert>
11
#include <string>
12

    
13
#if defined(__MINGW32__) || defined(__MINGW64__)
14
# ifndef  __MINGW__
15
#  define __MINGW__
16
# endif
17
#endif
18

    
19
#include <stdlib.h>
20
#include <limits.h>
21
#include <sys/types.h>
22
#include <sys/stat.h>
23

    
24
#if defined(_MSC_VER) || defined(__MINGW__)
25
#include <windows.h>
26
#ifndef  PATH_MAX
27
# define  PATH_MAX 512
28
#endif
29
const char* realpath(const char* file,char* path)
30
{
31
	GetFullPathName(file,PATH_MAX,path,NULL);
32
	return path;
33
}
34
#else
35
#include <unistd.h>
36
#endif
37

    
38
using namespace std;
39
using namespace Jzon;
40
using namespace Exiv2;
41

    
42
// http://stackoverflow.com/questions/236129/splitting-a-string-in-c
43
static size_t split(const std::string& s, char delim, std::vector<std::string>& elems)
44
{
45
    std::stringstream ss(s);
46
    std::string       item;
47
    while (std::getline(ss, item, delim)) {
48
        elems.push_back(item);
49
    }
50
    return elems.size();
51
}
52

    
53
Jzon::Object& objectForKey(std::string Key,std::string& name,Jzon::Object& root)
54
{
55
    static Jzon::Object object;
56
    
57
    std::vector<std::string> keys ;
58
    size_t l = split(Key,'.',keys);
59
    if   ( l < 3 || l > 7 ) return object; // maybe we should throw
60
    
61
    name     = keys[l-1];
62
    size_t k = 0;
63
    Jzon::Object& r1 = root;
64
    
65
    // this is horrible  References are pointers that don't work properly!
66
    if ( !r1.Has(keys[k]) )             r1.Add(keys[k],object);
67
    Jzon::Object& r2 = (Jzon::Object&)  r1.Get(keys[k]);
68
    if  ( l == 2 ) return r2;
69
    
70
    if ( !r2.Has(keys[++k]))             r2.Add(keys[k],object);
71
    Jzon::Object&   r3 = (Jzon::Object&) r2.Get(keys[k]);
72
    if  ( l == 3 ) return r3;
73
    
74
    if ( !r3.Has(keys[++k]))             r3.Add(keys[k],object);
75
    Jzon::Object&   r4 = (Jzon::Object&) r3.Get(keys[k]);
76
    if  ( l == 4 ) return r4;
77
    
78
    if ( !r4.Has(keys[++k]))             r4.Add(keys[k],object);
79
    Jzon::Object&   r5 = (Jzon::Object&) r4.Get(keys[k]);
80
    if  ( l == 5 ) return r5;
81
    
82
    if ( !r5.Has(keys[++k]))             r5.Add(keys[k],object);
83
    Jzon::Object&   r6 = (Jzon::Object&) r5.Get(keys[k]);
84
    if  ( l == 6 ) return r6;
85
    
86
    if ( !r6.Has(keys[++k]))             r6.Add(keys[k],object);
87
    Jzon::Object&   r7 = (Jzon::Object&) r6.Get(keys[k]);
88
    if  ( l == 7 ) return r7;
89

    
90
    return object;
91
}
92

    
93
// ExifData::const_iterator i
94
template <class T>
95
void push(Jzon::Object& json,const std::string& key,T i)
96
{
97
    std::string value = i->value().toString();
98

    
99
    switch ( i->typeId() ) {
100
        case Exiv2::xmpText:
101
        case Exiv2::asciiString : 
102
        case Exiv2::string:
103
        case Exiv2::comment:
104
             json.Add(key,value);
105
        break;
106

    
107
        case Exiv2::unsignedByte:
108
        case Exiv2::unsignedShort:
109
        case Exiv2::unsignedLong:
110
        case Exiv2::signedByte:
111
        case Exiv2::signedShort:
112
        case Exiv2::signedLong:
113
             json.Add(key,(int)i->value().toLong());
114
        break;
115
        
116
        case Exiv2::tiffFloat:
117
        case Exiv2::tiffDouble:
118
             json.Add(key,i->value().toFloat());
119
        break;
120

    
121
        case Exiv2::unsignedRational:
122
        case Exiv2::signedRational: {
123
             Jzon::Array arr;
124
             Rational rat = i->value().toRational();
125
             arr.Add (rat.first );
126
             arr.Add (rat.second);
127
             json.Add(key,arr);
128
        } break;
129

    
130
        case Exiv2::date:
131
        case Exiv2::time:
132
             json.Add(key,i->value().toString());
133
        break;
134

    
135
        default:
136
        case Exiv2::undefined:
137
        case Exiv2::tiffIfd:
138
        case Exiv2::directory:
139
        case Exiv2::xmpAlt:
140
        case Exiv2::xmpBag:
141
        case Exiv2::xmpSeq:
142
        case Exiv2::langAlt:
143
             // http://dev.exiv2.org/boards/3/topics/1367#message-1373
144
             if ( key == "UserComment" ) {
145
                size_t pos  = value.find('\0') ;
146
             	if (   pos != string::npos )
147
             	    value = value.substr(0,pos);
148
             }
149

    
150
             if ( key != "MakerNote") json.Add(key,value);
151
        break;
152
    }
153
}
154

    
155
void fileSystemPush(const char* path,Jzon::Node& nfs)
156
{
157
    Jzon::Object& fs = (Jzon::Object&) nfs;
158
    fs.Add("path",path);
159
    char resolved_path[PATH_MAX];
160
    fs.Add("realpath",realpath(path,resolved_path));
161

    
162
	struct stat buf;
163
    memset(&buf,0,sizeof(buf));
164
    stat(path,&buf);
165

    
166
    fs.Add("st_dev"    ,(int) buf.st_dev    ); /* ID of device containing file    */
167
    fs.Add("st_ino"    ,(int) buf.st_ino    ); /* inode number                    */
168
    fs.Add("st_mode"   ,(int) buf.st_mode   ); /* protection                      */
169
    fs.Add("st_nlink"  ,(int) buf.st_nlink  ); /* number of hard links            */
170
    fs.Add("st_uid"    ,(int) buf.st_uid    ); /* user ID of owner                */
171
    fs.Add("st_gid"    ,(int) buf.st_gid    ); /* group ID of owner               */
172
    fs.Add("st_rdev"   ,(int) buf.st_rdev   ); /* device ID (if special file)     */
173
    fs.Add("st_size"   ,(int) buf.st_size   ); /* total size, in bytes            */
174
    fs.Add("st_atime"  ,(int) buf.st_atime  ); /* time of last access             */
175
    fs.Add("st_mtime"  ,(int) buf.st_mtime  ); /* time of last modification       */
176
    fs.Add("st_ctime"  ,(int) buf.st_ctime  ); /* time of last status change      */
177

    
178
#if defined(_MSC_VER) || defined(__MINGW__)
179
	size_t blksize     = 1024;
180
	size_t blocks      = (buf.st_size+blksize-1)/blksize;
181
#else
182
    size_t blksize     = buf.st_blksize;
183
    size_t blocks      = buf.st_blocks ;
184
#endif    
185
    fs.Add("st_blksize",(int) blksize       ); /* blocksize for file system I/O   */
186
    fs.Add("st_blocks" ,(int) blocks        ); /* number of 512B blocks allocated */
187
}
188

    
189
int main(int argc, char* const argv[])
190
try {
191
    
192
    if (argc != 2) {
193
        std::cout << "Usage: " << argv[0] << " file\n";
194
        return 1;
195
    }
196
    
197
    const char* path=argv[1];
198
        
199
    Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(path);
200
    assert(image.get() != 0);
201
    image->readMetadata();
202
        
203
    Jzon::Object root;
204

    
205
    const char*    FS="FS";
206
    Jzon::Object      fs  ;
207
    root.Add      (FS,fs) ;
208
    fileSystemPush(path,root.Get(FS));
209
    
210
	Exiv2::ExifData &exifData = image->exifData();
211
    for ( ExifData::const_iterator i = exifData.begin(); i != exifData.end() ; ++i ) {
212
        std::string   key ;
213
        push(objectForKey(i->key(),key,root),key,i);
214
    }
215

    
216
	Exiv2::IptcData &iptcData = image->iptcData();
217
    for (Exiv2::IptcData::const_iterator i = iptcData.begin(); i != iptcData.end(); ++i) {
218
        std::string key ;
219
        push(objectForKey(i->key(),key,root),key,i);
220
    }
221

    
222
	Exiv2::XmpData  &xmpData  = image->xmpData();
223
    for (Exiv2::XmpData::const_iterator i = xmpData.begin(); i != xmpData.end(); ++i) {
224
        std::string key ;
225
        push(objectForKey(i->key(),key,root),key,i);
226
    }
227
/*
228
    This is only for testing long paths    
229
    {
230
    	ExifData::const_iterator i = exifData.begin();
231
    	std::string key;
232
    	push(objectForKey("This.Is.A.Rather.Long.Path.Key",key,root),key,i);
233
    }
234
*/        
235
    Jzon::Writer writer(root,Jzon::StandardFormat);
236
    writer.Write();
237
    std::cout << writer.GetResult() << std::endl;
238
    return 0;
239
}
240
        
241
//catch (std::exception& e) {
242
//catch (Exiv2::AnyError& e) {
243
catch (Exiv2::Error& e) {
244
    std::cout << "Caught Exiv2 exception '" << e.what() << "'\n";
245
    return -1;
246
}
    (1-1/1)