Project

General

Profile

Bug #589 ยป properties.patch

Redmine Admin, 12 Dec 2008 01:43

View differences:

src/pngimage.cpp (working copy)
20 20
 */
21 21
/*
22 22
  File:    pngimage.cpp
23
  Version: $Rev: 823 $
23
  Version: $Rev$
24 24
  Author(s): Gilles Caulier (cgilles) <caulier dot gilles at gmail dot com>
25 25
  History: 12-Jun-06, gc: submitted
26 26
  Credits: See header file
27 27
 */
28 28
// *****************************************************************************
29 29
#include "rcsid.hpp"
30
EXIV2_RCSID("@(#) $Id: pngimage.cpp 823 2006-06-12 07:35:00Z cgilles $")
30
EXIV2_RCSID("@(#) $Id$")
31 31

  
32 32
// *****************************************************************************
33 33

  
src/pngchunk.cpp (working copy)
20 20
 */
21 21
/*
22 22
  File:    pngchunk.cpp
23
  Version: $Rev: 823 $
23
  Version: $Rev$
24 24
  Author(s): Gilles Caulier (cgilles) <caulier dot gilles at gmail dot com>
25 25
  History: 12-Jun-06, gc: submitted
26 26
  Credits: See header file
27 27
 */
28 28
// *****************************************************************************
29 29
#include "rcsid.hpp"
30
EXIV2_RCSID("@(#) $Id: pngchunk.cpp 823 2006-06-23 07:35:00Z cgilles $")
30
EXIV2_RCSID("@(#) $Id$")
31 31

  
32 32
// *****************************************************************************
33 33
// included header files
src/pngchunk_int.hpp (working copy)
25 25
           <a href="http://www.vias.org/pngguide/chapter11_04.html">PNG tTXt and zTXt chunks structures</a> from PNG definitive guide,<br>
26 26
           <a href="http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/PNG.html">PNG tags list</a> by Phil Harvey<br>
27 27
           Email communication with <a href="mailto:caulier dot gilles at gmail dot com">caulier dot gilles at gmail dot com</a><br>
28
  @version $Rev: 823 $
28
  @version $Rev$
29 29
  @author  Andreas Huggel (ahu)
30 30
           <a href="mailto:ahuggel@gmx.net">ahuggel@gmx.net</a>
31 31
  @author  Gilles Caulier (cgilles)
src/pngimage.hpp (working copy)
23 23
  @brief   PNG image, implemented using the following references:
24 24
           <a href="http://www.w3.org/TR/PNG/">PNG specification</a> by W3C<br>
25 25
           <a href="http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/PNG.html">PNG tags list</a> by Phil Harvey<br>
26
  @version $Rev: 823 $
26
  @version $Rev$
27 27
  @author  Andreas Huggel (ahu)
28 28
           <a href="mailto:ahuggel@gmx.net">ahuggel@gmx.net</a>
29 29
  @author  Gilles Caulier (cgilles)
msvc/exivsimple/stdafx.h (working copy)
1
// ***************************************************************** -*- C++ -*-
2
/*
3
 * Copyright (C) 2004-2007 Andreas Huggel <ahuggel@gmx.net>
4
 * 
5
 * This program is part of the Exiv2 distribution.
6
 *
7
 * This program is free software; you can redistribute it and/or
8
 * modify it under the terms of the GNU General Public License
9
 * as published by the Free Software Foundation; either version 2
10
 * of the License, or (at your option) any later version.
11
 * 
12
 * This program is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU General Public License for more details.
16
 * 
17
 * You should have received a copy of the GNU General Public License
18
 * along with this program; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA.
20
 */
21
/*!
22
  @file    stdafx.h
23
  @brief   Precompiled header file support
24
  @version $Rev$
25
  @author  Brad Schick (brad) 
26
           <a href="mailto:brad@robotbattle.com">brad@robotbattle.com</a>
27
  @date    12-Nov-04, brad: created
28
 */
29
// *****************************************************************************
30

  
31
#pragma once
32

  
33
#define WIN32_LEAN_AND_MEAN
34
#include <windows.h>
1
// ***************************************************************** -*- C++ -*-
2
/*
3
 * Copyright (C) 2004-2007 Andreas Huggel <ahuggel@gmx.net>
4
 * 
5
 * This program is part of the Exiv2 distribution.
6
 *
7
 * This program is free software; you can redistribute it and/or
8
 * modify it under the terms of the GNU General Public License
9
 * as published by the Free Software Foundation; either version 2
10
 * of the License, or (at your option) any later version.
11
 * 
12
 * This program is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU General Public License for more details.
16
 * 
17
 * You should have received a copy of the GNU General Public License
18
 * along with this program; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA.
20
 */
21
/*!
22
  @file    stdafx.h
23
  @brief   Precompiled header file support
24
  @version $Rev$
25
  @author  Brad Schick (brad) 
26
           <a href="mailto:brad@robotbattle.com">brad@robotbattle.com</a>
27
  @date    12-Nov-04, brad: created
28
 */
29
// *****************************************************************************
30

  
31
#pragma once
32

  
33
#define WIN32_LEAN_AND_MEAN
34
#include <windows.h>
msvc/exivsimple/exivsimple.cpp (working copy)
1
// ***************************************************************** -*- C++ -*-
2
/*
3
 * Copyright (C) 2004-2008 Andreas Huggel <ahuggel@gmx.net>
4
 * 
5
 * This program is part of the Exiv2 distribution.
6
 *
7
 * This program is free software; you can redistribute it and/or
8
 * modify it under the terms of the GNU General Public License
9
 * as published by the Free Software Foundation; either version 2
10
 * of the License, or (at your option) any later version.
11
 * 
12
 * This program is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU General Public License for more details.
16
 * 
17
 * You should have received a copy of the GNU General Public License
18
 * along with this program; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA.
20
 */
21
/*
22
  File:      exivsimple.cpp
23
  Version:   $Rev$
24
  Author(s): Brad Schick <brad@robotbattle.com>
25
             Christian Kuster <christian@kusti.ch>
26
  History:   12-Nov-04, brad: created
27
 */
28
// *****************************************************************************
29

  
30
#include "stdafx.h"
31
#include "exivsimple.h"
32
#include <exiv2/image.hpp>
33
#include <exiv2/exif.hpp>
34
#include <exiv2/iptc.hpp>
35
#include <cassert>
36
#include <cstring>
37

  
38
struct ImageWrapper
39
{
40
    Exiv2::Image::AutoPtr image;
41
};
42

  
43
// Returns NULL (0) handle if failed.
44
EXIVSIMPLE_API HIMAGE OpenFileImage(const char *file)
45
{
46
    assert(file);
47

  
48
    // See if file exists. Sorry for very bad error handling
49
    if (INVALID_FILE_ATTRIBUTES == GetFileAttributes(file)) {
50
        return 0;
51
    }
52

  
53
    ImageWrapper *imgWrap = new ImageWrapper;
54
	try {
55
		imgWrap->image = Exiv2::ImageFactory::open(file);
56
	}
57
	catch(const Exiv2::AnyError&) {
58
		delete imgWrap;
59
		return 0;
60
	}
61
	if (imgWrap->image.get() == 0) {
62
		delete imgWrap;
63
		return 0;
64
	}
65
    // Load existing metadata
66
	try {
67
		imgWrap->image->readMetadata();
68
	}
69
	catch(const Exiv2::AnyError&) { 
70
		delete imgWrap;
71
		return 0;
72
	}
73

  
74
    return (HIMAGE)imgWrap;
75
}
76

  
77
EXIVSIMPLE_API HIMAGE OpenMemImage(const BYTE *data, unsigned int size)
78
{
79
    assert(data);
80
    ImageWrapper *imgWrap = new ImageWrapper;
81

  
82
	try {
83
	    imgWrap->image = Exiv2::ImageFactory::open(data, size);
84
	}
85
	catch(const Exiv2::AnyError&) {
86
		delete imgWrap;
87
		return 0;
88
	}
89
	if (imgWrap->image.get() == 0) {
90
        delete imgWrap;
91
		return 0;
92
    }
93
    // Load existing metadata
94
	try {
95
	    imgWrap->image->readMetadata();
96
	}
97
	catch(const Exiv2::AnyError&) {
98
		delete imgWrap;
99
		return 0;
100
	}
101

  
102
    return (HIMAGE)imgWrap;
103
}
104

  
105
EXIVSIMPLE_API void FreeImage(HIMAGE img)
106
{
107
    if (img) {
108
        ImageWrapper *imgWrap = (ImageWrapper*)img;
109
        delete imgWrap;
110
    }
111
}
112

  
113
// Returns 0 on success
114
EXIVSIMPLE_API int SaveImage(HIMAGE img)
115
{
116
    assert(img);
117
    ImageWrapper *imgWrap = (ImageWrapper*)img;
118
	try {
119
		imgWrap->image->writeMetadata();
120
	}
121
	catch(const Exiv2::AnyError&) {
122
		return 1;
123
	}
124
    return 0;
125
}
126

  
127
// Note that if you have modified the metadata in any way and want the
128
// size of the image after these modifications, you must call SaveImage
129
// before calling ImageSize.
130
// Returns -1 on failure, otherwise the image size
131
EXIVSIMPLE_API int ImageSize(HIMAGE img)
132
{
133
    assert(img);
134
    ImageWrapper *imgWrap = (ImageWrapper*)img;
135
    return imgWrap->image->io().size();
136
}
137

  
138
// Note that if you have modified the metadata in any way and want the
139
// image data after these modifications, you must call SaveImage before
140
// calling ImageData.
141
// Returns number of bytes read, 0 if failure
142
EXIVSIMPLE_API int ImageData(HIMAGE img, BYTE *buffer, unsigned int size)
143
{
144
    assert(img);
145
    int result = 0;
146
    ImageWrapper *imgWrap = (ImageWrapper*)img;
147
    Exiv2::BasicIo &io = imgWrap->image->io();
148
    if(io.open() == 0) {
149
        result = imgWrap->image->io().read(buffer, size);
150
        io.close();
151
    }
152
    return result;
153
}
154

  
155
EXIVSIMPLE_API void SetThumbnail(HIMAGE img, const BYTE *buffer, unsigned int size)
156
{
157
    ImageWrapper *imgWrap = (ImageWrapper*)img;
158
    Exiv2::ExifData& exifData = imgWrap->image->exifData();
159
    Exiv2::ExifThumb exifThumb(exifData);
160
    exifThumb.setJpegThumbnail(buffer, size);
161
}
162

  
163
EXIVSIMPLE_API unsigned int GetThumbnail(HIMAGE img, BYTE *buffer, unsigned int size)
164
{
165
    ImageWrapper *imgWrap = (ImageWrapper*)img;
166
    Exiv2::ExifData& exifData = imgWrap->image->exifData();
167
    Exiv2::ExifThumb exifThumb(exifData);
168
    Exiv2::DataBuf buf = exifThumb.copy();
169
    if (buf.size_ == 0) {
170
        return 0;
171
    }
172
    if (buf.size_ > (long)size) {
173
        return unsigned int(-1);
174
    }
175
    memcpy(buffer, buf.pData_, buf.size_);
176
    return buf.size_;
177
}
178

  
179
// This is weird because iptc and exif have not been "unified". Once
180
// they are unified, this DLL should not have to know
181
// about either... just generic images, keys, values, etc.
182
//
183
// buffsize should be the total size of *buff (including space for null)
184
// Note that if there is more than one entry (for some IPTC datasets) this
185
// returns the first one found. Currently no way to get the others.
186
// Returns 0 on success
187
EXIVSIMPLE_API int ReadMeta(HIMAGE img, const char *key, char *buff, int buffsize)
188
{
189
    assert(img && key && buff);
190
    if (img==0 || key==0 || buff==0 || buffsize==0) return -1;
191
    ImageWrapper *imgWrap = (ImageWrapper*)img;
192
    int rc = 2;
193

  
194
    Exiv2::IptcData &iptcData = imgWrap->image->iptcData();
195
    Exiv2::ExifData &exifData = imgWrap->image->exifData();
196

  
197
    try {
198
        // First try iptc
199
        Exiv2::IptcKey iptcKey(key);
200
        rc = 1;
201
        Exiv2::IptcData::const_iterator iter = iptcData.findKey(iptcKey);
202
        if (iter != iptcData.end()) {
203
            strncpy(buff, iter->value().toString().c_str(), buffsize);
204
            buff[buffsize-1] = 0;
205
            rc = 0;
206
        }
207
    } 
208
    catch(const Exiv2::AnyError&) {
209
    }
210

  
211
    if (rc) {
212
        // No iptc value, so try exif
213
        try {
214
            Exiv2::ExifKey exifKey(key);
215
            rc = 1;
216
            Exiv2::ExifData::const_iterator iter = exifData.findKey(exifKey);
217
            if (iter != exifData.end()) {
218
                strncpy(buff, iter->value().toString().c_str(), buffsize);
219
                buff[buffsize-1] = 0;
220
                rc = 0;
221
            }
222
        }
223
        catch(const Exiv2::AnyError&) {
224
        }
225
    }
226

  
227
    return rc;
228
}
229

  
230
// Overwrites existing value if found, otherwise creates a new one.
231
// Passing invalidTypeId causes the type to be guessed.
232
// Guessing types is accurate for IPTC, but not for EXIF.
233
// Returns 0 on success
234
EXIVSIMPLE_API int ModifyMeta(HIMAGE img, const char *key, const char *val, DllTypeId type)
235
{
236
    assert(img && key && val);
237
    if (img==0 || key==0 || val==0) return -1;
238
    ImageWrapper *imgWrap = (ImageWrapper*)img;
239
    int rc = 2;
240

  
241
    Exiv2::IptcData &iptcData = imgWrap->image->iptcData();
242
    Exiv2::ExifData &exifData = imgWrap->image->exifData();
243

  
244
    std::string data(val);
245
    // if data starts and ends with quotes, remove them
246
    if (data.at(0) == '\"' && data.at(data.size()-1) == '\"') {
247
        data = data.substr(1, data.size()-2);
248
    }
249

  
250
    try {
251
        Exiv2::IptcKey iptcKey(key);
252
        rc = 1;
253

  
254
        if (type == invalidTypeId)
255
            type = (DllTypeId)Exiv2::IptcDataSets::dataSetType(iptcKey.tag(), iptcKey.record());
256
        Exiv2::Value::AutoPtr value = Exiv2::Value::create((Exiv2::TypeId)type);
257
        value->read(data);
258

  
259
        Exiv2::IptcData::iterator iter = iptcData.findKey(iptcKey);
260
        if (iter != iptcData.end()) {
261
            iter->setValue(value.get());
262
            rc = 0;
263
        }
264
        else {
265
            rc = iptcData.add(iptcKey, value.get());
266
        }
267
    } 
268
    catch(const Exiv2::AnyError&) {
269
    }
270

  
271
    if (rc) {
272
        // Failed with iptc, so try exif
273
        try {
274
            Exiv2::ExifKey exifKey(key);
275
            rc = 1;
276

  
277
            // No way to get value type for exif... string is the most common
278
            if (type == invalidTypeId)
279
                type = asciiString;
280
            Exiv2::Value::AutoPtr value = Exiv2::Value::create((Exiv2::TypeId)type);
281
            value->read(data);
282

  
283
            Exiv2::ExifData::iterator iter = exifData.findKey(exifKey);
284
            if (iter != exifData.end()) {
285
                iter->setValue(value.get());
286
                rc = 0;
287
            }
288
            else {
289
                exifData.add(exifKey, value.get());
290
                rc = 0;
291
            }
292
        }
293
        catch(const Exiv2::AnyError&) {
294
        }
295
    }
296

  
297
    return rc;
298
}
299

  
300
// Always creates a new metadata entry.
301
// Passing invalidTypeId causes the type to be guessed.
302
// Guessing types is accurate for IPTC, but not for EXIF.
303
// Returns 0 on success
304
EXIVSIMPLE_API int AddMeta(HIMAGE img, const char *key, const char *val, DllTypeId type)
305
{
306
    assert(img && key && val);
307
    if (img==0 || key==0 || val==0) return -1;
308
    ImageWrapper *imgWrap = (ImageWrapper*)img;
309
    int rc = 2;
310

  
311
    Exiv2::IptcData &iptcData = imgWrap->image->iptcData();
312
    Exiv2::ExifData &exifData = imgWrap->image->exifData();
313

  
314
    std::string data(val);
315
    // if data starts and ends with quotes, remove them
316
    if (data.at(0) == '\"' && data.at(data.size()-1) == '\"') {
317
        data = data.substr(1, data.size()-2);
318
    }
319

  
320
    try {
321
        Exiv2::IptcKey iptcKey(key);
322
        rc = 1;
323

  
324
        if (type == invalidTypeId)
325
            type = (DllTypeId)Exiv2::IptcDataSets::dataSetType(iptcKey.tag(), iptcKey.record());
326
        Exiv2::Value::AutoPtr value = Exiv2::Value::create((Exiv2::TypeId)type);
327
        value->read(data);
328

  
329
        rc = iptcData.add(iptcKey, value.get());
330
    } 
331
    catch(const Exiv2::AnyError&) {
332
    }
333

  
334
    if (rc) {
335
        // Failed with iptc, so try exif
336
        try {
337
            Exiv2::ExifKey exifKey(key);
338
            rc = 1;
339

  
340
            // No way to get value type for exif... string is the most common
341
            if (type == invalidTypeId)
342
                type = asciiString;
343
            Exiv2::Value::AutoPtr value = Exiv2::Value::create((Exiv2::TypeId)type);
344
            value->read(data);
345

  
346
            exifData.add(exifKey, value.get());
347
            rc = 0;
348
        }
349
        catch(const Exiv2::AnyError&) {
350
        }
351
    }
352

  
353
    return rc;
354
}
355

  
356
// If multiple entires exist, this only remove the first one
357
// found. Call multiple times to remove many.
358
// Returns 0 on success
359
EXIVSIMPLE_API int RemoveMeta(HIMAGE img, const char *key)
360
{
361
    assert(img && key);
362
    if (img==0 || key==0) return -1;
363
    ImageWrapper *imgWrap = (ImageWrapper*)img;
364
    int rc = 2;
365

  
366
    Exiv2::IptcData &iptcData = imgWrap->image->iptcData();
367
    Exiv2::ExifData &exifData = imgWrap->image->exifData();
368

  
369
    try {
370
        Exiv2::IptcKey iptcKey(key);
371
        rc = 1;
372
        Exiv2::IptcData::iterator iter = iptcData.findKey(iptcKey);
373
        if (iter != iptcData.end()) {
374
            iptcData.erase(iter);
375
            rc = 0;
376
        }
377
    } 
378
    catch(const Exiv2::AnyError&) {
379
    }
380

  
381
    if (rc) {
382
        // No iptc value, so try exif
383
        try {
384
            Exiv2::ExifKey exifKey(key);
385
            rc = 1;
386
            Exiv2::ExifData::iterator iter = exifData.findKey(exifKey);
387
            if (iter != exifData.end()) {
388
                exifData.erase(iter);
389
                rc = 0;
390
            }
391
        }
392
        catch(const Exiv2::AnyError&) {
393
        }
394
    }
395

  
396
    return rc;
397
}
398

  
399
EXIVSIMPLE_API int EnumMeta(HIMAGE img, METAENUMPROC proc, void *user)
400
{
401
    assert(img && proc);
402
    if (img==0 || proc==0) return -1;
403
    ImageWrapper *imgWrap = (ImageWrapper*)img;
404
    bool more = true;
405

  
406
    Exiv2::IptcData &iptcData = imgWrap->image->iptcData();
407
    Exiv2::ExifData &exifData = imgWrap->image->exifData();
408

  
409
    Exiv2::IptcData::const_iterator iend = iptcData.end();
410
    for (Exiv2::IptcData::const_iterator i = iptcData.begin(); 
411
            i != iend && more; ++i) {
412
        more = proc(i->key().c_str(), i->value().toString().c_str(), user);
413
    }
414

  
415
    Exiv2::ExifData::const_iterator eend = exifData.end();
416
    for (Exiv2::ExifData::const_iterator e = exifData.begin();
417
            e != eend && more; ++e) {
418
        more = proc(e->key().c_str(), e->value().toString().c_str(), user);
419
    }
420

  
421
    return 0;
422
}
423

  
424

  
425
BOOL APIENTRY DllMain( HANDLE hModule, 
426
                       DWORD  ul_reason_for_call, 
427
                       LPVOID lpReserved
428
                     )
429
{
430
    switch (ul_reason_for_call) {
431
        case DLL_PROCESS_ATTACH:
432
        case DLL_THREAD_ATTACH:
433
        case DLL_THREAD_DETACH:
434
        case DLL_PROCESS_DETACH:
435
            break;
436
    }
437
    return TRUE;
438
}
439

  
1
// ***************************************************************** -*- C++ -*-
2
/*
3
 * Copyright (C) 2004-2008 Andreas Huggel <ahuggel@gmx.net>
4
 * 
5
 * This program is part of the Exiv2 distribution.
6
 *
7
 * This program is free software; you can redistribute it and/or
8
 * modify it under the terms of the GNU General Public License
9
 * as published by the Free Software Foundation; either version 2
10
 * of the License, or (at your option) any later version.
11
 * 
12
 * This program is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU General Public License for more details.
16
 * 
17
 * You should have received a copy of the GNU General Public License
18
 * along with this program; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA.
20
 */
21
/*
22
  File:      exivsimple.cpp
23
  Version:   $Rev$
24
  Author(s): Brad Schick <brad@robotbattle.com>
25
             Christian Kuster <christian@kusti.ch>
26
  History:   12-Nov-04, brad: created
27
 */
28
// *****************************************************************************
29

  
30
#include "stdafx.h"
31
#include "exivsimple.h"
32
#include <exiv2/image.hpp>
33
#include <exiv2/exif.hpp>
34
#include <exiv2/iptc.hpp>
35
#include <cassert>
36
#include <cstring>
37

  
38
struct ImageWrapper
39
{
40
    Exiv2::Image::AutoPtr image;
41
};
42

  
43
// Returns NULL (0) handle if failed.
44
EXIVSIMPLE_API HIMAGE OpenFileImage(const char *file)
45
{
46
    assert(file);
47

  
48
    // See if file exists. Sorry for very bad error handling
49
    if (INVALID_FILE_ATTRIBUTES == GetFileAttributes(file)) {
50
        return 0;
51
    }
52

  
53
    ImageWrapper *imgWrap = new ImageWrapper;
54
	try {
55
		imgWrap->image = Exiv2::ImageFactory::open(file);
56
	}
57
	catch(const Exiv2::AnyError&) {
58
		delete imgWrap;
59
		return 0;
60
	}
61
	if (imgWrap->image.get() == 0) {
62
		delete imgWrap;
63
		return 0;
64
	}
65
    // Load existing metadata
66
	try {
67
		imgWrap->image->readMetadata();
68
	}
69
	catch(const Exiv2::AnyError&) { 
70
		delete imgWrap;
71
		return 0;
72
	}
73

  
74
    return (HIMAGE)imgWrap;
75
}
76

  
77
EXIVSIMPLE_API HIMAGE OpenMemImage(const BYTE *data, unsigned int size)
78
{
79
    assert(data);
80
    ImageWrapper *imgWrap = new ImageWrapper;
81

  
82
	try {
83
	    imgWrap->image = Exiv2::ImageFactory::open(data, size);
84
	}
85
	catch(const Exiv2::AnyError&) {
86
		delete imgWrap;
87
		return 0;
88
	}
89
	if (imgWrap->image.get() == 0) {
90
        delete imgWrap;
91
		return 0;
92
    }
93
    // Load existing metadata
94
	try {
95
	    imgWrap->image->readMetadata();
96
	}
97
	catch(const Exiv2::AnyError&) {
98
		delete imgWrap;
99
		return 0;
100
	}
101

  
102
    return (HIMAGE)imgWrap;
103
}
104

  
105
EXIVSIMPLE_API void FreeImage(HIMAGE img)
106
{
107
    if (img) {
108
        ImageWrapper *imgWrap = (ImageWrapper*)img;
109
        delete imgWrap;
110
    }
111
}
112

  
113
// Returns 0 on success
114
EXIVSIMPLE_API int SaveImage(HIMAGE img)
115
{
116
    assert(img);
117
    ImageWrapper *imgWrap = (ImageWrapper*)img;
118
	try {
119
		imgWrap->image->writeMetadata();
120
	}
121
	catch(const Exiv2::AnyError&) {
122
		return 1;
123
	}
124
    return 0;
125
}
126

  
127
// Note that if you have modified the metadata in any way and want the
128
// size of the image after these modifications, you must call SaveImage
129
// before calling ImageSize.
130
// Returns -1 on failure, otherwise the image size
131
EXIVSIMPLE_API int ImageSize(HIMAGE img)
132
{
133
    assert(img);
134
    ImageWrapper *imgWrap = (ImageWrapper*)img;
135
    return imgWrap->image->io().size();
136
}
137

  
138
// Note that if you have modified the metadata in any way and want the
139
// image data after these modifications, you must call SaveImage before
140
// calling ImageData.
141
// Returns number of bytes read, 0 if failure
142
EXIVSIMPLE_API int ImageData(HIMAGE img, BYTE *buffer, unsigned int size)
143
{
144
    assert(img);
145
    int result = 0;
146
    ImageWrapper *imgWrap = (ImageWrapper*)img;
147
    Exiv2::BasicIo &io = imgWrap->image->io();
148
    if(io.open() == 0) {
149
        result = imgWrap->image->io().read(buffer, size);
150
        io.close();
151
    }
152
    return result;
153
}
154

  
155
EXIVSIMPLE_API void SetThumbnail(HIMAGE img, const BYTE *buffer, unsigned int size)
156
{
157
    ImageWrapper *imgWrap = (ImageWrapper*)img;
158
    Exiv2::ExifData& exifData = imgWrap->image->exifData();
159
    Exiv2::ExifThumb exifThumb(exifData);
160
    exifThumb.setJpegThumbnail(buffer, size);
161
}
162

  
163
EXIVSIMPLE_API unsigned int GetThumbnail(HIMAGE img, BYTE *buffer, unsigned int size)
164
{
165
    ImageWrapper *imgWrap = (ImageWrapper*)img;
166
    Exiv2::ExifData& exifData = imgWrap->image->exifData();
167
    Exiv2::ExifThumb exifThumb(exifData);
168
    Exiv2::DataBuf buf = exifThumb.copy();
169
    if (buf.size_ == 0) {
170
        return 0;
171
    }
172
    if (buf.size_ > (long)size) {
173
        return unsigned int(-1);
174
    }
175
    memcpy(buffer, buf.pData_, buf.size_);
176
    return buf.size_;
177
}
178

  
179
// This is weird because iptc and exif have not been "unified". Once
180
// they are unified, this DLL should not have to know
181
// about either... just generic images, keys, values, etc.
182
//
183
// buffsize should be the total size of *buff (including space for null)
184
// Note that if there is more than one entry (for some IPTC datasets) this
185
// returns the first one found. Currently no way to get the others.
186
// Returns 0 on success
187
EXIVSIMPLE_API int ReadMeta(HIMAGE img, const char *key, char *buff, int buffsize)
188
{
189
    assert(img && key && buff);
190
    if (img==0 || key==0 || buff==0 || buffsize==0) return -1;
191
    ImageWrapper *imgWrap = (ImageWrapper*)img;
192
    int rc = 2;
193

  
194
    Exiv2::IptcData &iptcData = imgWrap->image->iptcData();
195
    Exiv2::ExifData &exifData = imgWrap->image->exifData();
196

  
197
    try {
198
        // First try iptc
199
        Exiv2::IptcKey iptcKey(key);
200
        rc = 1;
201
        Exiv2::IptcData::const_iterator iter = iptcData.findKey(iptcKey);
202
        if (iter != iptcData.end()) {
203
            strncpy(buff, iter->value().toString().c_str(), buffsize);
204
            buff[buffsize-1] = 0;
205
            rc = 0;
206
        }
207
    } 
208
    catch(const Exiv2::AnyError&) {
209
    }
210

  
211
    if (rc) {
212
        // No iptc value, so try exif
213
        try {
214
            Exiv2::ExifKey exifKey(key);
215
            rc = 1;
216
            Exiv2::ExifData::const_iterator iter = exifData.findKey(exifKey);
217
            if (iter != exifData.end()) {
218
                strncpy(buff, iter->value().toString().c_str(), buffsize);
219
                buff[buffsize-1] = 0;
220
                rc = 0;
221
            }
222
        }
223
        catch(const Exiv2::AnyError&) {
224
        }
225
    }
226

  
227
    return rc;
228
}
229

  
230
// Overwrites existing value if found, otherwise creates a new one.
231
// Passing invalidTypeId causes the type to be guessed.
232
// Guessing types is accurate for IPTC, but not for EXIF.
233
// Returns 0 on success
234
EXIVSIMPLE_API int ModifyMeta(HIMAGE img, const char *key, const char *val, DllTypeId type)
235
{
236
    assert(img && key && val);
237
    if (img==0 || key==0 || val==0) return -1;
238
    ImageWrapper *imgWrap = (ImageWrapper*)img;
239
    int rc = 2;
240

  
241
    Exiv2::IptcData &iptcData = imgWrap->image->iptcData();
242
    Exiv2::ExifData &exifData = imgWrap->image->exifData();
243

  
244
    std::string data(val);
245
    // if data starts and ends with quotes, remove them
246
    if (data.at(0) == '\"' && data.at(data.size()-1) == '\"') {
247
        data = data.substr(1, data.size()-2);
248
    }
249

  
250
    try {
251
        Exiv2::IptcKey iptcKey(key);
252
        rc = 1;
253

  
254
        if (type == invalidTypeId)
255
            type = (DllTypeId)Exiv2::IptcDataSets::dataSetType(iptcKey.tag(), iptcKey.record());
256
        Exiv2::Value::AutoPtr value = Exiv2::Value::create((Exiv2::TypeId)type);
257
        value->read(data);
258

  
259
        Exiv2::IptcData::iterator iter = iptcData.findKey(iptcKey);
260
        if (iter != iptcData.end()) {
261
            iter->setValue(value.get());
262
            rc = 0;
263
        }
264
        else {
265
            rc = iptcData.add(iptcKey, value.get());
266
        }
267
    } 
268
    catch(const Exiv2::AnyError&) {
269
    }
270

  
271
    if (rc) {
272
        // Failed with iptc, so try exif
273
        try {
274
            Exiv2::ExifKey exifKey(key);
275
            rc = 1;
276

  
277
            // No way to get value type for exif... string is the most common
278
            if (type == invalidTypeId)
279
                type = asciiString;
280
            Exiv2::Value::AutoPtr value = Exiv2::Value::create((Exiv2::TypeId)type);
281
            value->read(data);
282

  
283
            Exiv2::ExifData::iterator iter = exifData.findKey(exifKey);
284
            if (iter != exifData.end()) {
285
                iter->setValue(value.get());
286
                rc = 0;
287
            }
288
            else {
289
                exifData.add(exifKey, value.get());
290
                rc = 0;
291
            }
292
        }
293
        catch(const Exiv2::AnyError&) {
294
        }
295
    }
296

  
297
    return rc;
298
}
299

  
300
// Always creates a new metadata entry.
301
// Passing invalidTypeId causes the type to be guessed.
302
// Guessing types is accurate for IPTC, but not for EXIF.
303
// Returns 0 on success
304
EXIVSIMPLE_API int AddMeta(HIMAGE img, const char *key, const char *val, DllTypeId type)
305
{
306
    assert(img && key && val);
307
    if (img==0 || key==0 || val==0) return -1;
308
    ImageWrapper *imgWrap = (ImageWrapper*)img;
309
    int rc = 2;
310

  
311
    Exiv2::IptcData &iptcData = imgWrap->image->iptcData();
312
    Exiv2::ExifData &exifData = imgWrap->image->exifData();
313

  
314
    std::string data(val);
315
    // if data starts and ends with quotes, remove them
316
    if (data.at(0) == '\"' && data.at(data.size()-1) == '\"') {
317
        data = data.substr(1, data.size()-2);
318
    }
319

  
320
    try {
321
        Exiv2::IptcKey iptcKey(key);
322
        rc = 1;
323

  
324
        if (type == invalidTypeId)
325
            type = (DllTypeId)Exiv2::IptcDataSets::dataSetType(iptcKey.tag(), iptcKey.record());
326
        Exiv2::Value::AutoPtr value = Exiv2::Value::create((Exiv2::TypeId)type);
327
        value->read(data);
328

  
329
        rc = iptcData.add(iptcKey, value.get());
330
    } 
331
    catch(const Exiv2::AnyError&) {
332
    }
333

  
334
    if (rc) {
335
        // Failed with iptc, so try exif
336
        try {
337
            Exiv2::ExifKey exifKey(key);
338
            rc = 1;
339

  
340
            // No way to get value type for exif... string is the most common
341
            if (type == invalidTypeId)
342
                type = asciiString;
343
            Exiv2::Value::AutoPtr value = Exiv2::Value::create((Exiv2::TypeId)type);
344
            value->read(data);
345

  
346
            exifData.add(exifKey, value.get());
347
            rc = 0;
348
        }
349
        catch(const Exiv2::AnyError&) {
350
        }
351
    }
352

  
353
    return rc;
354
}
355

  
356
// If multiple entires exist, this only remove the first one
357
// found. Call multiple times to remove many.
358
// Returns 0 on success
359
EXIVSIMPLE_API int RemoveMeta(HIMAGE img, const char *key)
360
{
361
    assert(img && key);
362
    if (img==0 || key==0) return -1;
363
    ImageWrapper *imgWrap = (ImageWrapper*)img;
364
    int rc = 2;
365

  
366
    Exiv2::IptcData &iptcData = imgWrap->image->iptcData();
367
    Exiv2::ExifData &exifData = imgWrap->image->exifData();
368

  
369
    try {
370
        Exiv2::IptcKey iptcKey(key);
371
        rc = 1;
372
        Exiv2::IptcData::iterator iter = iptcData.findKey(iptcKey);
373
        if (iter != iptcData.end()) {
374
            iptcData.erase(iter);
375
            rc = 0;
376
        }
377
    } 
378
    catch(const Exiv2::AnyError&) {
379
    }
380

  
381
    if (rc) {
382
        // No iptc value, so try exif
383
        try {
384
            Exiv2::ExifKey exifKey(key);
385
            rc = 1;
386
            Exiv2::ExifData::iterator iter = exifData.findKey(exifKey);
387
            if (iter != exifData.end()) {
388
                exifData.erase(iter);
389
                rc = 0;
390
            }
391
        }
392
        catch(const Exiv2::AnyError&) {
393
        }
394
    }
395

  
396
    return rc;
397
}
398

  
399
EXIVSIMPLE_API int EnumMeta(HIMAGE img, METAENUMPROC proc, void *user)
400
{
401
    assert(img && proc);
402
    if (img==0 || proc==0) return -1;
403
    ImageWrapper *imgWrap = (ImageWrapper*)img;
404
    bool more = true;
405

  
406
    Exiv2::IptcData &iptcData = imgWrap->image->iptcData();
407
    Exiv2::ExifData &exifData = imgWrap->image->exifData();
408

  
409
    Exiv2::IptcData::const_iterator iend = iptcData.end();
410
    for (Exiv2::IptcData::const_iterator i = iptcData.begin(); 
411
            i != iend && more; ++i) {
412
        more = proc(i->key().c_str(), i->value().toString().c_str(), user);
413
    }
414

  
415
    Exiv2::ExifData::const_iterator eend = exifData.end();
416
    for (Exiv2::ExifData::const_iterator e = exifData.begin();
417
            e != eend && more; ++e) {
418
        more = proc(e->key().c_str(), e->value().toString().c_str(), user);
419
    }
420

  
421
    return 0;
422
}
423

  
424

  
425
BOOL APIENTRY DllMain( HANDLE hModule, 
426
                       DWORD  ul_reason_for_call, 
427
                       LPVOID lpReserved
428
                     )
429
{
430
    switch (ul_reason_for_call) {
431
        case DLL_PROCESS_ATTACH:
432
        case DLL_THREAD_ATTACH:
433
        case DLL_THREAD_DETACH:
434
        case DLL_PROCESS_DETACH:
435
            break;
436
    }
437
    return TRUE;
438
}
439

  
msvc/exivsimple/stdafx.cpp (working copy)
1
// ***************************************************************** -*- C++ -*-
2
/*
3
 * Copyright (C) 2004-2007 Andreas Huggel <ahuggel@gmx.net>
4
 * 
5
 * This program is part of the Exiv2 distribution.
6
 *
7
 * This program is free software; you can redistribute it and/or
8
 * modify it under the terms of the GNU General Public License
9
 * as published by the Free Software Foundation; either version 2
10
 * of the License, or (at your option) any later version.
11
 * 
12
 * This program is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU General Public License for more details.
16
 * 
17
 * You should have received a copy of the GNU General Public License
18
 * along with this program; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA.
20
 */
21
/*
22
  File:      stdafx.cpp
23
  Version:   $Rev$
24
  Author(s): Brad Schick <brad@robotbattle.com>
25
  History:   12-Nov-04, brad: created
26
 */
27
// *****************************************************************************
28

  
29
#include "stdafx.h"
1
// ***************************************************************** -*- C++ -*-
2
/*
3
 * Copyright (C) 2004-2007 Andreas Huggel <ahuggel@gmx.net>
4
 * 
5
 * This program is part of the Exiv2 distribution.
6
 *
7
 * This program is free software; you can redistribute it and/or
8
 * modify it under the terms of the GNU General Public License
9
 * as published by the Free Software Foundation; either version 2
10
 * of the License, or (at your option) any later version.
11
 * 
12
 * This program is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU General Public License for more details.
16
 * 
17
 * You should have received a copy of the GNU General Public License
18
 * along with this program; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA.
20
 */
21
/*
22
  File:      stdafx.cpp
23
  Version:   $Rev$
24
  Author(s): Brad Schick <brad@robotbattle.com>
25
  History:   12-Nov-04, brad: created
26
 */
27
// *****************************************************************************
28

  
29
#include "stdafx.h"
msvc/exivsimple/exivsimple.h (working copy)
1
// ***************************************************************** -*- C++ -*-
2
/*
3
 * Copyright (C) 2004-2007 Andreas Huggel <ahuggel@gmx.net>
4
 * 
5
 * This program is part of the Exiv2 distribution.
6
 *
7
 * This program is free software; you can redistribute it and/or
8
 * modify it under the terms of the GNU General Public License
9
 * as published by the Free Software Foundation; either version 2
10
 * of the License, or (at your option) any later version.
11
 * 
12
 * This program is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU General Public License for more details.
16
 * 
17
 * You should have received a copy of the GNU General Public License
18
 * along with this program; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA.
20
 */
21
/*!
22
  @file    exivsimple.h
23
  @brief   Limited metadata dll for win32
24
  @version $Rev$
25
  @author  Brad Schick (brad)
26
           <a href="mailto:brad@robotbattle.com">brad@robotbattle.com</a>
27
           Christian Kuster (kusti)
28
           <a href="mailto:christian@kusti.ch">christian@kusti.ch</a>
29
  @date    12-Nov-04, brad: created
30
 */
31
#ifndef EXIVSIMPLE_H_
32
#define EXIVSIMPLE_H_
33

  
34
// *****************************************************************************
35

  
36

  
37
#ifdef EXIVSIMPLE_EXPORTS
38
#define EXIVSIMPLE_API __declspec(dllexport)
39
#else
40
#define EXIVSIMPLE_API __declspec(dllimport)
41
#endif
42

  
43
DECLARE_HANDLE (HIMAGE);
44

  
45
#ifdef __cplusplus
46
extern "C"
47
{
48
#endif
49

  
50
// These types should match those in types.hpp. Copied here so that
51
// exiv2 headers are not needed.
52
// For all of the functions
53
// that take a type, passing invalidTypeId causes the type to be guessed.
54
// Guessing types is accurate for IPTC but not for EXIF.
55
enum DllTypeId { invalidTypeId, unsignedByte, asciiString, unsignedShort, 
56
                unsignedLong, unsignedRational, invalid6, undefined, 
57
                signedShort, signedLong, signedRational, 
58
                string, isoDate, isoTime,
59
                lastTypeId };
60

  
61
typedef bool (CALLBACK* METAENUMPROC)(const char *key, const char *value, void *user);
62

  
63
EXIVSIMPLE_API HIMAGE OpenFileImage(const char *file);
64
EXIVSIMPLE_API HIMAGE OpenMemImage(const BYTE *data, unsigned int size);
65
EXIVSIMPLE_API void FreeImage(HIMAGE img);
66
EXIVSIMPLE_API int SaveImage(HIMAGE img);
67
EXIVSIMPLE_API int ImageSize(HIMAGE img);
68
EXIVSIMPLE_API int ImageData(HIMAGE img, BYTE *buffer, unsigned int size);
69
EXIVSIMPLE_API int ReadMeta(HIMAGE img, const char *key, char *buff, int buffsize);
70
EXIVSIMPLE_API int EnumMeta(HIMAGE img, METAENUMPROC proc, void *user);
71
EXIVSIMPLE_API int AddMeta(HIMAGE img, const char *key, const char *val, DllTypeId type);
72
EXIVSIMPLE_API int ModifyMeta(HIMAGE img, const char *key, const char *val, DllTypeId type);
73
EXIVSIMPLE_API int RemoveMeta(HIMAGE img, const char *key);
74
/*!
75
  @brief Set the Thumbnail
76

  
77
  @param img    Handle to the image
78
  @param buffer Pointer to the Thumbnail data (JPEG)
79
  @param size   Size of the thumbnail in bytes
80
*/
81
EXIVSIMPLE_API void SetThumbnail(HIMAGE img, const BYTE *buffer, unsigned int size);
82
/*!
83
  @brief Get the Thumbnail
84

  
85
  @param img    Handle to the image
86
  @param buffer Pointer where the thumbnaildata is written to (large enough!)
87
  @param size   Size of buffer
88

  
89
  @return size of the thumbnail, 0 if failed to read the thumbnail, 
90
          (unsigned int)-1 if buffer is too small.
91
*/
92
EXIVSIMPLE_API unsigned int GetThumbnail(HIMAGE img, BYTE *buffer, unsigned int size);
93

  
94
#ifdef __cplusplus
95
}
96
#endif
97

  
98
#endif                                  // #ifndef EXIVSIMPLE_H_
1
// ***************************************************************** -*- C++ -*-
2
/*
3
 * Copyright (C) 2004-2007 Andreas Huggel <ahuggel@gmx.net>
4
 * 
5
 * This program is part of the Exiv2 distribution.
6
 *
7
 * This program is free software; you can redistribute it and/or
8
 * modify it under the terms of the GNU General Public License
9
 * as published by the Free Software Foundation; either version 2
10
 * of the License, or (at your option) any later version.
11
 * 
12
 * This program is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU General Public License for more details.
16
 * 
17
 * You should have received a copy of the GNU General Public License
18
 * along with this program; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA.
20
 */
21
/*!
22
  @file    exivsimple.h
23
  @brief   Limited metadata dll for win32
24
  @version $Rev$
25
  @author  Brad Schick (brad)
26
           <a href="mailto:brad@robotbattle.com">brad@robotbattle.com</a>
27
           Christian Kuster (kusti)
28
           <a href="mailto:christian@kusti.ch">christian@kusti.ch</a>
29
  @date    12-Nov-04, brad: created
30
 */
31
#ifndef EXIVSIMPLE_H_
32
#define EXIVSIMPLE_H_
33

  
34
// *****************************************************************************
35

  
36

  
37
#ifdef EXIVSIMPLE_EXPORTS
38
#define EXIVSIMPLE_API __declspec(dllexport)
39
#else
40
#define EXIVSIMPLE_API __declspec(dllimport)
41
#endif
42

  
43
DECLARE_HANDLE (HIMAGE);
44

  
45
#ifdef __cplusplus
46
extern "C"
47
{
48
#endif
49

  
50
// These types should match those in types.hpp. Copied here so that
51
// exiv2 headers are not needed.
52
// For all of the functions
53
// that take a type, passing invalidTypeId causes the type to be guessed.
54
// Guessing types is accurate for IPTC but not for EXIF.
55
enum DllTypeId { invalidTypeId, unsignedByte, asciiString, unsignedShort, 
56
                unsignedLong, unsignedRational, invalid6, undefined, 
57
                signedShort, signedLong, signedRational, 
58
                string, isoDate, isoTime,
59
                lastTypeId };
60

  
61
typedef bool (CALLBACK* METAENUMPROC)(const char *key, const char *value, void *user);
62

  
63
EXIVSIMPLE_API HIMAGE OpenFileImage(const char *file);
64
EXIVSIMPLE_API HIMAGE OpenMemImage(const BYTE *data, unsigned int size);
65
EXIVSIMPLE_API void FreeImage(HIMAGE img);
66
EXIVSIMPLE_API int SaveImage(HIMAGE img);
67
EXIVSIMPLE_API int ImageSize(HIMAGE img);
68
EXIVSIMPLE_API int ImageData(HIMAGE img, BYTE *buffer, unsigned int size);
69
EXIVSIMPLE_API int ReadMeta(HIMAGE img, const char *key, char *buff, int buffsize);
70
EXIVSIMPLE_API int EnumMeta(HIMAGE img, METAENUMPROC proc, void *user);
71
EXIVSIMPLE_API int AddMeta(HIMAGE img, const char *key, const char *val, DllTypeId type);
72
EXIVSIMPLE_API int ModifyMeta(HIMAGE img, const char *key, const char *val, DllTypeId type);
73
EXIVSIMPLE_API int RemoveMeta(HIMAGE img, const char *key);
74
/*!
75
  @brief Set the Thumbnail
76

  
77
  @param img    Handle to the image
78
  @param buffer Pointer to the Thumbnail data (JPEG)
79
  @param size   Size of the thumbnail in bytes
80
*/
81
EXIVSIMPLE_API void SetThumbnail(HIMAGE img, const BYTE *buffer, unsigned int size);
82
/*!
83
  @brief Get the Thumbnail
84

  
85
  @param img    Handle to the image
86
  @param buffer Pointer where the thumbnaildata is written to (large enough!)
87
  @param size   Size of buffer
88

  
89
  @return size of the thumbnail, 0 if failed to read the thumbnail, 
90
          (unsigned int)-1 if buffer is too small.
91
*/
92
EXIVSIMPLE_API unsigned int GetThumbnail(HIMAGE img, BYTE *buffer, unsigned int size);
93

  
94
#ifdef __cplusplus
95
}
96
#endif
97

  
98
#endif                                  // #ifndef EXIVSIMPLE_H_
... This diff was truncated because it exceeds the maximum size that can be displayed.
    (1-1/1)