Skip to content

Commit

Permalink
Merge pull request #4 from rtio/rtio/add-strip-metadata
Browse files Browse the repository at this point in the history
Add strip metadata
  • Loading branch information
rtio authored Feb 28, 2023
2 parents 84c7443 + 3725cfd commit 940fe8a
Show file tree
Hide file tree
Showing 7 changed files with 291 additions and 0 deletions.
16 changes: 16 additions & 0 deletions exif.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,3 +145,19 @@ func makeExifDatumIterator(data *ExifData, cIter *C.Exiv2ExifDatumIterator) *Exi
func (i *Image) ExifStripKey(key string) error {
return i.StripKey(EXIF, key)
}

func (i *Image) ExifStripMetadata(unless []string) error {
exifData := i.GetExifData()
for iter := exifData.Iterator(); iter.HasNext(); {
key := iter.Next().Key()
// Skip unless
if contains(key, unless) {
continue
}
err := i.StripKey(EXIF, key)
if err != nil {
return err
}
}
return nil
}
27 changes: 27 additions & 0 deletions exiv.go
Original file line number Diff line number Diff line change
Expand Up @@ -258,3 +258,30 @@ func (i *Image) StripKey(f MetadataFormat, key string) error {

return nil
}

func (i *Image) StripMetadata(unless []string) error {
var err error
err = i.ExifStripMetadata(unless)
if err != nil {
return err
}
err = i.IptcStripMetadata(unless)
if err != nil {
return err
}
err = i.XmpStripMetadata(unless)
if err != nil {
return err
}
return nil
}

// contains checks if a string is present in a string slice
func contains(needle string, haystack []string) bool {
for _, s := range haystack {
if s == needle {
return true
}
}
return false
}
132 changes: 132 additions & 0 deletions exiv_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -522,6 +522,138 @@ func TestXmpStripKey(t *testing.T) {
require.Error(t, err)
}

func TestExifStrip(t *testing.T) {
img, err := goexiv.Open("testdata/pixel.jpg")
require.NoError(t, err)

// add two strings to the EXIF data
err = img.SetExifString("Exif.Photo.UserComment", "123")
require.NoError(t, err)

err = img.SetExifString("Exif.Photo.DateTimeOriginal", "123")
require.NoError(t, err)

err = img.ExifStripMetadata([]string{"Exif.Photo.UserComment"})
require.NoError(t, err)

err = img.ReadMetadata()
require.NoError(t, err)

data := img.GetExifData()

_, err = data.GetString("Exif.Photo.UserComment")
require.NoError(t, err)

_, err = data.GetString("Exif.Photo.DateTimeOriginal")
require.Error(t, err)
}

func TestIptcStrip(t *testing.T) {
img, err := goexiv.Open("testdata/pixel.jpg")
require.NoError(t, err)

// add two strings to the IPTC data
err = img.SetIptcString("Iptc.Application2.Caption", "123")
require.NoError(t, err)

err = img.SetIptcString("Iptc.Application2.Keywords", "123")
require.NoError(t, err)

err = img.IptcStripMetadata([]string{"Iptc.Application2.Caption"})
require.NoError(t, err)

err = img.ReadMetadata()
require.NoError(t, err)

data := img.GetIptcData()

_, err = data.GetString("Iptc.Application2.Caption")
require.NoError(t, err)

_, err = data.GetString("Iptc.Application2.Keywords")
require.Error(t, err)
}

func TestXmpStrip(t *testing.T) {
img, err := goexiv.Open("testdata/pixel.jpg")
require.NoError(t, err)

// add two strings to the XMP data
err = img.SetXmpString("Xmp.dc.description", "123")
require.NoError(t, err)

err = img.SetXmpString("Xmp.dc.subject", "123")
require.NoError(t, err)

err = img.XmpStripMetadata([]string{"Xmp.dc.description"})
require.NoError(t, err)

err = img.ReadMetadata()
require.NoError(t, err)

data := img.GetXmpData()

_, err = data.GetString("Xmp.dc.description")
require.NoError(t, err)

_, err = data.GetString("Xmp.dc.subject")
require.Error(t, err)
}

func TestStripMetadata(t *testing.T) {
img, err := goexiv.Open("testdata/pixel.jpg")
require.NoError(t, err)

// add two strings to the EXIF data
err = img.SetExifString("Exif.Photo.UserComment", "123")
require.NoError(t, err)

err = img.SetExifString("Exif.Photo.DateTimeOriginal", "123")
require.NoError(t, err)

// add two strings to the IPTC data
err = img.SetIptcString("Iptc.Application2.Caption", "123")
require.NoError(t, err)

err = img.SetIptcString("Iptc.Application2.Keywords", "123")
require.NoError(t, err)

// add two strings to the XMP data
err = img.SetXmpString("Xmp.dc.description", "123")
require.NoError(t, err)

err = img.SetXmpString("Xmp.dc.subject", "123")
require.NoError(t, err)

err = img.StripMetadata([]string{"Exif.Photo.UserComment", "Iptc.Application2.Caption", "Xmp.dc.description"})
require.NoError(t, err)

err = img.ReadMetadata()
require.NoError(t, err)

exifData := img.GetExifData()
iptcData := img.GetIptcData()
xmpData := img.GetXmpData()

_, err = exifData.GetString("Exif.Photo.UserComment")
require.NoError(t, err)

_, err = exifData.GetString("Exif.Photo.DateTimeOriginal")
require.Error(t, err)

_, err = iptcData.GetString("Iptc.Application2.Caption")
require.NoError(t, err)

_, err = iptcData.GetString("Iptc.Application2.Keywords")
require.Error(t, err)

_, err = xmpData.GetString("Xmp.dc.description")
require.NoError(t, err)

_, err = xmpData.GetString("Xmp.dc.subject")
require.Error(t, err)
}

func BenchmarkImage_GetBytes_KeepAlive(b *testing.B) {
bytes, err := ioutil.ReadFile("testdata/stripped_pixel.jpg")
require.NoError(b, err)
Expand Down
42 changes: 42 additions & 0 deletions helper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,14 @@ DEFINE_STRUCT(Exiv2Image, Exiv2::Image::AutoPtr, image);

DEFINE_STRUCT(Exiv2XmpData, const Exiv2::XmpData&, data);
DEFINE_STRUCT(Exiv2XmpDatum, const Exiv2::Xmpdatum&, datum);
struct _Exiv2XmpDatumIterator {
_Exiv2XmpDatumIterator(Exiv2::XmpMetadata::const_iterator i, Exiv2::XmpMetadata::const_iterator e) : it(i), end(e) {}
Exiv2::XmpMetadata::const_iterator it;
Exiv2::XmpMetadata::const_iterator end;

bool has_next() const;
Exiv2XmpDatum* next();
};

DEFINE_STRUCT(Exiv2ExifData, const Exiv2::ExifData&, data);
DEFINE_STRUCT(Exiv2ExifDatum, const Exiv2::Exifdatum&, datum);
Expand All @@ -46,6 +54,7 @@ struct _Exiv2IptcDatumIterator {
Exiv2IptcDatum* next();
};

DEFINE_FREE_FUNCTION(exiv2_xmp_datum_iterator, Exiv2XmpDatumIterator*);
DEFINE_FREE_FUNCTION(exiv2_iptc_datum_iterator, Exiv2IptcDatumIterator*);
DEFINE_FREE_FUNCTION(exiv2_exif_datum_iterator, Exiv2ExifDatumIterator*);

Expand Down Expand Up @@ -275,8 +284,41 @@ exiv2_xmp_data_find_key(const Exiv2XmpData *data, const char *key, Exiv2Error **
}
}

Exiv2XmpDatumIterator* exiv2_xmp_data_iterator(const Exiv2XmpData *data)
{
return new Exiv2XmpDatumIterator(data->data.begin(), data->data.end());
}

bool Exiv2XmpDatumIterator::has_next() const
{
return it != end;
}

int exiv2_xmp_data_iterator_has_next(const Exiv2XmpDatumIterator *iter)
{
return iter->has_next() ? 1 : 0;
}

Exiv2XmpDatum* Exiv2XmpDatumIterator::next()
{
if (it == end) {
return 0;
}
return new Exiv2XmpDatum(*it++);
}

Exiv2XmpDatum* exiv2_xmp_datum_iterator_next(Exiv2XmpDatumIterator *iter)
{
return iter->next();
}

DEFINE_FREE_FUNCTION(exiv2_xmp_data, Exiv2XmpData*);

const char* exiv2_xmp_datum_key(const Exiv2XmpDatum *datum)
{
return strdup(datum->datum.key().c_str());
}

char*
exiv2_xmp_datum_to_string(const Exiv2XmpDatum *datum)
{
Expand Down
6 changes: 6 additions & 0 deletions helper.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ DECLARE_STRUCT(Exiv2ImageFactory);
DECLARE_STRUCT(Exiv2Image);
DECLARE_STRUCT(Exiv2XmpData);
DECLARE_STRUCT(Exiv2XmpDatum);
DECLARE_STRUCT(Exiv2XmpDatumIterator);
DECLARE_STRUCT(Exiv2IptcData);
DECLARE_STRUCT(Exiv2IptcDatum);
DECLARE_STRUCT(Exiv2IptcDatumIterator);
Expand All @@ -16,6 +17,7 @@ DECLARE_STRUCT(Exiv2ExifDatum);
DECLARE_STRUCT(Exiv2ExifDatumIterator);
DECLARE_STRUCT(Exiv2Error);

void exiv2_xmp_datum_iterator_free(Exiv2XmpDatumIterator *datum);
void exiv2_iptc_datum_iterator_free(Exiv2IptcDatumIterator *datum);
void exiv2_exif_datum_iterator_free(Exiv2ExifDatumIterator *datum);

Expand All @@ -38,9 +40,13 @@ int exiv2_image_get_pixel_height(Exiv2Image *img);

Exiv2XmpData* exiv2_image_get_xmp_data(const Exiv2Image *img);
void exiv2_xmp_data_free(Exiv2XmpData *data);
const char* exiv2_xmp_datum_key(const Exiv2XmpDatum *datum);
char* exiv2_xmp_datum_to_string(const Exiv2XmpDatum *datum);
void exiv2_xmp_datum_free(Exiv2XmpDatum *datum);
Exiv2XmpDatum* exiv2_xmp_data_find_key(const Exiv2XmpData *data, const char *key, Exiv2Error **error);
Exiv2XmpDatumIterator* exiv2_xmp_data_iterator(const Exiv2XmpData *data);
int exiv2_xmp_data_iterator_has_next(const Exiv2XmpDatumIterator *iter);
Exiv2XmpDatum* exiv2_xmp_datum_iterator_next(Exiv2XmpDatumIterator *iter);

Exiv2IptcData* exiv2_image_get_iptc_data(const Exiv2Image *img);
void exiv2_iptc_data_free(Exiv2IptcData *data);
Expand Down
16 changes: 16 additions & 0 deletions iptc.go
Original file line number Diff line number Diff line change
Expand Up @@ -149,3 +149,19 @@ func makeIptcDatumIterator(data *IptcData, cIter *C.Exiv2IptcDatumIterator) *Ipt
func (i *Image) IptcStripKey(key string) error {
return i.StripKey(IPTC, key)
}

func (i *Image) IptcStripMetadata(unless []string) error {
iptcData := i.GetIptcData()
for iter := iptcData.Iterator(); iter.HasNext(); {
key := iter.Next().Key()
// Skip unless
if contains(key, unless) {
continue
}
err := i.StripKey(IPTC, key)
if err != nil {
return err
}
}
return nil
}
52 changes: 52 additions & 0 deletions xmp.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ type XmpDatum struct {
datum *C.Exiv2XmpDatum
}

// XmpDatumIterator wraps the respective C++ structure.
type XmpDatumIterator struct {
data *XmpData
iter *C.Exiv2XmpDatumIterator
}

func makeXmpData(img *Image, cdata *C.Exiv2XmpData) *XmpData {
data := &XmpData{
img,
Expand Down Expand Up @@ -105,3 +111,49 @@ func (d *XmpData) GetString(key string) (string, error) {

return datum.String(), nil
}

func (i *Image) XmpStripMetadata(unless []string) error {
xmpData := i.GetXmpData()
for iter := xmpData.Iterator(); iter.HasNext(); {
key := iter.Next().Key()
// Skip unless
if contains(key, unless) {
continue
}
err := i.StripKey(XMP, key)
if err != nil {
return err
}
}
return nil
}

// Iterator returns a new XmpDatumIterator to iterate over all IPTC data.
func (d *XmpData) Iterator() *XmpDatumIterator {
return makeXmpDatumIterator(d, C.exiv2_xmp_data_iterator(d.data))
}

// HasNext returns true as long as the iterator has another datum to deliver.
func (i *XmpDatumIterator) HasNext() bool {
return C.exiv2_xmp_data_iterator_has_next(i.iter) != 0
}

// Next returns the next XmpDatum of the iterator or nil if iterator has reached the end.
func (i *XmpDatumIterator) Next() *XmpDatum {
return makeXmpDatum(i.data, C.exiv2_xmp_datum_iterator_next(i.iter))
}

func makeXmpDatumIterator(data *XmpData, cIter *C.Exiv2XmpDatumIterator) *XmpDatumIterator {
datum := &XmpDatumIterator{data, cIter}

runtime.SetFinalizer(datum, func(i *XmpDatumIterator) {
C.exiv2_xmp_datum_iterator_free(i.iter)
})

return datum
}

// Key returns the XMP key of the datum.
func (d *XmpDatum) Key() string {
return C.GoString(C.exiv2_xmp_datum_key(d.datum))
}

0 comments on commit 940fe8a

Please sign in to comment.