Skip to content

Commit 24eec5f

Browse files
Merge pull request #3 from kolesa-team/short-values
writing short integers to image metadata
2 parents 00c1a75 + e308f9c commit 24eec5f

File tree

6 files changed

+179
-2
lines changed

6 files changed

+179
-2
lines changed

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,12 @@ if err != nil {
5151
return err
5252
}
5353

54+
// Write an EXIF short integer
55+
err = goexivImg.SetMetadataShort("exif", "Exif.Photo.ExposureProgram", "2")
56+
if err != nil {
57+
return err
58+
}
59+
5460
// Read metadata
5561
err = goexivImg.ReadMetadata()
5662
if err != nil {

exiv.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,3 +175,34 @@ func (i *Image) SetMetadataString(format, key, value string) error {
175175

176176
return nil
177177
}
178+
179+
// Sets an exif or iptc key with a given short value
180+
func (i *Image) SetMetadataShort(format, key, value string) error {
181+
if format != "iptc" && format != "exif" {
182+
return errors.New("invalid metadata type: " + format)
183+
}
184+
185+
cKey := C.CString(key)
186+
cValue := C.CString(value)
187+
188+
defer func() {
189+
C.free(unsafe.Pointer(cKey))
190+
C.free(unsafe.Pointer(cValue))
191+
}()
192+
193+
var cerr *C.Exiv2Error
194+
195+
if format == "iptc" {
196+
C.exiv2_image_set_iptc_short(i.img, cKey, cValue, &cerr)
197+
} else {
198+
C.exiv2_image_set_exif_short(i.img, cKey, cValue, &cerr)
199+
}
200+
201+
if cerr != nil {
202+
err := makeError(cerr)
203+
C.exiv2_error_free(cerr)
204+
return err
205+
}
206+
207+
return nil
208+
}

exiv_test.go

Lines changed: 96 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ type MetadataTestCase struct {
189189
ExpectedErrorSubstring string
190190
}
191191

192-
var metadataTestCases = []MetadataTestCase{
192+
var metadataSetStringTestCases = []MetadataTestCase{
193193
// valid exif key, jpeg
194194
{
195195
Format: "exif",
@@ -244,7 +244,7 @@ var metadataTestCases = []MetadataTestCase{
244244
func Test_SetMetadataStringFromFile(t *testing.T) {
245245
var data goexiv.MetadataProvider
246246

247-
for i, testcase := range metadataTestCases {
247+
for i, testcase := range metadataSetStringTestCases {
248248
img, err := goexiv.Open(testcase.ImageFilename)
249249
require.NoErrorf(t, err, "case #%d Error while opening image file", i)
250250

@@ -283,6 +283,100 @@ func Test_SetMetadataStringFromFile(t *testing.T) {
283283
}
284284
}
285285

286+
var metadataSetShortIntTestCases = []MetadataTestCase{
287+
// valid exif key, jpeg
288+
{
289+
Format: "exif",
290+
Key: "Exif.Photo.ExposureProgram",
291+
Value: "1",
292+
ImageFilename: "testdata/pixel.jpg",
293+
ExpectedErrorSubstring: "", // no error
294+
},
295+
// valid exif key, webp
296+
{
297+
Format: "exif",
298+
Key: "Exif.Photo.ExposureProgram",
299+
Value: "2",
300+
ImageFilename: "testdata/pixel.webp",
301+
ExpectedErrorSubstring: "",
302+
},
303+
// valid iptc key, jpeg.
304+
// webp iptc is not supported (see libexiv2/src/webpimage.cpp WebPImage::setIptcData))
305+
{
306+
Format: "iptc",
307+
Key: "Iptc.Envelope.ModelVersion",
308+
Value: "3",
309+
ImageFilename: "testdata/pixel.jpg",
310+
ExpectedErrorSubstring: "",
311+
},
312+
// invalid exif key, jpeg
313+
{
314+
Format: "exif",
315+
Key: "Exif.Invalid.Key",
316+
Value: "4",
317+
ImageFilename: "testdata/pixel.jpg",
318+
ExpectedErrorSubstring: "Invalid key",
319+
},
320+
// invalid exif key, webp
321+
{
322+
Format: "exif",
323+
Key: "Exif.Invalid.Key",
324+
Value: "5",
325+
ImageFilename: "testdata/pixel.webp",
326+
ExpectedErrorSubstring: "Invalid key",
327+
},
328+
// invalid iptc key, jpeg
329+
{
330+
Format: "iptc",
331+
Key: "Iptc.Invalid.Key",
332+
Value: "6",
333+
ImageFilename: "testdata/pixel.jpg",
334+
ExpectedErrorSubstring: "Invalid record name",
335+
},
336+
}
337+
338+
func Test_SetMetadataShortInt(t *testing.T) {
339+
var data goexiv.MetadataProvider
340+
341+
for i, testcase := range metadataSetShortIntTestCases {
342+
img, err := goexiv.Open(testcase.ImageFilename)
343+
require.NoErrorf(t, err, "case #%d Error while opening image file", i)
344+
345+
err = img.SetMetadataShort(testcase.Format, testcase.Key, testcase.Value)
346+
if testcase.ExpectedErrorSubstring != "" {
347+
require.Errorf(t, err, "case #%d Error was expected", i)
348+
require.Containsf(
349+
t,
350+
err.Error(),
351+
testcase.ExpectedErrorSubstring,
352+
"case #%d Error text must contain a given substring",
353+
i,
354+
)
355+
continue
356+
}
357+
358+
require.NoErrorf(t, err, "case #%d Cannot write image metadata", i)
359+
360+
err = img.ReadMetadata()
361+
require.NoErrorf(t, err, "case #%d Cannot read image metadata", i)
362+
363+
if testcase.Format == "iptc" {
364+
data = img.GetIptcData()
365+
} else {
366+
data = img.GetExifData()
367+
}
368+
369+
receivedValue, err := data.GetString(testcase.Key)
370+
require.Equalf(
371+
t,
372+
testcase.Value,
373+
receivedValue,
374+
"case #%d Value written must be equal to the value read",
375+
i,
376+
)
377+
}
378+
}
379+
286380
func Test_GetBytes(t *testing.T) {
287381
bytes, err := ioutil.ReadFile("testdata/stripped_pixel.jpg")
288382
require.NoError(t, err)

helper.cpp

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,26 @@ exiv2_image_set_exif_string(Exiv2Image *img, char *key, char *value, Exiv2Error
132132
}
133133
}
134134

135+
void
136+
exiv2_image_set_exif_short(Exiv2Image *img, char *key, char *value, Exiv2Error **error)
137+
{
138+
Exiv2::ExifData exifData = img->image->exifData();
139+
140+
try {
141+
Exiv2::Exifdatum& tag = exifData[key];
142+
Exiv2::Value::AutoPtr valueObject = Exiv2::Value::create(Exiv2::unsignedShort);
143+
valueObject->read(value);
144+
tag.setValue(valueObject.get());
145+
146+
img->image->setExifData(exifData);
147+
img->image->writeMetadata();
148+
} catch (Exiv2::Error &e) {
149+
if (error) {
150+
*error = new Exiv2Error(e);
151+
}
152+
}
153+
}
154+
135155
void
136156
exiv2_image_set_iptc_string(Exiv2Image *img, char *key, char *value, Exiv2Error **error)
137157
{
@@ -151,6 +171,26 @@ exiv2_image_set_iptc_string(Exiv2Image *img, char *key, char *value, Exiv2Error
151171
}
152172
}
153173

174+
void
175+
exiv2_image_set_iptc_short(Exiv2Image *img, char *key, char *value, Exiv2Error **error)
176+
{
177+
Exiv2::IptcData iptcData = img->image->iptcData();
178+
179+
try {
180+
Exiv2::Iptcdatum& tag = iptcData[key];
181+
Exiv2::Value::AutoPtr valueObject = Exiv2::Value::create(Exiv2::unsignedShort);
182+
valueObject->read(value);
183+
tag.setValue(valueObject.get());
184+
185+
img->image->setIptcData(iptcData);
186+
img->image->writeMetadata();
187+
} catch (Exiv2::Error &e) {
188+
if (error) {
189+
*error = new Exiv2Error(e);
190+
}
191+
}
192+
}
193+
154194
long
155195
exiv_image_get_size(Exiv2Image *img)
156196
{

helper.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@ unsigned char* exiv_image_get_bytes_ptr(Exiv2Image *img);
2727

2828
void exiv2_image_read_metadata(Exiv2Image *img, Exiv2Error **error);
2929
void exiv2_image_set_exif_string(Exiv2Image *img, char *key, char *value, Exiv2Error **error);
30+
void exiv2_image_set_exif_short(Exiv2Image *img, char *key, char *value, Exiv2Error **error);
3031
void exiv2_image_set_iptc_string(Exiv2Image *img, char *key, char *value, Exiv2Error **error);
32+
void exiv2_image_set_iptc_short(Exiv2Image *img, char *key, char *value, Exiv2Error **error);
3133
void exiv2_image_free(Exiv2Image *img);
3234

3335
int exiv2_image_get_pixel_width(Exiv2Image *img);

iptc.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,10 @@ func (i *Image) SetIptcString(key, value string) error {
6464
return i.SetMetadataString("iptc", key, value)
6565
}
6666

67+
func (i *Image) SetIptcShort(key, value string) error {
68+
return i.SetMetadataShort("iptc", key, value)
69+
}
70+
6771
func (d *IptcData) GetString(key string) (string, error) {
6872
datum, err := d.FindKey(key)
6973
if err != nil {

0 commit comments

Comments
 (0)