[gexiv2] Add `_try` versions of existing GError functions



commit d8a6f4b97fe77ed528241bb75b3902e7bdb17443
Author: postscript-dev <postscript-dev outlook com>
Date:   Sun Aug 15 22:02:49 2021 +0200

    Add `_try` versions of existing GError functions
    
    The library is moving to a new API, using GError to report errors and an
    `_try` prefix in the function name. Some existing functions already used
    GError but were not using the `_try` prefix.
    
    + Add missing `_try` versions of the functions and deprecate non-`_try` ones
    + Add new functions to gtk-docs and move non-`_try` ones to subsection
    + Add new functions to test_presence_of_expected_methods() in Python testing
    + Update gexiv2-tool with `try_open_path()` to prevent deprecation warning
    + NULL to nullptr as part of modernisation
    + Update gexiv2-tool with `try_get_xmp_namespace_for_tag()` to prevent
      deprecation warning
    + Python testing
    + Replace `g_ascii_strncasecmp()` with `strncmp()` as this is case sensitive
    + Add error message in functions, when filtering by @tag and does not match
      any of "Exif.", "Iptc." or "Xmp."
    + Update `Since` and `Deprecated` fields in function docs
    
    Closes !54

 docs/reference/gexiv2-sections.txt    |   68 ++-
 gexiv2/gexiv2-log.cpp                 |   12 +-
 gexiv2/gexiv2-log.h                   |    4 +-
 gexiv2/gexiv2-metadata-exif.cpp       |  153 ++---
 gexiv2/gexiv2-metadata-iptc.cpp       |   61 +-
 gexiv2/gexiv2-metadata-private.h      |    5 +-
 gexiv2/gexiv2-metadata-xmp.cpp        |  236 +++++---
 gexiv2/gexiv2-metadata.cpp            | 1075 +++++++++++++++++++++++----------
 gexiv2/gexiv2-metadata.h              |  379 +++++++++++-
 gexiv2/gexiv2-preview-image-private.h |    5 +-
 gexiv2/gexiv2-preview-image.cpp       |   89 ++-
 gexiv2/gexiv2-preview-image.h         |   14 +
 gexiv2/gexiv2-startup.cpp             |    2 +-
 test/python/test_metadata.py.in       |  122 ++++
 tools/gexiv2-tool.vala                |    2 +-
 15 files changed, 1668 insertions(+), 559 deletions(-)
---
diff --git a/docs/reference/gexiv2-sections.txt b/docs/reference/gexiv2-sections.txt
index e23b158..9a40906 100644
--- a/docs/reference/gexiv2-sections.txt
+++ b/docs/reference/gexiv2-sections.txt
@@ -24,12 +24,16 @@ gexiv2_metadata_clear_xmp
 gexiv2_metadata_try_generate_xmp_packet
 gexiv2_metadata_try_get_xmp_packet
 gexiv2_metadata_get_xmp_tags
+gexiv2_metadata_try_register_xmp_namespace
+gexiv2_metadata_try_unregister_xmp_namespace
+gexiv2_metadata_try_unregister_all_xmp_namespaces
+gexiv2_metadata_try_get_xmp_namespace_for_tag
+<SUBSECTION>
+gexiv2_metadata_get_xmp_packet
 gexiv2_metadata_register_xmp_namespace
 gexiv2_metadata_unregister_xmp_namespace
 gexiv2_metadata_unregister_all_xmp_namespaces
 gexiv2_metadata_get_xmp_namespace_for_tag
-<SUBSECTION>
-gexiv2_metadata_get_xmp_packet
 gexiv2_metadata_generate_xmp_packet
 gexiv2_metadata_set_xmp_tag_struct
 <SUBSECTION Standard>
@@ -49,11 +53,13 @@ gexiv2_metadata_try_set_exif_tag_rational
 gexiv2_metadata_get_exif_thumbnail
 gexiv2_metadata_get_exif_data
 gexiv2_metadata_set_exif_thumbnail_from_file
-gexiv2_metadata_set_exif_thumbnail_from_buffer
-gexiv2_metadata_erase_exif_thumbnail
+gexiv2_metadata_try_set_exif_thumbnail_from_buffer
+gexiv2_metadata_try_erase_exif_thumbnail
 <SUBSECTION>
 gexiv2_metadata_get_exif_tag_rational
 gexiv2_metadata_set_exif_tag_rational
+gexiv2_metadata_set_exif_thumbnail_from_buffer
+gexiv2_metadata_erase_exif_thumbnail
 </SECTION>
 
 <SECTION>
@@ -86,10 +92,34 @@ Stream_Seek
 Stream_Flush
 ManagedStreamCallbacks
 WrapperSeekOrigin
+
 </SECTION>
 
 <SECTION>
 <FILE>gexiv2-convenience</FILE>
+gexiv2_metadata_try_get_orientation
+gexiv2_metadata_try_set_orientation
+gexiv2_metadata_try_get_metadata_pixel_width
+gexiv2_metadata_try_get_metadata_pixel_height
+gexiv2_metadata_try_set_metadata_pixel_width
+gexiv2_metadata_try_set_metadata_pixel_height
+gexiv2_metadata_try_get_comment
+gexiv2_metadata_try_set_comment
+gexiv2_metadata_clear_comment
+gexiv2_metadata_try_get_exposure_time
+gexiv2_metadata_try_get_fnumber
+gexiv2_metadata_try_get_focal_length
+gexiv2_metadata_try_get_iso_speed
+gexiv2_metadata_try_get_gps_latitude
+gexiv2_metadata_try_get_gps_longitude
+gexiv2_metadata_try_get_gps_altitude
+gexiv2_metadata_try_get_gps_info
+gexiv2_metadata_try_set_gps_info
+gexiv2_metadata_try_update_gps_info
+gexiv2_metadata_try_delete_gps_info
+gexiv2_metadata_get_preview_properties
+gexiv2_metadata_try_get_preview_image
+<SUBSECTION>
 gexiv2_metadata_get_orientation
 gexiv2_metadata_set_orientation
 gexiv2_metadata_get_metadata_pixel_width
@@ -98,21 +128,10 @@ gexiv2_metadata_set_metadata_pixel_width
 gexiv2_metadata_set_metadata_pixel_height
 gexiv2_metadata_get_comment
 gexiv2_metadata_set_comment
-gexiv2_metadata_clear_comment
 gexiv2_metadata_get_exposure_time
 gexiv2_metadata_get_fnumber
 gexiv2_metadata_get_focal_length
 gexiv2_metadata_get_iso_speed
-gexiv2_metadata_try_get_gps_latitude
-gexiv2_metadata_try_get_gps_longitude
-gexiv2_metadata_try_get_gps_altitude
-gexiv2_metadata_try_get_gps_info
-gexiv2_metadata_try_set_gps_info
-gexiv2_metadata_try_update_gps_info
-gexiv2_metadata_try_delete_gps_info
-gexiv2_metadata_get_preview_properties
-gexiv2_metadata_get_preview_image
-<SUBSECTION>
 gexiv2_metadata_delete_gps_info
 gexiv2_metadata_get_gps_info
 gexiv2_metadata_get_gps_latitude
@@ -120,6 +139,7 @@ gexiv2_metadata_get_gps_longitude
 gexiv2_metadata_get_gps_altitude
 gexiv2_metadata_set_gps_info
 gexiv2_metadata_update_gps_info
+gexiv2_metadata_get_preview_image
 </SECTION>
 
 <SECTION>
@@ -131,8 +151,8 @@ GExiv2Metadata
 GExiv2ByteOrder
 gexiv2_metadata_new
 gexiv2_metadata_free
-gexiv2_metadata_has_tag
-gexiv2_metadata_clear_tag
+gexiv2_metadata_try_has_tag
+gexiv2_metadata_try_clear_tag
 gexiv2_metadata_clear
 gexiv2_metadata_try_get_tag_label
 gexiv2_metadata_try_get_tag_description
@@ -141,25 +161,27 @@ gexiv2_metadata_try_tag_supports_multiple_values
 gexiv2_metadata_get_mime_type
 gexiv2_metadata_get_pixel_width
 gexiv2_metadata_get_pixel_height
-gexiv2_metadata_get_tag_string
 gexiv2_metadata_try_get_tag_string
-gexiv2_metadata_set_tag_string
 gexiv2_metadata_try_set_tag_string
 gexiv2_metadata_try_get_tag_interpreted_string
 gexiv2_metadata_try_get_tag_long
 gexiv2_metadata_try_set_tag_long
-gexiv2_metadata_get_tag_multiple
 gexiv2_metadata_try_get_tag_multiple
-gexiv2_metadata_set_tag_multiple
 gexiv2_metadata_try_set_tag_multiple
 gexiv2_metadata_try_get_tag_raw
 <SUBSECTION>
+gexiv2_metadata_has_tag
+gexiv2_metadata_clear_tag
 gexiv2_metadata_get_tag_label
 gexiv2_metadata_get_tag_description
 gexiv2_metadata_get_tag_type
+gexiv2_metadata_get_tag_string
+gexiv2_metadata_set_tag_string
 gexiv2_metadata_get_tag_interpreted_string
 gexiv2_metadata_get_tag_long
 gexiv2_metadata_set_tag_long
+gexiv2_metadata_get_tag_multiple
+gexiv2_metadata_set_tag_multiple
 gexiv2_metadata_get_tag_raw
 <SUBSECTION Standard>
 GEXIV2_IS_METADATA
@@ -191,7 +213,7 @@ gexiv2_preview_image_get_mime_type
 gexiv2_preview_image_get_extension
 gexiv2_preview_image_get_width
 gexiv2_preview_image_get_height
-gexiv2_preview_image_write_file
+gexiv2_preview_image_try_write_file
 <SUBSECTION Standard>
 GEXIV2_IS_PREVIEW_IMAGE
 GEXIV2_IS_PREVIEW_IMAGE_CLASS
@@ -203,6 +225,8 @@ GExiv2PreviewImage
 GExiv2PreviewImageClass
 GExiv2PreviewImagePrivate
 gexiv2_preview_image_get_type
+<SUBSECTION>
+gexiv2_preview_image_write_file
 </SECTION>
 
 <SECTION>
diff --git a/gexiv2/gexiv2-log.cpp b/gexiv2/gexiv2-log.cpp
index f0646ad..3763d31 100644
--- a/gexiv2/gexiv2-log.cpp
+++ b/gexiv2/gexiv2-log.cpp
@@ -11,7 +11,7 @@
 
 G_BEGIN_DECLS
 
-static GExiv2LogHandler installed_handler = NULL;
+static GExiv2LogHandler installed_handler = nullptr;
 
 static GExiv2LogLevel exiv2_level_to_gexiv2_level(Exiv2::LogMsg::Level level) {
     switch (level) {
@@ -54,7 +54,7 @@ static Exiv2::LogMsg::Level gexiv2_level_to_exiv2_level(GExiv2LogLevel level) {
 }
 
 static void log_handler_converter(int level, const char *msg) {
-    if (installed_handler != NULL)
+    if (installed_handler != nullptr)
         installed_handler(exiv2_level_to_gexiv2_level((Exiv2::LogMsg::Level) level), msg);
     else
         Exiv2::LogMsg::defaultHandler(level, msg);
@@ -101,7 +101,7 @@ void gexiv2_log_set_level(GExiv2LogLevel level) {
 }
 
 GExiv2LogHandler gexiv2_log_get_handler(void) {
-    return (installed_handler != NULL) ? installed_handler : default_log_handler;
+    return (installed_handler != nullptr) ? installed_handler : default_log_handler;
 }
 
 GExiv2LogHandler gexiv2_log_get_default_handler(void) {
@@ -109,8 +109,8 @@ GExiv2LogHandler gexiv2_log_get_default_handler(void) {
 }
 
 void gexiv2_log_set_handler(GExiv2LogHandler handler) {
-    g_return_if_fail(handler != NULL);
-    
+    g_return_if_fail(handler != nullptr);
+
     installed_handler = handler;
     Exiv2::LogMsg::setHandler(log_handler_converter);
 }
@@ -120,7 +120,7 @@ void gexiv2_log_use_glib_logging(void) {
 }
 
 gboolean gexiv2_log_is_handler_installed(void) {
-    return (installed_handler != NULL);
+    return (installed_handler != nullptr);
 }
 
 G_END_DECLS
diff --git a/gexiv2/gexiv2-log.h b/gexiv2/gexiv2-log.h
index 6b0d838..72a4cef 100644
--- a/gexiv2/gexiv2-log.h
+++ b/gexiv2/gexiv2-log.h
@@ -17,8 +17,8 @@
  * @title: Logging functionality
  * @short_description: Utility functions related to GExiv2's and Exiv2's logging.
  *
- * The functions in this modules can be used do configure the log level of
- * GExiv2 and Exiv2 in terms of what to log (see gexiv2_log_set_level()) and
+ * The functions in this modules can be used to configure the log level of
+ * GExiv2 and Exiv2, in terms of what to log (see gexiv2_log_set_level()) and
  * how. Either a custom log handler can be used or GLib's logging mechanisms.
  */
 
diff --git a/gexiv2/gexiv2-metadata-exif.cpp b/gexiv2/gexiv2-metadata-exif.cpp
index 89749bf..1e62292 100644
--- a/gexiv2/gexiv2-metadata-exif.cpp
+++ b/gexiv2/gexiv2-metadata-exif.cpp
@@ -18,17 +18,17 @@ G_BEGIN_DECLS
 
 gboolean gexiv2_metadata_has_exif (GExiv2Metadata *self) {
     g_return_val_if_fail (GEXIV2_IS_METADATA (self), FALSE);
-    g_return_val_if_fail(self->priv->image.get() != NULL, FALSE);
-    
+    g_return_val_if_fail(self->priv != nullptr, FALSE);
+    g_return_val_if_fail(self->priv->image.get() != nullptr, FALSE);
+
     return ! (self->priv->image->exifData().empty());
 }
 
-
 gboolean gexiv2_metadata_has_exif_tag(GExiv2Metadata *self, const gchar* tag) {
     g_return_val_if_fail(GEXIV2_IS_METADATA(self), FALSE);
-    g_return_val_if_fail(tag != NULL, FALSE);
-    g_return_val_if_fail(self->priv->image.get() != NULL, FALSE);
-    
+    g_return_val_if_fail(tag != nullptr, FALSE);
+    g_return_val_if_fail(self->priv->image.get() != nullptr, FALSE);
+
     Exiv2::ExifData &exif_data = self->priv->image->exifData();
     for (Exiv2::ExifData::iterator it = exif_data.begin(); it != exif_data.end(); ++it) {
         if (it->count() > 0 && g_ascii_strcasecmp(tag, it->key().c_str()) == 0)
@@ -40,13 +40,13 @@ gboolean gexiv2_metadata_has_exif_tag(GExiv2Metadata *self, const gchar* tag) {
 
 gboolean gexiv2_metadata_clear_exif_tag(GExiv2Metadata *self, const gchar* tag) {
     g_return_val_if_fail(GEXIV2_IS_METADATA(self), FALSE);
-    g_return_val_if_fail(tag != NULL, FALSE);
-    g_return_val_if_fail(self->priv->image.get() != NULL, FALSE);
-    
+    g_return_val_if_fail(tag != nullptr, FALSE);
+    g_return_val_if_fail(self->priv->image.get() != nullptr, FALSE);
+
     Exiv2::ExifData &exif_data = self->priv->image->exifData();
-    
+
     gboolean erased = FALSE;
-    
+
     Exiv2::ExifData::iterator it = exif_data.begin();
     while (it != exif_data.end()) {
         if (it->count() > 0 && g_ascii_strcasecmp(tag, it->key().c_str()) == 0) {
@@ -62,8 +62,8 @@ gboolean gexiv2_metadata_clear_exif_tag(GExiv2Metadata *self, const gchar* tag)
 
 void gexiv2_metadata_clear_exif (GExiv2Metadata *self) {
     g_return_if_fail (GEXIV2_IS_METADATA (self));
-    g_return_if_fail(self->priv->image.get() != NULL);
-    
+    g_return_if_fail(self->priv->image.get() != nullptr);
+
     self->priv->image->exifData().clear ();
 }
 
@@ -78,8 +78,8 @@ gchar** gexiv2_metadata_get_exif_tags(GExiv2Metadata* self) {
     // Something is not right in ExifData that makes std::sort fail
 
     GSList* list = nullptr;
-    GSList *list_iter;
-    gchar** data;
+    GSList* list_iter = nullptr;
+    gchar** data = nullptr;
     gint count = 0;
     
     for (Exiv2::ExifData::iterator it = exif_data.begin(); it != exif_data.end(); ++it) {
@@ -90,8 +90,8 @@ gchar** gexiv2_metadata_get_exif_tags(GExiv2Metadata* self) {
     }
     
     data = g_new (gchar*, count + 1);
-    data[count --] = NULL;
-    for (list_iter = list; list_iter != NULL; list_iter = list_iter->next)
+    data[count--] = nullptr;
+    for (list_iter = list; list_iter != nullptr; list_iter = list_iter->next)
         data[count--] = static_cast<gchar*>(list_iter->data);
 
     g_slist_free (list);
@@ -100,14 +100,15 @@ gchar** gexiv2_metadata_get_exif_tags(GExiv2Metadata* self) {
 }
 
 gchar* gexiv2_metadata_get_exif_tag_string (GExiv2Metadata *self, const gchar* tag, GError **error) {
-    g_return_val_if_fail(GEXIV2_IS_METADATA (self), NULL);
-    g_return_val_if_fail(tag != NULL, NULL);
-    g_return_val_if_fail(self->priv->image.get() != NULL, NULL);
-    g_return_val_if_fail(error == nullptr || *error == nullptr, FALSE);
-    
-    Exiv2::ExifData &exif_data = self->priv->image->exifData();
-    
+    g_return_val_if_fail(GEXIV2_IS_METADATA(self), nullptr);
+    g_return_val_if_fail(tag != nullptr, nullptr);
+    g_return_val_if_fail(self->priv != nullptr, nullptr);
+    g_return_val_if_fail(self->priv->image.get() != nullptr, nullptr);
+    g_return_val_if_fail(error == nullptr || *error == nullptr, nullptr);
+
     try {
+        Exiv2::ExifData& exif_data = self->priv->image->exifData();
+
         Exiv2::ExifData::iterator it = exif_data.findKey(Exiv2::ExifKey(tag));
         while (it != exif_data.end() && it->count() == 0)
             it++;
@@ -117,8 +118,8 @@ gchar* gexiv2_metadata_get_exif_tag_string (GExiv2Metadata *self, const gchar* t
     } catch (Exiv2::Error& e) {
         g_set_error_literal (error, g_quark_from_string ("GExiv2"), e.code (), e.what ());
     }
-    
-    return NULL;
+
+    return nullptr;
 }
 
 gchar** gexiv2_metadata_get_exif_tag_multiple(GExiv2Metadata* self, const gchar* tag, GError** error) {
@@ -193,14 +194,15 @@ gboolean gexiv2_metadata_set_exif_tag_multiple(GExiv2Metadata* self,
 }
 
 gchar* gexiv2_metadata_get_exif_tag_interpreted_string (GExiv2Metadata *self, const gchar* tag, GError 
**error) {
-    g_return_val_if_fail(GEXIV2_IS_METADATA (self), NULL);
-    g_return_val_if_fail(tag != NULL, NULL);
-    g_return_val_if_fail(self->priv->image.get() != NULL, NULL);
-    g_return_val_if_fail(error == nullptr || *error == nullptr, FALSE);
-    
-    Exiv2::ExifData &exif_data = self->priv->image->exifData();
-    
+    g_return_val_if_fail(GEXIV2_IS_METADATA(self), nullptr);
+    g_return_val_if_fail(tag != nullptr, nullptr);
+    g_return_val_if_fail(self->priv != nullptr, nullptr);
+    g_return_val_if_fail(self->priv->image.get() != nullptr, nullptr);
+    g_return_val_if_fail(error == nullptr || *error == nullptr, nullptr);
+
     try {
+        Exiv2::ExifData& exif_data = self->priv->image->exifData();
+
         Exiv2::ExifData::iterator it = exif_data.findKey(Exiv2::ExifKey(tag));
         while (it != exif_data.end() && it->count() == 0)
             it++;
@@ -214,8 +216,8 @@ gchar* gexiv2_metadata_get_exif_tag_interpreted_string (GExiv2Metadata *self, co
     } catch (Exiv2::Error& e) {
         g_set_error_literal(error, g_quark_from_string("GExiv2"), e.code(), e.what());
     }
-    
-    return NULL;
+
+    return nullptr;
 }
 
 gboolean gexiv2_metadata_set_exif_tag_string (GExiv2Metadata *self, const gchar* tag, const gchar* value, 
GError **error) {
@@ -238,13 +240,14 @@ gboolean gexiv2_metadata_set_exif_tag_string (GExiv2Metadata *self, const gchar*
 
 glong gexiv2_metadata_get_exif_tag_long (GExiv2Metadata *self, const gchar* tag, GError **error) {
     g_return_val_if_fail(GEXIV2_IS_METADATA (self), 0);
-    g_return_val_if_fail(tag != NULL, 0);
-    g_return_val_if_fail(self->priv->image.get() != NULL, 0);
-    g_return_val_if_fail(error == nullptr || *error == nullptr, FALSE);
-    
-    Exiv2::ExifData& exif_data = self->priv->image->exifData();
-    
+    g_return_val_if_fail(tag != nullptr, 0);
+    g_return_val_if_fail(self->priv != nullptr, 0);
+    g_return_val_if_fail(self->priv->image.get() != nullptr, 0);
+    g_return_val_if_fail(error == nullptr || *error == nullptr, 0);
+
     try {
+        Exiv2::ExifData& exif_data = self->priv->image->exifData();
+
         Exiv2::ExifData::iterator it = exif_data.findKey(Exiv2::ExifKey(tag));
         while (it != exif_data.end() && it->count() == 0)
             it++;
@@ -278,15 +281,16 @@ gboolean gexiv2_metadata_set_exif_tag_long (GExiv2Metadata *self, const gchar* t
 gboolean gexiv2_metadata_try_get_exif_tag_rational (GExiv2Metadata *self, const gchar* tag, gint* nom,
     gint* den, GError **error) {
     g_return_val_if_fail(GEXIV2_IS_METADATA (self), FALSE);
-    g_return_val_if_fail(tag != NULL, FALSE);
-    g_return_val_if_fail(nom != NULL, FALSE);
-    g_return_val_if_fail(den != NULL, FALSE);
-    g_return_val_if_fail(self->priv->image.get() != NULL, FALSE);
+    g_return_val_if_fail(tag != nullptr, FALSE);
+    g_return_val_if_fail(nom != nullptr, FALSE);
+    g_return_val_if_fail(den != nullptr, FALSE);
+    g_return_val_if_fail(self->priv != nullptr, FALSE);
+    g_return_val_if_fail(self->priv->image.get() != nullptr, FALSE);
     g_return_val_if_fail(error == nullptr || *error == nullptr, FALSE);
     
-    Exiv2::ExifData& exif_data = self->priv->image->exifData();
-    
     try {
+        Exiv2::ExifData& exif_data = self->priv->image->exifData();
+
         Exiv2::ExifData::iterator it = exif_data.findKey(Exiv2::ExifKey(tag));
         while (it != exif_data.end() && it->count() == 0)
             it++;
@@ -370,6 +374,7 @@ gboolean gexiv2_metadata_set_exif_tag_rational (GExiv2Metadata *self, const gcha
  * @self: An instance of #GExiv2Metadata
  * @tag: Name of the tag to fetch
  * @def: Default value that is returned in error case
+ * @error: (allow-none): A return location for a #GError or %NULL
  *
  * A convenience wrapper around gexiv2_metadata_get_exif_tag_rational() that
  * will convert the fraction into a floating point number.
@@ -378,9 +383,19 @@ gboolean gexiv2_metadata_set_exif_tag_rational (GExiv2Metadata *self, const gcha
  * would be a division by zero or the tag could not be read, the fraction as a
  * floating point value otherwise.
  */
-gdouble gexiv2_metadata_get_exif_tag_rational_as_double (GExiv2Metadata *self, const gchar* tag, gdouble 
def) {
-    gint nom, den;
-    if (!gexiv2_metadata_try_get_exif_tag_rational(self, tag, &nom, &den, nullptr))
+gdouble gexiv2_metadata_get_exif_tag_rational_as_double(GExiv2Metadata* self,
+                                                        const gchar* tag,
+                                                        gdouble def,
+                                                        GError** error) {
+    gint nom = 0;
+    gint den = 0;
+    gboolean result = FALSE;
+
+    result = gexiv2_metadata_try_get_exif_tag_rational(self, tag, &nom, &den, error);
+    if (error && *error)
+        return def;
+
+    if (!result)
         return def;
     
     if (nom == 0.0) {
@@ -447,14 +462,15 @@ gboolean gexiv2_metadata_exif_tag_supports_multiple_values (const gchar* tag, GE
 }
 
 GBytes* gexiv2_metadata_get_exif_tag_raw (GExiv2Metadata *self, const gchar* tag, GError **error) {
-    g_return_val_if_fail(GEXIV2_IS_METADATA (self), NULL);
-    g_return_val_if_fail(tag != NULL, NULL);
-    g_return_val_if_fail(self->priv->image.get() != NULL, NULL);
-    g_return_val_if_fail(error == nullptr || *error == nullptr, FALSE);
-
-    Exiv2::ExifData &exif_data = self->priv->image->exifData();
+    g_return_val_if_fail(GEXIV2_IS_METADATA(self), nullptr);
+    g_return_val_if_fail(tag != nullptr, nullptr);
+    g_return_val_if_fail(self->priv != nullptr, nullptr);
+    g_return_val_if_fail(self->priv->image.get() != nullptr, nullptr);
+    g_return_val_if_fail(error == nullptr || *error == nullptr, nullptr);
 
     try {
+        Exiv2::ExifData& exif_data = self->priv->image->exifData();
+
         Exiv2::ExifData::iterator it = exif_data.findKey(Exiv2::ExifKey(tag));
         while (it != exif_data.end() && it->count() == 0)
             it++;
@@ -471,25 +487,26 @@ GBytes* gexiv2_metadata_get_exif_tag_raw (GExiv2Metadata *self, const gchar* tag
         g_set_error_literal(error, g_quark_from_string ("GExiv2"), e.code(), e.what());
     }
 
-    return NULL;
+    return nullptr;
 }
 
 GBytes * gexiv2_metadata_get_exif_data (GExiv2Metadata *self,
                                         GExiv2ByteOrder byte_order,
                                         GError **error) {
-    g_return_val_if_fail(GEXIV2_IS_METADATA (self), NULL);
-    g_return_val_if_fail(self->priv->image.get() != NULL, NULL);
-    g_return_val_if_fail(error == nullptr || *error == nullptr, FALSE);
+    g_return_val_if_fail(GEXIV2_IS_METADATA(self), nullptr);
+    g_return_val_if_fail(self->priv != nullptr, nullptr);
+    g_return_val_if_fail(self->priv->image.get() != nullptr, nullptr);
+    g_return_val_if_fail(error == nullptr || *error == nullptr, nullptr);
 
-    Exiv2::ExifData &exif_data = self->priv->image->exifData();
+    try {
+        Exiv2::ExifData& exif_data = self->priv->image->exifData();
 
-    if (exif_data.empty()) {
-        return NULL;
-    }
+        if (exif_data.empty()) {
+            return nullptr;
+        }
 
-    Exiv2::Blob blob;
+        Exiv2::Blob blob;
 
-    try {
         Exiv2::ExifParser::encode(blob,
                                   byte_order == GEXIV2_BYTE_ORDER_LITTLE ?
                                       Exiv2::littleEndian :
@@ -497,7 +514,7 @@ GBytes * gexiv2_metadata_get_exif_data (GExiv2Metadata *self,
                                   exif_data);
 
         if (blob.size() <= 0) {
-            return NULL;
+            return nullptr;
         }
 
         gpointer data = g_malloc0(blob.size());
@@ -508,7 +525,7 @@ GBytes * gexiv2_metadata_get_exif_data (GExiv2Metadata *self,
         g_set_error_literal(error, g_quark_from_string("GExiv2"), e.code(), e.what());
     }
 
-    return NULL;
+    return nullptr;
 }
 
 G_END_DECLS
diff --git a/gexiv2/gexiv2-metadata-iptc.cpp b/gexiv2/gexiv2-metadata-iptc.cpp
index 356fd7c..f2a20a0 100644
--- a/gexiv2/gexiv2-metadata-iptc.cpp
+++ b/gexiv2/gexiv2-metadata-iptc.cpp
@@ -17,17 +17,18 @@
 G_BEGIN_DECLS
 
 gboolean gexiv2_metadata_has_iptc (GExiv2Metadata *self) {
-    g_return_val_if_fail(GEXIV2_IS_METADATA (self), FALSE);
-    g_return_val_if_fail(self->priv->image.get() != NULL, FALSE);
-    
+    g_return_val_if_fail(GEXIV2_IS_METADATA(self), FALSE);
+    g_return_val_if_fail(self->priv != nullptr, FALSE);
+    g_return_val_if_fail(self->priv->image.get() != nullptr, FALSE);
+
     return ! (self->priv->image->iptcData().empty());
 }
 
 gboolean gexiv2_metadata_has_iptc_tag(GExiv2Metadata *self, const gchar* tag) {
     g_return_val_if_fail(GEXIV2_IS_METADATA(self), FALSE);
-    g_return_val_if_fail(tag != NULL, FALSE);
-    g_return_val_if_fail(self->priv->image.get() != NULL, FALSE);
-    
+    g_return_val_if_fail(tag != nullptr, FALSE);
+    g_return_val_if_fail(self->priv->image.get() != nullptr, FALSE);
+
     Exiv2::IptcData &iptc_data = self->priv->image->iptcData();
     
     for (Exiv2::IptcData::iterator it = iptc_data.begin(); it != iptc_data.end(); ++it) {
@@ -40,13 +41,13 @@ gboolean gexiv2_metadata_has_iptc_tag(GExiv2Metadata *self, const gchar* tag) {
 
 gboolean gexiv2_metadata_clear_iptc_tag(GExiv2Metadata *self, const gchar* tag) {
     g_return_val_if_fail(GEXIV2_IS_METADATA(self), FALSE);
-    g_return_val_if_fail(tag != NULL, FALSE);
-    g_return_val_if_fail(self->priv->image.get() != NULL, FALSE);
-    
+    g_return_val_if_fail(tag != nullptr, FALSE);
+    g_return_val_if_fail(self->priv->image.get() != nullptr, FALSE);
+
     Exiv2::IptcData &iptc_data = self->priv->image->iptcData();
-    
+
     gboolean erased = FALSE;
-    
+
     Exiv2::IptcData::iterator it = iptc_data.begin();
     while (it != iptc_data.end()) {
         if (it->count() > 0 && g_ascii_strcasecmp(tag, it->key().c_str()) == 0) {
@@ -62,7 +63,7 @@ gboolean gexiv2_metadata_clear_iptc_tag(GExiv2Metadata *self, const gchar* tag)
 
 void gexiv2_metadata_clear_iptc (GExiv2Metadata *self) {
     g_return_if_fail(GEXIV2_IS_METADATA (self));
-    g_return_if_fail(self->priv->image.get() != NULL);
+    g_return_if_fail(self->priv->image.get() != nullptr);
 
     self->priv->image->iptcData().clear ();
 }
@@ -105,8 +106,8 @@ gchar* gexiv2_metadata_get_iptc_tag_string (GExiv2Metadata *self, const gchar* t
     g_return_val_if_fail(tag != nullptr, nullptr);
     g_return_val_if_fail(self->priv != nullptr, nullptr);
     g_return_val_if_fail(self->priv->image.get() != nullptr, nullptr);
-    g_return_val_if_fail(error == nullptr || *error == nullptr, FALSE);
-    
+    g_return_val_if_fail(error == nullptr || *error == nullptr, nullptr);
+
     try {
         const auto& iptc_data = self->priv->image->iptcData();
        const Exiv2::IptcKey key(tag);
@@ -150,8 +151,8 @@ gchar* gexiv2_metadata_get_iptc_tag_interpreted_string (GExiv2Metadata *self, co
     g_return_val_if_fail(tag != nullptr, nullptr);
     g_return_val_if_fail(self->priv != nullptr, nullptr);
     g_return_val_if_fail(self->priv->image.get() != nullptr, nullptr);
-    g_return_val_if_fail(error == nullptr || *error == nullptr, FALSE);
-    
+    g_return_val_if_fail(error == nullptr || *error == nullptr, nullptr);
+
     try {
         const auto& iptc_data = self->priv->image->iptcData();
         const Exiv2::IptcKey key(tag);
@@ -240,19 +241,19 @@ gboolean gexiv2_metadata_set_iptc_tag_string (GExiv2Metadata *self, const gchar*
 }
 
 gchar** gexiv2_metadata_get_iptc_tag_multiple (GExiv2Metadata *self, const gchar* tag, GError **error) {
-    g_return_val_if_fail(GEXIV2_IS_METADATA (self), NULL);
-    g_return_val_if_fail(tag != NULL, NULL);
-    g_return_val_if_fail(self->priv->image.get() != NULL, NULL);
-    g_return_val_if_fail(error == nullptr || *error == nullptr, FALSE);
-    
-    Exiv2::IptcData &iptc_data = self->priv->image->iptcData();
-    
-    GSList *list = NULL;
-    GSList *list_iter;
-    gchar** values;
+    g_return_val_if_fail(GEXIV2_IS_METADATA(self), nullptr);
+    g_return_val_if_fail(tag != nullptr, nullptr);
+    g_return_val_if_fail(self->priv != nullptr, nullptr);
+    g_return_val_if_fail(self->priv->image.get() != nullptr, nullptr);
+    g_return_val_if_fail(error == nullptr || *error == nullptr, nullptr);
+
+    GSList* list = nullptr;
+    GSList* list_iter = nullptr;
+    gchar** values = nullptr;
     gint count = 0;
     
     try {
+        Exiv2::IptcData& iptc_data = self->priv->image->iptcData();
         Exiv2::IptcKey key (tag);
         for (Exiv2::IptcData::iterator it = iptc_data.begin(); it != iptc_data.end(); ++it) {
             if (it->count() > 0 && key.key () == it->key ()) {
@@ -262,7 +263,7 @@ gchar** gexiv2_metadata_get_iptc_tag_multiple (GExiv2Metadata *self, const gchar
         }
         
         values = g_new (gchar*, count + 1);
-        values[count --] = NULL;
+        values[count--] = nullptr;
         for (list_iter = list; list_iter != NULL; list_iter = list_iter->next)
             values[count--] = static_cast<gchar*>(list_iter->data);
         
@@ -274,8 +275,8 @@ gchar** gexiv2_metadata_get_iptc_tag_multiple (GExiv2Metadata *self, const gchar
     }
     
     g_slist_free_full (list, g_free);
-    
-    return NULL;
+
+    return nullptr;
 }
 
 gboolean gexiv2_metadata_set_iptc_tag_multiple (GExiv2Metadata *self, const gchar* tag,
@@ -410,7 +411,7 @@ GBytes* gexiv2_metadata_get_iptc_tag_raw (GExiv2Metadata *self, const gchar* tag
     g_return_val_if_fail(tag != nullptr, nullptr);
     g_return_val_if_fail(self->priv != nullptr, nullptr);
     g_return_val_if_fail(self->priv->image.get() != nullptr, nullptr);
-    g_return_val_if_fail(error == nullptr || *error == nullptr, FALSE);
+    g_return_val_if_fail(error == nullptr || *error == nullptr, nullptr);
 
     try {
         const auto& iptc_data = self->priv->image->iptcData();
diff --git a/gexiv2/gexiv2-metadata-private.h b/gexiv2/gexiv2-metadata-private.h
index d36ac50..f6cce7f 100644
--- a/gexiv2/gexiv2-metadata-private.h
+++ b/gexiv2/gexiv2-metadata-private.h
@@ -62,7 +62,10 @@ G_GNUC_INTERNAL gboolean gexiv2_metadata_set_exif_tag_multiple(GExiv2Metadata* s
 G_GNUC_INTERNAL gchar*                 gexiv2_metadata_get_exif_tag_interpreted_string (GExiv2Metadata 
*self, const gchar* tag, GError **error);
 G_GNUC_INTERNAL glong                  gexiv2_metadata_get_exif_tag_long       (GExiv2Metadata *self, const 
gchar* tag, GError **error);
 G_GNUC_INTERNAL gboolean               gexiv2_metadata_set_exif_tag_long       (GExiv2Metadata *self, const 
gchar* tag, glong value, GError **error);
-G_GNUC_INTERNAL gdouble                        gexiv2_metadata_get_exif_tag_rational_as_double 
(GExiv2Metadata *self, const gchar* tag, gdouble def);
+G_GNUC_INTERNAL gdouble gexiv2_metadata_get_exif_tag_rational_as_double(GExiv2Metadata* self,
+                                                                        const gchar* tag,
+                                                                        gdouble def,
+                                                                        GError** error);
 
 G_GNUC_INTERNAL const gchar*   gexiv2_metadata_get_exif_tag_label      (const gchar* tag, GError **error);
 G_GNUC_INTERNAL const gchar*   gexiv2_metadata_get_exif_tag_description (const gchar* tag, GError **error);
diff --git a/gexiv2/gexiv2-metadata-xmp.cpp b/gexiv2/gexiv2-metadata-xmp.cpp
index 777d624..6fa557f 100644
--- a/gexiv2/gexiv2-metadata-xmp.cpp
+++ b/gexiv2/gexiv2-metadata-xmp.cpp
@@ -21,15 +21,16 @@ G_BEGIN_DECLS
 
 gboolean gexiv2_metadata_has_xmp (GExiv2Metadata *self) {
     g_return_val_if_fail(GEXIV2_IS_METADATA (self), FALSE);
-    g_return_val_if_fail(self->priv->image.get() != NULL, FALSE);
-    
+    g_return_val_if_fail(self->priv != nullptr, FALSE);
+    g_return_val_if_fail(self->priv->image.get() != nullptr, FALSE);
+
     return !(self->priv->image->xmpData().empty());
 }
 
 void gexiv2_metadata_clear_xmp(GExiv2Metadata *self) {
     g_return_if_fail(GEXIV2_IS_METADATA (self));
-    g_return_if_fail(self->priv->image.get() != NULL);
-    
+    g_return_if_fail(self->priv->image.get() != nullptr);
+
     self->priv->image->xmpData().clear();
 }
 
@@ -100,9 +101,9 @@ gchar *gexiv2_metadata_get_xmp_packet(GExiv2Metadata *self) {
 
 gboolean gexiv2_metadata_has_xmp_tag(GExiv2Metadata *self, const gchar* tag) {
     g_return_val_if_fail(GEXIV2_IS_METADATA(self), FALSE);
-    g_return_val_if_fail(tag != NULL, FALSE);
-    g_return_val_if_fail(self->priv->image.get() != NULL, FALSE);
-    
+    g_return_val_if_fail(tag != nullptr, FALSE);
+    g_return_val_if_fail(self->priv->image.get() != nullptr, FALSE);
+
     Exiv2::XmpData &xmp_data = self->priv->image->xmpData();
     
     for (Exiv2::XmpData::iterator it = xmp_data.begin(); it != xmp_data.end(); ++it) {
@@ -115,9 +116,9 @@ gboolean gexiv2_metadata_has_xmp_tag(GExiv2Metadata *self, const gchar* tag) {
 
 gboolean gexiv2_metadata_clear_xmp_tag(GExiv2Metadata *self, const gchar* tag) {
     g_return_val_if_fail(GEXIV2_IS_METADATA(self), FALSE);
-    g_return_val_if_fail(tag != NULL, FALSE);
-    g_return_val_if_fail(self->priv->image.get() != NULL, FALSE);
-    
+    g_return_val_if_fail(tag != nullptr, FALSE);
+    g_return_val_if_fail(self->priv->image.get() != nullptr, FALSE);
+
     Exiv2::XmpData &xmp_data = self->priv->image->xmpData();
     
     gboolean erased = FALSE;
@@ -136,16 +137,16 @@ gboolean gexiv2_metadata_clear_xmp_tag(GExiv2Metadata *self, const gchar* tag) {
 }
 
 gchar** gexiv2_metadata_get_xmp_tags (GExiv2Metadata *self) {
-    g_return_val_if_fail(GEXIV2_IS_METADATA (self), NULL);
-    g_return_val_if_fail(self->priv->image.get() != NULL, NULL);
-    
+    g_return_val_if_fail(GEXIV2_IS_METADATA(self), nullptr);
+    g_return_val_if_fail(self->priv->image.get() != nullptr, nullptr);
+
     // get a copy of the original XmpData and sort it by key, preserving the original
     Exiv2::XmpData xmp_data = Exiv2::XmpData(self->priv->image->xmpData());
     detail::sortMetadata(xmp_data);
 
-    GSList *list = NULL;
-    GSList *list_iter;
-    gchar** data;
+    GSList* list = nullptr;
+    GSList* list_iter = nullptr;
+    gchar** data = nullptr;
     gint count = 0;
     
     for (Exiv2::XmpData::iterator it = xmp_data.begin(); it != xmp_data.end(); ++it) {
@@ -156,8 +157,8 @@ gchar** gexiv2_metadata_get_xmp_tags (GExiv2Metadata *self) {
     }
 
     data = g_new (gchar*, count + 1);
-    data[count --] = NULL;
-    for (list_iter = list; list_iter != NULL; list_iter = list_iter->next) {
+    data[count--] = nullptr;
+    for (list_iter = list; list_iter != nullptr; list_iter = list_iter->next) {
         data[count--] = static_cast<gchar*>(list_iter->data);
     }
 
@@ -167,14 +168,15 @@ gchar** gexiv2_metadata_get_xmp_tags (GExiv2Metadata *self) {
 }
 
 gchar* gexiv2_metadata_get_xmp_tag_string (GExiv2Metadata *self, const gchar* tag, GError **error) {
-    g_return_val_if_fail(GEXIV2_IS_METADATA (self), NULL);
-    g_return_val_if_fail(tag != NULL, NULL);
-    g_return_val_if_fail(self->priv->image.get() != NULL, NULL);
-    g_return_val_if_fail(error == nullptr || *error == nullptr, FALSE);
-    
-    Exiv2::XmpData& xmp_data = self->priv->image->xmpData();
-    
+    g_return_val_if_fail(GEXIV2_IS_METADATA(self), nullptr);
+    g_return_val_if_fail(tag != nullptr, nullptr);
+    g_return_val_if_fail(self->priv != nullptr, nullptr);
+    g_return_val_if_fail(self->priv->image.get() != nullptr, nullptr);
+    g_return_val_if_fail(error == nullptr || *error == nullptr, nullptr);
+
     try {
+        Exiv2::XmpData& xmp_data = self->priv->image->xmpData();
+
         Exiv2::XmpData::iterator it = xmp_data.findKey(Exiv2::XmpKey(tag));
         while (it != xmp_data.end() && it->count() == 0)
             it++;
@@ -184,19 +186,20 @@ gchar* gexiv2_metadata_get_xmp_tag_string (GExiv2Metadata *self, const gchar* ta
     } catch (Exiv2::Error& e) {
         g_set_error_literal(error, g_quark_from_string("GExiv2"), e.code(), e.what());
     }
-    
-    return NULL;
+
+    return nullptr;
 }
 
 gchar* gexiv2_metadata_get_xmp_tag_interpreted_string (GExiv2Metadata *self, const gchar* tag, GError 
**error) {
-    g_return_val_if_fail(GEXIV2_IS_METADATA (self), NULL);
-    g_return_val_if_fail(tag != NULL, NULL);
-    g_return_val_if_fail(self->priv->image.get() != NULL, NULL);
-    g_return_val_if_fail(error == nullptr || *error == nullptr, FALSE);
-    
-    Exiv2::XmpData& xmp_data = self->priv->image->xmpData();
-    
+    g_return_val_if_fail(GEXIV2_IS_METADATA(self), nullptr);
+    g_return_val_if_fail(tag != nullptr, nullptr);
+    g_return_val_if_fail(self->priv != nullptr, nullptr);
+    g_return_val_if_fail(self->priv->image.get() != nullptr, nullptr);
+    g_return_val_if_fail(error == nullptr || *error == nullptr, nullptr);
+
     try {
+        Exiv2::XmpData& xmp_data = self->priv->image->xmpData();
+
         Exiv2::XmpData::iterator it = xmp_data.findKey(Exiv2::XmpKey(tag));
         while (it != xmp_data.end() && it->count() == 0)
             it++;
@@ -210,8 +213,8 @@ gchar* gexiv2_metadata_get_xmp_tag_interpreted_string (GExiv2Metadata *self, con
     } catch (Exiv2::Error& e) {
         g_set_error_literal(error, g_quark_from_string("GExiv2"), e.code(), e.what());
     }
-    
-    return NULL;
+
+    return nullptr;
 }
 
 gboolean gexiv2_metadata_try_set_xmp_tag_struct (GExiv2Metadata *self, const gchar* tag, GExiv2StructureType 
type, GError **error) {
@@ -296,13 +299,14 @@ gboolean gexiv2_metadata_set_xmp_tag_string (GExiv2Metadata *self, const gchar*
 
 glong gexiv2_metadata_get_xmp_tag_long (GExiv2Metadata *self, const gchar* tag, GError **error) {
     g_return_val_if_fail(GEXIV2_IS_METADATA (self), 0);
-    g_return_val_if_fail(tag != NULL, 0);
-    g_return_val_if_fail(self->priv->image.get() != NULL, 0);
-    g_return_val_if_fail(error == nullptr || *error == nullptr, FALSE);
-    
-    Exiv2::XmpData& xmp_data = self->priv->image->xmpData();
-    
+    g_return_val_if_fail(tag != nullptr, 0);
+    g_return_val_if_fail(self->priv != nullptr, 0);
+    g_return_val_if_fail(self->priv->image.get() != nullptr, 0);
+    g_return_val_if_fail(error == nullptr || *error == nullptr, 0);
+
     try {
+        Exiv2::XmpData& xmp_data = self->priv->image->xmpData();
+
         Exiv2::XmpData::iterator it = xmp_data.findKey(Exiv2::XmpKey(tag));
         while (it != xmp_data.end() && it->count() == 0)
             it++;
@@ -455,14 +459,15 @@ gchar** gexiv2_metadata_get_xmp_tag_multiple_deprecated (GExiv2Metadata *self, c
 gboolean gexiv2_metadata_set_xmp_tag_multiple (GExiv2Metadata *self, const gchar* tag, 
     const gchar** values, GError **error) {
     g_return_val_if_fail(GEXIV2_IS_METADATA (self), FALSE);
-    g_return_val_if_fail(tag != NULL, FALSE);
-    g_return_val_if_fail(values != NULL, FALSE);
-    g_return_val_if_fail(self->priv->image.get() != NULL, FALSE);
+    g_return_val_if_fail(tag != nullptr, FALSE);
+    g_return_val_if_fail(values != nullptr, FALSE);
+    g_return_val_if_fail(self->priv != nullptr, FALSE);
+    g_return_val_if_fail(self->priv->image.get() != nullptr, FALSE);
     g_return_val_if_fail(error == nullptr || *error == nullptr, FALSE);
     
-    Exiv2::XmpData& xmp_data = self->priv->image->xmpData();
-    
     try {
+        Exiv2::XmpData& xmp_data = self->priv->image->xmpData();
+
         /* first clear existing tag */
         Exiv2::XmpData::iterator it = xmp_data.findKey(Exiv2::XmpKey(tag));
         while (it != xmp_data.end() && it->count() == 0)
@@ -473,11 +478,11 @@ gboolean gexiv2_metadata_set_xmp_tag_multiple (GExiv2Metadata *self, const gchar
         
         /* ... and then set the others */
         const gchar **val_it = values;
-        while (*val_it != NULL) {
+        while (*val_it != nullptr) {
             xmp_data[tag] = static_cast<const std::string> (*val_it);
             ++val_it;
         }
-        
+
         return TRUE;
     } catch (Exiv2::Error& e) {
         g_set_error_literal(error, g_quark_from_string("GExiv2"), e.code(), e.what());
@@ -567,14 +572,15 @@ gboolean gexiv2_metadata_xmp_tag_supports_multiple_values(GExiv2Metadata* self,
 }
 
 GBytes* gexiv2_metadata_get_xmp_tag_raw (GExiv2Metadata *self, const gchar* tag, GError **error) {
-    g_return_val_if_fail(GEXIV2_IS_METADATA (self), NULL);
-    g_return_val_if_fail(tag != NULL, NULL);
-    g_return_val_if_fail(self->priv->image.get() != NULL, NULL);
-    g_return_val_if_fail(error == nullptr || *error == nullptr, FALSE);
-
-    Exiv2::XmpData& xmp_data = self->priv->image->xmpData();
+    g_return_val_if_fail(GEXIV2_IS_METADATA(self), nullptr);
+    g_return_val_if_fail(tag != nullptr, nullptr);
+    g_return_val_if_fail(self->priv != nullptr, nullptr);
+    g_return_val_if_fail(self->priv->image.get() != nullptr, nullptr);
+    g_return_val_if_fail(error == nullptr || *error == nullptr, nullptr);
 
     try {
+        Exiv2::XmpData& xmp_data = self->priv->image->xmpData();
+
         Exiv2::XmpData::iterator it = xmp_data.findKey(Exiv2::XmpKey(tag));
         while (it != xmp_data.end() && it->count() == 0)
             it++;
@@ -591,51 +597,120 @@ GBytes* gexiv2_metadata_get_xmp_tag_raw (GExiv2Metadata *self, const gchar* tag,
         g_set_error_literal(error, g_quark_from_string("GExiv2"), e.code(), e.what());
     }
 
-    return NULL;
+    return nullptr;
 }
 
 gboolean gexiv2_metadata_register_xmp_namespace (const gchar* name, const gchar* prefix) {
-    g_return_val_if_fail(name != NULL, FALSE);
-    g_return_val_if_fail(prefix != NULL, FALSE);
+    gboolean value = FALSE;
+    GError* error = nullptr;
+
+    value = gexiv2_metadata_try_register_xmp_namespace(name, prefix, &error);
+
+    if (error) {
+        g_warning("%s", error->message);
+        g_clear_error(&error);
+    }
+
+    return value;
+}
+
+gboolean gexiv2_metadata_try_register_xmp_namespace(const gchar* name, const gchar* prefix, GError** error) {
+    g_return_val_if_fail(name != nullptr, FALSE);
+    g_return_val_if_fail(prefix != nullptr, FALSE);
+    g_return_val_if_fail(error == nullptr || *error == nullptr, FALSE);
 
     try {
         Exiv2::XmpProperties::ns(prefix);
-    } catch (Exiv2::AnyError& error) {
+    } catch (Exiv2::AnyError& e1) {
         // No namespace, OK to register
-        Exiv2::XmpProperties::registerNs(name, prefix);
-        return TRUE;
+        try {
+            Exiv2::XmpProperties::registerNs(name, prefix);
+            return TRUE;
+        } catch (Exiv2::AnyError& e2) {
+            g_set_error_literal(error, g_quark_from_string("GExiv2"), e2.code(), e2.what());
+        }
     }
 
     return FALSE;
 }
 
 gboolean gexiv2_metadata_unregister_xmp_namespace (const gchar* name) {
-    g_return_val_if_fail(name != NULL, FALSE);
+    gboolean value = FALSE;
+    GError* error = nullptr;
 
-    std::string prefix = Exiv2::XmpProperties::prefix(name);
+    value = gexiv2_metadata_try_unregister_xmp_namespace(name, &error);
 
-    if (!prefix.empty()) {
-        // Unregister
-        Exiv2::XmpProperties::unregisterNs(name);
+    if (error) {
+        g_warning("%s", error->message);
+        g_clear_error(&error);
+    }
 
-        try {
-            Exiv2::XmpProperties::ns(prefix);
-        } catch (Exiv2::Error& error) {
-            // Namespace successfully removed
-            return TRUE;
+    return value;
+}
+
+gboolean gexiv2_metadata_try_unregister_xmp_namespace(const gchar* name, GError** error) {
+    g_return_val_if_fail(name != nullptr, FALSE);
+    g_return_val_if_fail(error == nullptr || *error == nullptr, FALSE);
+
+    try {
+        std::string prefix = Exiv2::XmpProperties::prefix(name);
+
+        if (!prefix.empty()) {
+            // Unregister
+            Exiv2::XmpProperties::unregisterNs(name);
+
+            try {
+                Exiv2::XmpProperties::ns(prefix);
+            } catch (Exiv2::Error& e1) {
+                // Namespace successfully removed
+                return TRUE;
+            }
         }
+    } catch (Exiv2::Error& e2) {
+        g_set_error_literal(error, g_quark_from_string("GExiv2"), e2.code(), e2.what());
     }
-
     return FALSE;
 }
 
 void gexiv2_metadata_unregister_all_xmp_namespaces (void) {
-    Exiv2::XmpProperties::unregisterNs();
+    GError* error = nullptr;
+
+    gexiv2_metadata_try_unregister_all_xmp_namespaces(&error);
+
+    if (error) {
+        g_warning("%s", error->message);
+        g_clear_error(&error);
+    }
+}
+
+void gexiv2_metadata_try_unregister_all_xmp_namespaces(GError** error) {
+    g_return_if_fail(error == nullptr || *error == nullptr);
+
+    try {
+        Exiv2::XmpProperties::unregisterNs();
+    } catch (Exiv2::Error& e) {
+        g_set_error_literal(error, g_quark_from_string("GExiv2"), e.code(), e.what());
+    }
 }
 
 char* gexiv2_metadata_get_xmp_namespace_for_tag(const char* tag) {
+    gchar* value = nullptr;
+    GError* error = nullptr;
+
+    value = gexiv2_metadata_try_get_xmp_namespace_for_tag(tag, &error);
+
+    if (error) {
+        g_warning("%s", error->message);
+        g_clear_error(&error);
+    }
+
+    return value;
+}
+
+char* gexiv2_metadata_try_get_xmp_namespace_for_tag(const char* tag, GError** error) {
     g_return_val_if_fail(tag != nullptr, nullptr);
     g_return_val_if_fail(strlen(tag) != 0, nullptr);
+    g_return_val_if_fail(error == nullptr || *error == nullptr, nullptr);
 
     char** list = nullptr;
     char* result = nullptr;
@@ -645,18 +720,23 @@ char* gexiv2_metadata_get_xmp_namespace_for_tag(const char* tag) {
         const char* name = nullptr;
         if (g_strv_length(list) == 0) {
             g_assert_not_reached();
-        }
-        if (g_strv_length(list) == 1) {
+        } else if (g_strv_length(list) == 1) {
+            // @tag is in the format "groupName"
             name = list[0];
-        } else  {
+        } else if (g_strv_length(list) == 3) {
+            // Check @tag is in the format "Xmp.groupName.tagName"
+            if (g_strcmp0(list[0], "Xmp") != 0 || strlen(list[1]) == 0 || strlen(list[2]) == 0)
+                throw Exiv2::Error(Exiv2::ErrorCode::kerInvalidKey, tag);
             name = list[1];
+        } else {
+            throw Exiv2::Error(Exiv2::ErrorCode::kerInvalidKey, tag);
         }
 
         auto info = Exiv2::XmpProperties::ns(name);
 
         result = g_strdup(info.c_str());
-    } catch (Exiv2::Error&) {
-        // No such namespace
+    } catch (Exiv2::Error& e) {
+        g_set_error_literal(error, g_quark_from_string("GExiv2"), e.code(), e.what());
     }
 
     g_clear_pointer(&list, g_strfreev);
diff --git a/gexiv2/gexiv2-metadata.cpp b/gexiv2/gexiv2-metadata.cpp
index eb07f5f..928b07b 100644
--- a/gexiv2/gexiv2-metadata.cpp
+++ b/gexiv2/gexiv2-metadata.cpp
@@ -347,56 +347,79 @@ void gexiv2_metadata_free (GExiv2Metadata *self) {
 
 static void gexiv2_metadata_set_comment_internal (GExiv2Metadata* self, const gchar* new_comment) {
     g_return_if_fail (GEXIV2_IS_METADATA (self));
-    
+    g_return_if_fail(self->priv != nullptr);
+
     g_free (self->priv->comment);
-    
+
     self->priv->comment = g_strdup (new_comment);
 }
 
-static void gexiv2_metadata_init_internal (GExiv2Metadata *self) {
+static void gexiv2_metadata_init_internal(GExiv2Metadata* self, GError** error) {
+    g_return_if_fail(GEXIV2_IS_METADATA(self));
+    g_return_if_fail(self->priv != nullptr);
+    g_return_if_fail(self->priv->image.get() != nullptr);
+    g_return_if_fail(error == nullptr || *error == nullptr);
+
     GExiv2MetadataPrivate* priv = self->priv;
-    
-    // must be set prior to calling this function
-    g_return_if_fail(priv->image.get() != NULL);
-    
-    gexiv2_metadata_set_comment_internal (self, priv->image->comment ().c_str ());
-    priv->mime_type = g_strdup (priv->image->mimeType ().c_str ());
-    
-    priv->pixel_width = priv->image->pixelWidth ();
-    priv->pixel_height = priv->image->pixelHeight ();
-    
-    Exiv2::AccessMode mode = priv->image->checkMode (Exiv2::mdExif);
-    priv->supports_exif = (mode == Exiv2::amWrite || mode == Exiv2::amReadWrite);
-    
-    mode = priv->image->checkMode (Exiv2::mdXmp);
-    priv->supports_xmp = (mode == Exiv2::amWrite || mode == Exiv2::amReadWrite);
-    
-    mode = priv->image->checkMode (Exiv2::mdIptc);
-    priv->supports_iptc = (mode == Exiv2::amWrite || mode == Exiv2::amReadWrite);
-    
-    priv->preview_manager = new Exiv2::PreviewManager(*priv->image.get());
-    
-    Exiv2::PreviewPropertiesList list = priv->preview_manager->getPreviewProperties();
-    int count = list.size();
-    if (count > 0) {
-        priv->preview_properties = g_new(GExiv2PreviewProperties *, count + 1);
-        for (int ctr = 0; ctr < count; ctr++)
-            priv->preview_properties[ctr] = gexiv2_preview_properties_new(list[ctr]);
-        priv->preview_properties[count] = NULL;
+    try {
+
+        gexiv2_metadata_set_comment_internal(self, priv->image->comment().c_str());
+        priv->mime_type = g_strdup(priv->image->mimeType().c_str());
+
+        priv->pixel_width = priv->image->pixelWidth();
+        priv->pixel_height = priv->image->pixelHeight();
+
+        Exiv2::AccessMode mode = priv->image->checkMode(Exiv2::mdExif);
+        priv->supports_exif = (mode == Exiv2::amWrite || mode == Exiv2::amReadWrite);
+
+        mode = priv->image->checkMode(Exiv2::mdXmp);
+        priv->supports_xmp = (mode == Exiv2::amWrite || mode == Exiv2::amReadWrite);
+
+        mode = priv->image->checkMode(Exiv2::mdIptc);
+        priv->supports_iptc = (mode == Exiv2::amWrite || mode == Exiv2::amReadWrite);
+
+        priv->preview_manager = new Exiv2::PreviewManager(*priv->image.get());
+
+        Exiv2::PreviewPropertiesList list = priv->preview_manager->getPreviewProperties();
+        int count = list.size();
+        if (count > 0) {
+            priv->preview_properties = g_new(GExiv2PreviewProperties*, count + 1);
+            for (int ctr = 0; ctr < count; ctr++)
+                priv->preview_properties[ctr] = gexiv2_preview_properties_new(list[ctr]);
+            priv->preview_properties[count] = nullptr;
+        }
+    } catch (Exiv2::Error& e) {
+        if (priv->mime_type)
+            g_free(priv->mime_type);
+
+        if (priv->preview_manager)
+            delete priv->preview_manager;
+
+        g_set_error_literal(error, g_quark_from_string("GExiv2"), e.code(), e.what());
     }
 }
 
 static gboolean gexiv2_metadata_open_internal (GExiv2Metadata* self, GError** error) {
-    if (self->priv->image.get () == NULL || ! self->priv->image->good ()) {
+    g_return_val_if_fail(GEXIV2_IS_METADATA(self), FALSE);
+    g_return_val_if_fail(self->priv != nullptr, FALSE);
+    g_return_val_if_fail(error == nullptr || *error == nullptr, FALSE);
+
+    if (self->priv->image.get() == nullptr || !self->priv->image->good()) {
         g_set_error_literal (error, g_quark_from_string ("GExiv2"),
             501, "unsupported format");
         return FALSE;
     }
-    
-    self->priv->image->readMetadata ();
-    gexiv2_metadata_init_internal(self);
-    
-    return TRUE;
+
+    try {
+        self->priv->image->readMetadata();
+        gexiv2_metadata_init_internal(self, error);
+
+        return !(error && *error);
+    } catch (Exiv2::Error& e) {
+        g_set_error_literal(error, g_quark_from_string("GExiv2"), e.code(), e.what());
+    }
+
+    return FALSE;
 }
 
 #ifdef EXV_UNICODE_PATH
@@ -464,8 +487,7 @@ gboolean gexiv2_metadata_open_path(GExiv2Metadata* self, const gchar* path, GErr
     return FALSE;
 }
 
-gboolean gexiv2_metadata_open_buf (GExiv2Metadata *self, const guint8 *data, glong n_data,
-    GError **error) {
+gboolean gexiv2_metadata_open_buf(GExiv2Metadata* self, const guint8* data, glong n_data, GError** error) {
     g_return_val_if_fail (GEXIV2_IS_METADATA (self), FALSE);
     
     try {
@@ -526,10 +548,9 @@ gboolean gexiv2_metadata_from_stream(GExiv2Metadata *self, GInputStream *stream,
 // is closed this code can revert to a direct image decode.  To be more flexible for other
 // file formats that encode EXIF via other means (such as PNG), search for the TIFF header and
 // decode from there.
-gboolean gexiv2_metadata_from_app1_segment(GExiv2Metadata *self, const guint8 *data, glong n_data,
-    GError **error) {
+gboolean gexiv2_metadata_from_app1_segment(GExiv2Metadata* self, const guint8* data, glong n_data, GError** 
error) {
     g_return_val_if_fail(GEXIV2_IS_METADATA(self), FALSE);
-    g_return_val_if_fail(data != NULL, FALSE);
+    g_return_val_if_fail(data != nullptr, FALSE);
     g_return_val_if_fail(n_data > 0, FALSE);
     
     int offset = 0;
@@ -549,77 +570,92 @@ gboolean gexiv2_metadata_from_app1_segment(GExiv2Metadata *self, const guint8 *d
     
     try {
         self->priv->image = Exiv2::ImageFactory::create(Exiv2::ImageType::jpeg);
-        if (self->priv->image.get() == NULL)
+        if (self->priv->image.get() == nullptr)
             return FALSE;
         
         Exiv2::ExifParser::decode(self->priv->image->exifData(), data + offset, n_data - offset);
-        gexiv2_metadata_init_internal(self);
-        
+        gexiv2_metadata_init_internal(self, error);
+        if (error && *error) {
+            // Cleanup
+            delete self->priv->image.release();
+            return FALSE;
+        }
+
         return TRUE;
     } catch (Exiv2::Error &e) {
+        delete self->priv->image.release();
         g_set_error_literal(error, g_quark_from_string("GExiv2"), e.code(), e.what());
-        
-        return FALSE;
     }
+    return FALSE;
 }
 
 static gboolean gexiv2_metadata_save_internal (GExiv2Metadata *self, image_ptr image, GError **error) {
-    if (image.get () == NULL || ! image->good ()) {
+    g_return_val_if_fail(GEXIV2_IS_METADATA(self), FALSE);
+    g_return_val_if_fail(self->priv != nullptr, FALSE);
+    g_return_val_if_fail(self->priv->image.get() != nullptr, FALSE);
+    g_return_val_if_fail(error == nullptr || *error == nullptr, FALSE);
+
+    if (image.get() == nullptr || !image->good()) {
         g_set_error_literal (error, g_quark_from_string ("GExiv2"),
             501, "format seems not to be supported");
         
         return FALSE;
     }
-    
-    image->readMetadata ();
-        
-    Exiv2::AccessMode mode = image->checkMode (Exiv2::mdExif);
-    if (mode == Exiv2::amWrite || mode == Exiv2::amReadWrite) {
-        /* For tiff some image data is stored in exif. This should not
-           be overwritten. (see libkexiv2/kexiv2.cpp)
-         */
-        if (image->mimeType () == "image/tiff") {
-            // FIXME
-            /*Exiv2::ExifData new_exif_data = self->priv->exif_data;
-            Exiv2::ExifData old_exif_data = image->getExifData ();
-            
-            new_exif_data["Exif.Image.ImageWidth"];
-            new_exif_data["Exif.Image.ImageLength"];
-            new_exif_data["Exif.Image.BitsPerSample"];
-            new_exif_data["Exif.Image.Compression"];
-            new_exif_data["Exif.Image.PhotometricInterpretation"];
-            new_exif_data["Exif.Image.FillOrder"];
-            new_exif_data["Exif.Image.SamplesPerPixel"];
-            new_exif_data["Exif.Image.StripOffsets"];
-            new_exif_data["Exif.Image.RowsPerStrip"];
-            new_exif_data["Exif.Image.StripByteCounts"];
-            new_exif_data["Exif.Image.XResolution"];
-            new_exif_data["Exif.Image.YResolution"];
-            new_exif_data["Exif.Image.PlanarConfiguration"];
-            new_exif_data["Exif.Image.ResolutionUnit"];
-            */
-            
-            image->setExifData (self->priv->image->exifData());
-        } else {
-            image->setExifData (self->priv->image->exifData());
+
+    try {
+        image->readMetadata();
+
+        Exiv2::AccessMode mode = image->checkMode(Exiv2::mdExif);
+        if (mode == Exiv2::amWrite || mode == Exiv2::amReadWrite) {
+            /* For tiff some image data is stored in exif. This should not
+               be overwritten. (see libkexiv2/kexiv2.cpp)
+             */
+            if (image->mimeType() == "image/tiff") {
+                // FIXME
+                /*Exiv2::ExifData new_exif_data = self->priv->exif_data;
+                Exiv2::ExifData old_exif_data = image->getExifData ();
+
+                new_exif_data["Exif.Image.ImageWidth"];
+                new_exif_data["Exif.Image.ImageLength"];
+                new_exif_data["Exif.Image.BitsPerSample"];
+                new_exif_data["Exif.Image.Compression"];
+                new_exif_data["Exif.Image.PhotometricInterpretation"];
+                new_exif_data["Exif.Image.FillOrder"];
+                new_exif_data["Exif.Image.SamplesPerPixel"];
+                new_exif_data["Exif.Image.StripOffsets"];
+                new_exif_data["Exif.Image.RowsPerStrip"];
+                new_exif_data["Exif.Image.StripByteCounts"];
+                new_exif_data["Exif.Image.XResolution"];
+                new_exif_data["Exif.Image.YResolution"];
+                new_exif_data["Exif.Image.PlanarConfiguration"];
+                new_exif_data["Exif.Image.ResolutionUnit"];
+                */
+
+                image->setExifData(self->priv->image->exifData());
+            } else {
+                image->setExifData(self->priv->image->exifData());
+            }
         }
+
+        mode = image->checkMode(Exiv2::mdXmp);
+        if (mode == Exiv2::amWrite || mode == Exiv2::amReadWrite)
+            image->setXmpData(self->priv->image->xmpData());
+
+        mode = image->checkMode(Exiv2::mdIptc);
+        if (mode == Exiv2::amWrite || mode == Exiv2::amReadWrite)
+            image->setIptcData(self->priv->image->iptcData());
+
+        mode = image->checkMode(Exiv2::mdComment);
+        if (mode == Exiv2::amWrite || mode == Exiv2::amReadWrite)
+            image->setComment(self->priv->comment);
+
+        image->writeMetadata();
+
+        return TRUE;
+    } catch (Exiv2::Error& e) {
+        g_set_error_literal(error, g_quark_from_string("GExiv2"), e.code(), e.what());
     }
-        
-    mode = image->checkMode (Exiv2::mdXmp);
-    if (mode == Exiv2::amWrite || mode == Exiv2::amReadWrite)
-        image->setXmpData (self->priv->image->xmpData());
-    
-    mode = image->checkMode (Exiv2::mdIptc);
-    if (mode == Exiv2::amWrite || mode == Exiv2::amReadWrite)
-        image->setIptcData (self->priv->image->iptcData());
-    
-    mode = image->checkMode (Exiv2::mdComment);
-    if (mode == Exiv2::amWrite || mode == Exiv2::amReadWrite)
-        image->setComment (self->priv->comment);
-    
-    image->writeMetadata ();
-    
-    return TRUE;
+    return FALSE;
 }
 
 gboolean gexiv2_metadata_save_external (GExiv2Metadata *self, const gchar *path, GError **error) {
@@ -695,68 +731,125 @@ gboolean gexiv2_metadata_save_stream (GExiv2Metadata *self, ManagedStreamCallbac
 }
 
 gboolean gexiv2_metadata_has_tag(GExiv2Metadata *self, const gchar* tag) {
+    GError* error = nullptr;
+    gboolean value = FALSE;
+
+    value = gexiv2_metadata_try_has_tag(self, tag, &error);
+
+    if (error) {
+        g_warning("%s", error->message);
+        g_clear_error(&error);
+    }
+
+    return value;
+}
+
+gboolean gexiv2_metadata_try_has_tag(GExiv2Metadata* self, const gchar* tag, GError** error) {
     g_return_val_if_fail(GEXIV2_IS_METADATA(self), FALSE);
-    g_return_val_if_fail(tag != NULL, FALSE);
-    g_return_val_if_fail(self->priv->image.get() != NULL, FALSE);
-    
+    g_return_val_if_fail(tag != nullptr, FALSE);
+    g_return_val_if_fail(self->priv->image.get() != nullptr, FALSE);
+    g_return_val_if_fail(error == nullptr || *error == nullptr, FALSE);
+
     if (gexiv2_metadata_is_xmp_tag(tag))
         return gexiv2_metadata_has_xmp_tag(self, tag);
-    
+
     if (gexiv2_metadata_is_exif_tag(tag))
         return gexiv2_metadata_has_exif_tag(self, tag);
-    
+
     if (gexiv2_metadata_is_iptc_tag(tag))
         return gexiv2_metadata_has_iptc_tag(self, tag);
-    
+
+    // Invalid "familyName"
+    Exiv2::Error e(Exiv2::ErrorCode::kerInvalidKey, tag);
+    g_set_error_literal(error, g_quark_from_string("GExiv2"), e.code(), e.what());
+
     return FALSE;
 }
 
 gboolean gexiv2_metadata_clear_tag(GExiv2Metadata *self, const gchar* tag) {
+    GError* error = nullptr;
+    gboolean value = FALSE;
+
+    value = gexiv2_metadata_try_clear_tag(self, tag, &error);
+
+    if (error) {
+        g_warning("%s", error->message);
+        g_clear_error(&error);
+    }
+
+    return value;
+}
+
+gboolean gexiv2_metadata_try_clear_tag(GExiv2Metadata* self, const gchar* tag, GError** error) {
     g_return_val_if_fail(GEXIV2_IS_METADATA(self), FALSE);
-    g_return_val_if_fail(tag != NULL, FALSE);
-    g_return_val_if_fail(self->priv->image.get() != NULL, FALSE);
-    
+    g_return_val_if_fail(tag != nullptr, FALSE);
+    g_return_val_if_fail(self->priv->image.get() != nullptr, FALSE);
+    g_return_val_if_fail(error == nullptr || *error == nullptr, FALSE);
+
     if (gexiv2_metadata_is_xmp_tag(tag))
         return gexiv2_metadata_clear_xmp_tag(self, tag);
-    
+
     if (gexiv2_metadata_is_exif_tag(tag))
         return gexiv2_metadata_clear_exif_tag(self, tag);
-    
+
     if (gexiv2_metadata_is_iptc_tag(tag))
         return gexiv2_metadata_clear_iptc_tag(self, tag);
-    
+
+    // Invalid "familyName"
+    Exiv2::Error e(Exiv2::ErrorCode::kerInvalidKey, tag);
+    g_set_error_literal(error, g_quark_from_string("GExiv2"), e.code(), e.what());
+
     return FALSE;
 }
 
 void gexiv2_metadata_clear (GExiv2Metadata *self) {
     g_return_if_fail(GEXIV2_IS_METADATA (self));
-    
-    if (self->priv->image.get() == NULL)
-        return;
-    
+    g_return_if_fail(self->priv != nullptr);
+    g_return_if_fail(self->priv->image.get() != nullptr);
+
     gexiv2_metadata_clear_exif (self);
     gexiv2_metadata_clear_xmp (self);
     gexiv2_metadata_clear_iptc (self);
+
     gexiv2_metadata_clear_comment (self);
-    
+
     self->priv->image->clearMetadata();
 }
 
 const gchar* gexiv2_metadata_get_mime_type (GExiv2Metadata *self) {
-    g_return_val_if_fail(GEXIV2_IS_METADATA (self), NULL);
-    
+    g_return_val_if_fail(GEXIV2_IS_METADATA(self), nullptr);
+    g_return_val_if_fail(self->priv != nullptr, nullptr);
+
     return self->priv->mime_type;
 }
 
 GExiv2Orientation gexiv2_metadata_get_orientation (GExiv2Metadata *self) {
+    GError* error = nullptr;
+    GExiv2Orientation value = GEXIV2_ORIENTATION_UNSPECIFIED;
+
+    value = gexiv2_metadata_try_get_orientation(self, &error);
+
+    if (error) {
+        g_warning("%s", error->message);
+        g_clear_error(&error);
+    }
+
+    return value;
+}
+
+GExiv2Orientation gexiv2_metadata_try_get_orientation(GExiv2Metadata* self, GError** error) {
     g_return_val_if_fail(GEXIV2_IS_METADATA (self), GEXIV2_ORIENTATION_UNSPECIFIED);
-    g_return_val_if_fail(self->priv->image.get() != NULL, GEXIV2_ORIENTATION_UNSPECIFIED);
-    
+    g_return_val_if_fail(self->priv->image.get() != nullptr, GEXIV2_ORIENTATION_UNSPECIFIED);
+    g_return_val_if_fail(error == nullptr || *error == nullptr, GEXIV2_ORIENTATION_UNSPECIFIED);
+
     if (gexiv2_metadata_has_exif(self)) {
-        // Because some camera set a wrong standard exif orientation tag,
+        // Because some cameras set a wrong standard exif orientation tag,
         // We need to check makernote tags first!
         if (gexiv2_metadata_has_exif_tag(self, "Exif.MinoltaCs7D.Rotation")) {
-            long orientation = gexiv2_metadata_get_exif_tag_long(self, "Exif.MinoltaCs7D.Rotation", nullptr);
+            long orientation = gexiv2_metadata_get_exif_tag_long(self, "Exif.MinoltaCs7D.Rotation", error);
+            if (error && *error) {
+                return GEXIV2_ORIENTATION_UNSPECIFIED;
+            }
             switch (orientation) {
                 case 76:
                     return GEXIV2_ORIENTATION_ROT_90;
@@ -770,11 +863,14 @@ GExiv2Orientation gexiv2_metadata_get_orientation (GExiv2Metadata *self) {
         }
 
         if (gexiv2_metadata_has_exif_tag(self, "Exif.MinoltaCs5D.Rotation")) {
-            long orientation = gexiv2_metadata_get_exif_tag_long(self, "Exif.MinoltaCs5D.Rotation", nullptr);
+            long orientation = gexiv2_metadata_get_exif_tag_long(self, "Exif.MinoltaCs5D.Rotation", error);
+            if (error && *error) {
+                return GEXIV2_ORIENTATION_UNSPECIFIED;
+            }
+
             switch (orientation) {
                 case 76:
                     return GEXIV2_ORIENTATION_ROT_90;
-                
                 case 82:
                     return GEXIV2_ORIENTATION_ROT_270;
                 case 72:
@@ -783,17 +879,23 @@ GExiv2Orientation gexiv2_metadata_get_orientation (GExiv2Metadata *self) {
                     g_debug ("Unknown Minolta rotation value %ld, ignoring", orientation);
             }
         }
-        
-        GExiv2Orientation orientation = (GExiv2Orientation) gexiv2_metadata_get_exif_tag_long(self,
-            "Exif.Image.Orientation", nullptr);
+
+        GExiv2Orientation orientation =
+            (GExiv2Orientation) gexiv2_metadata_get_exif_tag_long(self, "Exif.Image.Orientation", error);
+        if (error && *error) {
+            return GEXIV2_ORIENTATION_UNSPECIFIED;
+        }
+
         if (orientation >= GEXIV2_ORIENTATION_MIN && orientation <= GEXIV2_ORIENTATION_MAX)
             return orientation;
     }
     
     GExiv2Orientation orientation = GEXIV2_ORIENTATION_UNSPECIFIED;
     if (gexiv2_metadata_has_xmp_tag(self, "Xmp.tiff.ImageWidth")) {
-        orientation = (GExiv2Orientation) gexiv2_metadata_get_xmp_tag_long(self,
-            "Xmp.tiff.ImageWidth", nullptr);
+        orientation = (GExiv2Orientation) gexiv2_metadata_get_xmp_tag_long(self, "Xmp.tiff.ImageWidth", 
error);
+        if (error && *error) {
+            return GEXIV2_ORIENTATION_UNSPECIFIED;
+        }
     }
     
     return (orientation < GEXIV2_ORIENTATION_MIN || orientation > GEXIV2_ORIENTATION_MAX)
@@ -802,250 +904,399 @@ GExiv2Orientation gexiv2_metadata_get_orientation (GExiv2Metadata *self) {
 
 gboolean gexiv2_metadata_get_supports_exif (GExiv2Metadata *self) {
     g_return_val_if_fail(GEXIV2_IS_METADATA (self), FALSE);
-    g_return_val_if_fail(self->priv->image.get() != NULL, FALSE);
-    
+    g_return_val_if_fail(self->priv != nullptr, FALSE);
+    g_return_val_if_fail(self->priv->image.get() != nullptr, FALSE);
+
     return self->priv->supports_exif;
 }
 
 gboolean gexiv2_metadata_get_supports_xmp (GExiv2Metadata *self) {
     g_return_val_if_fail(GEXIV2_IS_METADATA (self), FALSE);
-    g_return_val_if_fail(self->priv->image.get() != NULL, FALSE);
-    
+    g_return_val_if_fail(self->priv != nullptr, FALSE);
+    g_return_val_if_fail(self->priv->image.get() != nullptr, FALSE);
+
     return self->priv->supports_xmp;
 }
 
 gboolean gexiv2_metadata_get_supports_iptc (GExiv2Metadata *self) {
     g_return_val_if_fail(GEXIV2_IS_METADATA (self), FALSE);
-    g_return_val_if_fail(self->priv->image.get() != NULL, FALSE);
-    
+    g_return_val_if_fail(self->priv != nullptr, FALSE);
+    g_return_val_if_fail(self->priv->image.get() != nullptr, FALSE);
+
     return self->priv->supports_iptc;
 }
 
 void gexiv2_metadata_set_orientation (GExiv2Metadata *self, GExiv2Orientation orientation) {
+    GError* error = nullptr;
+
+    gexiv2_metadata_try_set_orientation(self, orientation, &error);
+
+    if (error) {
+        g_warning("%s", error->message);
+        g_clear_error(&error);
+    }
+}
+
+void gexiv2_metadata_try_set_orientation(GExiv2Metadata* self, GExiv2Orientation orientation, GError** 
error) {
     g_return_if_fail(GEXIV2_IS_METADATA (self));
-    g_return_if_fail(self->priv->image.get() != NULL);
+    g_return_if_fail(self->priv->image.get() != nullptr);
     g_return_if_fail(orientation <= GEXIV2_ORIENTATION_ROT_270);
     g_return_if_fail(orientation >= GEXIV2_ORIENTATION_UNSPECIFIED);
-    
-    Exiv2::ExifData& exif_data = self->priv->image->exifData();
-    Exiv2::XmpData& xmp_data = self->priv->image->xmpData();
-    
-    exif_data["Exif.Image.Orientation"] = static_cast<uint16_t> (orientation);
-    xmp_data["Xmp.tiff.Orientation"] = static_cast<uint16_t> (orientation);
-    
-    gexiv2_metadata_clear_exif_tag(self, "Exif.MinoltaCs7D.Rotation");
-    gexiv2_metadata_clear_exif_tag(self, "Exif.MinoltaCs5D.Rotation");
+    g_return_if_fail(error == nullptr || *error == nullptr);
+
+    try {
+        Exiv2::ExifData& exif_data = self->priv->image->exifData();
+        Exiv2::XmpData& xmp_data = self->priv->image->xmpData();
+
+        exif_data["Exif.Image.Orientation"] = static_cast<uint16_t>(orientation);
+        xmp_data["Xmp.tiff.Orientation"] = static_cast<uint16_t>(orientation);
+
+        gexiv2_metadata_clear_exif_tag(self, "Exif.MinoltaCs7D.Rotation");
+        gexiv2_metadata_clear_exif_tag(self, "Exif.MinoltaCs5D.Rotation");
+    } catch (Exiv2::Error& e) {
+        g_set_error_literal(error, g_quark_from_string("GExiv2"), e.code(), e.what());
+    }
 }
 
 gint gexiv2_metadata_get_pixel_width (GExiv2Metadata *self) {
     g_return_val_if_fail(GEXIV2_IS_METADATA (self), -1);
-    g_return_val_if_fail(self->priv->image.get() != NULL, -1);
-    
+    g_return_val_if_fail(self->priv != nullptr, -1);
+    g_return_val_if_fail(self->priv->image.get() != nullptr, -1);
+
     return self->priv->pixel_width;
 }
 
 gint gexiv2_metadata_get_pixel_height (GExiv2Metadata *self) {
     g_return_val_if_fail (GEXIV2_IS_METADATA (self), -1);
-    g_return_val_if_fail(self->priv->image.get() != NULL, -1);
-    
+    g_return_val_if_fail(self->priv != nullptr, -1);
+    g_return_val_if_fail(self->priv->image.get() != nullptr, -1);
+
     return self->priv->pixel_height;
 }
 
 gint gexiv2_metadata_get_metadata_pixel_width (GExiv2Metadata *self) {
+    GError* error = nullptr;
+    gint value = -1;
+
+    value = gexiv2_metadata_try_get_metadata_pixel_width(self, &error);
+
+    if (error) {
+        g_warning("%s", error->message);
+        g_clear_error(&error);
+    }
+
+    return value;
+}
+
+gint gexiv2_metadata_try_get_metadata_pixel_width(GExiv2Metadata* self, GError** error) {
     g_return_val_if_fail (GEXIV2_IS_METADATA (self), -1);
-    g_return_val_if_fail(self->priv->image.get() != NULL, -1);
-    
+    g_return_val_if_fail(self->priv->image.get() != nullptr, -1);
+    g_return_val_if_fail(error == nullptr || *error == nullptr, -1);
+
     if (gexiv2_metadata_has_exif(self)) {
         if (gexiv2_metadata_has_exif_tag(self, "Exif.Photo.PixelXDimension"))
-            return gexiv2_metadata_get_exif_tag_long(self, "Exif.Photo.PixelXDimension", nullptr);
-        
+            return gexiv2_metadata_get_exif_tag_long(self, "Exif.Photo.PixelXDimension", error);
+
         if (gexiv2_metadata_has_exif_tag(self, "Exif.Image.ImageWidth"))
-            return gexiv2_metadata_get_exif_tag_long(self, "Exif.Image.ImageWidth", nullptr);
+            return gexiv2_metadata_get_exif_tag_long(self, "Exif.Image.ImageWidth", error);
     }
     
     if (gexiv2_metadata_has_xmp(self)) {
         if (gexiv2_metadata_has_xmp_tag(self, "Xmp.tiff.ImageWidth"))
-            return gexiv2_metadata_get_xmp_tag_long(self, "Xmp.tiff.ImageWidth", nullptr);
-        
+            return gexiv2_metadata_get_xmp_tag_long(self, "Xmp.tiff.ImageWidth", error);
+
         if (gexiv2_metadata_has_xmp_tag(self, "Xmp.exif.PixelXDimension"))
-            return gexiv2_metadata_get_xmp_tag_long(self, "Xmp.exif.PixelXDimension", nullptr);
+            return gexiv2_metadata_get_xmp_tag_long(self, "Xmp.exif.PixelXDimension", error);
     }
     
     return -1;
 }
 
 gint gexiv2_metadata_get_metadata_pixel_height (GExiv2Metadata *self) {
+    GError* error = nullptr;
+    gint value = -1;
+
+    value = gexiv2_metadata_try_get_metadata_pixel_height(self, &error);
+
+    if (error) {
+        g_warning("%s", error->message);
+        g_clear_error(&error);
+    }
+
+    return value;
+}
+
+gint gexiv2_metadata_try_get_metadata_pixel_height(GExiv2Metadata* self, GError** error) {
     g_return_val_if_fail (GEXIV2_IS_METADATA (self), -1);
-    g_return_val_if_fail(self->priv->image.get() != NULL, -1);
-    
+    g_return_val_if_fail(self->priv->image.get() != nullptr, -1);
+    g_return_val_if_fail(error == nullptr || *error == nullptr, -1);
+
     if (gexiv2_metadata_has_exif(self)) {
         if (gexiv2_metadata_has_exif_tag(self, "Exif.Photo.PixelYDimension"))
-            return gexiv2_metadata_get_exif_tag_long(self, "Exif.Photo.PixelYDimension", nullptr);
-        
+            return gexiv2_metadata_get_exif_tag_long(self, "Exif.Photo.PixelYDimension", error);
+
         if (gexiv2_metadata_has_exif_tag(self, "Exif.Image.ImageLength"))
-            return gexiv2_metadata_get_exif_tag_long(self, "Exif.Image.ImageLength", nullptr);
+            return gexiv2_metadata_get_exif_tag_long(self, "Exif.Image.ImageLength", error);
     }
     
     if (gexiv2_metadata_has_xmp(self)) {
         if (gexiv2_metadata_has_xmp_tag(self, "Xmp.tiff.ImageHeight"))
-            return gexiv2_metadata_get_xmp_tag_long(self, "Xmp.tiff.ImageHeight", nullptr);
-            
+            return gexiv2_metadata_get_xmp_tag_long(self, "Xmp.tiff.ImageHeight", error);
+
         if (gexiv2_metadata_has_xmp_tag(self, "Xmp.exif.PixelYDimension"))
-            return gexiv2_metadata_get_xmp_tag_long(self, "Xmp.exif.PixelYDimension", nullptr);
+            return gexiv2_metadata_get_xmp_tag_long(self, "Xmp.exif.PixelYDimension", error);
     }
     
     return -1;
 }
 
 void gexiv2_metadata_set_metadata_pixel_width (GExiv2Metadata *self, gint width) {
+    GError* error = nullptr;
+
+    gexiv2_metadata_try_set_metadata_pixel_width(self, width, &error);
+
+    if (error) {
+        g_warning("%s", error->message);
+        g_clear_error(&error);
+    }
+}
+
+void gexiv2_metadata_try_set_metadata_pixel_width(GExiv2Metadata* self, gint width, GError** error) {
     g_return_if_fail(GEXIV2_IS_METADATA (self));
-    g_return_if_fail(self->priv->image.get() != NULL);
-    
-    Exiv2::ExifData& exif_data = self->priv->image->exifData();
-    Exiv2::XmpData& xmp_data = self->priv->image->xmpData();
-    
-    exif_data["Exif.Photo.PixelXDimension"] = static_cast<uint32_t>(width);
-    exif_data["Exif.Image.ImageWidth"] = static_cast<uint32_t>(width);
-    xmp_data["Xmp.tiff.ImageWidth"] = static_cast<uint32_t>(width);
-    xmp_data["Xmp.exif.PixelXDimension"] = static_cast<uint32_t>(width);
+    g_return_if_fail(self->priv->image.get() != nullptr);
+    g_return_if_fail(error == nullptr || *error == nullptr);
+
+    try {
+        Exiv2::ExifData& exif_data = self->priv->image->exifData();
+        Exiv2::XmpData& xmp_data = self->priv->image->xmpData();
+
+        exif_data["Exif.Photo.PixelXDimension"] = static_cast<uint32_t>(width);
+        exif_data["Exif.Image.ImageWidth"] = static_cast<uint32_t>(width);
+        xmp_data["Xmp.tiff.ImageWidth"] = static_cast<uint32_t>(width);
+        xmp_data["Xmp.exif.PixelXDimension"] = static_cast<uint32_t>(width);
+    } catch (Exiv2::Error& e) {
+        g_set_error_literal(error, g_quark_from_string("GExiv2"), e.code(), e.what());
+    }
 }
 
 void gexiv2_metadata_set_metadata_pixel_height (GExiv2Metadata *self, gint height) {
+    GError* error = nullptr;
+
+    gexiv2_metadata_try_set_metadata_pixel_height(self, height, &error);
+
+    if (error) {
+        g_warning("%s", error->message);
+        g_clear_error(&error);
+    }
+}
+
+void gexiv2_metadata_try_set_metadata_pixel_height(GExiv2Metadata* self, gint height, GError** error) {
     g_return_if_fail(GEXIV2_IS_METADATA (self));
     g_return_if_fail(self->priv->image.get() != NULL);
-    
-    Exiv2::ExifData& exif_data = self->priv->image->exifData();
-    Exiv2::XmpData& xmp_data = self->priv->image->xmpData();
-    
-    exif_data ["Exif.Photo.PixelYDimension"] = static_cast<uint32_t>(height);
-    exif_data ["Exif.Image.ImageLength"] = static_cast<uint32_t>(height);
-    xmp_data ["Xmp.tiff.ImageLength"] = static_cast<uint32_t>(height);
-    xmp_data ["Xmp.exif.PixelYDimension"] = static_cast<uint32_t>(height);
+    g_return_if_fail(error == nullptr || *error == nullptr);
+
+    try {
+        Exiv2::ExifData& exif_data = self->priv->image->exifData();
+        Exiv2::XmpData& xmp_data = self->priv->image->xmpData();
+
+        exif_data["Exif.Photo.PixelYDimension"] = static_cast<uint32_t>(height);
+        exif_data["Exif.Image.ImageLength"] = static_cast<uint32_t>(height);
+        xmp_data["Xmp.tiff.ImageLength"] = static_cast<uint32_t>(height);
+        xmp_data["Xmp.exif.PixelYDimension"] = static_cast<uint32_t>(height);
+    } catch (Exiv2::Error& e) {
+        g_set_error_literal(error, g_quark_from_string("GExiv2"), e.code(), e.what());
+    }
 }
 
 gchar* gexiv2_metadata_get_comment (GExiv2Metadata *self) {
-    g_return_val_if_fail(GEXIV2_IS_METADATA (self), NULL);
-    g_return_val_if_fail(self->priv->image.get() != NULL, NULL);
-    
+    GError* error = nullptr;
+    gchar* value = nullptr;
+
+    value = gexiv2_metadata_try_get_comment(self, &error);
+
+    if (error) {
+        g_warning("%s", error->message);
+        g_clear_error(&error);
+    }
+
+    return value;
+}
+
+gchar* gexiv2_metadata_try_get_comment(GExiv2Metadata* self, GError** error) {
+    g_return_val_if_fail(GEXIV2_IS_METADATA(self), nullptr);
+    g_return_val_if_fail(self->priv->image.get() != nullptr, nullptr);
+    g_return_val_if_fail(error == nullptr || *error == nullptr, nullptr);
+
     gchar* str = self->priv->comment;
-    if (str != NULL && *str != '\0')
+    if (str != nullptr && *str != '\0')
         return g_strdup(str);
-    
-    str = gexiv2_metadata_get_exif_tag_interpreted_string (self, "Exif.Image.ImageDescription", NULL);
-    if (str != NULL && *str != '\0')
+
+    str = gexiv2_metadata_get_exif_tag_interpreted_string(self, "Exif.Image.ImageDescription", error);
+    if (error && *error) {
+        return nullptr;
+    }
+
+    if (str != nullptr && *str != '\0')
         return str;
     else
         g_free (str);
-    
-    str = gexiv2_metadata_get_exif_tag_interpreted_string (self, "Exif.Photo.UserComment", NULL);
-    if (str != NULL && *str != '\0')
+
+    str = gexiv2_metadata_get_exif_tag_interpreted_string(self, "Exif.Photo.UserComment", error);
+    if (error && *error) {
+        return nullptr;
+    }
+
+    if (str != nullptr && *str != '\0')
         return str;
     else
         g_free (str);
-    
-    str = gexiv2_metadata_get_exif_tag_interpreted_string (self, "Exif.Image.XPComment", NULL);
-    if (str != NULL && *str != '\0')
+
+    str = gexiv2_metadata_get_exif_tag_interpreted_string(self, "Exif.Image.XPComment", error);
+    if (error && *error) {
+        return nullptr;
+    }
+
+    if (str != nullptr && *str != '\0')
         return str;
     else
         g_free (str);
-    
-    str = gexiv2_metadata_get_iptc_tag_interpreted_string (self, "Iptc.Application2.Caption", NULL);
-    if (str != NULL && *str != '\0')
+
+    str = gexiv2_metadata_get_iptc_tag_interpreted_string(self, "Iptc.Application2.Caption", error);
+    if (error && *error) {
+        return nullptr;
+    }
+
+    if (str != nullptr && *str != '\0')
         return str;
     else
         g_free (str);
-    
-    str = gexiv2_metadata_get_xmp_tag_interpreted_string (self, "Xmp.dc.description", NULL);
-    if (str != NULL && *str != '\0')
+
+    str = gexiv2_metadata_get_xmp_tag_interpreted_string(self, "Xmp.dc.description", error);
+    if (error && *error) {
+        return nullptr;
+    }
+
+    if (str != nullptr && *str != '\0')
         return str;
     else
         g_free (str);
-    
-    str = gexiv2_metadata_get_xmp_tag_interpreted_string (self, "Xmp.acdsee.notes", NULL);
-    if (str != NULL && *str != '\0')
+
+    str = gexiv2_metadata_get_xmp_tag_interpreted_string(self, "Xmp.acdsee.notes", error);
+    if (error && *error) {
+        return nullptr;
+    }
+
+    if (str != nullptr && *str != '\0')
         return str;
     else
         g_free (str);
-    
-    return NULL;
+
+    return nullptr;
+}
+
+void gexiv2_metadata_set_comment (GExiv2Metadata *self, const gchar* comment) {
+    GError* error = nullptr;
+
+    gexiv2_metadata_try_set_comment(self, comment, &error);
+
+    if (error) {
+        g_warning("%s", error->message);
+        g_clear_error(&error);
+    }
 }
 
-void gexiv2_metadata_set_comment (GExiv2Metadata *self, const gchar* comment) {
+void gexiv2_metadata_try_set_comment(GExiv2Metadata* self, const gchar* comment, GError** error) {
     g_return_if_fail(GEXIV2_IS_METADATA (self));
-    g_return_if_fail(self->priv->image.get() != NULL);
-    g_return_if_fail(comment != NULL);
-    
-    Exiv2::ExifData& exif_data = self->priv->image->exifData();
-    Exiv2::IptcData& iptc_data = self->priv->image->iptcData();
-    Exiv2::XmpData& xmp_data = self->priv->image->xmpData();
-    
-    gexiv2_metadata_set_comment_internal (self, comment);
-    exif_data ["Exif.Image.ImageDescription"] = comment;
-    exif_data ["Exif.Photo.UserComment"] = comment;
-    exif_data ["Exif.Image.XPComment"] = comment;
-    iptc_data ["Iptc.Application2.Caption"] = comment;
-    xmp_data ["Xmp.dc.description"] = comment;
-    /* Do not need to write to acdsee properties, just read from them */ 
-    // xmp_data ["Xmp.acdsee.notes"] = comment;
+    g_return_if_fail(self->priv->image.get() != nullptr);
+    g_return_if_fail(comment != nullptr);
+    g_return_if_fail(error == nullptr || *error == nullptr);
+
+    try {
+        Exiv2::ExifData& exif_data = self->priv->image->exifData();
+        Exiv2::IptcData& iptc_data = self->priv->image->iptcData();
+        Exiv2::XmpData& xmp_data = self->priv->image->xmpData();
+
+        gexiv2_metadata_set_comment_internal(self, comment);
+
+        exif_data["Exif.Image.ImageDescription"] = comment;
+        exif_data["Exif.Photo.UserComment"] = comment;
+        exif_data["Exif.Image.XPComment"] = comment;
+        iptc_data["Iptc.Application2.Caption"] = comment;
+        xmp_data["Xmp.dc.description"] = comment;
+        /* Do not need to write to acdsee properties, just read from them */
+        // xmp_data ["Xmp.acdsee.notes"] = comment;
+    } catch (Exiv2::Error& e) {
+        g_set_error_literal(error, g_quark_from_string("GExiv2"), e.code(), e.what());
+    }
 }
 
 void gexiv2_metadata_clear_comment (GExiv2Metadata *self) {
     g_return_if_fail(GEXIV2_IS_METADATA (self));
-    g_return_if_fail(self->priv->image.get() != NULL);
+    g_return_if_fail(self->priv->image.get() != nullptr);
 
     /* don't delete the comment field, merely empty it */
     gexiv2_metadata_set_comment_internal (self, "");
 }
 
 gboolean gexiv2_metadata_is_exif_tag(const gchar* tag) {
-    g_return_val_if_fail(tag != NULL, FALSE);
-    
-    return g_ascii_strncasecmp("Exif.", tag, 5) == 0;
+    g_return_val_if_fail(tag != nullptr, FALSE);
+
+    return strncmp("Exif.", tag, 4) == 0;
 }
 
 gboolean gexiv2_metadata_is_xmp_tag(const gchar* tag) {
-    g_return_val_if_fail(tag != NULL, FALSE);
-    
-    return g_ascii_strncasecmp("Xmp.", tag, 4) == 0;
+    g_return_val_if_fail(tag != nullptr, FALSE);
+
+    return strncmp("Xmp.", tag, 4) == 0;
 }
 
 gboolean gexiv2_metadata_is_iptc_tag(const gchar* tag) {
-    g_return_val_if_fail(tag != NULL, FALSE);
-    
-    return g_ascii_strncasecmp("Iptc.", tag, 5) == 0;
+    g_return_val_if_fail(tag != nullptr, FALSE);
+
+    return strncmp("Iptc.", tag, 5) == 0;
 }
 
 gchar* gexiv2_metadata_try_get_tag_string (GExiv2Metadata *self, const gchar* tag, GError **error) {
     g_return_val_if_fail(GEXIV2_IS_METADATA (self), nullptr);
     g_return_val_if_fail(tag != nullptr, nullptr);
     g_return_val_if_fail(self->priv->image.get() != nullptr, nullptr);
-    
+    g_return_val_if_fail(error == nullptr || *error == nullptr, nullptr);
+
     if (gexiv2_metadata_is_xmp_tag(tag))
         return gexiv2_metadata_get_xmp_tag_string (self, tag, error);
-        
+
     if (gexiv2_metadata_is_exif_tag(tag))
         return gexiv2_metadata_get_exif_tag_string (self, tag, error);
-        
+
     if (gexiv2_metadata_is_iptc_tag(tag))
         return gexiv2_metadata_get_iptc_tag_string (self, tag, error);
-    
-    return NULL;
+
+    // Invalid "familyName"
+    Exiv2::Error e(Exiv2::ErrorCode::kerInvalidKey, tag);
+    g_set_error_literal(error, g_quark_from_string("GExiv2"), e.code(), e.what());
+
+    return nullptr;
 }
 
 gboolean gexiv2_metadata_try_set_tag_string (GExiv2Metadata *self, const gchar* tag, const gchar* value, 
GError **error) {
     g_return_val_if_fail(GEXIV2_IS_METADATA(self), FALSE);
     g_return_val_if_fail(tag != nullptr, FALSE);
     g_return_val_if_fail(self->priv->image.get() != nullptr, FALSE);
-    
+    g_return_val_if_fail(error == nullptr || *error == nullptr, FALSE);
+
     if (gexiv2_metadata_is_xmp_tag(tag))
         return gexiv2_metadata_set_xmp_tag_string(self, tag, value, error);
-    
+
     if (gexiv2_metadata_is_exif_tag(tag))
         return gexiv2_metadata_set_exif_tag_string(self, tag, value, error);
-    
+
     if (gexiv2_metadata_is_iptc_tag(tag))
         return gexiv2_metadata_set_iptc_tag_string(self, tag, value, error);
-    
+
+    // Invalid "familyName"
+    Exiv2::Error e(Exiv2::ErrorCode::kerInvalidKey, tag);
+    g_set_error_literal(error, g_quark_from_string("GExiv2"), e.code(), e.what());
+
     return FALSE;
 }
 
@@ -1086,20 +1337,25 @@ gboolean gexiv2_metadata_set_tag_string (GExiv2Metadata *self, const gchar* tag,
 }
 
 gchar* gexiv2_metadata_try_get_tag_interpreted_string (GExiv2Metadata *self, const gchar* tag, GError 
**error) {
-    g_return_val_if_fail(GEXIV2_IS_METADATA (self), NULL);
-    g_return_val_if_fail(tag != NULL, NULL);
-    g_return_val_if_fail(self->priv->image.get() != NULL, NULL);
-    
+    g_return_val_if_fail(GEXIV2_IS_METADATA(self), nullptr);
+    g_return_val_if_fail(tag != nullptr, nullptr);
+    g_return_val_if_fail(self->priv->image.get() != nullptr, nullptr);
+    g_return_val_if_fail(error == nullptr || *error == nullptr, nullptr);
+
     if (gexiv2_metadata_is_xmp_tag(tag))
-        return gexiv2_metadata_get_xmp_tag_interpreted_string (self, tag, error);
-        
+        return gexiv2_metadata_get_xmp_tag_interpreted_string(self, tag, error);
+
     if (gexiv2_metadata_is_exif_tag(tag))
-        return gexiv2_metadata_get_exif_tag_interpreted_string (self, tag, error);
-        
+        return gexiv2_metadata_get_exif_tag_interpreted_string(self, tag, error);
+
     if (gexiv2_metadata_is_iptc_tag(tag))
-        return gexiv2_metadata_get_iptc_tag_interpreted_string (self, tag, error);
-    
-    return NULL;
+        return gexiv2_metadata_get_iptc_tag_interpreted_string(self, tag, error);
+
+    // Invalid "familyName"
+    Exiv2::Error e(Exiv2::ErrorCode::kerInvalidKey, tag);
+    g_set_error_literal(error, g_quark_from_string("GExiv2"), e.code(), e.what());
+
+    return nullptr;
 }
 
 gchar* gexiv2_metadata_get_tag_interpreted_string (GExiv2Metadata *self, const gchar* tag) {
@@ -1124,6 +1380,7 @@ gchar** gexiv2_metadata_try_get_tag_multiple(GExiv2Metadata *self, const gchar*
     g_return_val_if_fail(GEXIV2_IS_METADATA(self), nullptr);
     g_return_val_if_fail(tag != nullptr, nullptr);
     g_return_val_if_fail(self->priv->image.get() != nullptr, nullptr);
+    g_return_val_if_fail(error == nullptr || *error == nullptr, nullptr);
 
     if (gexiv2_metadata_is_xmp_tag(tag))
         return gexiv2_metadata_get_xmp_tag_multiple(self, tag, error);
@@ -1134,7 +1391,11 @@ gchar** gexiv2_metadata_try_get_tag_multiple(GExiv2Metadata *self, const gchar*
     if (gexiv2_metadata_is_iptc_tag(tag))
         return gexiv2_metadata_get_iptc_tag_multiple(self, tag, error);
 
-    return NULL;
+    // Invalid "familyName"
+    Exiv2::Error e(Exiv2::ErrorCode::kerInvalidKey, tag);
+    g_set_error_literal(error, g_quark_from_string("GExiv2"), e.code(), e.what());
+
+    return nullptr;
 }
 
 gboolean gexiv2_metadata_try_set_tag_multiple(GExiv2Metadata *self, const gchar* tag, const gchar** values, 
GError **error) {
@@ -1142,6 +1403,7 @@ gboolean gexiv2_metadata_try_set_tag_multiple(GExiv2Metadata *self, const gchar*
     g_return_val_if_fail(tag != nullptr, FALSE);
     g_return_val_if_fail(values != nullptr, FALSE);
     g_return_val_if_fail(self->priv->image.get() != nullptr, FALSE);
+    g_return_val_if_fail(error == nullptr || *error == nullptr, FALSE);
 
     if (gexiv2_metadata_is_xmp_tag(tag))
         return gexiv2_metadata_set_xmp_tag_multiple(self, tag, values, error);
@@ -1152,6 +1414,10 @@ gboolean gexiv2_metadata_try_set_tag_multiple(GExiv2Metadata *self, const gchar*
     if (gexiv2_metadata_is_iptc_tag(tag))
         return gexiv2_metadata_set_iptc_tag_multiple(self, tag, values, error);
 
+    // Invalid "familyName"
+    Exiv2::Error e(Exiv2::ErrorCode::kerInvalidKey, tag);
+    g_set_error_literal(error, g_quark_from_string("GExiv2"), e.code(), e.what());
+
     return FALSE;
 }
 
@@ -1164,18 +1430,39 @@ gchar** gexiv2_metadata_get_tag_multiple(GExiv2Metadata* self, const gchar* tag)
     g_return_val_if_fail(self->priv != nullptr, nullptr);
     g_return_val_if_fail(self->priv->image.get() != nullptr, nullptr);
 
-    if (gexiv2_metadata_is_xmp_tag(tag))
+    if (gexiv2_metadata_is_xmp_tag(tag)) {
         tags = gexiv2_metadata_get_xmp_tag_multiple_deprecated(self, tag, &error);
-    else if (gexiv2_metadata_is_exif_tag(tag))
+        if (error) {
+            g_warning("%s", error->message);
+            g_clear_error(&error);
+        }
+        return tags;
+    }
+
+    if (gexiv2_metadata_is_exif_tag(tag)) {
         tags = gexiv2_metadata_get_exif_tag_multiple(self, tag, &error);
-    else if (gexiv2_metadata_is_iptc_tag(tag))
-        tags = gexiv2_metadata_get_iptc_tag_multiple(self, tag, &error);
+        if (error) {
+            g_warning("%s", error->message);
+            g_clear_error(&error);
+        }
+        return tags;
+    }
 
-    if (error) {
-        g_warning("%s", error->message);
-        g_clear_error(&error);
+    if (gexiv2_metadata_is_iptc_tag(tag)) {
+        tags = gexiv2_metadata_get_iptc_tag_multiple(self, tag, &error);
+        if (error) {
+            g_warning("%s", error->message);
+            g_clear_error(&error);
+        }
+        return tags;
     }
 
+    // Invalid "familyName"
+    Exiv2::Error e(Exiv2::ErrorCode::kerInvalidKey, tag);
+    g_set_error_literal(&error, g_quark_from_string("GExiv2"), e.code(), e.what());
+    g_warning("%s", error->message);
+    g_clear_error(&error);
+
     return tags;
 }
 
@@ -1200,15 +1487,20 @@ gboolean gexiv2_metadata_set_tag_multiple(GExiv2Metadata *self, const gchar* tag
 
 glong gexiv2_metadata_try_get_tag_long(GExiv2Metadata *self, const gchar* tag, GError **error) {
     g_return_val_if_fail(GEXIV2_IS_METADATA(self), 0);
-    g_return_val_if_fail(tag != NULL, 0);
-    g_return_val_if_fail(self->priv->image.get() != NULL, 0);
-    
+    g_return_val_if_fail(tag != nullptr, 0);
+    g_return_val_if_fail(self->priv->image.get() != nullptr, 0);
+    g_return_val_if_fail(error == nullptr || *error == nullptr, 0);
+
     if (gexiv2_metadata_is_xmp_tag(tag))
         return gexiv2_metadata_get_xmp_tag_long(self, tag, error);
-    
+
     if (gexiv2_metadata_is_exif_tag(tag))
         return gexiv2_metadata_get_exif_tag_long(self, tag, error);
-    
+
+    // Invalid "familyName"
+    Exiv2::Error e(Exiv2::ErrorCode::kerInvalidKey, tag);
+    g_set_error_literal(error, g_quark_from_string("GExiv2"), e.code(), e.what());
+
     return 0;
 }
 
@@ -1232,15 +1524,20 @@ glong gexiv2_metadata_get_tag_long(GExiv2Metadata *self, const gchar* tag) {
 
 gboolean gexiv2_metadata_try_set_tag_long(GExiv2Metadata *self, const gchar* tag, glong value, GError 
**error) {
     g_return_val_if_fail(GEXIV2_IS_METADATA(self), FALSE);
-    g_return_val_if_fail(tag != NULL, FALSE);
-    g_return_val_if_fail(self->priv->image.get() != NULL, 0);
-    
+    g_return_val_if_fail(tag != nullptr, FALSE);
+    g_return_val_if_fail(self->priv->image.get() != nullptr, 0);
+    g_return_val_if_fail(error == nullptr || *error == nullptr, FALSE);
+
     if (gexiv2_metadata_is_xmp_tag(tag))
         return gexiv2_metadata_set_xmp_tag_long(self, tag, value, error);
-    
+
     if (gexiv2_metadata_is_exif_tag(tag))
         return gexiv2_metadata_set_exif_tag_long(self, tag, value, error);
-    
+
+    // Invalid "familyName"
+    Exiv2::Error e(Exiv2::ErrorCode::kerInvalidKey, tag);
+    g_set_error_literal(error, g_quark_from_string("GExiv2"), e.code(), e.what());
+
     return FALSE;
 }
 
@@ -1263,15 +1560,50 @@ gboolean gexiv2_metadata_set_tag_long(GExiv2Metadata *self, const gchar* tag, gl
 }
 
 gboolean gexiv2_metadata_get_exposure_time (GExiv2Metadata *self, gint *nom, gint *den) {
-    return gexiv2_metadata_try_get_exif_tag_rational (self, "Exif.Photo.ExposureTime", nom, den, nullptr);
+    GError* error = nullptr;
+    gboolean value = FALSE;
+
+    value = gexiv2_metadata_try_get_exposure_time(self, nom, den, &error);
+
+    if (error) {
+        g_warning("%s", error->message);
+        g_clear_error(&error);
+    }
+
+    return value;
+}
+
+gboolean gexiv2_metadata_try_get_exposure_time(GExiv2Metadata* self, gint* nom, gint* den, GError** error) {
+    return gexiv2_metadata_try_get_exif_tag_rational(self, "Exif.Photo.ExposureTime", nom, den, error);
 }
 
 gdouble gexiv2_metadata_get_fnumber (GExiv2Metadata *self) {
-    gdouble fnumber = gexiv2_metadata_get_exif_tag_rational_as_double(self, "Exif.Photo.FNumber", -1.0);
+    GError* error = nullptr;
+    gdouble value = -1.0;
+
+    value = gexiv2_metadata_try_get_fnumber(self, &error);
+
+    if (error) {
+        g_warning("%s", error->message);
+        g_clear_error(&error);
+    }
+
+    return value;
+}
+
+gdouble gexiv2_metadata_try_get_fnumber(GExiv2Metadata* self, GError** error) {
+    g_return_val_if_fail(error == nullptr || *error == nullptr, FALSE);
+
+    gdouble fnumber = gexiv2_metadata_get_exif_tag_rational_as_double(self, "Exif.Photo.FNumber", -1.0, 
error);
+    if (error && *error)
+        return -1.0;
+
     if (fnumber == -1.0) {
-        gdouble aperture_value = gexiv2_metadata_get_exif_tag_rational_as_double(self,
-                                                                                 "Exif.Photo.ApertureValue",
-                                                                                 -1.0);
+        gdouble aperture_value =
+            gexiv2_metadata_get_exif_tag_rational_as_double(self, "Exif.Photo.ApertureValue", -1.0, error);
+        if (error && *error)
+            return -1.0;
+
         if (aperture_value == -1.0)
           return fnumber;
 
@@ -1282,55 +1614,101 @@ gdouble gexiv2_metadata_get_fnumber (GExiv2Metadata *self) {
 }
 
 gdouble gexiv2_metadata_get_focal_length (GExiv2Metadata *self) {
-    return gexiv2_metadata_get_exif_tag_rational_as_double(self, "Exif.Photo.FocalLength", -1.0);
+    GError* error = nullptr;
+    gdouble value = -1.0;
+
+    value = gexiv2_metadata_try_get_focal_length(self, &error);
+
+    if (error) {
+        g_warning("%s", error->message);
+        g_clear_error(&error);
+    }
+
+    return value;
+}
+
+gdouble gexiv2_metadata_try_get_focal_length(GExiv2Metadata* self, GError** error) {
+    return gexiv2_metadata_get_exif_tag_rational_as_double(self, "Exif.Photo.FocalLength", -1.0, error);
 }
 
 gint gexiv2_metadata_get_iso_speed (GExiv2Metadata *self) {
-    return (gint) gexiv2_metadata_get_exif_tag_long (self, "Exif.Photo.ISOSpeedRatings", NULL);
+    GError* error = nullptr;
+    gdouble value = -1.0;
+
+    value = gexiv2_metadata_try_get_iso_speed(self, &error);
+
+    if (error) {
+        g_warning("%s", error->message);
+        g_clear_error(&error);
+    }
+
+    return value;
+}
+
+gint gexiv2_metadata_try_get_iso_speed(GExiv2Metadata* self, GError** error) {
+    return (gint) gexiv2_metadata_get_exif_tag_long(self, "Exif.Photo.ISOSpeedRatings", error);
 }
 
 GExiv2PreviewProperties** gexiv2_metadata_get_preview_properties (GExiv2Metadata *self) {
-    g_return_val_if_fail(GEXIV2_IS_METADATA(self), NULL);
-    g_return_val_if_fail(self->priv->image.get() != NULL, NULL);
-    
+    g_return_val_if_fail(GEXIV2_IS_METADATA(self), nullptr);
+    g_return_val_if_fail(self->priv != nullptr, nullptr);
+    g_return_val_if_fail(self->priv->image.get() != nullptr, nullptr);
+
     return self->priv->preview_properties;
 }
 
 GExiv2PreviewImage* gexiv2_metadata_get_preview_image (GExiv2Metadata *self,
     GExiv2PreviewProperties *props) {
-    g_return_val_if_fail(GEXIV2_IS_METADATA(self), NULL);
-    g_return_val_if_fail(GEXIV2_IS_PREVIEW_PROPERTIES(props), NULL);
-    g_return_val_if_fail(self->priv->image.get() != NULL, NULL);
-    
-    return gexiv2_preview_image_new(self->priv->preview_manager, *props->priv->props);
+
+    GExiv2PreviewImage* value = nullptr;
+    GError* error = nullptr;
+
+    value = gexiv2_metadata_try_get_preview_image(self, props, &error);
+
+    if (error) {
+        g_warning("%s", error->message);
+        g_clear_error(&error);
+    }
+
+    return value;
+}
+
+GExiv2PreviewImage* gexiv2_metadata_try_get_preview_image(GExiv2Metadata* self,
+                                                          GExiv2PreviewProperties* props,
+                                                          GError** error) {
+    g_return_val_if_fail(GEXIV2_IS_METADATA(self), nullptr);
+    g_return_val_if_fail(GEXIV2_IS_PREVIEW_PROPERTIES(props), nullptr);
+    g_return_val_if_fail(self->priv->image.get() != nullptr, nullptr);
+    g_return_val_if_fail(error == nullptr || *error == nullptr, nullptr);
+
+    return gexiv2_preview_image_new(self->priv->preview_manager, *props->priv->props, error);
 }
 
 gboolean gexiv2_metadata_get_exif_thumbnail (GExiv2Metadata *self, guint8** buffer, gint *size) {
     g_return_val_if_fail(GEXIV2_IS_METADATA(self), FALSE);
-    g_return_val_if_fail(buffer != NULL, FALSE);
-    g_return_val_if_fail(size != NULL, FALSE);
-    g_return_val_if_fail(self->priv->image.get() != NULL, FALSE);
-    
+    g_return_val_if_fail(buffer != nullptr, FALSE);
+    g_return_val_if_fail(size != nullptr, FALSE);
+    g_return_val_if_fail(self->priv->image.get() != nullptr, FALSE);
+
     Exiv2::ExifThumb thumb = Exiv2::ExifThumb(self->priv->image->exifData());
     Exiv2::DataBuf data = thumb.copy();
-    if (data.pData_ == NULL)
+    if (data.pData_ == nullptr)
         return FALSE;
     
     *buffer = (guint8*) g_malloc(data.size_);
     memcpy(*buffer, data.pData_, data.size_);
     *size = data.size_;
-    
+
     return TRUE;
 }
 
-gboolean gexiv2_metadata_set_exif_thumbnail_from_file (GExiv2Metadata *self, const gchar *path,
-    GError **error) {
+gboolean gexiv2_metadata_set_exif_thumbnail_from_file(GExiv2Metadata* self, const gchar* path, GError** 
error) {
     g_return_val_if_fail(GEXIV2_IS_METADATA(self), FALSE);
-    g_return_val_if_fail(path != NULL && g_utf8_strlen(path, -1) > 0, FALSE);
-    g_return_val_if_fail(self->priv->image.get() != NULL, FALSE);
-    
-    Exiv2::ExifThumb thumb = Exiv2::ExifThumb(self->priv->image->exifData());
+    g_return_val_if_fail(path != nullptr && g_utf8_strlen(path, -1) > 0, FALSE);
+    g_return_val_if_fail(self->priv->image.get() != nullptr, FALSE);
+
     try {
+        Exiv2::ExifThumb thumb = Exiv2::ExifThumb(self->priv->image->exifData());
         thumb.setJpegThumbnail(std::string(path));
         
         return TRUE;
@@ -1343,35 +1721,75 @@ gboolean gexiv2_metadata_set_exif_thumbnail_from_file (GExiv2Metadata *self, con
 
 void gexiv2_metadata_set_exif_thumbnail_from_buffer (GExiv2Metadata *self, const guint8 *buffer,
     gint size) {
+    GError* error = nullptr;
+
+    gexiv2_metadata_try_set_exif_thumbnail_from_buffer(self, buffer, size, &error);
+
+    if (error) {
+        g_warning("%s", error->message);
+        g_clear_error(&error);
+    }
+}
+
+void gexiv2_metadata_try_set_exif_thumbnail_from_buffer(GExiv2Metadata* self,
+                                                        const guint8* buffer,
+                                                        gint size,
+                                                        GError** error) {
     g_return_if_fail(GEXIV2_IS_METADATA(self));
-    g_return_if_fail(buffer != NULL);
+    g_return_if_fail(buffer != nullptr);
     g_return_if_fail(size > 0);
-    g_return_if_fail(self->priv->image.get() != NULL);
-    
-    Exiv2::ExifThumb thumb = Exiv2::ExifThumb(self->priv->image->exifData());
-    thumb.setJpegThumbnail(buffer, size);
+    g_return_if_fail(self->priv->image.get() != nullptr);
+    g_return_if_fail(error == nullptr || *error == nullptr);
+
+    try {
+        Exiv2::ExifThumb thumb = Exiv2::ExifThumb(self->priv->image->exifData());
+        thumb.setJpegThumbnail(buffer, size);
+    } catch (Exiv2::Error& e) {
+        g_set_error_literal(error, g_quark_from_string("GExiv2"), e.code(), e.what());
+    }
 }
 
 void gexiv2_metadata_erase_exif_thumbnail (GExiv2Metadata *self) {
+    GError* error = nullptr;
+
+    gexiv2_metadata_try_erase_exif_thumbnail(self, &error);
+
+    if (error) {
+        g_warning("%s", error->message);
+        g_clear_error(&error);
+    }
+}
+
+void gexiv2_metadata_try_erase_exif_thumbnail(GExiv2Metadata* self, GError** error) {
     g_return_if_fail(GEXIV2_IS_METADATA(self));
-    g_return_if_fail(self->priv->image.get() != NULL);
-    
-    Exiv2::ExifThumb thumb = Exiv2::ExifThumb(self->priv->image->exifData());
-    thumb.erase();
+    g_return_if_fail(self->priv->image.get() != nullptr);
+    g_return_if_fail(error == nullptr || *error == nullptr);
+
+    try {
+        Exiv2::ExifThumb thumb = Exiv2::ExifThumb(self->priv->image->exifData());
+        thumb.erase();
+    } catch (Exiv2::Error& e) {
+        g_set_error_literal(error, g_quark_from_string("GExiv2"), e.code(), e.what());
+    }
 }
 
 const gchar* gexiv2_metadata_try_get_tag_label (const gchar *tag, GError **error) {
     g_return_val_if_fail(tag != nullptr, nullptr);
-    
+    g_return_val_if_fail(error == nullptr || *error == nullptr, nullptr);
+
     if (gexiv2_metadata_is_xmp_tag(tag))
         return gexiv2_metadata_get_xmp_tag_label(tag, error);
-    
+
     if (gexiv2_metadata_is_exif_tag(tag))
         return gexiv2_metadata_get_exif_tag_label(tag, error);
-    
+
     if (gexiv2_metadata_is_iptc_tag(tag))
         return gexiv2_metadata_get_iptc_tag_label(tag, error);
-    
+
+    // Invalid "familyName"
+    Exiv2::Error e(Exiv2::ErrorCode::kerInvalidKey, tag);
+    g_set_error_literal(error, g_quark_from_string("GExiv2"), e.code(), e.what());
+
     return nullptr;
 }
 
@@ -1393,16 +1811,21 @@ const gchar* gexiv2_metadata_get_tag_label (const gchar *tag) {
 
 const gchar* gexiv2_metadata_try_get_tag_description (const gchar *tag, GError **error) {
     g_return_val_if_fail(tag != nullptr, nullptr);
-    
+    g_return_val_if_fail(error == nullptr || *error == nullptr, nullptr);
+
     if (gexiv2_metadata_is_xmp_tag(tag))
         return gexiv2_metadata_get_xmp_tag_description(tag, error);
-    
+
     if (gexiv2_metadata_is_exif_tag(tag))
         return gexiv2_metadata_get_exif_tag_description(tag, error);
-    
+
     if (gexiv2_metadata_is_iptc_tag(tag))
         return gexiv2_metadata_get_iptc_tag_description(tag, error);
-    
+
+    // Invalid "familyName"
+    Exiv2::Error e(Exiv2::ErrorCode::kerInvalidKey, tag);
+    g_set_error_literal(error, g_quark_from_string("GExiv2"), e.code(), e.what());
+
     return nullptr;
 }
 
@@ -1423,18 +1846,23 @@ const gchar* gexiv2_metadata_get_tag_description (const gchar *tag) {
 }
 
 const gchar* gexiv2_metadata_try_get_tag_type (const gchar *tag, GError **error) {
-    g_return_val_if_fail(tag != NULL, NULL);
-    
+    g_return_val_if_fail(tag != nullptr, nullptr);
+    g_return_val_if_fail(error == nullptr || *error == nullptr, nullptr);
+
     if (gexiv2_metadata_is_xmp_tag(tag))
         return gexiv2_metadata_get_xmp_tag_type(tag, error);
-    
+
     if (gexiv2_metadata_is_exif_tag(tag))
         return gexiv2_metadata_get_exif_tag_type(tag, error);
-    
+
     if (gexiv2_metadata_is_iptc_tag(tag))
         return gexiv2_metadata_get_iptc_tag_type(tag, error);
-    
-    return NULL;
+
+    // Invalid "familyName"
+    Exiv2::Error e(Exiv2::ErrorCode::kerInvalidKey, tag);
+    g_set_error_literal(error, g_quark_from_string("GExiv2"), e.code(), e.what());
+
+    return nullptr;
 }
 
 const gchar* gexiv2_metadata_get_tag_type (const gchar *tag) {
@@ -1477,9 +1905,10 @@ gboolean gexiv2_metadata_try_tag_supports_multiple_values(GExiv2Metadata* self,
 }
 
 GBytes* gexiv2_metadata_try_get_tag_raw(GExiv2Metadata *self, const gchar* tag, GError **error) {
-    g_return_val_if_fail(GEXIV2_IS_METADATA (self), NULL);
-    g_return_val_if_fail(tag != NULL, NULL);
-    g_return_val_if_fail(self->priv->image.get() != NULL, NULL);
+    g_return_val_if_fail(GEXIV2_IS_METADATA(self), nullptr);
+    g_return_val_if_fail(tag != nullptr, nullptr);
+    g_return_val_if_fail(self->priv->image.get() != nullptr, nullptr);
+    g_return_val_if_fail(error == nullptr || *error == nullptr, nullptr);
 
     if (gexiv2_metadata_is_xmp_tag(tag))
         return gexiv2_metadata_get_xmp_tag_raw(self, tag, error);
@@ -1490,7 +1919,11 @@ GBytes* gexiv2_metadata_try_get_tag_raw(GExiv2Metadata *self, const gchar* tag,
     if (gexiv2_metadata_is_iptc_tag(tag))
         return gexiv2_metadata_get_iptc_tag_raw(self, tag, error);
 
-    return NULL;
+    // Invalid "familyName"
+    Exiv2::Error e(Exiv2::ErrorCode::kerInvalidKey, tag);
+    g_set_error_literal(error, g_quark_from_string("GExiv2"), e.code(), e.what());
+
+    return nullptr;
 }
 
 GBytes* gexiv2_metadata_get_tag_raw(GExiv2Metadata *self, const gchar* tag) {
diff --git a/gexiv2/gexiv2-metadata.h b/gexiv2/gexiv2-metadata.h
index c6c2a97..97b943f 100644
--- a/gexiv2/gexiv2-metadata.h
+++ b/gexiv2/gexiv2-metadata.h
@@ -297,6 +297,8 @@ void                        gexiv2_metadata_free                            
(GExiv2Metadata *self);
  * The file must be an image format supported by Exiv2.
  *
  * Returns: Boolean success indicator
+ *
+ *
  */
 gboolean               gexiv2_metadata_open_path                       (GExiv2Metadata *self, const gchar 
*path, GError **error);
 
@@ -310,6 +312,7 @@ gboolean            gexiv2_metadata_open_path                       (GExiv2Metadata 
*self, const gchar *path,
  * The buffer must be an image format supported by Exiv2.
  *
  * Returns: Boolean success indicator
+ *
  */
 gboolean               gexiv2_metadata_open_buf                        (GExiv2Metadata *self, const guint8 
*data, glong n_data, GError **error);
 
@@ -322,10 +325,10 @@ gboolean          gexiv2_metadata_open_buf                        (GExiv2Metadata 
*self, const guint8 *data,
  * The stream must be an image format supported by Exiv2.
  *
  * Returns: Boolean success indicator
+ *
  */
 gboolean               gexiv2_metadata_open_stream                     (GExiv2Metadata *self, 
ManagedStreamCallbacks* cb, GError **error);
 
-
 /**
  * gexiv2_metadata_from_stream:
  *
@@ -345,6 +348,7 @@ gboolean            gexiv2_metadata_from_stream                     (GExiv2Metadata 
*self, GInputStream* str
  * Load only an EXIF buffer, typically stored in a JPEG's APP1 segment.
  *
  * Returns: Boolean success indicator.
+ *
  */
 gboolean               gexiv2_metadata_from_app1_segment       (GExiv2Metadata *self, const guint8 *data, 
glong n_data, GError **error);
 
@@ -359,10 +363,10 @@ gboolean          gexiv2_metadata_from_app1_segment       (GExiv2Metadata *self, const 
guint8
  * Returns: Boolean success indicator.
  *
  * Since: 0.10.6
+ *
  */
 gboolean               gexiv2_metadata_save_external                   (GExiv2Metadata *self, const gchar 
*path, GError **error);
 
-
 /**
  * gexiv2_metadata_save_file:
  * @self: An instance of #GExiv2Metadata
@@ -373,6 +377,7 @@ gboolean            gexiv2_metadata_save_external                   (GExiv2Metadata 
*self, const gchar *pa
  * metadata into the image, then writing the image back out.
  *
  * Returns: Boolean success indicator.
+ *
  */
 gboolean               gexiv2_metadata_save_file                       (GExiv2Metadata *self, const gchar 
*path, GError **error);
 
@@ -386,6 +391,7 @@ gboolean            gexiv2_metadata_save_file                       (GExiv2Metadata 
*self, const gchar *path,
  * metadata into the image, then writing the image as a stream back out.
  *
  * Returns: Boolean success indicator.
+ *
  */
 gboolean               gexiv2_metadata_save_stream                     (GExiv2Metadata *self, 
ManagedStreamCallbacks* cb, GError **error);
 
@@ -397,9 +403,26 @@ gboolean           gexiv2_metadata_save_stream                     (GExiv2Metadata 
*self, ManagedStreamCall
  * The Exiv2 Tag Reference can be found at <ulink url="http://exiv2.org/metadata.html";></ulink>
  *
  * Returns: TRUE if the tag is present.
+ *
+ * Deprecated: 0.14.0: Use gexiv2_metadata_try_has_tag() instead.
  */
+G_DEPRECATED_FOR(gexiv2_metadata_try_has_tag)
 gboolean               gexiv2_metadata_has_tag                         (GExiv2Metadata *self, const gchar* 
tag);
 
+/**
+ * gexiv2_metadata_try_has_tag:
+ * @self: An instance of #GExiv2Metadata
+ * @tag: Exiv2 tag
+ * @error: (allow-none): A return location for a #GError or %NULL
+ *
+ * The Exiv2 Tag Reference can be found at <ulink url="http://exiv2.org/metadata.html";></ulink>
+ *
+ * Returns: TRUE if the tag is present.
+ *
+ * Since: 0.14.0
+ */
+gboolean gexiv2_metadata_try_has_tag(GExiv2Metadata* self, const gchar* tag, GError** error);
+
 /**
  * gexiv2_metadata_clear_tag:
  * @self: An instance of #GExiv2Metadata
@@ -410,9 +433,28 @@ gboolean           gexiv2_metadata_has_tag                         (GExiv2Metadata 
*self, const gchar* tag);
  * The Exiv2 Tag Reference can be found at <ulink url="http://exiv2.org/metadata.html";></ulink>
  *
  * Returns: TRUE if the tag was present.
+ *
+ * Deprecated: 0.14.0: Use gexiv2_metadata_try_clear_tag() instead.
  */
+G_DEPRECATED_FOR(gexiv2_metadata_try_clear_tag)
 gboolean               gexiv2_metadata_clear_tag                       (GExiv2Metadata *self, const gchar* 
tag);
 
+/**
+ * gexiv2_metadata_try_clear_tag:
+ * @self: An instance of #GExiv2Metadata
+ * @tag: Exiv2 tag
+ * @error: (allow-none): A return location for a #GError or %NULL
+ *
+ * Removes the Exiv2 tag from the metadata object.
+ *
+ * The Exiv2 Tag Reference can be found at <ulink url="http://exiv2.org/metadata.html";></ulink>
+ *
+ * Returns: TRUE if the tag was present.
+ *
+ * Since: 0.14.0
+ */
+gboolean gexiv2_metadata_try_clear_tag(GExiv2Metadata* self, const gchar* tag, GError** error);
+
 /**
  * gexiv2_metadata_clear:
  * @self: An instance of #GExiv2Metadata
@@ -1053,6 +1095,7 @@ gboolean          gexiv2_metadata_get_exif_thumbnail (GExiv2Metadata *self, guint8** buf
  * Sets or replaces the EXIF thumbnail with the image in the file
  *
  * Returns: Boolean success value
+ *
  */
 gboolean               gexiv2_metadata_set_exif_thumbnail_from_file (GExiv2Metadata *self, const gchar 
*path, GError **error);
 
@@ -1061,17 +1104,48 @@ gboolean                gexiv2_metadata_set_exif_thumbnail_from_file (GExiv2Metadata 
*self, co
  * @self: An instance of #GExiv2Metadata
  * @buffer: (array length=size): A buffer containing thumbnail data
  * @size: (skip): Size of the thumbnail's buffer
+ *
+ * Deprecated: 0.14.0: Use gexiv2_metadata_try_set_exif_thumbnail_from_buffer() instead.
  */
+G_DEPRECATED_FOR(gexiv2_metadata_try_set_exif_thumbnail_from_buffer)
 void                   gexiv2_metadata_set_exif_thumbnail_from_buffer (GExiv2Metadata *self, const guint8 
*buffer, gint size);
 
+/**
+ * gexiv2_metadata_try_set_exif_thumbnail_from_buffer:
+ * @self: An instance of #GExiv2Metadata
+ * @buffer: (array length=size): A buffer containing thumbnail data
+ * @size: (skip): Size of the thumbnail's buffer
+ * @error: (allow-none): A return location for a #GError or %NULL
+ *
+ * Since: 0.14.0
+ */
+void gexiv2_metadata_try_set_exif_thumbnail_from_buffer(GExiv2Metadata* self,
+                                                        const guint8* buffer,
+                                                        gint size,
+                                                        GError** error);
+
 /**
  * gexiv2_metadata_erase_exif_thumbnail:
  * @self: An instance of #GExiv2Metadata
  *
  * Removes the EXIF thumbnail from the loaded image.
+ *
+ * Deprecated: 0.14.0: Use gexiv2_metadata_try_erase_exif_thumbnail() instead.
  */
+G_DEPRECATED_FOR(gexiv2_metadata_try_erase_exif_thumbnail)
 void                   gexiv2_metadata_erase_exif_thumbnail (GExiv2Metadata *self);
 
+/**
+ * gexiv2_metadata_try_erase_exif_thumbnail:
+ * @self: An instance of #GExiv2Metadata
+ * @error: (allow-none): A return location for a #GError or %NULL
+ *
+ * Removes the EXIF thumbnail from the loaded image.
+ *
+ * Since: 0.14.0
+ */
+void gexiv2_metadata_try_erase_exif_thumbnail(GExiv2Metadata* self, GError** error);
+
 /**
  * gexiv2_metadata_get_exif_data:
  * @self: An instance of #GExiv2Metadata
@@ -1081,6 +1155,7 @@ void                      gexiv2_metadata_erase_exif_thumbnail (GExiv2Metadata *self);
  * Returns: (transfer full) (allow-none): The content of the EXIF data or %NULL on error
  *
  * Since: 0.12.2
+ *
  */
 GBytes *        gexiv2_metadata_get_exif_data (GExiv2Metadata *self, GExiv2ByteOrder byte_order, GError 
**error);
 
@@ -1170,31 +1245,86 @@ gchar**                 gexiv2_metadata_get_xmp_tags            (GExiv2Metadata 
*self);
  * @prefix: (in): XMP namespace prefix
  *
  * Returns: (skip): Boolean success value
+ *
+ * Deprecated: 0.14.0: Use gexiv2_metadata_try_register_xmp_namespace() instead.
  */
+G_DEPRECATED_FOR(gexiv2_metadata_try_register_xmp_namespace)
 gboolean        gexiv2_metadata_register_xmp_namespace (const gchar* name, const gchar *prefix);
 
+/**
+ * gexiv2_metadata_try_register_xmp_namespace:
+ * @name: (in): XMP URI name (should end in /)
+ * @prefix: (in): XMP namespace prefix
+ * @error: (allow-none): A return location for a #GError or %NULL
+ *
+ * Returns: (skip): Boolean success value
+ *
+ * Since: 0.14.0
+ */
+gboolean gexiv2_metadata_try_register_xmp_namespace(const gchar* name, const gchar* prefix, GError** error);
+
 /**
  * gexiv2_metadata_unregister_xmp_namespace:
  * @name: (in): XMP URI name (should end in /)
  *
  * Returns: (skip): Boolean success value
+ *
+ * Deprecated: 0.14.0: Use gexiv2_metadata_try_unregister_xmp_namespace() instead.
  */
+G_DEPRECATED_FOR(gexiv2_metadata_try_unregister_xmp_namespace)
 gboolean        gexiv2_metadata_unregister_xmp_namespace (const gchar* name);
 
+/**
+ * gexiv2_metadata_try_unregister_xmp_namespace:
+ * @name: (in): XMP URI name (should end in /)
+ * @error: (allow-none): A return location for a #GError or %NULL
+ *
+ * Returns: (skip): Boolean success value
+ *
+ * Since: 0.14.0
+ */
+gboolean gexiv2_metadata_try_unregister_xmp_namespace(const gchar* name, GError** error);
+
 /**
  * gexiv2_metadata_unregister_all_xmp_namespaces:
+ *
+ * Deprecated: 0.14.0: Use gexiv2_metadata_try_unregister_all_xmp_namespaces() instead.
  */
+G_DEPRECATED_FOR(gexiv2_metadata_try_unregister_all_xmp_namespaces)
 void            gexiv2_metadata_unregister_all_xmp_namespaces (void);
 
+/**
+ * gexiv2_metadata_try_unregister_all_xmp_namespaces:
+ * @error: (allow-none): A return location for a #GError or %NULL
+ *
+ * Since: 0.14.0
+ */
+void gexiv2_metadata_try_unregister_all_xmp_namespaces(GError** error);
+
 /**
  * gexiv2_metadata_get_xmp_namespace_for_tag:
- * @tag: (in): Full tag name or XMP namespace identifier
+ * @tag: (in): Full tag name (e.g. "Xmp.dc.subject") or XMP namespace identifier (e.g. "dc")
+ *
  * Returns: (transfer full): %NULL if there was no namespace registered for the tag, the URI of the 
namespace otherwise.
  *
  * Since: 0.12.2
+ *
+ * Deprecated: 0.14.0: Use gexiv2_metadata_try_get_xmp_namespace_for_tag() instead.
  */
+G_DEPRECATED_FOR(gexiv2_metadata_try_get_xmp_namespace_for_tag)
 char* gexiv2_metadata_get_xmp_namespace_for_tag(const char* tag);
 
+/**
+ * gexiv2_metadata_try_get_xmp_namespace_for_tag:
+ * @tag: (in): Full tag name (e.g. "Xmp.dc.subject") or XMP namespace identifier (e.g. "dc")
+ * @error: (allow-none): A return location for a #GError or %NULL
+ *
+ * Returns: (transfer full): %NULL if there was no namespace registered for the tag, the URI of the 
namespace otherwise.
+ *
+ * Since: 0.14.0
+ */
+char* gexiv2_metadata_try_get_xmp_namespace_for_tag(const char* tag, GError** error);
+
 /* IPTC functions */
 
 /**
@@ -1235,18 +1365,50 @@ gchar**                 gexiv2_metadata_get_iptc_tags           (GExiv2Metadata 
*self);
  *
  * Returns: A #GExiv2Orientation value representing the EXIF orientation
  * value.
+ *
+ * Deprecated: 0.14.0: Use gexiv2_metadata_try_get_orientation() instead.
  */
+G_DEPRECATED_FOR(gexiv2_metadata_try_get_orientation)
 GExiv2Orientation gexiv2_metadata_get_orientation      (GExiv2Metadata *self);
 
+/**
+ * gexiv2_metadata_try_get_orientation:
+ * @self: An instance of #GExiv2Metadata
+ * @error: (allow-none): A return location for a #GError or %NULL
+ *
+ * The EXIF Orientation field
+ *
+ * Returns: A #GExiv2Orientation value representing the EXIF orientation
+ * value.
+ *
+ * Since: 0.14.0
+ */
+GExiv2Orientation gexiv2_metadata_try_get_orientation(GExiv2Metadata* self, GError** error);
+
 /**
  * gexiv2_metadata_set_orientation:
  * @self: An instance of #GExiv2Metadata
  * @orientation: The new #GExiv2Orientation for the image.
  *
  * The orientation must be valid and cannot be #GEXIV2_ORIENTATION_UNSPECIFIED.
+ *
+ * Deprecated: 0.14.0: Use gexiv2_metadata_try_set_orientation() instead.
  */
+G_DEPRECATED_FOR(gexiv2_metadata_try_set_orientation)
 void                   gexiv2_metadata_set_orientation         (GExiv2Metadata *self, GExiv2Orientation 
orientation);
 
+/**
+ * gexiv2_metadata_try_set_orientation:
+ * @self: An instance of #GExiv2Metadata
+ * @orientation: The new #GExiv2Orientation for the image.
+ * @error: (allow-none): A return location for a #GError or %NULL
+ *
+ * The orientation must be valid and cannot be #GEXIV2_ORIENTATION_UNSPECIFIED.
+ *
+ * Since: 0.14.0
+ */
+void gexiv2_metadata_try_set_orientation(GExiv2Metadata* self, GExiv2Orientation orientation, GError** 
error);
+
 /**
  * gexiv2_metadata_get_metadata_pixel_width:
  * @self: An instance of #GExiv2Metadata
@@ -1256,9 +1418,27 @@ void                     gexiv2_metadata_set_orientation         (GExiv2Metadata 
*self, GExiv2Orientation
  * gexiv2_metadata_get_pixel_width()
  *
  * Returns: Width of images in pixels as stored in the metadata
+ *
+ * Deprecated: 0.14.0: Use gexiv2_metadata_try_get_metadata_pixel_width() instead.
  */
+G_DEPRECATED_FOR(gexiv2_metadata_try_get_metadata_pixel_width)
 gint gexiv2_metadata_get_metadata_pixel_width (GExiv2Metadata *self);
 
+/**
+ * gexiv2_metadata_try_get_metadata_pixel_width:
+ * @self: An instance of #GExiv2Metadata
+ * @error: (allow-none): A return location for a #GError or %NULL
+ *
+ * Composite accessor to query the pixel with stored in the metadata. This
+ * might differ from the width of image that is available through
+ * gexiv2_metadata_get_pixel_width()
+ *
+ * Returns: Width of images in pixels as stored in the metadata
+ *
+ * Since: 0.14.0
+ */
+gint gexiv2_metadata_try_get_metadata_pixel_width(GExiv2Metadata* self, GError** error);
+
 /**
  * gexiv2_metadata_get_metadata_pixel_height:
  * @self: An instance of #GExiv2Metadata
@@ -1268,36 +1448,84 @@ gint gexiv2_metadata_get_metadata_pixel_width (GExiv2Metadata *self);
  * gexiv2_metadata_get_pixel_height()
  *
  * Returns: Height of images in pixels as stored in the metadata
+ *
+ * Deprecated: 0.14.0: Use gexiv2_metadata_try_get_metadata_pixel_height() instead.
  */
+G_DEPRECATED_FOR(gexiv2_metadata_try_get_metadata_pixel_height)
 gint gexiv2_metadata_get_metadata_pixel_height (GExiv2Metadata *self);
 
+/**
+ * gexiv2_metadata_try_get_metadata_pixel_height:
+ * @self: An instance of #GExiv2Metadata
+ * @error: (allow-none): A return location for a #GError or %NULL
+ *
+ * Composite accessor to query the pixel with stored in the metadata. This
+ * might differ from the height of image that is available through
+ * gexiv2_metadata_get_pixel_height()
+ *
+ * Returns: Height of images in pixels as stored in the metadata
+ *
+ * Since: 0.14.0
+ */
+gint gexiv2_metadata_try_get_metadata_pixel_height(GExiv2Metadata* self, GError** error);
+
 /**
  * gexiv2_metadata_set_metadata_pixel_width:
  * @self: An instance of #GExiv2Metadata
- * @width: The width of the image as it should be put into the metadata.
+ * @width: The width of the image as it should be put into the metadata
  *
  * Composite setter to update the image's metadata with @width
+ *
+ * Deprecated: 0.14.0: Use gexiv2_metadata_try_set_metadata_pixel_width() instead.
  */
+G_DEPRECATED_FOR(gexiv2_metadata_try_set_metadata_pixel_width)
 void gexiv2_metadata_set_metadata_pixel_width (GExiv2Metadata *self, gint width);
 
+/**
+ * gexiv2_metadata_try_set_metadata_pixel_width:
+ * @self: An instance of #GExiv2Metadata
+ * @width: The width of the image as it should be put into the metadata
+ * @error: (allow-none): A return location for a #GError or %NULL
+ *
+ * Composite setter to update the image's metadata with @width
+ *
+ * Since: 0.14.0
+ */
+void gexiv2_metadata_try_set_metadata_pixel_width(GExiv2Metadata* self, gint width, GError** error);
+
 /**
  * gexiv2_metadata_set_metadata_pixel_height:
  * @self: An instance of #GExiv2Metadata
  * @height: The width of the image as it should be put into the metadata.
  *
  * Update the image's metadata with @height
+ *
+ * Deprecated: 0.14.0: Use gexiv2_metadata_try_set_metadata_pixel_height() instead.
  */
+G_DEPRECATED_FOR(gexiv2_metadata_try_set_metadata_pixel_height)
 void gexiv2_metadata_set_metadata_pixel_height (GExiv2Metadata *self, gint height);
 
+/**
+ * gexiv2_metadata_try_set_metadata_pixel_height:
+ * @self: An instance of #GExiv2Metadata
+ * @height: The width of the image as it should be put into the metadata.
+ * @error: (allow-none): A return location for a #GError or %NULL
+ *
+ * Update the image's metadata with @height
+ *
+ * Since: 0.14.0
+ */
+void gexiv2_metadata_try_set_metadata_pixel_height(GExiv2Metadata* self, gint height, GError** error);
+
 /**
  * gexiv2_metadata_get_comment:
  * @self: An instance of #GExiv2Metadata
  *
  * A composite accessor that uses the first available metadata field from a list of well-known
- * locations to find the photo's comment (or description).  
+ * locations to find the photo's comment (or description).
  *
  * MWG guidelines refer to these as <emphasis>Description</emphasis>: a textual description of a resource's 
content.
- * 
+ *
  * These fields are:
  *
  * - Exif.Image.ImageDescription  (MWG Guidelines)
@@ -1316,9 +1544,45 @@ void gexiv2_metadata_set_metadata_pixel_height (GExiv2Metadata *self, gint heigh
  * which is more useful for quick or casual use.
  *
  * Returns: (transfer full) (allow-none): The photo's comment field.
+ *
+ * Deprecated: 0.14.0: Use gexiv2_metadata_try_get_comment() instead.
  */
+G_DEPRECATED_FOR(gexiv2_metadata_try_get_comment)
 gchar*                 gexiv2_metadata_get_comment                     (GExiv2Metadata *self);
 
+/**
+ * gexiv2_metadata_try_get_comment:
+ * @self: An instance of #GExiv2Metadata
+ * @error: (allow-none): A return location for a #GError or %NULL
+ *
+ * A composite accessor that uses the first available metadata field from a list of well-known
+ * locations to find the photo's comment (or description).
+ *
+ * MWG guidelines refer to these as <emphasis>Description</emphasis>: a textual description of a resource's 
content.
+ *
+ * These fields are:
+ *
+ * - Exif.Image.ImageDescription  (MWG Guidelines)
+ * - Exif.Photo.UserComment
+ * - Exif.Image.XPComment
+ * - Iptc.Application2.Caption    (MWG Guidelines)
+ * - Xmp.dc.description           (MWG Guidelines)
+ * - Xmp.acdsee.notes             (Commonly requested, read only)
+ *
+ * <note>Note that in the EXIF specification Exif.Image.ImageDescription is
+ * described  as "the title of the image".  Also, it does not support
+ * two-byte character codes for encoding.  However, it's still used here for legacy reasons.
+ * </note>
+ *
+ * For fine-grained control, it's recommended to use Exiv2 tags directly rather than this method,
+ * which is more useful for quick or casual use.
+ *
+ * Returns: (transfer full) (allow-none): The photo's comment field.
+ *
+ * Since: 0.14.0
+ */
+gchar* gexiv2_metadata_try_get_comment(GExiv2Metadata* self, GError** error);
+
 /**
  * gexiv2_metadata_set_comment:
  * @self: An instance of #GExiv2Metadata
@@ -1326,9 +1590,25 @@ gchar*                   gexiv2_metadata_get_comment                     
(GExiv2Metadata *self);
  *
  * This is a composite setter that will set a number of fields to the supplied value.  See
  * #gexiv2_metadata_get_comment for more information.
+ *
+ * Deprecated: 0.14.0: Use gexiv2_metadata_try_set_comment() instead.
  */
+G_DEPRECATED_FOR(gexiv2_metadata_try_set_comment)
 void                   gexiv2_metadata_set_comment                     (GExiv2Metadata *self, const gchar* 
comment);
 
+/**
+ * gexiv2_metadata_try_set_comment:
+ * @self: An instance of #GExiv2Metadata
+ * @comment: Comment string to set. Must not be %NULL
+ * @error: (allow-none): A return location for a #GError or %NULL
+ *
+ * This is a composite setter that will set a number of fields to the supplied value.  See
+ * #gexiv2_metadata_get_comment for more information.
+ *
+ * Since: 0.14.0
+ */
+void gexiv2_metadata_try_set_comment(GExiv2Metadata* self, const gchar* comment, GError** error);
+
 /**
  * gexiv2_metadata_clear_comment:
  * @self: An instance of #GExiv2Metadata
@@ -1348,9 +1628,28 @@ void                     gexiv2_metadata_clear_comment           (GExiv2Metadata 
*self);
  * rational.  See <ulink url="https://en.wikipedia.org/wiki/Shutter_speed";></ulink> for more information.
  *
  * Returns: (skip): Boolean success value
+ *
+ * Deprecated: 0.14.0: Use gexiv2_metadata_try_get_exposure_time() instead.
  */
+G_DEPRECATED_FOR(gexiv2_metadata_try_get_exposure_time)
 gboolean               gexiv2_metadata_get_exposure_time       (GExiv2Metadata *self, gint *nom, gint *den);
 
+/**
+ * gexiv2_metadata_try_get_exposure_time:
+ * @self: An instance of #GExiv2Metadata
+ * @nom: (out): The numerator
+ * @den: (out): The denominator
+ * @error: (allow-none): A return location for a #GError or %NULL
+ *
+ * Returns the exposure time in seconds (shutter speed, <emphasis>not</emphasis> date-time of exposure) as a
+ * rational.  See <ulink url="https://en.wikipedia.org/wiki/Shutter_speed";></ulink> for more information.
+ *
+ * Returns: (skip): Boolean success value
+ *
+ * Since: 0.14.0
+ */
+gboolean gexiv2_metadata_try_get_exposure_time(GExiv2Metadata* self, gint* nom, gint* den, GError** error);
+
 /**
  * gexiv2_metadata_get_fnumber:
  * @self: An instance of #GExiv2Metadata
@@ -1360,9 +1659,27 @@ gboolean         gexiv2_metadata_get_exposure_time       (GExiv2Metadata *self, gint 
*nom, gi
  * Exif.Photo.ApertureValue (if available);
  *
  * Returns: The exposure Fnumber as a gdouble, or -1.0 if tag is not present or invalid.
+ *
+ * Deprecated: 0.14.0: Use gexiv2_metadata_try_get_fnumber() instead.
  */
+G_DEPRECATED_FOR(gexiv2_metadata_try_get_fnumber)
 gdouble                        gexiv2_metadata_get_fnumber                     (GExiv2Metadata *self);
 
+/**
+ * gexiv2_metadata_try_get_fnumber:
+ * @self: An instance of #GExiv2Metadata
+ * @error: (allow-none): A return location for a #GError or %NULL
+ *
+ * See <ulink url="https://en.wikipedia.org/wiki/F-number";></ulink> for more information.
+ * If Exif.Photo.FNumber does not exist, it will fall back to calculating the FNumber from
+ * Exif.Photo.ApertureValue (if available);
+ *
+ * Returns: The exposure Fnumber as a gdouble, or -1.0 if tag is not present or invalid.
+ *
+ * Since: 0.14.0
+ */
+gdouble gexiv2_metadata_try_get_fnumber(GExiv2Metadata* self, GError** error);
+
 /**
  * gexiv2_metadata_get_focal_length:
  * @self: An instance of #GExiv2Metadata
@@ -1370,9 +1687,25 @@ gdouble                  gexiv2_metadata_get_fnumber                     
(GExiv2Metadata *self);
  * See <ulink url="https://en.wikipedia.org/wiki/Flange_focal_distance";></ulink> for more information.
  *
  * Returns: The focal length as a gdouble, or -1.0 if tag is not present or invalid.
+ *
+ * Deprecated: 0.14.0: Use gexiv2_metadata_try_get_focal_length() instead.
  */
+G_DEPRECATED_FOR(gexiv2_metadata_try_get_focal_length)
 gdouble                        gexiv2_metadata_get_focal_length        (GExiv2Metadata *self);
 
+/**
+ * gexiv2_metadata_try_get_focal_length:
+ * @self: An instance of #GExiv2Metadata
+ * @error: (allow-none): A return location for a #GError or %NULL
+ *
+ * See <ulink url="https://en.wikipedia.org/wiki/Flange_focal_distance";></ulink> for more information.
+ *
+ * Returns: The focal length as a gdouble, or -1.0 if tag is not present or invalid.
+ *
+ * Since: 0.14.0
+ */
+gdouble gexiv2_metadata_try_get_focal_length(GExiv2Metadata* self, GError** error);
+
 /**
  * gexiv2_metadata_get_iso_speed:
  * @self: An instance of #GExiv2Metadata
@@ -1380,9 +1713,25 @@ gdouble                  gexiv2_metadata_get_focal_length        (GExiv2Metadata 
*self);
  * See <ulink url="https://en.wikipedia.org/wiki/Iso_speed";></ulink> for more information.
  *
  * Returns: The ISO speed rating as a gint, or 0 if tag is not present or invalid.
+ *
+ * Deprecated: 0.14.0: Use gexiv2_metadata_try_get_iso_speed() instead.
  */
+G_DEPRECATED_FOR(gexiv2_metadata_try_get_iso_speed)
 gint                   gexiv2_metadata_get_iso_speed           (GExiv2Metadata *self);
 
+/**
+ * gexiv2_metadata_try_get_iso_speed:
+ * @self: An instance of #GExiv2Metadata
+ * @error: (allow-none): A return location for a #GError or %NULL
+ *
+ * See <ulink url="https://en.wikipedia.org/wiki/Iso_speed";></ulink> for more information.
+ *
+ * Returns: The ISO speed rating as a gint, or 0 if tag is not present or invalid.
+ *
+ * Since: 0.14.0
+ */
+gint gexiv2_metadata_try_get_iso_speed(GExiv2Metadata* self, GError** error);
+
 /*
  * GPS functions
  */
@@ -1622,9 +1971,27 @@ GExiv2PreviewProperties** gexiv2_metadata_get_preview_properties (GExiv2Metadata
  *
  * Returns: (transfer full): A #GExiv2PreviewImage instance for the particular
  * #GExiv2PreviewProperties.
+ *
+ * Deprecated: 0.14.0: Use gexiv2_metadata_try_get_preview_image() instead.
  */
+G_DEPRECATED_FOR(gexiv2_metadata_try_get_preview_image)
 GExiv2PreviewImage* gexiv2_metadata_get_preview_image          (GExiv2Metadata *self, 
GExiv2PreviewProperties *props);
 
+/**
+ * gexiv2_metadata_try_get_preview_image:
+ * @self: An instance of #GExiv2Metadata
+ * @props: A #GExiv2PreviewProperties instance
+ * @error: (allow-none): A return location for a #GError or %NULL
+ *
+ * Returns: (transfer full): A #GExiv2PreviewImage instance for the particular
+ * #GExiv2PreviewProperties.
+ *
+ * Since: 0.14.0
+ */
+GExiv2PreviewImage* gexiv2_metadata_try_get_preview_image(GExiv2Metadata* self,
+                                                          GExiv2PreviewProperties* props,
+                                                          GError** error);
+
 G_END_DECLS
 
 #endif /* GEXIV2_METADATA_H */
diff --git a/gexiv2/gexiv2-preview-image-private.h b/gexiv2/gexiv2-preview-image-private.h
index b096f20..f8d8ac1 100644
--- a/gexiv2/gexiv2-preview-image-private.h
+++ b/gexiv2/gexiv2-preview-image-private.h
@@ -22,8 +22,9 @@ struct _GExiv2PreviewImagePrivate
     gchar *extension;
 };
 
-G_GNUC_INTERNAL GExiv2PreviewImage* gexiv2_preview_image_new (Exiv2::PreviewManager *manager,
-   const Exiv2::PreviewProperties &props);
+G_GNUC_INTERNAL GExiv2PreviewImage* gexiv2_preview_image_new(Exiv2::PreviewManager* manager,
+                                                             const Exiv2::PreviewProperties& props,
+                                                             GError** error);
 
 G_END_DECLS
 
diff --git a/gexiv2/gexiv2-preview-image.cpp b/gexiv2/gexiv2-preview-image.cpp
index 3d58a23..8f0cdf7 100644
--- a/gexiv2/gexiv2-preview-image.cpp
+++ b/gexiv2/gexiv2-preview-image.cpp
@@ -42,15 +42,33 @@ static void gexiv2_preview_image_finalize (GObject *object) {
     G_OBJECT_CLASS (gexiv2_preview_image_parent_class)->finalize (object);
 }
 
-GExiv2PreviewImage* gexiv2_preview_image_new (Exiv2::PreviewManager *manager, 
-       const Exiv2::PreviewProperties &props) {
-    GExiv2PreviewImage* self = GEXIV2_PREVIEW_IMAGE (g_object_new (GEXIV2_TYPE_PREVIEW_IMAGE, NULL));
-    
-    self->priv->image = new Exiv2::PreviewImage(manager->getPreviewImage(props));
-    self->priv->mime_type = g_strdup(self->priv->image->mimeType().c_str());
-    self->priv->extension = g_strdup(self->priv->image->extension().c_str());
-    
-    return self;
+GExiv2PreviewImage* gexiv2_preview_image_new(Exiv2::PreviewManager* manager,
+                                             const Exiv2::PreviewProperties& props,
+                                             GError** error) {
+    g_return_val_if_fail(manager != nullptr, nullptr);
+    g_return_val_if_fail(error == nullptr || *error == nullptr, nullptr);
+
+    GExiv2PreviewImage* self = GEXIV2_PREVIEW_IMAGE(g_object_new(GEXIV2_TYPE_PREVIEW_IMAGE, nullptr));
+    try {
+        self->priv->image = new Exiv2::PreviewImage(manager->getPreviewImage(props));
+        self->priv->mime_type = g_strdup(self->priv->image->mimeType().c_str());
+        self->priv->extension = g_strdup(self->priv->image->extension().c_str());
+
+        return self;
+    } catch (Exiv2::Error& e) {
+        // Cleanup
+        if (self->priv->image)
+            delete self->priv->image;
+        if (self->priv->mime_type)
+            g_free(self->priv->mime_type);
+        if (self->priv->extension)
+            g_free(self->priv->extension);
+
+        g_object_unref(self);
+
+        g_set_error_literal(error, g_quark_from_string("GExiv2"), e.code(), e.what());
+    }
+    return nullptr;
 }
 
 void gexiv2_preview_image_free(GExiv2PreviewImage *self) {
@@ -60,43 +78,72 @@ void gexiv2_preview_image_free(GExiv2PreviewImage *self) {
 }
 
 const guint8* gexiv2_preview_image_get_data (GExiv2PreviewImage *self, guint32 *size) {
-    g_return_val_if_fail(GEXIV2_IS_PREVIEW_IMAGE(self), NULL);
-    g_return_val_if_fail(size != NULL, NULL);
-    
+    g_return_val_if_fail(GEXIV2_IS_PREVIEW_IMAGE(self), nullptr);
+    g_return_val_if_fail(self->priv != nullptr, nullptr);
+    g_return_val_if_fail(self->priv->image != nullptr, nullptr);
+    g_return_val_if_fail(size != nullptr, nullptr);
+
     *size = self->priv->image->size();
     
     return self->priv->image->pData();
 }
 
 const gchar * gexiv2_preview_image_get_mime_type (GExiv2PreviewImage *self) {
-    g_return_val_if_fail(GEXIV2_IS_PREVIEW_IMAGE(self), NULL);
-    
+    g_return_val_if_fail(GEXIV2_IS_PREVIEW_IMAGE(self), nullptr);
+    g_return_val_if_fail(self->priv != nullptr, nullptr);
+
     return self->priv->mime_type;
 }
 
 const gchar *gexiv2_preview_image_get_extension (GExiv2PreviewImage *self) {
-    g_return_val_if_fail(GEXIV2_IS_PREVIEW_IMAGE(self), NULL);
-    
+    g_return_val_if_fail(GEXIV2_IS_PREVIEW_IMAGE(self), nullptr);
+    g_return_val_if_fail(self->priv != nullptr, nullptr);
+
     return self->priv->extension;
 }
 
 guint32 gexiv2_preview_image_get_width (GExiv2PreviewImage *self) {
     g_return_val_if_fail(GEXIV2_IS_PREVIEW_IMAGE(self), 0);
-    
+    g_return_val_if_fail(self->priv != nullptr, 0);
+    g_return_val_if_fail(self->priv->image != nullptr, 0);
+
     return self->priv->image->width();
 }
 
 guint32 gexiv2_preview_image_get_height (GExiv2PreviewImage *self) {
     g_return_val_if_fail(GEXIV2_IS_PREVIEW_IMAGE(self), 0);
-    
+    g_return_val_if_fail(self->priv != nullptr, 0);
+    g_return_val_if_fail(self->priv->image != nullptr, 0);
+
     return self->priv->image->height();
 }
 
 glong gexiv2_preview_image_write_file (GExiv2PreviewImage *self, const gchar *path) {
+    GError* error = nullptr;
+    glong value = -1;
+
+    value = gexiv2_preview_image_try_write_file(self, path, &error);
+
+    if (error) {
+        g_warning("%s", error->message);
+        g_clear_error(&error);
+    }
+
+    return value;
+}
+
+glong gexiv2_preview_image_try_write_file(GExiv2PreviewImage* self, const gchar* path, GError** error) {
     g_return_val_if_fail(GEXIV2_IS_PREVIEW_IMAGE(self), -1);
-    g_return_val_if_fail(path != NULL && strlen(path) > 0, -1);
-    
-    return self->priv->image->writeFile(path);
+    g_return_val_if_fail(self->priv != nullptr, -1);
+    g_return_val_if_fail(self->priv->image != nullptr, -1);
+    g_return_val_if_fail(path != nullptr && strlen(path) > 0, -1);
+
+    try {
+        return self->priv->image->writeFile(path);
+    } catch (Exiv2::Error& e) {
+        g_set_error_literal(error, g_quark_from_string("GExiv2"), e.code(), e.what());
+    }
+    return -1;
 }
 
 G_END_DECLS
diff --git a/gexiv2/gexiv2-preview-image.h b/gexiv2/gexiv2-preview-image.h
index f051223..3378370 100644
--- a/gexiv2/gexiv2-preview-image.h
+++ b/gexiv2/gexiv2-preview-image.h
@@ -119,9 +119,23 @@ guint32                    gexiv2_preview_image_get_height                 
(GExiv2PreviewImage *self);
  * @path: (in): The file path to write the preview image to.
  *
  * Returns: The number of bytes written to the file.
+ *
+ * Deprecated: 0.14.0: Use gexiv2_preview_image_try_write_file() instead.
  */
+G_DEPRECATED_FOR(gexiv2_preview_image_try_write_file)
 glong                  gexiv2_preview_image_write_file                 (GExiv2PreviewImage *self, const 
gchar *path);
 
+/**
+ * gexiv2_preview_image_try_write_file:
+ * @self: An instance of #GExiv2PreviewImage
+ * @path: (in): The file path to write the preview image to.
+ * @error: (allow-none): A return location for a #GError or %NULL
+ *
+ * Returns: The number of bytes written to the file.
+ *
+ * Since: 0.14.0
+ */
+glong gexiv2_preview_image_try_write_file(GExiv2PreviewImage* self, const gchar* path, GError** error);
 
 G_END_DECLS
 
diff --git a/gexiv2/gexiv2-startup.cpp b/gexiv2/gexiv2-startup.cpp
index aef65b7..918724b 100644
--- a/gexiv2/gexiv2-startup.cpp
+++ b/gexiv2/gexiv2-startup.cpp
@@ -12,7 +12,7 @@
 #include "gexiv2-version.h"
 
 gboolean gexiv2_initialize(void) {
-#ifdef EXV_ENABLE_BMFF
+#if EXIV2_TEST_VERSION(0, 27, 4)
     Exiv2::enableBMFF();
 #endif
 
diff --git a/test/python/test_metadata.py.in b/test/python/test_metadata.py.in
index a27aff2..45d9d45 100644
--- a/test/python/test_metadata.py.in
+++ b/test/python/test_metadata.py.in
@@ -185,14 +185,25 @@ class TestMetadata(unittest.TestCase):
                        'stop_emission',
                        'stop_emission_by_name',
                        'thaw_notify',
+                       'try_clear_tag',
                        'try_tag_supports_multiple_values',
                        'try_delete_gps_info',
+                       'try_erase_exif_thumbnail',
                        'try_generate_xmp_packet',
+                       'try_get_comment',
                        'try_get_exif_tag_rational',
+                       'try_get_exposure_time',
+                       'try_get_fnumber',
+                       'try_get_focal_length',
                        'try_get_gps_altitude',
                        'try_get_gps_info',
                        'try_get_gps_latitude',
                        'try_get_gps_longitude',
+                       'try_get_iso_speed',
+                       'try_get_metadata_pixel_height',
+                       'try_get_metadata_pixel_width',
+                       'try_get_orientation',
+                       'try_get_preview_image',
                        'try_get_tag_description',
                        'try_get_tag_interpreted_string',
                        'try_get_tag_label',
@@ -201,13 +212,23 @@ class TestMetadata(unittest.TestCase):
                        'try_get_tag_raw',
                        'try_get_tag_string',
                        'try_get_tag_type',
+                       'try_get_xmp_namespace_for_tag',
                        'try_get_xmp_packet',
+                       'try_has_tag',
+                       'try_register_xmp_namespace',
+                       'try_set_comment',
                        'try_set_exif_tag_rational',
+                       'try_set_exif_thumbnail_from_buffer',
                        'try_set_gps_info',
+                       'try_set_metadata_pixel_height',
+                       'try_set_metadata_pixel_width',
+                       'try_set_orientation',
                        'try_set_tag_long',
                        'try_set_tag_multiple',
                        'try_set_tag_string',
                        'try_set_xmp_tag_struct',
+                       'try_unregister_all_xmp_namespaces',
+                       'try_unregister_xmp_namespace',
                        'try_update_gps_info',
                        'unref',
                        'unregister_all_xmp_namespaces',
@@ -217,6 +238,88 @@ class TestMetadata(unittest.TestCase):
                        'weak_ref']:
             self.assertIn(method, methods)
 
+        preview_properties = GExiv2.PreviewProperties()
+        methods = [m for m in dir(preview_properties) if not m.startswith('_')]
+        for method in ['bind_property',
+                       'bind_property_full',
+                       'chain',
+                       'connect',
+                       'connect_after',
+                       'connect_object',
+                       'connect_object_after',
+                       'disconnect',
+                       'disconnect_by_func',
+                       'emit',
+                       'emit_stop_by_name',
+                       'force_floating',
+                       'freeze_notify',
+                       'g_type_instance',
+                       'get_extension',
+                       'get_height',
+                       'get_mime_type',
+                       'get_qdata',
+                       'get_size',
+                       'get_width',
+                       'interface_find_property',
+                       'interface_install_property',
+                       'interface_list_properties',
+                       'notify',
+                       'ref_count',
+                       'ref_sink',
+                       'replace_data',
+                       'replace_qdata',
+                       'set_property',
+                       'steal_data',
+                       'steal_qdata',
+                       'thaw_notify',
+                       'unref',
+                       'watch_closure',
+                       'weak_ref'
+                       ]:
+            self.assertIn(method, methods)
+
+        preview_image = GExiv2.PreviewImage()
+        methods = [m for m in dir(preview_image) if not m.startswith('_')]
+        for method in ['bind_property',
+                       'bind_property_full',
+                       'chain',
+                       'connect',
+                       'connect_after',
+                       'connect_object',
+                       'connect_object_after',
+                       'disconnect',
+                       'disconnect_by_func',
+                       'emit',
+                       'emit_stop_by_name',
+                       'force_floating',
+                       'freeze_notify',
+                       'g_type_instance',
+                       'get_data',
+                       'get_extension',
+                       'get_mime_type',
+                       'get_height',
+                       'get_width',
+                       'get_qdata',
+                       'interface_find_property',
+                       'interface_install_property',
+                       'interface_list_properties',
+                       'notify',
+                       'ref_count',
+                       'ref_sink',
+                       'replace_data',
+                       'replace_qdata',
+                       'set_property',
+                       'steal_data',
+                       'steal_qdata',
+                       'thaw_notify',
+                       'try_write_file',
+                       'unref',
+                       'watch_closure',
+                       'write_file',
+                       'weak_ref'
+                       ]:
+            self.assertIn(method, methods)
+
     def test_open_buf(self):
         with open(self.get_input_file(), 'rb' if PY3K else 'r') as fd:
             buf = fd.read()
@@ -911,3 +1014,22 @@ generated the image. When the field is left blank, it is treated as unknown.""")
         self.assertEqual(self.metadata.get_comment(), 'Lego Dragon, Copenhagen.')
         self.metadata.clear_comment()
         self.assertEqual(self.metadata.get_comment().strip(), '')
+
+    def test_try_get_xmp_namespace_for_tag(self):
+        self.assertEqual(self.metadata.try_get_xmp_namespace_for_tag('dc'), 
'http://purl.org/dc/elements/1.1/')
+        self.assertEqual(self.metadata.try_get_xmp_namespace_for_tag('Xmp.dc.subject'), 
'http://purl.org/dc/elements/1.1/')
+        self.assertEqual(self.metadata.try_get_xmp_namespace_for_tag('Xmp.dc.MadeUp'), 
'http://purl.org/dc/elements/1.1/')
+
+        # Invalid "familyName"
+        self.assertEqual(self.metadata.get_xmp_namespace_for_tag('xmp.dc.subject'), None)
+        self.assertEqual(self.metadata.get_xmp_namespace_for_tag('MadeUp.dc.subject'), None)
+        self.assertEqual(self.metadata.get_xmp_namespace_for_tag('.dc.subject'), None)
+
+        # Invalid "groupName"
+        self.assertEqual(self.metadata.get_xmp_namespace_for_tag('MadeUp'), None)
+        self.assertEqual(self.metadata.get_xmp_namespace_for_tag('Xmp.MadeUp.subject'), None)
+        self.assertEqual(self.metadata.get_xmp_namespace_for_tag('Xmp..subject'), None)
+
+        # Missing "tagName"
+        self.assertEqual(self.metadata.get_xmp_namespace_for_tag('Xmp.dc'), None)
+        self.assertEqual(self.metadata.get_xmp_namespace_for_tag('Xmp.dc.'), None)
diff --git a/tools/gexiv2-tool.vala b/tools/gexiv2-tool.vala
index 1cedd35..780d0cc 100644
--- a/tools/gexiv2-tool.vala
+++ b/tools/gexiv2-tool.vala
@@ -218,7 +218,7 @@ void print_all_xmp_namespaces(string[] xmp_tags) throws Error {
 
         // Only output one example of a groupName's namespace
         if (last_groupName != groupName) {
-            print("Xmp ns: %-56s%s\n", groupName, GExiv2.Metadata.get_xmp_namespace_for_tag(groupName));
+            print("Xmp ns: %-56s%s\n", groupName, GExiv2.Metadata.try_get_xmp_namespace_for_tag(groupName));
             last_groupName = groupName;
         }
     }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]