add support for new PICTURE metadata block
diff --git a/include/FLAC++/metadata.h b/include/FLAC++/metadata.h
index 549546b..9641f91 100644
--- a/include/FLAC++/metadata.h
+++ b/include/FLAC++/metadata.h
@@ -782,6 +782,80 @@
 			FLAC__uint32 calculate_cddb_id() const;
 		};
 
+		/** PICTURE metadata block.
+		 *  See <A HREF="../format.html#metadata_block_picture">format specification</A>.
+		 */
+		class FLACPP_API Picture : public Prototype {
+		public:
+			Picture();
+
+			//@{
+			/** Constructs a copy of the given object.  This form
+			 *  always performs a deep copy.
+			 */
+			inline Picture(const Picture &object): Prototype(object) { }
+			inline Picture(const ::FLAC__StreamMetadata &object): Prototype(object) { }
+			inline Picture(const ::FLAC__StreamMetadata *object): Prototype(object) { }
+			//@}
+
+			/** Constructs an object with copy control.  See
+			 *  Prototype(::FLAC__StreamMetadata *object, bool copy).
+			 */
+			inline Picture(::FLAC__StreamMetadata *object, bool copy): Prototype(object, copy) { }
+
+			~Picture();
+
+			//@{
+			/** Assign from another object.  Always performs a deep copy. */
+			inline Picture &operator=(const Picture &object) { Prototype::operator=(object); return *this; }
+			inline Picture &operator=(const ::FLAC__StreamMetadata &object) { Prototype::operator=(object); return *this; }
+			inline Picture &operator=(const ::FLAC__StreamMetadata *object) { Prototype::operator=(object); return *this; }
+			//@}
+
+			/** Assigns an object with copy control.  See
+			 *  Prototype::assign_object(::FLAC__StreamMetadata *object, bool copy).
+			 */
+			inline Picture &assign(::FLAC__StreamMetadata *object, bool copy) { Prototype::assign_object(object, copy); return *this; }
+
+			//@{
+			/** Check for equality, performing a deep compare by following pointers. */
+			inline bool operator==(const Picture &object) const { return Prototype::operator==(object); }
+			inline bool operator==(const ::FLAC__StreamMetadata &object) const { return Prototype::operator==(object); }
+			inline bool operator==(const ::FLAC__StreamMetadata *object) const { return Prototype::operator==(object); }
+			//@}
+
+			//@{
+			/** Check for inequality, performing a deep compare by following pointers. */
+			inline bool operator!=(const Picture &object) const { return Prototype::operator!=(object); }
+			inline bool operator!=(const ::FLAC__StreamMetadata &object) const { return Prototype::operator!=(object); }
+			inline bool operator!=(const ::FLAC__StreamMetadata *object) const { return Prototype::operator!=(object); }
+			//@}
+
+			::FLAC__StreamMetadata_Picture_Type get_type() const;
+			const char *get_mime_type() const; // NUL-terminated printable ASCII string
+			const FLAC__byte *get_description() const; // NUL-terminated UTF-8 string
+			FLAC__uint32 get_width() const;
+			FLAC__uint32 get_height() const;
+			FLAC__uint32 get_depth() const;
+			FLAC__uint32 get_data_length() const;
+			const FLAC__byte *get_data() const;
+
+			void set_type(::FLAC__StreamMetadata_Picture_Type type);
+
+			//! See FLAC__metadata_object_picture_set_mime_type()
+			bool set_mime_type(const char *string); // NUL-terminated printable ASCII string
+
+			//! See FLAC__metadata_object_picture_set_description()
+			bool set_description(const FLAC__byte *string); // NUL-terminated UTF-8 string
+
+			void set_width(FLAC__uint32 value) const;
+			void set_height(FLAC__uint32 value) const;
+			void set_depth(FLAC__uint32 value) const;
+
+			//! See FLAC__metadata_object_picture_set_data()
+			bool set_data(const FLAC__byte *data, FLAC__uint32 data_length);
+		};
+
 		/** Opaque metadata block for storing unknown types.
 		 *  This should not be used unless you know what you are doing;
 		 *  it is currently used only internally to support forward
@@ -855,16 +929,16 @@
 		 * \{
 		 */
 
-	 	//! See FLAC__metadata_get_streaminfo().
-		FLACPP_API bool get_streaminfo(const char *filename, StreamInfo &streaminfo);
+		FLACPP_API bool get_streaminfo(const char *filename, StreamInfo &streaminfo); //< See FLAC__metadata_get_streaminfo().
 
-	 	//! See FLAC__metadata_get_tags().
-		FLACPP_API bool get_tags(const char *filename, VorbisComment *&tags);
-		FLACPP_API bool get_tags(const char *filename, VorbisComment &tags);
+		FLACPP_API bool get_tags(const char *filename, VorbisComment *&tags); //< See FLAC__metadata_get_tags().
+		FLACPP_API bool get_tags(const char *filename, VorbisComment &tags); //< See FLAC__metadata_get_tags().
 
-	 	//! See FLAC__metadata_get_cuesheet().
-		FLACPP_API bool get_cuesheet(const char *filename, CueSheet *&cuesheet);
-		FLACPP_API bool get_cuesheet(const char *filename, CueSheet &cuesheet);
+		FLACPP_API bool get_cuesheet(const char *filename, CueSheet *&cuesheet); //! See FLAC__metadata_get_cuesheet().
+		FLACPP_API bool get_cuesheet(const char *filename, CueSheet &cuesheet); //! See FLAC__metadata_get_cuesheet().
+
+		FLACPP_API bool get_picture(const char *filename, Picture *&picture, ::FLAC__StreamMetadata_Picture_Type type, const char *mime_type, const FLAC__byte *description, unsigned max_width, unsigned max_height, unsigned max_depth); //! See FLAC__metadata_get_picture().
+		FLACPP_API bool get_picture(const char *filename, Picture &picture, ::FLAC__StreamMetadata_Picture_Type type, const char *mime_type, const FLAC__byte *description, unsigned max_width, unsigned max_height, unsigned max_depth); //! See FLAC__metadata_get_picture().
 
 		/* \} */
 
diff --git a/include/FLAC/format.h b/include/FLAC/format.h
index de9f6ea..6d09df6 100644
--- a/include/FLAC/format.h
+++ b/include/FLAC/format.h
@@ -478,7 +478,10 @@
 	FLAC__METADATA_TYPE_CUESHEET = 5,
 	/**< <A HREF="../format.html#metadata_block_cuesheet">CUESHEET</A> block */
 
-	FLAC__METADATA_TYPE_UNDEFINED = 6
+	FLAC__METADATA_TYPE_PICTURE = 6,
+	/**< <A HREF="../format.html#metadata_block_picture">PICTURE</A> block */
+
+	FLAC__METADATA_TYPE_UNDEFINED = 7
 	/**< marker to denote beginning of undefined type range; this number will increase as new metadata types are added */
 
 } FLAC__MetadataType;
@@ -678,7 +681,7 @@
 	/**< The number of lead-in samples. */
 
 	FLAC__bool is_cd;
-	/**< \c true if CUESHEET corresponds to a Compact Disc, else \c false */
+	/**< \c true if CUESHEET corresponds to a Compact Disc, else \c false. */
 
 	unsigned num_tracks;
 	/**< The number of tracks. */
@@ -695,6 +698,92 @@
 extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN; /**< == 8 (bits) */
 
 
+/** An enumeration of the PICTURE types (see FLAC__StreamMetadataPicture and id3 v2.4 APIC tag). */
+typedef enum {
+	FLAC__STREAM_METADATA_PICTURE_TYPE_OTHER = 0, /**< Other */
+	FLAC__STREAM_METADATA_PICTURE_TYPE_FILE_ICON_STANDARD = 1, /**< 32x32 pixels 'file icon' (PNG only) */
+	FLAC__STREAM_METADATA_PICTURE_TYPE_FILE_ICON = 2, /**< Other file icon */
+	FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER = 3, /**< Cover (front) */
+	FLAC__STREAM_METADATA_PICTURE_TYPE_BACK_COVER = 4, /**< Cover (back) */
+	FLAC__STREAM_METADATA_PICTURE_TYPE_LEAFLET_PAGE = 5, /**< Leaflet page */
+	FLAC__STREAM_METADATA_PICTURE_TYPE_MEDIA = 6, /**< Media (e.g. label side of CD) */
+	FLAC__STREAM_METADATA_PICTURE_TYPE_LEAD_ARTIST = 7, /**< Lead artist/lead performer/soloist */
+	FLAC__STREAM_METADATA_PICTURE_TYPE_ARTIST = 8, /**< Artist/performer */
+	FLAC__STREAM_METADATA_PICTURE_TYPE_CONDUCTOR = 9, /**< Conductor */
+	FLAC__STREAM_METADATA_PICTURE_TYPE_BAND = 10, /**< Band/Orchestra */
+	FLAC__STREAM_METADATA_PICTURE_TYPE_COMPOSER = 11, /**< Composer */
+	FLAC__STREAM_METADATA_PICTURE_TYPE_LYRICIST = 12, /**< Lyricist/text writer */
+	FLAC__STREAM_METADATA_PICTURE_TYPE_RECORDING_LOCATION = 13, /**< Recording Location */
+	FLAC__STREAM_METADATA_PICTURE_TYPE_DURING_RECORDING = 14, /**< During recording */
+	FLAC__STREAM_METADATA_PICTURE_TYPE_DURING_PERFORMANCE = 15, /**< During performance */
+	FLAC__STREAM_METADATA_PICTURE_TYPE_VIDEO_SCREEN_CAPTURE = 16, /**< Movie/video screen capture */
+	FLAC__STREAM_METADATA_PICTURE_TYPE_FISH = 17, /**< A bright coloured fish */
+	FLAC__STREAM_METADATA_PICTURE_TYPE_ILLUSTRATION = 18, /**< Illustration */
+	FLAC__STREAM_METADATA_PICTURE_TYPE_BAND_LOGOTYPE = 19, /**< Band/artist logotype */
+	FLAC__STREAM_METADATA_PICTURE_TYPE_PUBLISHER_LOGOTYPE = 20, /**< Publisher/Studio logotype */
+	FLAC__STREAM_METADATA_PICTURE_TYPE_UNDEFINED
+} FLAC__StreamMetadata_Picture_Type;
+
+/** Maps a FLAC__StreamMetadata_Picture_Type to a C string.
+ *
+ *  Using a FLAC__StreamMetadata_Picture_Type as the index to this array
+ *  will give the string equivalent.  The contents should not be
+ *  modified.
+ */
+extern FLAC_API const char * const FLAC__StreamMetadata_Picture_TypeString[];
+
+/** FLAC PICTURE structure.  (See the
+ * <A HREF="../format.html#metadata_block_picture">format specification</A>
+ * for the full description of each field.)
+ */
+typedef struct {
+	FLAC__StreamMetadata_Picture_Type type;
+	/**< The kind of picture stored. */
+
+	char *mime_type;
+	/**< Picture data's MIME type, in ASCII printable characters
+	 * 0x20-0x7e, NUL terminated.  For best compatibility with players,
+	 * use picture data of MIME type \c image/jpeg or \c image/png.  A
+	 * MIME type of '-->' is also allowed, in which case the picture
+	 * data should be a complete URL.  In file storage, the MIME type is
+	 * stored as a 32-bit length followed by the ASCII string with no NUL
+	 * terminator, but is converted to a plain C string in this structure
+	 * for convenience.
+	 */
+
+	FLAC__byte *description;
+	/**< Picture's description in UTF-8, NUL terminated.  In file storage,
+	 * the description is stored as a 32-bit length followed by the UTF-8
+	 * string with no NUL terminator, but is converted to a plain C string
+	 * in this structure for convenience.
+	 */
+
+	FLAC__uint32 width;
+	/**< Picture's width in pixels. */
+
+	FLAC__uint32 height;
+	/**< Picture's height in pixels. */
+
+	FLAC__uint32 depth;
+	/**< Picture's color depth in bits-per-pixel. */
+
+	FLAC__uint32 data_length;
+	/**< Length of binary picture data in bytes. */
+
+	FLAC__byte *data;
+	/**< Binary picture data. */
+
+} FLAC__StreamMetadata_Picture;
+
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_TYPE_LEN; /**< == 32 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN; /**< == 32 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN; /**< == 32 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN; /**< == 32 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN; /**< == 32 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN; /**< == 32 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN; /**< == 32 (bits) */
+
+
 /** Structure that is used when a metadata block of unknown type is loaded.
  *  The contents are opaque.  The structure is used only internally to
  *  correctly handle unknown metadata.
@@ -725,6 +814,7 @@
 		FLAC__StreamMetadata_SeekTable seek_table;
 		FLAC__StreamMetadata_VorbisComment vorbis_comment;
 		FLAC__StreamMetadata_CueSheet cue_sheet;
+		FLAC__StreamMetadata_Picture picture;
 		FLAC__StreamMetadata_Unknown unknown;
 	} data;
 	/**< Polymorphic block data; use the \a type value to determine which
@@ -852,6 +942,25 @@
  */
 FLAC_API FLAC__bool FLAC__format_cuesheet_is_legal(const FLAC__StreamMetadata_CueSheet *cue_sheet, FLAC__bool check_cd_da_subset, const char **violation);
 
+/* @@@@ add to unit tests; it is already indirectly tested by the metadata_object tests */
+/** Check picture data to see if it conforms to the FLAC specification.
+ *  See the format specification for limits on the contents of the
+ *  PICTURE block.
+ *
+ * \param picture    A pointer to existing picture data to be checked.
+ * \param violation  Address of a pointer to a string.  If there is a
+ *                   violation, a pointer to a string explanation of the
+ *                   violation will be returned here. \a violation may be
+ *                   \c NULL if you don't need the returned string.  Do not
+ *                   free the returned string; it will always point to static
+ *                   data.
+ * \assert
+ *    \code picture != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if picture data is illegal, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__format_picture_is_legal(const FLAC__StreamMetadata_Picture *picture, const char **violation);
+
 /* \} */
 
 #ifdef __cplusplus
diff --git a/include/FLAC/metadata.h b/include/FLAC/metadata.h
index e5799de..68b2453 100644
--- a/include/FLAC/metadata.h
+++ b/include/FLAC/metadata.h
@@ -64,7 +64,8 @@
  *  There are three metadata interfaces of increasing complexity:
  *
  *  Level 0:
- *  Read-only access to the STREAMINFO and VORBIS_COMMENT blocks.
+ *  Read-only access to the STREAMINFO, VORBIS_COMMENT, CUESHEET, and
+ *  PICTURE blocks.
  *
  *  Level 1:
  *  Read-write access to all metadata blocks.  This level is write-
@@ -124,7 +125,8 @@
  *
  *  \brief
  *  The level 0 interface consists of individual routines to read the
- *  STREAMINFO, VORBIS_COMMENT, and CUESHEET blocks, requiring only a filename.
+ *  STREAMINFO, VORBIS_COMMENT, CUESHEET, and PICTURE blocks, requiring
+ *   only a filename.
  *
  *  They try to skip any ID3v2 tag at the head of the file.
  *
@@ -162,7 +164,7 @@
  *    \code tags != NULL \endcode
  * \retval FLAC__bool
  *    \c true if a valid VORBIS_COMMENT block was read from \a filename,
- *    and \a *tags will be set to the address of the tag structure.
+ *    and \a *tags will be set to the address of the metadata structure.
  *    Returns \c false if there was a memory allocation error, a file
  *    decoder error, or the file contained no VORBIS_COMMENT block, and
  *    \a *tags will be set to \c NULL.
@@ -181,13 +183,51 @@
  *    \code cuesheet != NULL \endcode
  * \retval FLAC__bool
  *    \c true if a valid CUESHEET block was read from \a filename,
- *    and \a *cuesheet will be set to the address of the tag structure.
- *    Returns \c false if there was a memory allocation error, a file
- *    decoder error, or the file contained no CUESHEET block, and
- *    \a *cuesheet will be set to \c NULL.
+ *    and \a *cuesheet will be set to the address of the metadata
+ *    structure.  Returns \c false if there was a memory allocation
+ *    error, a file decoder error, or the file contained no CUESHEET
+ *    block, and \a *cuesheet will be set to \c NULL.
  */
 FLAC_API FLAC__bool FLAC__metadata_get_cuesheet(const char *filename, FLAC__StreamMetadata **cuesheet);
 
+/** Read a PICTURE metadata block of the given FLAC file.  This
+ *  function will try to skip any ID3v2 tag at the head of the file.
+ *  Since there can be more than one PICTURE block in a file, this
+ *  function takes a number of parameters that act as constraints to
+ *  the search.  The PICTURE block with the largest area matching all
+ *  the constraints will be returned, or \a *picture will be set to
+ *  \c NULL if there was no such block.
+ *
+ * \param filename    The path to the FLAC file to read.
+ * \param picture     The address where the returned pointer will be
+ *                    stored.  The \a picture object must be deleted by
+ *                    the caller using FLAC__metadata_object_delete().
+ * \param type        The desired picture type.  Use \c -1 to mean
+ *                    "any type".
+ * \param mime_type   The desired MIME type, e.g. "image/jpeg".  The
+ *                    string will be matched exactly.  Use \c NULL to
+ *                    mean "any MIME type".
+ * \param description The desired description.  The string will be
+ *                    matched exactly.  Use \c NULL to mean "any
+ *                    description".
+ * \param max_width   The maximum width in pixels desired.  Use
+ *                    \c (unsigned)(-1) to mean "any width".
+ * \param max_height  The maximum height in pixels desired.  Use
+ *                    \c (unsigned)(-1) to mean "any height".
+ * \param max_depth   The maximum color depth in bits-per-pixel desired.
+ *                    Use \c (unsigned)(-1) to mean "any depth".
+ * \assert
+ *    \code filename != NULL \endcode
+ *    \code picture != NULL \endcode
+ * \retval FLAC__bool
+ *    \c true if a valid PICTURE block was read from \a filename,
+ *    and \a *picture will be set to the address of the metadata
+ *    structure.  Returns \c false if there was a memory allocation
+ *    error, a file decoder error, or the file contained no PICTURE
+ *    block, and \a *picture will be set to \c NULL.
+ */
+FLAC_API FLAC__bool FLAC__metadata_get_picture(const char *filename, FLAC__StreamMetadata **picture, FLAC__StreamMetadata_Picture_Type type, const char *mime_type, const FLAC__byte *description, unsigned max_width, unsigned max_height, unsigned max_depth);
+
 /* \} */
 
 
@@ -203,9 +243,9 @@
  * - Create an iterator using FLAC__metadata_simple_iterator_new()
  * - Attach it to a file using FLAC__metadata_simple_iterator_init() and check
  *   the exit code.  Call FLAC__metadata_simple_iterator_is_writable() to
- *   see if the file is writable, or read-only access is allowed.
+ *   see if the file is writable, or only read access is allowed.
  * - Use FLAC__metadata_simple_iterator_next() and
- *   FLAC__metadata_simple_iterator_prev() to move around the blocks.
+ *   FLAC__metadata_simple_iterator_prev() to traverse the blocks.
  *   This is does not read the actual blocks themselves.
  *   FLAC__metadata_simple_iterator_next() is relatively fast.
  *   FLAC__metadata_simple_iterator_prev() is slower since it needs to search
@@ -1185,7 +1225,11 @@
 /** Sets the application data of an APPLICATION block.
  *
  *  If \a copy is \c true, a copy of the data is stored; otherwise, the object
- *  takes ownership of the pointer.
+ *  takes ownership of the pointer.  The existing data will be freed if this
+ *  function is successful, otherwise the original data will remain if \a copy
+ *  is \c true and malloc() fails.
+ *
+ * \note It is safe to pass a const pointer to \a data if \a copy is \c true.
  *
  * \param object  A pointer to an existing APPLICATION object.
  * \param data    A pointer to the data to set.
@@ -1911,6 +1955,95 @@
  */
 FLAC_API FLAC__uint32 FLAC__metadata_object_cuesheet_calculate_cddb_id(const FLAC__StreamMetadata *object);
 
+/** Sets the MIME type of a PICTURE block.
+ *
+ *  If \a copy is \c true, a copy of the string is stored; otherwise, the object
+ *  takes ownership of the pointer.  The existing string will be freed if this
+ *  function is successful, otherwise the original string will remain if \a copy
+ *  is \c true and malloc() fails.
+ *
+ * \note It is safe to pass a const pointer to \a mime_type if \a copy is \c true.
+ *
+ * \param object      A pointer to an existing PICTURE object.
+ * \param mime_type   A pointer to the MIME type string.  The string must be
+ *                    ASCII characters 0x20-0x7e, NUL-terminated.  No validation
+ *                    is done.
+ * \param copy        See above.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_PICTURE \endcode
+ *    \code (mime_type != NULL) \endcode
+ * \retval FLAC__bool
+ *    \c false if \a copy is \c true and malloc() fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_picture_set_mime_type(FLAC__StreamMetadata *object, char *mime_type, FLAC__bool copy);
+
+/** Sets the description of a PICTURE block.
+ *
+ *  If \a copy is \c true, a copy of the string is stored; otherwise, the object
+ *  takes ownership of the pointer.  The existing string will be freed if this
+ *  function is successful, otherwise the original string will remain if \a copy
+ *  is \c true and malloc() fails.
+ *
+ * \note It is safe to pass a const pointer to \a description if \a copy is \c true.
+ *
+ * \param object      A pointer to an existing PICTURE object.
+ * \param description A pointer to the description string.  The string must be
+ *                    valid UTF-8, NUL-terminated.  No validation is done.
+ * \param copy        See above.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_PICTURE \endcode
+ *    \code (description != NULL) \endcode
+ * \retval FLAC__bool
+ *    \c false if \a copy is \c true and malloc() fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_picture_set_description(FLAC__StreamMetadata *object, FLAC__byte *description, FLAC__bool copy);
+
+/** Sets the picture data of a PICTURE block.
+ *
+ *  If \a copy is \c true, a copy of the data is stored; otherwise, the object
+ *  takes ownership of the pointer.  Also sets the \a data_length field of the
+ *  metadata object to what is passed in as the \a length parameter.  The
+ *  existing data will be freed if this function is successful, otherwise the
+ *  original data and data_length will remain if \a copy is \c true and
+ *  malloc() fails.
+ *
+ * \note It is safe to pass a const pointer to \a data if \a copy is \c true.
+ *
+ * \param object  A pointer to an existing PICTURE object.
+ * \param data    A pointer to the data to set.
+ * \param length  The length of \a data in bytes.
+ * \param copy    See above.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_PICTURE \endcode
+ *    \code (data != NULL && length > 0) ||
+ * (data == NULL && length == 0 && copy == false) \endcode
+ * \retval FLAC__bool
+ *    \c false if \a copy is \c true and malloc() fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_picture_set_data(FLAC__StreamMetadata *object, FLAC__byte *data, FLAC__uint32 length, FLAC__bool copy);
+
+/** Check a PICTURE block to see if it conforms to the FLAC specification.
+ *  See the format specification for limits on the contents of the
+ *  PICTURE block.
+ *
+ * \param picture    A pointer to existing PICTURE block to be checked.
+ * \param violation  Address of a pointer to a string.  If there is a
+ *                   violation, a pointer to a string explanation of the
+ *                   violation will be returned here. \a violation may be
+ *                   \c NULL if you don't need the returned string.  Do not
+ *                   free the returned string; it will always point to static
+ *                   data.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_PICTURE \endcode
+ * \retval FLAC__bool
+ *    \c false if PICTURE block is illegal, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_picture_is_legal(const FLAC__StreamMetadata *object, const char **violation);
+
 /* \} */
 
 #ifdef __cplusplus
diff --git a/include/test_libs_common/metadata_utils.h b/include/test_libs_common/metadata_utils.h
index 3d7af19..882bf5b 100644
--- a/include/test_libs_common/metadata_utils.h
+++ b/include/test_libs_common/metadata_utils.h
@@ -40,6 +40,8 @@
 
 FLAC__bool mutils__compare_block_data_cuesheet(const FLAC__StreamMetadata_CueSheet *block, const FLAC__StreamMetadata_CueSheet *blockcopy);
 
+FLAC__bool mutils__compare_block_data_picture(const FLAC__StreamMetadata_Picture *block, const FLAC__StreamMetadata_Picture *blockcopy);
+
 FLAC__bool mutils__compare_block_data_unknown(const FLAC__StreamMetadata_Unknown *block, const FLAC__StreamMetadata_Unknown *blockcopy, unsigned block_length);
 
 FLAC__bool mutils__compare_block(const FLAC__StreamMetadata *block, const FLAC__StreamMetadata *blockcopy);
@@ -52,6 +54,7 @@
 	FLAC__StreamMetadata *application2,
 	FLAC__StreamMetadata *vorbiscomment,
 	FLAC__StreamMetadata *cuesheet,
+	FLAC__StreamMetadata *picture,
 	FLAC__StreamMetadata *unknown
 );
 
@@ -63,6 +66,7 @@
 	FLAC__StreamMetadata *application2,
 	FLAC__StreamMetadata *vorbiscomment,
 	FLAC__StreamMetadata *cuesheet,
+	FLAC__StreamMetadata *picture,
 	FLAC__StreamMetadata *unknown
 );
 
diff --git a/src/libFLAC++/metadata.cpp b/src/libFLAC++/metadata.cpp
index fc55703..30ca841 100644
--- a/src/libFLAC++/metadata.cpp
+++ b/src/libFLAC++/metadata.cpp
@@ -68,6 +68,9 @@
 					case FLAC__METADATA_TYPE_CUESHEET:
 						ret = new CueSheet(object, /*copy=*/false);
 						break;
+					case FLAC__METADATA_TYPE_PICTURE:
+						ret = new Picture(object, /*copy=*/false);
+						break;
 					default:
 						ret = new Unknown(object, /*copy=*/false);
 						break;
@@ -87,6 +90,7 @@
 			const SeekTable *seektable = dynamic_cast<const SeekTable *>(object);
 			const VorbisComment *vorbiscomment = dynamic_cast<const VorbisComment *>(object);
 			const CueSheet *cuesheet = dynamic_cast<const CueSheet *>(object);
+			const Picture *picture = dynamic_cast<const Picture *>(object);
 			const Unknown *unknown = dynamic_cast<const Unknown *>(object);
 
 			if(0 != streaminfo)
@@ -101,6 +105,8 @@
 				return new VorbisComment(*vorbiscomment);
 			else if(0 != cuesheet)
 				return new CueSheet(*cuesheet);
+			else if(0 != picture)
+				return new Picture(*picture);
 			else if(0 != unknown)
 				return new Unknown(*unknown);
 			else {
@@ -1015,6 +1021,111 @@
 
 
 		//
+		// Picture
+		//
+
+		Picture::Picture():
+		Prototype(FLAC__metadata_object_new(FLAC__METADATA_TYPE_PICTURE), /*copy=*/false)
+		{ }
+
+		Picture::~Picture()
+		{ }
+
+		::FLAC__StreamMetadata_Picture_Type Picture::get_type() const
+		{
+			FLAC__ASSERT(is_valid());
+			return object_->data.picture.type;
+		}
+
+		const char *Picture::get_mime_type() const
+		{
+			FLAC__ASSERT(is_valid());
+			return object_->data.picture.mime_type;
+		}
+
+		const FLAC__byte *Picture::get_description() const
+		{
+			FLAC__ASSERT(is_valid());
+			return object_->data.picture.description;
+		}
+
+		FLAC__uint32 Picture::get_width() const
+		{
+			FLAC__ASSERT(is_valid());
+			return object_->data.picture.width;
+		}
+
+		FLAC__uint32 Picture::get_height() const
+		{
+			FLAC__ASSERT(is_valid());
+			return object_->data.picture.height;
+		}
+
+		FLAC__uint32 Picture::get_depth() const
+		{
+			FLAC__ASSERT(is_valid());
+			return object_->data.picture.depth;
+		}
+
+		FLAC__uint32 Picture::get_data_length() const
+		{
+			FLAC__ASSERT(is_valid());
+			return object_->data.picture.data_length;
+		}
+
+		const FLAC__byte *Picture::get_data() const
+		{
+			FLAC__ASSERT(is_valid());
+			return object_->data.picture.data;
+		}
+
+		void Picture::set_type(::FLAC__StreamMetadata_Picture_Type type)
+		{
+			FLAC__ASSERT(is_valid());
+			object_->data.picture.type = type;
+		}
+
+		bool Picture::set_mime_type(const char *string)
+		{
+			FLAC__ASSERT(is_valid());
+			// We can safely const_cast since copy=true
+			return (bool)::FLAC__metadata_object_picture_set_mime_type(object_, const_cast<char*>(string), /*copy=*/true);
+		}
+
+		bool Picture::set_description(const FLAC__byte *string)
+		{
+			FLAC__ASSERT(is_valid());
+			// We can safely const_cast since copy=true
+			return (bool)::FLAC__metadata_object_picture_set_description(object_, const_cast<FLAC__byte*>(string), /*copy=*/true);
+		}
+
+		void Picture::set_width(FLAC__uint32 value) const
+		{
+			FLAC__ASSERT(is_valid());
+			object_->data.picture.width = value;
+		}
+
+		void Picture::set_height(FLAC__uint32 value) const
+		{
+			FLAC__ASSERT(is_valid());
+			object_->data.picture.height = value;
+		}
+
+		void Picture::set_depth(FLAC__uint32 value) const
+		{
+			FLAC__ASSERT(is_valid());
+			object_->data.picture.depth = value;
+		}
+
+		bool Picture::set_data(const FLAC__byte *data, FLAC__uint32 data_length)
+		{
+			FLAC__ASSERT(is_valid());
+			// We can safely const_cast since copy=true
+			return (bool)::FLAC__metadata_object_picture_set_data(object_, const_cast<FLAC__byte*>(data), data_length, /*copy=*/true);
+		}
+
+
+		//
 		// Unknown
 		//
 
@@ -1124,6 +1235,36 @@
 				return false;
 		}
 
+		FLACPP_API bool get_picture(const char *filename, Picture *&picture, ::FLAC__StreamMetadata_Picture_Type type, const char *mime_type, const FLAC__byte *description, unsigned max_width, unsigned max_height, unsigned max_depth)
+		{
+			FLAC__ASSERT(0 != filename);
+
+			::FLAC__StreamMetadata *object;
+
+			picture = 0;
+
+			if(::FLAC__metadata_get_picture(filename, &object, type, mime_type, description, max_width, max_height, max_depth)) {
+				picture = new Picture(object, /*copy=*/false);
+				return true;
+			}
+			else
+				return false;
+		}
+
+		FLACPP_API bool get_picture(const char *filename, Picture &picture, ::FLAC__StreamMetadata_Picture_Type type, const char *mime_type, const FLAC__byte *description, unsigned max_width, unsigned max_height, unsigned max_depth)
+		{
+			FLAC__ASSERT(0 != filename);
+
+			::FLAC__StreamMetadata *object;
+
+			if(::FLAC__metadata_get_picture(filename, &object, type, mime_type, description, max_width, max_height, max_depth)) {
+				picture.assign(object, /*copy=*/false);
+				return true;
+			}
+			else
+				return false;
+		}
+
 
 		// ============================================================
 		//
diff --git a/src/libFLAC/format.c b/src/libFLAC/format.c
index 939ec67..bb5feeb 100644
--- a/src/libFLAC/format.c
+++ b/src/libFLAC/format.c
@@ -104,6 +104,14 @@
 FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN = 7+258*8; /* bits */
 FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN = 8; /* bits */
 
+FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_TYPE_LEN = 32; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN = 32; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN = 32; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN = 32; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN = 32; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN = 32; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN = 32; /* bits */
+
 FLAC_API const unsigned FLAC__STREAM_METADATA_IS_LAST_LEN = 1; /* bits */
 FLAC_API const unsigned FLAC__STREAM_METADATA_TYPE_LEN = 7; /* bits */
 FLAC_API const unsigned FLAC__STREAM_METADATA_LENGTH_LEN = 24; /* bits */
@@ -168,7 +176,32 @@
 	"APPLICATION",
 	"SEEKTABLE",
 	"VORBIS_COMMENT",
-	"CUESHEET"
+	"CUESHEET",
+	"PICTURE"
+};
+
+FLAC_API const char * const FLAC__StreamMetadata_Picture_TypeString[] = {
+	"Other",
+	"32x32 pixels 'file icon' (PNG only)",
+	"Other file icon",
+	"Cover (front)",
+	"Cover (back)",
+	"Leaflet page",
+	"Media (e.g. label side of CD)",
+	"Lead artist/lead performer/soloist",
+	"Artist/performer",
+	"Conductor",
+	"Band/Orchestra",
+	"Composer",
+	"Lyricist/text writer",
+	"Recording Location",
+	"During recording",
+	"During performance",
+	"Movie/video screen capture",
+	"A bright coloured fish",
+	"Illustration",
+	"Band/artist logotype",
+	"Publisher/Studio logotype"
 };
 
 FLAC_API FLAC__bool FLAC__format_sample_rate_is_valid(unsigned sample_rate)
@@ -437,6 +470,30 @@
 	return true;
 }
 
+FLAC_API FLAC__bool FLAC__format_picture_is_legal(const FLAC__StreamMetadata_Picture *picture, const char **violation)
+{
+	char *p;
+	FLAC__byte *b;
+
+	for(p = picture->mime_type; *p; p++) {
+		if(*p < 0x20 || *p > 0x7e) {
+			if(violation) *violation = "MIME type string must contain only printable ASCII characters (0x20-0x7e)";
+			return false;
+		}
+	}
+
+	for(b = picture->description; *b; ) {
+		unsigned n = utf8len_(b);
+		if(n == 0) {
+			if(violation) *violation = "description string must be valid UTF-8";
+			return false;
+		}
+		b += n;
+	}
+
+	return true;
+}
+
 /*
  * These routines are private to libFLAC
  */
diff --git a/src/libFLAC/include/private/metadata.h b/src/libFLAC/include/private/metadata.h
index 277d989..7d4b5d8 100644
--- a/src/libFLAC/include/private/metadata.h
+++ b/src/libFLAC/include/private/metadata.h
@@ -34,7 +34,12 @@
 
 #include "FLAC/metadata.h"
 
+/* WATCHOUT: all malloc()ed data in the block is free()ed; this may not
+ * be a consistent state (e.g. PICTURE) or equivalent to the initial
+ * state after FLAC__metadata_object_new()
+ */
 void FLAC__metadata_object_delete_data(FLAC__StreamMetadata *object);
+
 void FLAC__metadata_object_cuesheet_track_delete_data(FLAC__StreamMetadata_CueSheet_Track *object);
 
 #endif
diff --git a/src/libFLAC/metadata_iterators.c b/src/libFLAC/metadata_iterators.c
index 2ecb8b1..a1c699a 100644
--- a/src/libFLAC/metadata_iterators.c
+++ b/src/libFLAC/metadata_iterators.c
@@ -92,6 +92,7 @@
 static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_vorbis_comment_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_VorbisComment *block);
 static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_cuesheet_track_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_CueSheet_Track *track);
 static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_cuesheet_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_CueSheet *block);
+static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_picture_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_Picture *block);
 static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_unknown_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_Unknown *block, unsigned block_length);
 
 static FLAC__bool write_metadata_block_header_(FILE *file, FLAC__Metadata_SimpleIteratorStatus *status, const FLAC__StreamMetadata *block);
@@ -104,6 +105,7 @@
 static FLAC__bool write_metadata_block_data_seektable_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_SeekTable *block);
 static FLAC__bool write_metadata_block_data_vorbis_comment_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_VorbisComment *block);
 static FLAC__bool write_metadata_block_data_cuesheet_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_CueSheet *block);
+static FLAC__bool write_metadata_block_data_picture_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Picture *block);
 static FLAC__bool write_metadata_block_data_unknown_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Unknown *block, unsigned block_length);
 
 static FLAC__bool write_metadata_block_stationary_(FLAC__Metadata_SimpleIterator *iterator, const FLAC__StreamMetadata *block);
@@ -274,6 +276,55 @@
 		cd->got_error = true;
 }
 
+FLAC_API FLAC__bool FLAC__metadata_get_picture(const char *filename, FLAC__StreamMetadata **picture, FLAC__StreamMetadata_Picture_Type type, const char *mime_type, const FLAC__byte *description, unsigned max_width, unsigned max_height, unsigned max_depth)
+{
+	FLAC__Metadata_SimpleIterator *it;
+	FLAC__uint64 max_area_seen = 0;
+	FLAC__uint64 max_depth_seen = 0;
+
+	FLAC__ASSERT(0 != filename);
+	FLAC__ASSERT(0 != picture);
+
+	*picture = 0;
+
+	it = FLAC__metadata_simple_iterator_new();
+	if(0 == it)
+		return false;
+	if(!FLAC__metadata_simple_iterator_init(it, filename, /*read_only=*/true, /*preserve_file_stats=*/true)) {
+		FLAC__metadata_simple_iterator_delete(it);
+		return false;
+	}
+	do {
+		if(FLAC__metadata_simple_iterator_get_block_type(it) == FLAC__METADATA_TYPE_PICTURE) {
+			FLAC__StreamMetadata *obj = FLAC__metadata_simple_iterator_get_block(it);
+			FLAC__uint64 area = (FLAC__uint64)obj->data.picture.width * (FLAC__uint64)obj->data.picture.height;
+			/* check constraints */
+			if(
+				(type == (FLAC__StreamMetadata_Picture_Type)(-1) || type == obj->data.picture.type) &&
+				(mime_type == 0 || !strcmp(mime_type, obj->data.picture.mime_type)) &&
+				(description == 0 || !strcmp((const char *)description, (const char *)obj->data.picture.description)) &&
+				obj->data.picture.width <= max_width &&
+				obj->data.picture.height <= max_height &&
+				obj->data.picture.depth <= max_depth &&
+				(area > max_area_seen || (area == max_area_seen && obj->data.picture.depth > max_depth_seen))
+			) {
+				if(*picture)
+					FLAC__metadata_object_delete(*picture);
+				*picture = obj;
+				max_area_seen = area;
+				max_depth_seen = obj->data.picture.depth;
+			}
+			else {
+				FLAC__metadata_object_delete(obj);
+			}
+		}
+	} while(FLAC__metadata_simple_iterator_next(it));
+
+	FLAC__metadata_simple_iterator_delete(it);
+
+	return (0 != *picture);
+}
+
 
 /****************************************************************************
  *
@@ -1851,6 +1902,8 @@
 			return read_metadata_block_data_vorbis_comment_cb_(handle, read_cb, &block->data.vorbis_comment);
 		case FLAC__METADATA_TYPE_CUESHEET:
 			return read_metadata_block_data_cuesheet_cb_(handle, read_cb, &block->data.cue_sheet);
+		case FLAC__METADATA_TYPE_PICTURE:
+			return read_metadata_block_data_picture_cb_(handle, read_cb, &block->data.picture);
 		default:
 			return read_metadata_block_data_unknown_cb_(handle, read_cb, &block->data.unknown, block->length);
 	}
@@ -1882,7 +1935,6 @@
 	return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
 }
 
-
 FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_padding_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Seek seek_cb, FLAC__StreamMetadata_Padding *block, unsigned block_length)
 {
 	(void)block; /* nothing to do; we don't care about reading the padding bytes */
@@ -1947,7 +1999,7 @@
 	const unsigned entry_length_len = FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN / 8;
 	FLAC__byte buffer[4]; /* magic number is asserted below */
 
-	FLAC__ASSERT(FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN / 8 == 4);
+	FLAC__ASSERT(FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN / 8 == sizeof(buffer));
 
 	if(read_cb(buffer, 1, entry_length_len, handle) != entry_length_len)
 		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
@@ -1979,7 +2031,7 @@
 	const unsigned num_comments_len = FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN / 8;
 	FLAC__byte buffer[4]; /* magic number is asserted below */
 
-	FLAC__ASSERT(FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN / 8 == 4);
+	FLAC__ASSERT(FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN / 8 == sizeof(buffer));
 
 	if(FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK != (status = read_metadata_block_data_vorbis_comment_entry_cb_(handle, read_cb, &(block->vendor_string))))
 		return status;
@@ -2117,6 +2169,85 @@
 	return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
 }
 
+FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_picture_cstring_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__byte **data, FLAC__uint32 *length, FLAC__uint32 length_len)
+{
+	FLAC__byte buffer[sizeof(FLAC__uint32)];
+
+	FLAC__ASSERT(0 != data);
+	FLAC__ASSERT(length_len%8 == 0);
+
+	length_len /= 8; /* convert to bytes */
+
+	FLAC__ASSERT(sizeof(buffer) >= length_len);
+
+	if(read_cb(buffer, 1, length_len, handle) != length_len)
+		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+	*length = unpack_uint32_(buffer, length_len);
+
+	if(0 != *data)
+		free(*data);
+
+	if(0 == (*data = (FLAC__byte*)malloc(*length+1)))
+		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
+
+	if(*length > 0) {
+		if(read_cb(*data, 1, *length, handle) != *length)
+			return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+	}
+
+	(*data)[*length] = '\0';
+
+	return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
+}
+
+FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_picture_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_Picture *block)
+{
+	FLAC__Metadata_SimpleIteratorStatus status;
+	FLAC__byte buffer[4]; /* asserted below that this is big enough */
+	FLAC__uint32 len;
+
+	FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_TYPE_LEN/8);
+	FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN/8);
+	FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN/8);
+	FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN/8);
+
+	FLAC__ASSERT(FLAC__STREAM_METADATA_PICTURE_TYPE_LEN % 8 == 0);
+	len = FLAC__STREAM_METADATA_PICTURE_TYPE_LEN / 8;
+	if(read_cb(buffer, 1, len, handle) != len)
+		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+	block->type = (FLAC__StreamMetadata_Picture_Type)unpack_uint32_(buffer, len);
+
+	if((status = read_metadata_block_data_picture_cstring_cb_(handle, read_cb, (FLAC__byte**)(&(block->mime_type)), &len, FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN)) != FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK)
+		return status;
+
+	if((status = read_metadata_block_data_picture_cstring_cb_(handle, read_cb, &(block->description), &len, FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN)) != FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK)
+		return status;
+
+	FLAC__ASSERT(FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN % 8 == 0);
+	len = FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN / 8;
+	if(read_cb(buffer, 1, len, handle) != len)
+		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+	block->width = unpack_uint32_(buffer, len);
+
+	FLAC__ASSERT(FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN % 8 == 0);
+	len = FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN / 8;
+	if(read_cb(buffer, 1, len, handle) != len)
+		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+	block->height = unpack_uint32_(buffer, len);
+
+	FLAC__ASSERT(FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN % 8 == 0);
+	len = FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN / 8;
+	if(read_cb(buffer, 1, len, handle) != len)
+		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+	block->depth = unpack_uint32_(buffer, len);
+
+	/* for convenience we use read_metadata_block_data_picture_cstring_cb_() even though it adds an extra terminating NUL we don't use */
+	if((status = read_metadata_block_data_picture_cstring_cb_(handle, read_cb, &(block->data), &(block->data_length), FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN)) != FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK)
+		return status;
+
+	return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
+}
+
 FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_unknown_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_Unknown *block, unsigned block_length)
 {
 	if(block_length == 0) {
@@ -2193,6 +2324,8 @@
 			return write_metadata_block_data_vorbis_comment_cb_(handle, write_cb, &block->data.vorbis_comment);
 		case FLAC__METADATA_TYPE_CUESHEET:
 			return write_metadata_block_data_cuesheet_cb_(handle, write_cb, &block->data.cue_sheet);
+		case FLAC__METADATA_TYPE_PICTURE:
+			return write_metadata_block_data_picture_cb_(handle, write_cb, &block->data.picture);
 		default:
 			return write_metadata_block_data_unknown_cb_(handle, write_cb, &block->data.unknown, block->length);
 	}
@@ -2285,7 +2418,7 @@
 	const unsigned num_comments_len = FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN / 8;
 	FLAC__byte buffer[4]; /* magic number is asserted below */
 
-	FLAC__ASSERT(max(FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN, FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN) / 8 == 4);
+	FLAC__ASSERT(max(FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN, FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN) / 8 == sizeof(buffer));
 
 	pack_uint32_little_endian_(block->vendor_string.length, buffer, entry_length_len);
 	if(write_cb(buffer, 1, entry_length_len, handle) != entry_length_len)
@@ -2402,6 +2535,73 @@
 	return true;
 }
 
+FLAC__bool write_metadata_block_data_picture_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Picture *block)
+{
+	unsigned len;
+	size_t slen;
+	FLAC__byte buffer[4]; /* magic number is asserted below */
+
+	FLAC__ASSERT(0 == FLAC__STREAM_METADATA_PICTURE_TYPE_LEN%8);
+	FLAC__ASSERT(0 == FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN%8);
+	FLAC__ASSERT(0 == FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN%8);
+	FLAC__ASSERT(0 == FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN%8);
+	FLAC__ASSERT(0 == FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN%8);
+	FLAC__ASSERT(0 == FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN%8);
+	FLAC__ASSERT(0 == FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN%8);
+	FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_TYPE_LEN/8);
+	FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN/8);
+	FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN/8);
+	FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN/8);
+	FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN/8);
+	FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN/8);
+	FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN/8);
+
+	len = FLAC__STREAM_METADATA_PICTURE_TYPE_LEN/8;
+	pack_uint32_(block->type, buffer, len);
+	if(write_cb(buffer, 1, len, handle) != len)
+		return false;
+
+	len = FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN/8;
+	slen = strlen(block->mime_type);
+	pack_uint32_(slen, buffer, len);
+	if(write_cb(buffer, 1, len, handle) != len)
+		return false;
+	if(write_cb(block->mime_type, 1, slen, handle) != slen)
+		return false;
+
+	len = FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN/8;
+	slen = strlen((const char *)block->description);
+	pack_uint32_(slen, buffer, len);
+	if(write_cb(buffer, 1, len, handle) != len)
+		return false;
+	if(write_cb(block->description, 1, slen, handle) != slen)
+		return false;
+
+	len = FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN/8;
+	pack_uint32_(block->width, buffer, len);
+	if(write_cb(buffer, 1, len, handle) != len)
+		return false;
+
+	len = FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN/8;
+	pack_uint32_(block->height, buffer, len);
+	if(write_cb(buffer, 1, len, handle) != len)
+		return false;
+
+	len = FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN/8;
+	pack_uint32_(block->depth, buffer, len);
+	if(write_cb(buffer, 1, len, handle) != len)
+		return false;
+
+	len = FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN/8;
+	pack_uint32_(block->data_length, buffer, len);
+	if(write_cb(buffer, 1, len, handle) != len)
+		return false;
+	if(write_cb(block->data, 1, block->data_length, handle) != block->data_length)
+		return false;
+
+	return true;
+}
+
 FLAC__bool write_metadata_block_data_unknown_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Unknown *block, unsigned block_length)
 {
 	if(write_cb(block->data, 1, block_length, handle) != block_length)
@@ -2556,7 +2756,7 @@
 	size_t n;
 	unsigned i;
 
-	FLAC__ASSERT(FLAC__STREAM_SYNC_LENGTH == 4);
+	FLAC__ASSERT(FLAC__STREAM_SYNC_LENGTH == sizeof(buffer));
 
 	/* skip any id3v2 tag */
 	errno = 0;
diff --git a/src/libFLAC/metadata_object.c b/src/libFLAC/metadata_object.c
index 6846c3b..7efa2cf 100644
--- a/src/libFLAC/metadata_object.c
+++ b/src/libFLAC/metadata_object.c
@@ -47,8 +47,17 @@
  *
  ***************************************************************************/
 
+/* copy bytes:
+ *  from = NULL  && bytes = 0
+ *       to <- NULL
+ *  from != NULL && bytes > 0
+ *       to <- copy of from
+ *  else ASSERT
+ * malloc error leaved 'to' unchanged
+ */
 static FLAC__bool copy_bytes_(FLAC__byte **to, const FLAC__byte *from, unsigned bytes)
 {
+	FLAC__ASSERT(0 != to);
 	if(bytes > 0 && 0 != from) {
 		FLAC__byte *x;
 		if(0 == (x = (FLAC__byte*)malloc(bytes)))
@@ -64,6 +73,25 @@
 	return true;
 }
 
+#if 0 /* UNUSED */
+/* like copy_bytes_(), but free()s the original '*to' if the copy succeeds and the original '*to' is non-NULL */
+static FLAC__bool free_copy_bytes_(FLAC__byte **to, const FLAC__byte *from, unsigned bytes)
+{
+	FLAC__byte *copy;
+	FLAC__ASSERT(0 != to);
+	if(copy_bytes_(&copy, from, bytes)) {
+		if(*to)
+			free(*to);
+		*to = copy;
+		return true;
+	}
+	else
+		return false;
+}
+#endif
+
+/* reallocate entry to 1 byte larger and add a terminating NUL */
+/* realloc() failure leaves entry unchanged */
 static FLAC__bool ensure_null_terminated_(FLAC__byte **entry, unsigned length)
 {
 	FLAC__byte *x = (FLAC__byte*)realloc(*entry, length+1);
@@ -76,6 +104,24 @@
 		return false;
 }
 
+/* copies the NUL-terminated C-string 'from' to '*to', leaving '*to'
+ * unchanged if malloc fails, free()ing the original '*to' if it
+ * succeeds and the original '*to' was not NULL
+ */
+static FLAC__bool copy_cstring_(char **to, const char *from)
+{
+	FLAC__ASSERT(to);
+	char *copy = strdup(from);
+	if(copy) {
+		if(*to)
+			free(*to);
+		*to = copy;
+		return true;
+	}
+	else
+		return false;
+}
+
 static FLAC__bool copy_vcentry_(FLAC__StreamMetadata_VorbisComment_Entry *to, const FLAC__StreamMetadata_VorbisComment_Entry *from)
 {
 	to->length = from->length;
@@ -417,18 +463,49 @@
 				*/
 				break;
 			case FLAC__METADATA_TYPE_VORBIS_COMMENT:
-				{
-					object->data.vorbis_comment.vendor_string.length = (unsigned)strlen(FLAC__VENDOR_STRING);
-					if(!copy_bytes_(&object->data.vorbis_comment.vendor_string.entry, (const FLAC__byte*)FLAC__VENDOR_STRING, object->data.vorbis_comment.vendor_string.length+1)) {
-						free(object);
-						return 0;
-					}
-					vorbiscomment_calculate_length_(object);
+				object->data.vorbis_comment.vendor_string.length = (unsigned)strlen(FLAC__VENDOR_STRING);
+				if(!copy_bytes_(&object->data.vorbis_comment.vendor_string.entry, (const FLAC__byte*)FLAC__VENDOR_STRING, object->data.vorbis_comment.vendor_string.length+1)) {
+					free(object);
+					return 0;
 				}
+				vorbiscomment_calculate_length_(object);
 				break;
 			case FLAC__METADATA_TYPE_CUESHEET:
 				cuesheet_calculate_length_(object);
 				break;
+			case FLAC__METADATA_TYPE_PICTURE:
+				object->length = (
+					FLAC__STREAM_METADATA_PICTURE_TYPE_LEN +
+					FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN + /* empty mime_type string */
+					FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN + /* empty description string */
+					FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN +
+					FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN +
+					FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN +
+					FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN +
+					0 /* no data */
+				) / 8;
+				object->data.picture.type = FLAC__STREAM_METADATA_PICTURE_TYPE_OTHER;
+				object->data.picture.mime_type = 0;
+				object->data.picture.description = 0;
+				/* calloc() took care of this for us:
+				object->data.picture.width = 0;
+				object->data.picture.height = 0;
+				object->data.picture.depth = 0;
+				object->data.picture.data_length = 0;
+				object->data.picture.data = 0;
+				*/
+				/* now initialize mime_type and description with empty strings to make things easier on the client */
+				if(!copy_cstring_(&object->data.picture.mime_type, "")) {
+					free(object);
+					return 0;
+				}
+				if(!copy_cstring_((char**)(&object->data.picture.description), "")) {
+					if(object->data.picture.mime_type)
+						free(object->data.picture.mime_type);
+					free(object);
+					return 0;
+				}
+				break;
 			default:
 				/* calloc() took care of this for us:
 				object->length = 0;
@@ -508,6 +585,25 @@
 					}
 				}
 				break;
+			case FLAC__METADATA_TYPE_PICTURE:
+				to->data.picture.type = object->data.picture.type;
+				if(!copy_cstring_(&to->data.picture.mime_type, object->data.picture.mime_type)) {
+					FLAC__metadata_object_delete(to);
+					return 0;
+				}
+				if(!copy_cstring_((char**)(&to->data.picture.description), (const char*)object->data.picture.description)) {
+					FLAC__metadata_object_delete(to);
+					return 0;
+				}
+				to->data.picture.width = object->data.picture.width;
+				to->data.picture.height = object->data.picture.height;
+				to->data.picture.depth = object->data.picture.depth;
+				to->data.picture.data_length = object->data.picture.data_length;
+				if(!copy_bytes_((&to->data.picture.data), object->data.picture.data, object->data.picture.data_length)) {
+					FLAC__metadata_object_delete(to);
+					return 0;
+				}
+				break;
 			default:
 				if(!copy_bytes_(&to->data.unknown.data, object->data.unknown.data, object->length)) {
 					FLAC__metadata_object_delete(to);
@@ -556,6 +652,20 @@
 				cuesheet_track_array_delete_(object->data.cue_sheet.tracks, object->data.cue_sheet.num_tracks);
 			}
 			break;
+		case FLAC__METADATA_TYPE_PICTURE:
+			if(0 != object->data.picture.mime_type) {
+				free(object->data.picture.mime_type);
+				object->data.picture.mime_type = 0;
+			}
+			if(0 != object->data.picture.description) {
+				free(object->data.picture.description);
+				object->data.picture.description = 0;
+			}
+			if(0 != object->data.picture.data) {
+				free(object->data.picture.data);
+				object->data.picture.data = 0;
+			}
+			break;
 		default:
 			if(0 != object->data.unknown.data) {
 				free(object->data.unknown.data);
@@ -710,6 +820,27 @@
 	return true;
 }
 
+static FLAC__bool compare_block_data_picture_(const FLAC__StreamMetadata_Picture *block1, const FLAC__StreamMetadata_Picture *block2)
+{
+	if(block1->type != block2->type)
+		return false;
+	if(block1->mime_type != block2->mime_type && (0 == block1->mime_type || 0 == block2->mime_type || strcmp(block1->mime_type, block2->mime_type)))
+		return false;
+	if(block1->description != block2->description && (0 == block1->description || 0 == block2->description || strcmp((const char *)block1->description, (const char *)block2->description)))
+		return false;
+	if(block1->width != block2->width)
+		return false;
+	if(block1->height != block2->height)
+		return false;
+	if(block1->depth != block2->depth)
+		return false;
+	if(block1->data_length != block2->data_length)
+		return false;
+	if(block1->data != block2->data && (0 == block1->data || 0 == block2->data || memcmp(block1->data, block2->data, block1->data_length)))
+		return false;
+	return true;
+}
+
 static FLAC__bool compare_block_data_unknown_(const FLAC__StreamMetadata_Unknown *block1, const FLAC__StreamMetadata_Unknown *block2, unsigned block_length)
 {
 	FLAC__ASSERT(0 != block1);
@@ -748,6 +879,8 @@
 			return compare_block_data_vorbiscomment_(&block1->data.vorbis_comment, &block2->data.vorbis_comment);
 		case FLAC__METADATA_TYPE_CUESHEET:
 			return compare_block_data_cuesheet_(&block1->data.cue_sheet, &block2->data.cue_sheet);
+		case FLAC__METADATA_TYPE_PICTURE:
+			return compare_block_data_picture_(&block1->data.picture, &block2->data.picture);
 		default:
 			return compare_block_data_unknown_(&block1->data.unknown, &block2->data.unknown, block1->length);
 	}
@@ -1553,3 +1686,99 @@
 		return (sum % 0xFF) << 24 | length << 8 | (FLAC__uint32)(cs->num_tracks-1);
 	}
 }
+
+FLAC_API FLAC__bool FLAC__metadata_object_picture_set_mime_type(FLAC__StreamMetadata *object, char *mime_type, FLAC__bool copy)
+{
+	char *old;
+	size_t old_length, new_length;
+
+	FLAC__ASSERT(0 != object);
+	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_PICTURE);
+	FLAC__ASSERT(0 != mime_type);
+
+	old = object->data.picture.mime_type;
+	old_length = old? strlen(old) : 0;
+	new_length = strlen(mime_type);
+
+	/* do the copy first so that if we fail we leave the object untouched */
+	if(copy) {
+		if(!copy_bytes_((FLAC__byte**)(&object->data.picture.mime_type), (FLAC__byte*)mime_type, new_length+1))
+			return false;
+	}
+	else {
+		object->data.picture.mime_type = mime_type;
+	}
+
+	if(0 != old)
+		free(old);
+
+	object->length -= old_length;
+	object->length += new_length;
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_picture_set_description(FLAC__StreamMetadata *object, FLAC__byte *description, FLAC__bool copy)
+{
+	FLAC__byte *old;
+	size_t old_length, new_length;
+
+	FLAC__ASSERT(0 != object);
+	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_PICTURE);
+	FLAC__ASSERT(0 != description);
+
+	old = object->data.picture.description;
+	old_length = old? strlen((const char *)old) : 0;
+	new_length = strlen((const char *)description);
+
+	/* do the copy first so that if we fail we leave the object untouched */
+	if(copy) {
+		if(!copy_bytes_(&object->data.picture.description, description, new_length+1))
+			return false;
+	}
+	else {
+		object->data.picture.description = description;
+	}
+
+	if(0 != old)
+		free(old);
+
+	object->length -= old_length;
+	object->length += new_length;
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_picture_set_data(FLAC__StreamMetadata *object, FLAC__byte *data, FLAC__uint32 length, FLAC__bool copy)
+{
+	FLAC__byte *old;
+
+	FLAC__ASSERT(0 != object);
+	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_PICTURE);
+	FLAC__ASSERT((0 != data && length > 0) || (0 == data && length == 0 && copy == false));
+
+	old = object->data.picture.data;
+
+	/* do the copy first so that if we fail we leave the object untouched */
+	if(copy) {
+		if(!copy_bytes_(&object->data.picture.data, data, length))
+			return false;
+	}
+	else {
+		object->data.picture.data = data;
+	}
+
+	if(0 != old)
+		free(old);
+
+	object->length -= object->data.picture.data_length;
+	object->data.picture.data_length = length;
+	object->length += length;
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_picture_is_legal(const FLAC__StreamMetadata *object, const char **violation)
+{
+	FLAC__ASSERT(0 != object);
+	FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_PICTURE);
+
+	return FLAC__format_picture_is_legal(&object->data.picture, violation);
+}
diff --git a/src/libFLAC/stream_decoder.c b/src/libFLAC/stream_decoder.c
index d64280d..802d495 100644
--- a/src/libFLAC/stream_decoder.c
+++ b/src/libFLAC/stream_decoder.c
@@ -99,6 +99,7 @@
 static FLAC__bool read_metadata_seektable_(FLAC__StreamDecoder *decoder, FLAC__bool is_last, unsigned length);
 static FLAC__bool read_metadata_vorbiscomment_(FLAC__StreamDecoder *decoder, FLAC__StreamMetadata_VorbisComment *obj);
 static FLAC__bool read_metadata_cuesheet_(FLAC__StreamDecoder *decoder, FLAC__StreamMetadata_CueSheet *obj);
+static FLAC__bool read_metadata_picture_(FLAC__StreamDecoder *decoder, FLAC__StreamMetadata_Picture *obj);
 static FLAC__bool skip_id3v2_tag_(FLAC__StreamDecoder *decoder);
 static FLAC__bool frame_sync_(FLAC__StreamDecoder *decoder);
 static FLAC__bool read_frame_(FLAC__StreamDecoder *decoder, FLAC__bool *got_a_frame, FLAC__bool do_full_decode);
@@ -1296,6 +1297,10 @@
 					if(!read_metadata_cuesheet_(decoder, &block.data.cue_sheet))
 						return false;
 					break;
+				case FLAC__METADATA_TYPE_PICTURE:
+					if(!read_metadata_picture_(decoder, &block.data.picture))
+						return false;
+					break;
 				case FLAC__METADATA_TYPE_STREAMINFO:
 				case FLAC__METADATA_TYPE_SEEKTABLE:
 					FLAC__ASSERT(0);
@@ -1342,6 +1347,14 @@
 					if(0 != block.data.cue_sheet.tracks)
 						free(block.data.cue_sheet.tracks);
 					break;
+				case FLAC__METADATA_TYPE_PICTURE:
+					if(0 != block.data.picture.mime_type)
+						free(block.data.picture.mime_type);
+					if(0 != block.data.picture.description)
+						free(block.data.picture.description);
+					if(0 != block.data.picture.data)
+						free(block.data.picture.data);
+					break;
 				case FLAC__METADATA_TYPE_STREAMINFO:
 				case FLAC__METADATA_TYPE_SEEKTABLE:
 					FLAC__ASSERT(0);
@@ -1616,6 +1629,69 @@
 	return true;
 }
 
+FLAC__bool read_metadata_picture_(FLAC__StreamDecoder *decoder, FLAC__StreamMetadata_Picture *obj)
+{
+	FLAC__uint32 len;
+
+	FLAC__ASSERT(FLAC__bitbuffer_is_consumed_byte_aligned(decoder->private_->input));
+
+	/* read type */
+	if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &obj->type, FLAC__STREAM_METADATA_PICTURE_TYPE_LEN, read_callback_, decoder))
+		return false; /* read_callback_ sets the state for us */
+
+	/* read MIME type */
+	if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &len, FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN, read_callback_, decoder))
+		return false; /* read_callback_ sets the state for us */
+	if(0 == (obj->mime_type = (char*)malloc(len+1))) {
+		decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+		return false;
+	}
+	if(len > 0) {
+		if(!FLAC__bitbuffer_read_byte_block_aligned_no_crc(decoder->private_->input, (FLAC__byte*)obj->mime_type, len, read_callback_, decoder))
+			return false; /* read_callback_ sets the state for us */
+	}
+	obj->mime_type[len] = '\0';
+
+	/* read description */
+	if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &len, FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN, read_callback_, decoder))
+		return false; /* read_callback_ sets the state for us */
+	if(0 == (obj->description = (FLAC__byte*)malloc(len+1))) {
+		decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+		return false;
+	}
+	if(len > 0) {
+		if(!FLAC__bitbuffer_read_byte_block_aligned_no_crc(decoder->private_->input, obj->description, len, read_callback_, decoder))
+			return false; /* read_callback_ sets the state for us */
+	}
+	obj->description[len] = '\0';
+
+	/* read width */
+	if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &obj->width, FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN, read_callback_, decoder))
+		return false; /* read_callback_ sets the state for us */
+
+	/* read height */
+	if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &obj->height, FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN, read_callback_, decoder))
+		return false; /* read_callback_ sets the state for us */
+
+	/* read depth */
+	if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &obj->depth, FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN, read_callback_, decoder))
+		return false; /* read_callback_ sets the state for us */
+
+	/* read data */
+	if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &(obj->data_length), FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN, read_callback_, decoder))
+		return false; /* read_callback_ sets the state for us */
+	if(0 == (obj->data = (FLAC__byte*)malloc(obj->data_length))) {
+		decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+		return false;
+	}
+	if(obj->data_length > 0) {
+		if(!FLAC__bitbuffer_read_byte_block_aligned_no_crc(decoder->private_->input, obj->data, obj->data_length, read_callback_, decoder))
+			return false; /* read_callback_ sets the state for us */
+	}
+
+	return true;
+}
+
 FLAC__bool skip_id3v2_tag_(FLAC__StreamDecoder *decoder)
 {
 	FLAC__uint32 x;
diff --git a/src/libFLAC/stream_encoder.c b/src/libFLAC/stream_encoder.c
index be11e5e..407346f 100644
--- a/src/libFLAC/stream_encoder.c
+++ b/src/libFLAC/stream_encoder.c
@@ -773,6 +773,10 @@
 			if(!FLAC__format_cuesheet_is_legal(&encoder->protected_->metadata[i]->data.cue_sheet, encoder->protected_->metadata[i]->data.cue_sheet.is_cd, /*violation=*/0))
 				return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA;
 		}
+		else if(encoder->protected_->metadata[i]->type == FLAC__METADATA_TYPE_PICTURE) {
+			if(!FLAC__format_picture_is_legal(&encoder->protected_->metadata[i]->data.picture, /*violation=*/0))
+				return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA;
+		}
 	}
 
 	encoder->private_->input_capacity = 0;
diff --git a/src/libFLAC/stream_encoder_framing.c b/src/libFLAC/stream_encoder_framing.c
index 87611b7..29bde9e 100644
--- a/src/libFLAC/stream_encoder_framing.c
+++ b/src/libFLAC/stream_encoder_framing.c
@@ -177,6 +177,33 @@
 				}
 			}
 			break;
+		case FLAC__METADATA_TYPE_PICTURE:
+			{
+				size_t len;
+				if(!FLAC__bitbuffer_write_raw_uint32(bb, metadata->data.picture.type, FLAC__STREAM_METADATA_PICTURE_TYPE_LEN))
+					return false;
+				len = strlen(metadata->data.picture.mime_type);
+				if(!FLAC__bitbuffer_write_raw_uint32(bb, len, FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN))
+					return false;
+				if(!FLAC__bitbuffer_write_byte_block(bb, (const FLAC__byte*)metadata->data.picture.mime_type, len))
+					return false;
+				len = strlen((const char *)metadata->data.picture.description);
+				if(!FLAC__bitbuffer_write_raw_uint32(bb, len, FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN))
+					return false;
+				if(!FLAC__bitbuffer_write_byte_block(bb, metadata->data.picture.description, len))
+					return false;
+				if(!FLAC__bitbuffer_write_raw_uint32(bb, metadata->data.picture.width, FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN))
+					return false;
+				if(!FLAC__bitbuffer_write_raw_uint32(bb, metadata->data.picture.height, FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN))
+					return false;
+				if(!FLAC__bitbuffer_write_raw_uint32(bb, metadata->data.picture.depth, FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN))
+					return false;
+				if(!FLAC__bitbuffer_write_raw_uint32(bb, metadata->data.picture.data_length, FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN))
+					return false;
+				if(!FLAC__bitbuffer_write_byte_block(bb, metadata->data.picture.data, metadata->data.picture.data_length))
+					return false;
+			}
+			break;
 		default:
 			if(!FLAC__bitbuffer_write_byte_block(bb, metadata->data.unknown.data, metadata->length))
 				return false;
diff --git a/src/metaflac/operations.c b/src/metaflac/operations.c
index a2a7d7f..aad872b 100644
--- a/src/metaflac/operations.c
+++ b/src/metaflac/operations.c
@@ -646,6 +646,18 @@
 				}
 			}
 			break;
+		case FLAC__METADATA_TYPE_PICTURE:
+			PPR; printf("  type: %u (%s)\n", block->data.picture.type, block->data.picture.type < FLAC__STREAM_METADATA_PICTURE_TYPE_UNDEFINED? FLAC__StreamMetadata_Picture_TypeString[block->data.picture.type] : "UNDEFINED");
+			PPR; printf("  MIME type: %s\n", block->data.picture.mime_type);
+			PPR; printf("  description: %s\n", block->data.picture.description);
+			PPR; printf("  width: %u\n", (unsigned)block->data.picture.width);
+			PPR; printf("  height: %u\n", (unsigned)block->data.picture.height);
+			PPR; printf("  depth: %u\n", (unsigned)block->data.picture.depth);
+			PPR; printf("  data length: %u\n", (unsigned)block->data.picture.data_length);
+			PPR; printf("  data:\n");
+			if(0 != block->data.picture.data)
+				hexdump(filename, block->data.picture.data, block->data.picture.data_length, "    ");
+			break;
 		default:
 			PPR; printf("  data contents:\n");
 			if(0 != block->data.unknown.data)
diff --git a/src/test_libFLAC++/decoders.cpp b/src/test_libFLAC++/decoders.cpp
index 486af3b..976342d 100644
--- a/src/test_libFLAC++/decoders.cpp
+++ b/src/test_libFLAC++/decoders.cpp
@@ -58,8 +58,8 @@
 	"Filename"
 };
 
-static ::FLAC__StreamMetadata streaminfo_, padding_, seektable_, application1_, application2_, vorbiscomment_, cuesheet_, unknown_;
-static ::FLAC__StreamMetadata *expected_metadata_sequence_[8];
+static ::FLAC__StreamMetadata streaminfo_, padding_, seektable_, application1_, application2_, vorbiscomment_, cuesheet_, picture_, unknown_;
+static ::FLAC__StreamMetadata *expected_metadata_sequence_[9];
 static unsigned num_expected_;
 static const char *flacfilename_ = "metadata.flac";
 static off_t flacfilesize_;
@@ -86,12 +86,12 @@
 
 static void init_metadata_blocks_()
 {
-	mutils__init_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &unknown_);
+	mutils__init_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &picture_, &unknown_);
 }
 
 static void free_metadata_blocks_()
 {
-	mutils__free_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &unknown_);
+	mutils__free_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &picture_, &unknown_);
 }
 
 static bool generate_file_()
@@ -105,6 +105,7 @@
 	expected_metadata_sequence_[num_expected_++] = &application2_;
 	expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
 	expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+	expected_metadata_sequence_[num_expected_++] = &picture_;
 	expected_metadata_sequence_[num_expected_++] = &unknown_;
 
 	if(!file_utils__generate_flacfile(flacfilename_, &flacfilesize_, 512 * 1024, &streaminfo_, expected_metadata_sequence_, num_expected_))
@@ -710,6 +711,7 @@
 	expected_metadata_sequence_[num_expected_++] = &application2_;
 	expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
 	expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+	expected_metadata_sequence_[num_expected_++] = &picture_;
 	expected_metadata_sequence_[num_expected_++] = &unknown_;
 
 	if(!(layer < LAYER_FILE? dynamic_cast<StreamDecoder*>(decoder)->test_respond() : dynamic_cast<FileDecoder*>(decoder)->test_respond()))
@@ -756,6 +758,7 @@
 	expected_metadata_sequence_[num_expected_++] = &application1_;
 	expected_metadata_sequence_[num_expected_++] = &application2_;
 	expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+	expected_metadata_sequence_[num_expected_++] = &picture_;
 	expected_metadata_sequence_[num_expected_++] = &unknown_;
 
 	if(!(layer < LAYER_FILE? dynamic_cast<StreamDecoder*>(decoder)->test_respond() : dynamic_cast<FileDecoder*>(decoder)->test_respond()))
@@ -785,6 +788,7 @@
 	expected_metadata_sequence_[num_expected_++] = &seektable_;
 	expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
 	expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+	expected_metadata_sequence_[num_expected_++] = &picture_;
 	expected_metadata_sequence_[num_expected_++] = &unknown_;
 
 	if(!(layer < LAYER_FILE? dynamic_cast<StreamDecoder*>(decoder)->test_respond() : dynamic_cast<FileDecoder*>(decoder)->test_respond()))
@@ -815,6 +819,7 @@
 	expected_metadata_sequence_[num_expected_++] = &application2_;
 	expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
 	expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+	expected_metadata_sequence_[num_expected_++] = &picture_;
 	expected_metadata_sequence_[num_expected_++] = &unknown_;
 
 	if(!(layer < LAYER_FILE? dynamic_cast<StreamDecoder*>(decoder)->test_respond() : dynamic_cast<FileDecoder*>(decoder)->test_respond()))
@@ -851,6 +856,7 @@
 	expected_metadata_sequence_[num_expected_++] = &seektable_;
 	expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
 	expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+	expected_metadata_sequence_[num_expected_++] = &picture_;
 	expected_metadata_sequence_[num_expected_++] = &unknown_;
 
 	if(!(layer < LAYER_FILE? dynamic_cast<StreamDecoder*>(decoder)->test_respond() : dynamic_cast<FileDecoder*>(decoder)->test_respond()))
@@ -993,6 +999,7 @@
 	expected_metadata_sequence_[num_expected_++] = &application1_;
 	expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
 	expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+	expected_metadata_sequence_[num_expected_++] = &picture_;
 	expected_metadata_sequence_[num_expected_++] = &unknown_;
 
 	if(!(layer < LAYER_FILE? dynamic_cast<StreamDecoder*>(decoder)->test_respond() : dynamic_cast<FileDecoder*>(decoder)->test_respond()))
diff --git a/src/test_libFLAC++/encoders.cpp b/src/test_libFLAC++/encoders.cpp
index 24845b8..94124b9 100644
--- a/src/test_libFLAC++/encoders.cpp
+++ b/src/test_libFLAC++/encoders.cpp
@@ -42,8 +42,8 @@
 	"Filename"
 };
 
-static ::FLAC__StreamMetadata streaminfo_, padding_, seektable_, application1_, application2_, vorbiscomment_, cuesheet_, unknown_;
-static ::FLAC__StreamMetadata *metadata_sequence_[] = { &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &unknown_ };
+static ::FLAC__StreamMetadata streaminfo_, padding_, seektable_, application1_, application2_, vorbiscomment_, cuesheet_, picture_, unknown_;
+static ::FLAC__StreamMetadata *metadata_sequence_[] = { &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &picture_, &unknown_ };
 static const unsigned num_metadata_ = sizeof(metadata_sequence_) / sizeof(metadata_sequence_[0]);
 static const char *flacfilename_ = "metadata.flac";
 
@@ -73,12 +73,12 @@
 
 static void init_metadata_blocks_()
 {
-	mutils__init_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &unknown_);
+	mutils__init_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &picture_, &unknown_);
 }
 
 static void free_metadata_blocks_()
 {
-	mutils__free_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &unknown_);
+	mutils__free_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &picture_, &unknown_);
 }
 
 class StreamEncoder : public FLAC::Encoder::Stream {
diff --git a/src/test_libFLAC++/metadata_manip.cpp b/src/test_libFLAC++/metadata_manip.cpp
index a813813..cf27b9e 100644
--- a/src/test_libFLAC++/metadata_manip.cpp
+++ b/src/test_libFLAC++/metadata_manip.cpp
@@ -106,6 +106,16 @@
 	return x;
 }
 
+static char *strdup_or_die_(const char *s)
+{
+	char *x = strdup(s);
+	if(0 == x) {
+		fprintf(stderr, "ERROR: out of memory copying string \"%s\"\n", s);
+		exit(1);
+	}
+	return x;
+}
+
 /* functions for working with our metadata copy */
 
 static bool replace_in_our_metadata_(FLAC::Metadata::Prototype *block, unsigned position, bool copy)
@@ -474,10 +484,10 @@
 	printf("ERROR: got error callback, status = %s (%u)\n", FLAC__StreamDecoderErrorStatusString[status], (unsigned)status);
 }
 
-static bool generate_file_(FLAC__bool include_cuesheet)
+static bool generate_file_(FLAC__bool include_extras)
 {
-	::FLAC__StreamMetadata streaminfo, vorbiscomment, *cuesheet, padding;
-	::FLAC__StreamMetadata *metadata[3];
+	::FLAC__StreamMetadata streaminfo, vorbiscomment, *cuesheet, picture, padding;
+	::FLAC__StreamMetadata *metadata[4];
 	unsigned i = 0, n = 0;
 
 	printf("generating FLAC file for test\n");
@@ -524,23 +534,54 @@
 			return die_("priming our metadata");
 	}
 
+	{
+		picture.is_last = false;
+		picture.type = ::FLAC__METADATA_TYPE_PICTURE;
+		picture.length =
+			(
+				FLAC__STREAM_METADATA_PICTURE_TYPE_LEN +
+				FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN + /* will add the length for the string later */
+				FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN + /* will add the length for the string later */
+				FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN +
+				FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN +
+				FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN +
+				FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN /* will add the length for the data later */
+			) / 8
+		;
+		picture.data.picture.type = ::FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER;
+		picture.data.picture.mime_type = strdup_or_die_("image/jpeg");
+		picture.length += strlen(picture.data.picture.mime_type);
+		picture.data.picture.description = (FLAC__byte*)strdup_or_die_("desc");
+		picture.length += strlen((const char *)picture.data.picture.description);
+		picture.data.picture.width = 300;
+		picture.data.picture.height = 300;
+		picture.data.picture.depth = 24;
+		picture.data.picture.data = (FLAC__byte*)strdup_or_die_("SOMEJPEGDATA");
+		picture.data.picture.data_length = strlen((const char *)picture.data.picture.data);
+		picture.length += picture.data.picture.data_length;
+	}
+
 	padding.is_last = true;
 	padding.type = ::FLAC__METADATA_TYPE_PADDING;
 	padding.length = 1234;
 
 	metadata[n++] = &vorbiscomment;
-	if (include_cuesheet)
+	if(include_extras) {
 		metadata[n++] = cuesheet;
+		metadata[n++] = &picture;
+	}
 	metadata[n++] = &padding;
 
 	FLAC::Metadata::StreamInfo s(&streaminfo);
 	FLAC::Metadata::VorbisComment v(&vorbiscomment);
 	FLAC::Metadata::CueSheet c(cuesheet, /*copy=*/false);
+	FLAC::Metadata::Picture pi(&picture);
 	FLAC::Metadata::Padding p(&padding);
 	if(
 		!insert_to_our_metadata_(&s, i++, /*copy=*/true) ||
 		!insert_to_our_metadata_(&v, i++, /*copy=*/true) ||
-		(include_cuesheet && !insert_to_our_metadata_(&v, i++, /*copy=*/true)) ||
+		(include_extras && !insert_to_our_metadata_(&c, i++, /*copy=*/true)) ||
+		(include_extras && !insert_to_our_metadata_(&pi, i++, /*copy=*/true)) ||
 		!insert_to_our_metadata_(&p, i++, /*copy=*/true)
 	)
 		return die_("priming our metadata");
@@ -616,7 +657,7 @@
 
 	printf("\n\n++++++ testing level 0 interface\n");
 
-	if(!generate_file_(/*include_cuesheet=*/true))
+	if(!generate_file_(/*include_extras=*/true))
 		return false;
 
 	if(!test_file_(flacfile_, /*ignore_metadata=*/true))
@@ -705,6 +746,38 @@
 		printf("OK\n");
 	}
 
+	{
+		printf("testing FLAC::Metadata::get_picture(Picture *&)... ");
+
+		FLAC::Metadata::Picture *picture = 0;
+
+		if(!FLAC::Metadata::get_picture(flacfile_, picture, /*type=*/(::FLAC__StreamMetadata_Picture_Type)(-1), /*mime_type=*/0, /*description=*/0, /*max_width=*/(unsigned)(-1), /*max_height=*/(unsigned)(-1), /*max_depth=*/(unsigned)(-1)))
+			return die_("during FLAC::Metadata::get_picture()");
+
+		/* check to see if some basic data matches (c.f. generate_file_()) */
+		if(picture->get_type () != ::FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER)
+			return die_("mismatch in picture->get_type ()");
+
+		printf("OK\n");
+
+		delete picture;
+	}
+
+	{
+		printf("testing FLAC::Metadata::get_picture(Picture &)... ");
+
+		FLAC::Metadata::Picture picture;
+
+		if(!FLAC::Metadata::get_picture(flacfile_, picture, /*type=*/(::FLAC__StreamMetadata_Picture_Type)(-1), /*mime_type=*/0, /*description=*/0, /*max_width=*/(unsigned)(-1), /*max_height=*/(unsigned)(-1), /*max_depth=*/(unsigned)(-1)))
+			return die_("during FLAC::Metadata::get_picture()");
+
+		/* check to see if some basic data matches (c.f. generate_file_()) */
+		if(picture.get_type () != ::FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER)
+			return die_("mismatch in picture->get_type ()");
+
+		printf("OK\n");
+	}
+
 	if(!remove_file_(flacfile_))
 		return false;
 
@@ -729,7 +802,7 @@
 	{
 	printf("simple iterator on read-only file\n");
 
-	if(!generate_file_(/*include_cuesheet=*/false))
+	if(!generate_file_(/*include_extras=*/false))
 		return false;
 
 	if(!change_stats_(flacfile_, /*read_only=*/true))
@@ -1394,7 +1467,7 @@
 
 	printf("generate read-only file\n");
 
-	if(!generate_file_(/*include_cuesheet=*/false))
+	if(!generate_file_(/*include_extras=*/false))
 		return false;
 
 	if(!change_stats_(flacfile_, /*read_only=*/true))
@@ -1949,7 +2022,7 @@
 
 	printf("generate file\n");
 
-	if(!generate_file_(/*include_cuesheet=*/false))
+	if(!generate_file_(/*include_extras=*/false))
 		return false;
 
 	printf("create chain\n");
diff --git a/src/test_libFLAC++/metadata_object.cpp b/src/test_libFLAC++/metadata_object.cpp
index 845fb1f..ccf41f5 100644
--- a/src/test_libFLAC++/metadata_object.cpp
+++ b/src/test_libFLAC++/metadata_object.cpp
@@ -22,7 +22,7 @@
 #include <stdlib.h> /* for malloc() */
 #include <string.h> /* for memcmp() */
 
-static ::FLAC__StreamMetadata streaminfo_, padding_, seektable_, application_, vorbiscomment_, cuesheet_;
+static ::FLAC__StreamMetadata streaminfo_, padding_, seektable_, application_, vorbiscomment_, cuesheet_, picture_;
 
 static bool die_(const char *msg)
 {
@@ -40,6 +40,16 @@
 	return x;
 }
 
+static char *strdup_or_die_(const char *s)
+{
+	char *x = strdup(s);
+	if(0 == x) {
+		fprintf(stderr, "ERROR: out of memory copying string \"%s\"\n", s);
+		exit(1);
+	}
+	return x;
+}
+
 static bool index_is_equal_(const ::FLAC__StreamMetadata_CueSheet_Index &index, const ::FLAC__StreamMetadata_CueSheet_Index &indexcopy)
 {
 	if(indexcopy.offset != index.offset)
@@ -131,7 +141,7 @@
 	vorbiscomment_.data.vorbis_comment.comments[1].entry = (FLAC__byte*)malloc_or_die_(12+1);
 	memcpy(vorbiscomment_.data.vorbis_comment.comments[1].entry, "name3=value3", 12+1);
 
-	cuesheet_.is_last = true;
+	cuesheet_.is_last = false;
 	cuesheet_.type = ::FLAC__METADATA_TYPE_CUESHEET;
 	cuesheet_.length =
 		/* cuesheet guts */
@@ -186,6 +196,31 @@
 	cuesheet_.data.cue_sheet.tracks[1].indices = (FLAC__StreamMetadata_CueSheet_Index*)malloc_or_die_(cuesheet_.data.cue_sheet.tracks[1].num_indices * sizeof(FLAC__StreamMetadata_CueSheet_Index));
 	cuesheet_.data.cue_sheet.tracks[1].indices[0].offset = 0;
 	cuesheet_.data.cue_sheet.tracks[1].indices[0].number = 1;
+
+	picture_.is_last = true;
+	picture_.type = FLAC__METADATA_TYPE_PICTURE;
+	picture_.length =
+		(
+			FLAC__STREAM_METADATA_PICTURE_TYPE_LEN +
+			FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN + /* will add the length for the string later */
+			FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN + /* will add the length for the string later */
+			FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN +
+			FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN +
+			FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN +
+			FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN /* will add the length for the data later */
+		) / 8
+	;
+	picture_.data.picture.type = FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER;
+	picture_.data.picture.mime_type = strdup_or_die_("image/jpeg");
+	picture_.length += strlen(picture_.data.picture.mime_type);
+	picture_.data.picture.description = (FLAC__byte*)strdup_or_die_("desc");
+	picture_.length += strlen((const char *)picture_.data.picture.description);
+	picture_.data.picture.width = 300;
+	picture_.data.picture.height = 300;
+	picture_.data.picture.depth = 24;
+	picture_.data.picture.data = (FLAC__byte*)strdup_or_die_("SOMEJPEGDATA");
+	picture_.data.picture.data_length = strlen((const char *)picture_.data.picture.data);
+	picture_.length += picture_.data.picture.data_length;
 }
 
 static void free_metadata_blocks_()
@@ -199,6 +234,9 @@
 	free(cuesheet_.data.cue_sheet.tracks[0].indices);
 	free(cuesheet_.data.cue_sheet.tracks[1].indices);
 	free(cuesheet_.data.cue_sheet.tracks);
+	free(picture_.data.picture.mime_type);
+	free(picture_.data.picture.description);
+	free(picture_.data.picture.data);
 }
 
 bool test_metadata_object_streaminfo()
@@ -223,7 +261,7 @@
 	{
 		FLAC::Metadata::StreamInfo blockcopy(block);
 		if(!blockcopy.is_valid())
-			return die_("!block.is_valid()");
+			return die_("!blockcopy.is_valid()");
 		if(blockcopy != block)
 			return die_("copy is not identical to original");
 		printf("OK\n");
@@ -237,7 +275,7 @@
 	{
 		FLAC::Metadata::StreamInfo blockcopy(streaminfo_);
 		if(!blockcopy.is_valid())
-			return die_("!block.is_valid()");
+			return die_("!blockcopy.is_valid()");
 		if(blockcopy != streaminfo_)
 			return die_("copy is not identical to original");
 		printf("OK\n");
@@ -248,7 +286,7 @@
 	{
 		FLAC::Metadata::StreamInfo blockcopy(&streaminfo_);
 		if(!blockcopy.is_valid())
-			return die_("!block.is_valid()");
+			return die_("!blockcopy.is_valid()");
 		if(blockcopy != streaminfo_)
 			return die_("copy is not identical to original");
 		printf("OK\n");
@@ -259,7 +297,7 @@
 	{
 		FLAC::Metadata::StreamInfo blockcopy(&streaminfo_, /*copy=*/true);
 		if(!blockcopy.is_valid())
-			return die_("!block.is_valid()");
+			return die_("!blockcopy.is_valid()");
 		if(blockcopy != streaminfo_)
 			return die_("copy is not identical to original");
 		printf("OK\n");
@@ -271,7 +309,7 @@
 		::FLAC__StreamMetadata *copy = ::FLAC__metadata_object_clone(&streaminfo_);
 		FLAC::Metadata::StreamInfo blockcopy(copy, /*copy=*/false);
 		if(!blockcopy.is_valid())
-			return die_("!block.is_valid()");
+			return die_("!blockcopy.is_valid()");
 		if(blockcopy != streaminfo_)
 			return die_("copy is not identical to original");
 		printf("OK\n");
@@ -283,7 +321,7 @@
 		FLAC::Metadata::StreamInfo blockcopy;
 		blockcopy.assign(&streaminfo_, /*copy=*/true);
 		if(!blockcopy.is_valid())
-			return die_("!block.is_valid()");
+			return die_("!blockcopy.is_valid()");
 		if(blockcopy != streaminfo_)
 			return die_("copy is not identical to original");
 		printf("OK\n");
@@ -296,7 +334,7 @@
 		FLAC::Metadata::StreamInfo blockcopy;
 		blockcopy.assign(copy, /*copy=*/false);
 		if(!blockcopy.is_valid())
-			return die_("!block.is_valid()");
+			return die_("!blockcopy.is_valid()");
 		if(blockcopy != streaminfo_)
 			return die_("copy is not identical to original");
 		printf("OK\n");
@@ -307,7 +345,7 @@
 	{
 		FLAC::Metadata::StreamInfo blockcopy = block;
 		if(!blockcopy.is_valid())
-			return die_("!block.is_valid()");
+			return die_("!blockcopy.is_valid()");
 		if(!(blockcopy == block))
 			return die_("copy is not identical to original");
 		printf("OK\n");
@@ -318,7 +356,7 @@
 	{
 		FLAC::Metadata::StreamInfo blockcopy = streaminfo_;
 		if(!blockcopy.is_valid())
-			return die_("!block.is_valid()");
+			return die_("!blockcopy.is_valid()");
 		if(!(blockcopy == streaminfo_))
 			return die_("copy is not identical to original");
 		printf("OK\n");
@@ -329,7 +367,7 @@
 	{
 		FLAC::Metadata::StreamInfo blockcopy = &streaminfo_;
 		if(!blockcopy.is_valid())
-			return die_("!block.is_valid()");
+			return die_("!blockcopy.is_valid()");
 		if(!(blockcopy == streaminfo_))
 			return die_("copy is not identical to original");
 		printf("OK\n");
@@ -456,7 +494,7 @@
 	{
 		FLAC::Metadata::Padding blockcopy(block);
 		if(!blockcopy.is_valid())
-			return die_("!block.is_valid()");
+			return die_("!blockcopy.is_valid()");
 		if(blockcopy != block)
 			return die_("copy is not identical to original");
 		printf("OK\n");
@@ -470,7 +508,7 @@
 	{
 		FLAC::Metadata::Padding blockcopy(padding_);
 		if(!blockcopy.is_valid())
-			return die_("!block.is_valid()");
+			return die_("!blockcopy.is_valid()");
 		if(blockcopy != padding_)
 			return die_("copy is not identical to original");
 		printf("OK\n");
@@ -481,7 +519,7 @@
 	{
 		FLAC::Metadata::Padding blockcopy(&padding_);
 		if(!blockcopy.is_valid())
-			return die_("!block.is_valid()");
+			return die_("!blockcopy.is_valid()");
 		if(blockcopy != padding_)
 			return die_("copy is not identical to original");
 		printf("OK\n");
@@ -492,7 +530,7 @@
 	{
 		FLAC::Metadata::Padding blockcopy(&padding_, /*copy=*/true);
 		if(!blockcopy.is_valid())
-			return die_("!block.is_valid()");
+			return die_("!blockcopy.is_valid()");
 		if(blockcopy != padding_)
 			return die_("copy is not identical to original");
 		printf("OK\n");
@@ -504,7 +542,7 @@
 		::FLAC__StreamMetadata *copy = ::FLAC__metadata_object_clone(&padding_);
 		FLAC::Metadata::Padding blockcopy(copy, /*copy=*/false);
 		if(!blockcopy.is_valid())
-			return die_("!block.is_valid()");
+			return die_("!blockcopy.is_valid()");
 		if(blockcopy != padding_)
 			return die_("copy is not identical to original");
 		printf("OK\n");
@@ -516,7 +554,7 @@
 		FLAC::Metadata::Padding blockcopy;
 		blockcopy.assign(&padding_, /*copy=*/true);
 		if(!blockcopy.is_valid())
-			return die_("!block.is_valid()");
+			return die_("!blockcopy.is_valid()");
 		if(blockcopy != padding_)
 			return die_("copy is not identical to original");
 		printf("OK\n");
@@ -529,7 +567,7 @@
 		FLAC::Metadata::Padding blockcopy;
 		blockcopy.assign(copy, /*copy=*/false);
 		if(!blockcopy.is_valid())
-			return die_("!block.is_valid()");
+			return die_("!blockcopy.is_valid()");
 		if(blockcopy != padding_)
 			return die_("copy is not identical to original");
 		printf("OK\n");
@@ -540,7 +578,7 @@
 	{
 		FLAC::Metadata::Padding blockcopy = block;
 		if(!blockcopy.is_valid())
-			return die_("!block.is_valid()");
+			return die_("!blockcopy.is_valid()");
 		if(!(blockcopy == block))
 			return die_("copy is not identical to original");
 		printf("OK\n");
@@ -551,7 +589,7 @@
 	{
 		FLAC::Metadata::Padding blockcopy = padding_;
 		if(!blockcopy.is_valid())
-			return die_("!block.is_valid()");
+			return die_("!blockcopy.is_valid()");
 		if(!(blockcopy == padding_))
 			return die_("copy is not identical to original");
 		printf("OK\n");
@@ -562,7 +600,7 @@
 	{
 		FLAC::Metadata::Padding blockcopy = &padding_;
 		if(!blockcopy.is_valid())
-			return die_("!block.is_valid()");
+			return die_("!blockcopy.is_valid()");
 		if(!(blockcopy == padding_))
 			return die_("copy is not identical to original");
 		printf("OK\n");
@@ -617,7 +655,7 @@
 	{
 		FLAC::Metadata::Application blockcopy(block);
 		if(!blockcopy.is_valid())
-			return die_("!block.is_valid()");
+			return die_("!blockcopy.is_valid()");
 		if(blockcopy != block)
 			return die_("copy is not identical to original");
 		printf("OK\n");
@@ -631,7 +669,7 @@
 	{
 		FLAC::Metadata::Application blockcopy(application_);
 		if(!blockcopy.is_valid())
-			return die_("!block.is_valid()");
+			return die_("!blockcopy.is_valid()");
 		if(blockcopy != application_)
 			return die_("copy is not identical to original");
 		printf("OK\n");
@@ -642,7 +680,7 @@
 	{
 		FLAC::Metadata::Application blockcopy(&application_);
 		if(!blockcopy.is_valid())
-			return die_("!block.is_valid()");
+			return die_("!blockcopy.is_valid()");
 		if(blockcopy != application_)
 			return die_("copy is not identical to original");
 		printf("OK\n");
@@ -653,7 +691,7 @@
 	{
 		FLAC::Metadata::Application blockcopy(&application_, /*copy=*/true);
 		if(!blockcopy.is_valid())
-			return die_("!block.is_valid()");
+			return die_("!blockcopy.is_valid()");
 		if(blockcopy != application_)
 			return die_("copy is not identical to original");
 		printf("OK\n");
@@ -665,7 +703,7 @@
 		::FLAC__StreamMetadata *copy = ::FLAC__metadata_object_clone(&application_);
 		FLAC::Metadata::Application blockcopy(copy, /*copy=*/false);
 		if(!blockcopy.is_valid())
-			return die_("!block.is_valid()");
+			return die_("!blockcopy.is_valid()");
 		if(blockcopy != application_)
 			return die_("copy is not identical to original");
 		printf("OK\n");
@@ -677,7 +715,7 @@
 		FLAC::Metadata::Application blockcopy;
 		blockcopy.assign(&application_, /*copy=*/true);
 		if(!blockcopy.is_valid())
-			return die_("!block.is_valid()");
+			return die_("!blockcopy.is_valid()");
 		if(blockcopy != application_)
 			return die_("copy is not identical to original");
 		printf("OK\n");
@@ -690,7 +728,7 @@
 		FLAC::Metadata::Application blockcopy;
 		blockcopy.assign(copy, /*copy=*/false);
 		if(!blockcopy.is_valid())
-			return die_("!block.is_valid()");
+			return die_("!blockcopy.is_valid()");
 		if(blockcopy != application_)
 			return die_("copy is not identical to original");
 		printf("OK\n");
@@ -701,7 +739,7 @@
 	{
 		FLAC::Metadata::Application blockcopy = block;
 		if(!blockcopy.is_valid())
-			return die_("!block.is_valid()");
+			return die_("!blockcopy.is_valid()");
 		if(!(blockcopy == block))
 			return die_("copy is not identical to original");
 		printf("OK\n");
@@ -712,7 +750,7 @@
 	{
 		FLAC::Metadata::Application blockcopy = application_;
 		if(!blockcopy.is_valid())
-			return die_("!block.is_valid()");
+			return die_("!blockcopy.is_valid()");
 		if(!(blockcopy == application_))
 			return die_("copy is not identical to original");
 		printf("OK\n");
@@ -723,7 +761,7 @@
 	{
 		FLAC::Metadata::Application blockcopy = &application_;
 		if(!blockcopy.is_valid())
-			return die_("!block.is_valid()");
+			return die_("!blockcopy.is_valid()");
 		if(!(blockcopy == application_))
 			return die_("copy is not identical to original");
 		printf("OK\n");
@@ -787,7 +825,7 @@
 	{
 		FLAC::Metadata::SeekTable blockcopy(block);
 		if(!blockcopy.is_valid())
-			return die_("!block.is_valid()");
+			return die_("!blockcopy.is_valid()");
 		if(blockcopy != block)
 			return die_("copy is not identical to original");
 		printf("OK\n");
@@ -801,7 +839,7 @@
 	{
 		FLAC::Metadata::SeekTable blockcopy(seektable_);
 		if(!blockcopy.is_valid())
-			return die_("!block.is_valid()");
+			return die_("!blockcopy.is_valid()");
 		if(blockcopy != seektable_)
 			return die_("copy is not identical to original");
 		printf("OK\n");
@@ -812,7 +850,7 @@
 	{
 		FLAC::Metadata::SeekTable blockcopy(&seektable_);
 		if(!blockcopy.is_valid())
-			return die_("!block.is_valid()");
+			return die_("!blockcopy.is_valid()");
 		if(blockcopy != seektable_)
 			return die_("copy is not identical to original");
 		printf("OK\n");
@@ -823,7 +861,7 @@
 	{
 		FLAC::Metadata::SeekTable blockcopy(&seektable_, /*copy=*/true);
 		if(!blockcopy.is_valid())
-			return die_("!block.is_valid()");
+			return die_("!blockcopy.is_valid()");
 		if(blockcopy != seektable_)
 			return die_("copy is not identical to original");
 		printf("OK\n");
@@ -835,7 +873,7 @@
 		::FLAC__StreamMetadata *copy = ::FLAC__metadata_object_clone(&seektable_);
 		FLAC::Metadata::SeekTable blockcopy(copy, /*copy=*/false);
 		if(!blockcopy.is_valid())
-			return die_("!block.is_valid()");
+			return die_("!blockcopy.is_valid()");
 		if(blockcopy != seektable_)
 			return die_("copy is not identical to original");
 		printf("OK\n");
@@ -847,7 +885,7 @@
 		FLAC::Metadata::SeekTable blockcopy;
 		blockcopy.assign(&seektable_, /*copy=*/true);
 		if(!blockcopy.is_valid())
-			return die_("!block.is_valid()");
+			return die_("!blockcopy.is_valid()");
 		if(blockcopy != seektable_)
 			return die_("copy is not identical to original");
 		printf("OK\n");
@@ -860,7 +898,7 @@
 		FLAC::Metadata::SeekTable blockcopy;
 		blockcopy.assign(copy, /*copy=*/false);
 		if(!blockcopy.is_valid())
-			return die_("!block.is_valid()");
+			return die_("!blockcopy.is_valid()");
 		if(blockcopy != seektable_)
 			return die_("copy is not identical to original");
 		printf("OK\n");
@@ -871,7 +909,7 @@
 	{
 		FLAC::Metadata::SeekTable blockcopy = block;
 		if(!blockcopy.is_valid())
-			return die_("!block.is_valid()");
+			return die_("!blockcopy.is_valid()");
 		if(!(blockcopy == block))
 			return die_("copy is not identical to original");
 		printf("OK\n");
@@ -882,7 +920,7 @@
 	{
 		FLAC::Metadata::SeekTable blockcopy = seektable_;
 		if(!blockcopy.is_valid())
-			return die_("!block.is_valid()");
+			return die_("!blockcopy.is_valid()");
 		if(!(blockcopy == seektable_))
 			return die_("copy is not identical to original");
 		printf("OK\n");
@@ -893,7 +931,7 @@
 	{
 		FLAC::Metadata::SeekTable blockcopy = &seektable_;
 		if(!blockcopy.is_valid())
-			return die_("!block.is_valid()");
+			return die_("!blockcopy.is_valid()");
 		if(!(blockcopy == seektable_))
 			return die_("copy is not identical to original");
 		printf("OK\n");
@@ -1140,7 +1178,7 @@
 	{
 		FLAC::Metadata::VorbisComment blockcopy(block);
 		if(!blockcopy.is_valid())
-			return die_("!block.is_valid()");
+			return die_("!blockcopy.is_valid()");
 		if(blockcopy != block)
 			return die_("copy is not identical to original");
 		printf("OK\n");
@@ -1154,7 +1192,7 @@
 	{
 		FLAC::Metadata::VorbisComment blockcopy(vorbiscomment_);
 		if(!blockcopy.is_valid())
-			return die_("!block.is_valid()");
+			return die_("!blockcopy.is_valid()");
 		if(blockcopy != vorbiscomment_)
 			return die_("copy is not identical to original");
 		printf("OK\n");
@@ -1165,7 +1203,7 @@
 	{
 		FLAC::Metadata::VorbisComment blockcopy(&vorbiscomment_);
 		if(!blockcopy.is_valid())
-			return die_("!block.is_valid()");
+			return die_("!blockcopy.is_valid()");
 		if(blockcopy != vorbiscomment_)
 			return die_("copy is not identical to original");
 		printf("OK\n");
@@ -1176,7 +1214,7 @@
 	{
 		FLAC::Metadata::VorbisComment blockcopy(&vorbiscomment_, /*copy=*/true);
 		if(!blockcopy.is_valid())
-			return die_("!block.is_valid()");
+			return die_("!blockcopy.is_valid()");
 		if(blockcopy != vorbiscomment_)
 			return die_("copy is not identical to original");
 		printf("OK\n");
@@ -1188,7 +1226,7 @@
 		::FLAC__StreamMetadata *copy = ::FLAC__metadata_object_clone(&vorbiscomment_);
 		FLAC::Metadata::VorbisComment blockcopy(copy, /*copy=*/false);
 		if(!blockcopy.is_valid())
-			return die_("!block.is_valid()");
+			return die_("!blockcopy.is_valid()");
 		if(blockcopy != vorbiscomment_)
 			return die_("copy is not identical to original");
 		printf("OK\n");
@@ -1200,7 +1238,7 @@
 		FLAC::Metadata::VorbisComment blockcopy;
 		blockcopy.assign(&vorbiscomment_, /*copy=*/true);
 		if(!blockcopy.is_valid())
-			return die_("!block.is_valid()");
+			return die_("!blockcopy.is_valid()");
 		if(blockcopy != vorbiscomment_)
 			return die_("copy is not identical to original");
 		printf("OK\n");
@@ -1213,7 +1251,7 @@
 		FLAC::Metadata::VorbisComment blockcopy;
 		blockcopy.assign(copy, /*copy=*/false);
 		if(!blockcopy.is_valid())
-			return die_("!block.is_valid()");
+			return die_("!blockcopy.is_valid()");
 		if(blockcopy != vorbiscomment_)
 			return die_("copy is not identical to original");
 		printf("OK\n");
@@ -1224,7 +1262,7 @@
 	{
 		FLAC::Metadata::VorbisComment blockcopy = block;
 		if(!blockcopy.is_valid())
-			return die_("!block.is_valid()");
+			return die_("!blockcopy.is_valid()");
 		if(!(blockcopy == block))
 			return die_("copy is not identical to original");
 		printf("OK\n");
@@ -1235,7 +1273,7 @@
 	{
 		FLAC::Metadata::VorbisComment blockcopy = vorbiscomment_;
 		if(!blockcopy.is_valid())
-			return die_("!block.is_valid()");
+			return die_("!blockcopy.is_valid()");
 		if(!(blockcopy == vorbiscomment_))
 			return die_("copy is not identical to original");
 		printf("OK\n");
@@ -1246,7 +1284,7 @@
 	{
 		FLAC::Metadata::VorbisComment blockcopy = &vorbiscomment_;
 		if(!blockcopy.is_valid())
-			return die_("!block.is_valid()");
+			return die_("!blockcopy.is_valid()");
 		if(!(blockcopy == vorbiscomment_))
 			return die_("copy is not identical to original");
 		printf("OK\n");
@@ -1518,7 +1556,7 @@
 	{
 		FLAC::Metadata::CueSheet blockcopy(block);
 		if(!blockcopy.is_valid())
-			return die_("!block.is_valid()");
+			return die_("!blockcopy.is_valid()");
 		if(blockcopy != block)
 			return die_("copy is not identical to original");
 		printf("OK\n");
@@ -1532,7 +1570,7 @@
 	{
 		FLAC::Metadata::CueSheet blockcopy(cuesheet_);
 		if(!blockcopy.is_valid())
-			return die_("!block.is_valid()");
+			return die_("!blockcopy.is_valid()");
 		if(blockcopy != cuesheet_)
 			return die_("copy is not identical to original");
 		printf("OK\n");
@@ -1543,7 +1581,7 @@
 	{
 		FLAC::Metadata::CueSheet blockcopy(&cuesheet_);
 		if(!blockcopy.is_valid())
-			return die_("!block.is_valid()");
+			return die_("!blockcopy.is_valid()");
 		if(blockcopy != cuesheet_)
 			return die_("copy is not identical to original");
 		printf("OK\n");
@@ -1554,7 +1592,7 @@
 	{
 		FLAC::Metadata::CueSheet blockcopy(&cuesheet_, /*copy=*/true);
 		if(!blockcopy.is_valid())
-			return die_("!block.is_valid()");
+			return die_("!blockcopy.is_valid()");
 		if(blockcopy != cuesheet_)
 			return die_("copy is not identical to original");
 		printf("OK\n");
@@ -1566,7 +1604,7 @@
 		::FLAC__StreamMetadata *copy = ::FLAC__metadata_object_clone(&cuesheet_);
 		FLAC::Metadata::CueSheet blockcopy(copy, /*copy=*/false);
 		if(!blockcopy.is_valid())
-			return die_("!block.is_valid()");
+			return die_("!blockcopy.is_valid()");
 		if(blockcopy != cuesheet_)
 			return die_("copy is not identical to original");
 		printf("OK\n");
@@ -1578,7 +1616,7 @@
 		FLAC::Metadata::CueSheet blockcopy;
 		blockcopy.assign(&cuesheet_, /*copy=*/true);
 		if(!blockcopy.is_valid())
-			return die_("!block.is_valid()");
+			return die_("!blockcopy.is_valid()");
 		if(blockcopy != cuesheet_)
 			return die_("copy is not identical to original");
 		printf("OK\n");
@@ -1591,7 +1629,7 @@
 		FLAC::Metadata::CueSheet blockcopy;
 		blockcopy.assign(copy, /*copy=*/false);
 		if(!blockcopy.is_valid())
-			return die_("!block.is_valid()");
+			return die_("!blockcopy.is_valid()");
 		if(blockcopy != cuesheet_)
 			return die_("copy is not identical to original");
 		printf("OK\n");
@@ -1602,7 +1640,7 @@
 	{
 		FLAC::Metadata::CueSheet blockcopy = block;
 		if(!blockcopy.is_valid())
-			return die_("!block.is_valid()");
+			return die_("!blockcopy.is_valid()");
 		if(!(blockcopy == block))
 			return die_("copy is not identical to original");
 		printf("OK\n");
@@ -1613,7 +1651,7 @@
 	{
 		FLAC::Metadata::CueSheet blockcopy = cuesheet_;
 		if(!blockcopy.is_valid())
-			return die_("!block.is_valid()");
+			return die_("!blockcopy.is_valid()");
 		if(!(blockcopy == cuesheet_))
 			return die_("copy is not identical to original");
 		printf("OK\n");
@@ -1624,7 +1662,7 @@
 	{
 		FLAC::Metadata::CueSheet blockcopy = &cuesheet_;
 		if(!blockcopy.is_valid())
-			return die_("!block.is_valid()");
+			return die_("!blockcopy.is_valid()");
 		if(!(blockcopy == cuesheet_))
 			return die_("copy is not identical to original");
 		printf("OK\n");
@@ -1759,6 +1797,254 @@
 	return true;
 }
 
+bool test_metadata_object_picture()
+{
+	unsigned expected_length;
+
+	printf("testing class FLAC::Metadata::Picture\n");
+
+	printf("testing Picture::Picture()... ");
+	FLAC::Metadata::Picture block;
+	if(!block.is_valid())
+		return die_("!block.is_valid()");
+	expected_length = (
+		FLAC__STREAM_METADATA_PICTURE_TYPE_LEN +
+		FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN +
+		FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN +
+		FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN +
+		FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN +
+		FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN +
+		FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN
+	) / 8;
+	if(block.get_length() != expected_length) {
+		printf("FAILED, bad length, expected %u, got %u\n", expected_length, block.get_length());
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing Picture::Picture(const Picture &)... +\n");
+	printf("        Picture::operator!=(const Picture &)... ");
+	{
+		FLAC::Metadata::Picture blockcopy(block);
+		if(!blockcopy.is_valid())
+			return die_("!blockcopy.is_valid()");
+		if(blockcopy != block)
+			return die_("copy is not identical to original");
+		printf("OK\n");
+
+		printf("testing Picture::~Picture()... ");
+	}
+	printf("OK\n");
+
+	printf("testing Picture::Picture(const ::FLAC__StreamMetadata &)... +\n");
+	printf("        Picture::operator!=(const ::FLAC__StreamMetadata &)... ");
+	{
+		FLAC::Metadata::Picture blockcopy(picture_);
+		if(!blockcopy.is_valid())
+			return die_("!blockcopy.is_valid()");
+		if(blockcopy != picture_)
+			return die_("copy is not identical to original");
+		printf("OK\n");
+	}
+
+	printf("testing Picture::Picture(const ::FLAC__StreamMetadata *)... +\n");
+	printf("        Picture::operator!=(const ::FLAC__StreamMetadata *)... ");
+	{
+		FLAC::Metadata::Picture blockcopy(&picture_);
+		if(!blockcopy.is_valid())
+			return die_("!blockcopy.is_valid()");
+		if(blockcopy != picture_)
+			return die_("copy is not identical to original");
+		printf("OK\n");
+	}
+
+	printf("testing Picture::Picture(const ::FLAC__StreamMetadata *, copy=true)... +\n");
+	printf("        Picture::operator!=(const ::FLAC__StreamMetadata *)... ");
+	{
+		FLAC::Metadata::Picture blockcopy(&picture_, /*copy=*/true);
+		if(!blockcopy.is_valid())
+			return die_("!blockcopy.is_valid()");
+		if(blockcopy != picture_)
+			return die_("copy is not identical to original");
+		printf("OK\n");
+	}
+
+	printf("testing Picture::Picture(const ::FLAC__StreamMetadata *, copy=false)... +\n");
+	printf("        Picture::operator!=(const ::FLAC__StreamMetadata *)... ");
+	{
+		::FLAC__StreamMetadata *copy = ::FLAC__metadata_object_clone(&picture_);
+		FLAC::Metadata::Picture blockcopy(copy, /*copy=*/false);
+		if(!blockcopy.is_valid())
+			return die_("!blockcopy.is_valid()");
+		if(blockcopy != picture_)
+			return die_("copy is not identical to original");
+		printf("OK\n");
+	}
+
+	printf("testing Picture::assign(const ::FLAC__StreamMetadata *, copy=true)... +\n");
+	printf("        Picture::operator!=(const ::FLAC__StreamMetadata *)... ");
+	{
+		FLAC::Metadata::Picture blockcopy;
+		blockcopy.assign(&picture_, /*copy=*/true);
+		if(!blockcopy.is_valid())
+			return die_("!blockcopy.is_valid()");
+		if(blockcopy != picture_)
+			return die_("copy is not identical to original");
+		printf("OK\n");
+	}
+
+	printf("testing Picture::assign(const ::FLAC__StreamMetadata *, copy=false)... +\n");
+	printf("        Picture::operator!=(const ::FLAC__StreamMetadata *)... ");
+	{
+		::FLAC__StreamMetadata *copy = ::FLAC__metadata_object_clone(&picture_);
+		FLAC::Metadata::Picture blockcopy;
+		blockcopy.assign(copy, /*copy=*/false);
+		if(!blockcopy.is_valid())
+			return die_("!blockcopy.is_valid()");
+		if(blockcopy != picture_)
+			return die_("copy is not identical to original");
+		printf("OK\n");
+	}
+
+	printf("testing Picture::operator=(const Picture &)... +\n");
+	printf("        Picture::operator==(const Picture &)... ");
+	{
+		FLAC::Metadata::Picture blockcopy = block;
+		if(!blockcopy.is_valid())
+			return die_("!blockcopy.is_valid()");
+		if(!(blockcopy == block))
+			return die_("copy is not identical to original");
+		printf("OK\n");
+	}
+
+	printf("testing Picture::operator=(const ::FLAC__StreamMetadata &)... +\n");
+	printf("        Picture::operator==(const ::FLAC__StreamMetadata &)... ");
+	{
+		FLAC::Metadata::Picture blockcopy = picture_;
+		if(!blockcopy.is_valid())
+			return die_("!blockcopy.is_valid()");
+		if(!(blockcopy == picture_))
+			return die_("copy is not identical to original");
+		printf("OK\n");
+	}
+
+	printf("testing Picture::operator=(const ::FLAC__StreamMetadata *)... +\n");
+	printf("        Picture::operator==(const ::FLAC__StreamMetadata *)... ");
+	{
+		FLAC::Metadata::Picture blockcopy = &picture_;
+		if(!blockcopy.is_valid())
+			return die_("!blockcopy.is_valid()");
+		if(!(blockcopy == picture_))
+			return die_("copy is not identical to original");
+		printf("OK\n");
+	}
+
+	printf("testing Picture::get_type()... ");
+	if(block.get_type() != ::FLAC__STREAM_METADATA_PICTURE_TYPE_OTHER)
+		return die_("value mismatch, expected ::FLAC__STREAM_METADATA_PICTURE_TYPE_OTHER");
+	printf("OK\n");
+
+	printf("testing Picture::set_type()... +\n");
+	printf("        Picture::get_type()... ");
+	block.set_type(::FLAC__STREAM_METADATA_PICTURE_TYPE_MEDIA);
+	if(block.get_type() != ::FLAC__STREAM_METADATA_PICTURE_TYPE_MEDIA)
+		return die_("value mismatch, expected ::FLAC__STREAM_METADATA_PICTURE_TYPE_MEDIA");
+	printf("OK\n");
+
+	printf("testing Picture::set_mime_type()... ");
+	if(!block.set_mime_type("qmage/jpeg"))
+		return die_("returned false");
+	printf("OK\n");
+	picture_.data.picture.mime_type[0] = 'q';
+
+	printf("testing Picture::get_mime_type()... ");
+	if(0 != strcmp(block.get_mime_type(), picture_.data.picture.mime_type))
+		return die_("value mismatch");
+	printf("OK\n");
+
+	printf("testing Picture::set_description()... ");
+	if(!block.set_description((const FLAC__byte*)"qesc"))
+		return die_("returned false");
+	printf("OK\n");
+	picture_.data.picture.description[0] = 'q';
+
+	printf("testing Picture::get_description()... ");
+	if(0 != strcmp((const char *)block.get_description(), (const char *)picture_.data.picture.description))
+		return die_("value mismatch");
+	printf("OK\n");
+
+	printf("testing Picture::get_width()... ");
+	if(block.get_width() != 0)
+		return die_("value mismatch, expected 0");
+	printf("OK\n");
+
+	printf("testing Picture::set_width()... +\n");
+	printf("        Picture::get_width()... ");
+	block.set_width(400);
+	if(block.get_width() != 400)
+		return die_("value mismatch, expected 400");
+	printf("OK\n");
+
+	printf("testing Picture::get_height()... ");
+	if(block.get_height() != 0)
+		return die_("value mismatch, expected 0");
+	printf("OK\n");
+
+	printf("testing Picture::set_height()... +\n");
+	printf("        Picture::get_height()... ");
+	block.set_height(200);
+	if(block.get_height() != 200)
+		return die_("value mismatch, expected 200");
+	printf("OK\n");
+
+	printf("testing Picture::get_depth()... ");
+	if(block.get_depth() != 0)
+		return die_("value mismatch, expected 0");
+	printf("OK\n");
+
+	printf("testing Picture::set_depth()... +\n");
+	printf("        Picture::get_depth()... ");
+	block.set_depth(16);
+	if(block.get_depth() != 16)
+		return die_("value mismatch, expected 16");
+	printf("OK\n");
+
+	printf("testing Picture::get_data_length()... ");
+	if(block.get_data_length() != 0)
+		return die_("value mismatch, expected 0");
+	printf("OK\n");
+
+	printf("testing Picture::set_data()... ");
+	if(!block.set_data((const FLAC__byte*)"qOMEJPEGDATA", strlen("qOMEJPEGDATA")))
+		return die_("returned false");
+	printf("OK\n");
+	picture_.data.picture.data[0] = 'q';
+
+	printf("testing Picture::get_data()... ");
+	if(block.get_data_length() != picture_.data.picture.data_length)
+		return die_("length mismatch");
+	if(0 != memcmp(block.get_data(), picture_.data.picture.data, picture_.data.picture.data_length))
+		return die_("value mismatch");
+	printf("OK\n");
+
+	printf("testing FLAC::Metadata::clone(const FLAC::Metadata::Prototype *)... ");
+	FLAC::Metadata::Prototype *clone_ = FLAC::Metadata::clone(&block);
+	if(0 == clone_)
+		return die_("returned NULL");
+	if(0 == dynamic_cast<FLAC::Metadata::Picture *>(clone_))
+		return die_("downcast is NULL");
+	if(*dynamic_cast<FLAC::Metadata::Picture *>(clone_) != block)
+		return die_("clone is not identical");
+	printf("OK\n");
+	printf("testing Picture::~Picture()... ");
+	delete clone_;
+	printf("OK\n");
+
+
+	printf("PASSED\n\n");
+	return true;
+}
+
 bool test_metadata_object()
 {
 	printf("\n+++ libFLAC++ unit test: metadata objects\n\n");
@@ -1783,6 +2069,9 @@
 	if(!test_metadata_object_cuesheet())
 		return false;
 
+	if(!test_metadata_object_picture())
+		return false;
+
 	free_metadata_blocks_();
 
 	return true;
diff --git a/src/test_libFLAC/decoders.c b/src/test_libFLAC/decoders.c
index 1ac22d4..3765853 100644
--- a/src/test_libFLAC/decoders.c
+++ b/src/test_libFLAC/decoders.c
@@ -58,8 +58,8 @@
 	FLAC__bool error_occurred;
 } StreamDecoderClientData;
 
-static FLAC__StreamMetadata streaminfo_, padding_, seektable_, application1_, application2_, vorbiscomment_, cuesheet_, unknown_;
-static FLAC__StreamMetadata *expected_metadata_sequence_[8];
+static FLAC__StreamMetadata streaminfo_, padding_, seektable_, application1_, application2_, vorbiscomment_, cuesheet_, picture_, unknown_;
+static FLAC__StreamMetadata *expected_metadata_sequence_[9];
 static unsigned num_expected_;
 static const char *flacfilename_ = "metadata.flac";
 static off_t flacfilesize_;
@@ -86,12 +86,12 @@
 
 static void init_metadata_blocks_()
 {
-	mutils__init_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &unknown_);
+	mutils__init_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &picture_, &unknown_);
 }
 
 static void free_metadata_blocks_()
 {
-	mutils__free_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &unknown_);
+	mutils__free_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &picture_, &unknown_);
 }
 
 static FLAC__bool generate_file_()
@@ -105,6 +105,7 @@
 	expected_metadata_sequence_[num_expected_++] = &application2_;
 	expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
 	expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+	expected_metadata_sequence_[num_expected_++] = &picture_;
 	expected_metadata_sequence_[num_expected_++] = &unknown_;
 
 	if(!file_utils__generate_flacfile(flacfilename_, &flacfilesize_, 512 * 1024, &streaminfo_, expected_metadata_sequence_, num_expected_))
@@ -627,6 +628,7 @@
 	expected_metadata_sequence_[num_expected_++] = &application2_;
 	expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
 	expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+	expected_metadata_sequence_[num_expected_++] = &picture_;
 	expected_metadata_sequence_[num_expected_++] = &unknown_;
 
 	if(!stream_decoder_test_respond_(decoder, &decoder_client_data))
@@ -667,6 +669,7 @@
 	expected_metadata_sequence_[num_expected_++] = &application1_;
 	expected_metadata_sequence_[num_expected_++] = &application2_;
 	expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+	expected_metadata_sequence_[num_expected_++] = &picture_;
 	expected_metadata_sequence_[num_expected_++] = &unknown_;
 
 	if(!stream_decoder_test_respond_(decoder, &decoder_client_data))
@@ -692,6 +695,7 @@
 	expected_metadata_sequence_[num_expected_++] = &seektable_;
 	expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
 	expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+	expected_metadata_sequence_[num_expected_++] = &picture_;
 	expected_metadata_sequence_[num_expected_++] = &unknown_;
 
 	if(!stream_decoder_test_respond_(decoder, &decoder_client_data))
@@ -718,6 +722,7 @@
 	expected_metadata_sequence_[num_expected_++] = &application2_;
 	expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
 	expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+	expected_metadata_sequence_[num_expected_++] = &picture_;
 	expected_metadata_sequence_[num_expected_++] = &unknown_;
 
 	if(!stream_decoder_test_respond_(decoder, &decoder_client_data))
@@ -748,6 +753,7 @@
 	expected_metadata_sequence_[num_expected_++] = &seektable_;
 	expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
 	expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+	expected_metadata_sequence_[num_expected_++] = &picture_;
 	expected_metadata_sequence_[num_expected_++] = &unknown_;
 
 	if(!stream_decoder_test_respond_(decoder, &decoder_client_data))
@@ -866,6 +872,7 @@
 	expected_metadata_sequence_[num_expected_++] = &application1_;
 	expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
 	expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+	expected_metadata_sequence_[num_expected_++] = &picture_;
 	expected_metadata_sequence_[num_expected_++] = &unknown_;
 
 	if(!stream_decoder_test_respond_(decoder, &decoder_client_data))
diff --git a/src/test_libFLAC/encoders.c b/src/test_libFLAC/encoders.c
index 053695f..f3e9788 100644
--- a/src/test_libFLAC/encoders.c
+++ b/src/test_libFLAC/encoders.c
@@ -45,8 +45,8 @@
 	"Filename"
 };
 
-static FLAC__StreamMetadata streaminfo_, padding_, seektable_, application1_, application2_, vorbiscomment_, cuesheet_, unknown_;
-static FLAC__StreamMetadata *metadata_sequence_[] = { &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &unknown_ };
+static FLAC__StreamMetadata streaminfo_, padding_, seektable_, application1_, application2_, vorbiscomment_, cuesheet_, picture_, unknown_;
+static FLAC__StreamMetadata *metadata_sequence_[] = { &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &picture_, &unknown_ };
 static const unsigned num_metadata_ = sizeof(metadata_sequence_) / sizeof(metadata_sequence_[0]);
 static const char *flacfilename_ = "metadata.flac";
 
@@ -76,12 +76,12 @@
 
 static void init_metadata_blocks_()
 {
-	mutils__init_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &unknown_);
+	mutils__init_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &picture_, &unknown_);
 }
 
 static void free_metadata_blocks_()
 {
-	mutils__free_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &unknown_);
+	mutils__free_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &picture_, &unknown_);
 }
 
 static FLAC__StreamEncoderWriteStatus stream_encoder_write_callback_(const FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], unsigned bytes, unsigned samples, unsigned current_frame, void *client_data)
diff --git a/src/test_libFLAC/metadata_manip.c b/src/test_libFLAC/metadata_manip.c
index 21a8fa4..81885fd 100644
--- a/src/test_libFLAC/metadata_manip.c
+++ b/src/test_libFLAC/metadata_manip.c
@@ -100,6 +100,16 @@
 	return x;
 }
 
+static char *strdup_or_die_(const char *s)
+{
+	char *x = strdup(s);
+	if(0 == x) {
+		fprintf(stderr, "ERROR: out of memory copying string \"%s\"\n", s);
+		exit(1);
+	}
+	return x;
+}
+
 /* functions for working with our metadata copy */
 
 static FLAC__bool replace_in_our_metadata_(FLAC__StreamMetadata *block, unsigned position, FLAC__bool copy)
@@ -485,10 +495,10 @@
 	printf("ERROR: got error callback, status = %s (%u)\n", FLAC__StreamDecoderErrorStatusString[status], (unsigned)status);
 }
 
-static FLAC__bool generate_file_(FLAC__bool include_cuesheet)
+static FLAC__bool generate_file_(FLAC__bool include_extras)
 {
-	FLAC__StreamMetadata streaminfo, vorbiscomment, *cuesheet, padding;
-	FLAC__StreamMetadata *metadata[3];
+	FLAC__StreamMetadata streaminfo, vorbiscomment, *cuesheet, picture, padding;
+	FLAC__StreamMetadata *metadata[4];
 	unsigned i = 0, n = 0;
 
 	printf("generating FLAC file for test\n");
@@ -535,19 +545,49 @@
 			return die_("priming our metadata");
 	}
 
+	{
+		picture.is_last = false;
+		picture.type = FLAC__METADATA_TYPE_PICTURE;
+		picture.length =
+			(
+				FLAC__STREAM_METADATA_PICTURE_TYPE_LEN +
+				FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN + /* will add the length for the string later */
+				FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN + /* will add the length for the string later */
+				FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN +
+				FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN +
+				FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN +
+				FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN /* will add the length for the data later */
+			) / 8
+		;
+		picture.data.picture.type = FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER;
+		picture.data.picture.mime_type = strdup_or_die_("image/jpeg");
+		picture.length += strlen(picture.data.picture.mime_type);
+		picture.data.picture.description = (FLAC__byte*)strdup_or_die_("desc");
+		picture.length += strlen((const char *)picture.data.picture.description);
+		picture.data.picture.width = 300;
+		picture.data.picture.height = 300;
+		picture.data.picture.depth = 24;
+		picture.data.picture.data = (FLAC__byte*)strdup_or_die_("SOMEJPEGDATA");
+		picture.data.picture.data_length = strlen((const char *)picture.data.picture.data);
+		picture.length += picture.data.picture.data_length;
+	}
+
 	padding.is_last = true;
 	padding.type = FLAC__METADATA_TYPE_PADDING;
 	padding.length = 1234;
 
 	metadata[n++] = &vorbiscomment;
-	if (include_cuesheet)
+	if(include_extras) {
 		metadata[n++] = cuesheet;
+		metadata[n++] = &picture;
+	}
 	metadata[n++] = &padding;
 
 	if(
 		!insert_to_our_metadata_(&streaminfo, i++, /*copy=*/true) ||
 		!insert_to_our_metadata_(&vorbiscomment, i++, /*copy=*/true) ||
-		(include_cuesheet && !insert_to_our_metadata_(cuesheet, i++, /*copy=*/false)) ||
+		(include_extras && !insert_to_our_metadata_(cuesheet, i++, /*copy=*/false)) ||
+		(include_extras && !insert_to_our_metadata_(&picture, i++, /*copy=*/true)) ||
 		!insert_to_our_metadata_(&padding, i++, /*copy=*/true)
 	)
 		return die_("priming our metadata");
@@ -627,10 +667,11 @@
 	FLAC__StreamMetadata streaminfo;
 	FLAC__StreamMetadata *tags = 0;
 	FLAC__StreamMetadata *cuesheet = 0;
+	FLAC__StreamMetadata *picture = 0;
 
 	printf("\n\n++++++ testing level 0 interface\n");
 
-	if(!generate_file_(/*include_cuesheet=*/true))
+	if(!generate_file_(/*include_extras=*/true))
 		return false;
 
 	if(!test_file_(flacfile_, decoder_metadata_callback_null_))
@@ -675,12 +716,25 @@
 
 	/* check to see if some basic data matches (c.f. generate_file_()) */
 	if(cuesheet->data.cue_sheet.lead_in != 123)
-		return die_("mismatch in cuesheet->data.vorbis_comment.num_comments");
+		return die_("mismatch in cuesheet->data.cue_sheet.lead_in");
 
 	printf("OK\n");
 
 	FLAC__metadata_object_delete(cuesheet);
 
+	printf("testing FLAC__metadata_get_picture()... ");
+
+	if(!FLAC__metadata_get_picture(flacfile_, &picture, /*type=*/(FLAC__StreamMetadata_Picture_Type)(-1), /*mime_type=*/0, /*description=*/0, /*max_width=*/(unsigned)(-1), /*max_height=*/(unsigned)(-1), /*max_depth=*/(unsigned)(-1)))
+		return die_("during FLAC__metadata_get_picture()");
+
+	/* check to see if some basic data matches (c.f. generate_file_()) */
+	if(picture->data.picture.type != FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER)
+		return die_("mismatch in picture->data.picture.type");
+
+	printf("OK\n");
+
+	FLAC__metadata_object_delete(picture);
+
 	if(!remove_file_(flacfile_))
 		return false;
 
@@ -703,7 +757,7 @@
 
 	printf("simple iterator on read-only file\n");
 
-	if(!generate_file_(/*include_cuesheet=*/false))
+	if(!generate_file_(/*include_extras=*/false))
 		return false;
 
 	if(!change_stats_(flacfile_, /*read_only=*/true))
@@ -1362,7 +1416,7 @@
 
 	printf("generate read-only file\n");
 
-	if(!generate_file_(/*include_cuesheet=*/false))
+	if(!generate_file_(/*include_extras=*/false))
 		return false;
 
 	if(!change_stats_(flacfile_, /*read_only=*/true))
@@ -1875,7 +1929,7 @@
 
 	printf("generate file\n");
 
-	if(!generate_file_(/*include_cuesheet=*/false))
+	if(!generate_file_(/*include_extras=*/false))
 		return false;
 
 	printf("create chain\n");
diff --git a/src/test_libFLAC/metadata_object.c b/src/test_libFLAC/metadata_object.c
index 304df90..2939ed3 100644
--- a/src/test_libFLAC/metadata_object.c
+++ b/src/test_libFLAC/metadata_object.c
@@ -463,10 +463,43 @@
 	cs_calc_len_(block);
 }
 
+static void pi_set_mime_type(FLAC__StreamMetadata *block, const char *s)
+{
+	if(block->data.picture.mime_type) {
+		block->length -= strlen(block->data.picture.mime_type);
+		free(block->data.picture.mime_type);
+	}
+	block->data.picture.mime_type = strdup(s);
+	FLAC__ASSERT(block->data.picture.mime_type);
+	block->length += strlen(block->data.picture.mime_type);
+}
+
+static void pi_set_description(FLAC__StreamMetadata *block, const FLAC__byte *s)
+{
+	if(block->data.picture.description) {
+		block->length -= strlen((const char *)block->data.picture.description);
+		free(block->data.picture.description);
+	}
+	block->data.picture.description = (FLAC__byte*)strdup((const char *)s);
+	FLAC__ASSERT(block->data.picture.description);
+	block->length += strlen((const char *)block->data.picture.description);
+}
+
+static void pi_set_data(FLAC__StreamMetadata *block, const FLAC__byte *data, FLAC__uint32 len)
+{
+	if(block->data.picture.data) {
+		block->length -= block->data.picture.data_length;
+		free(block->data.picture.data);
+	}
+	block->data.picture.data = (FLAC__byte*)strdup((const char *)data);
+	FLAC__ASSERT(block->data.picture.data);
+	block->data.picture.data_length = len;
+	block->length += len;
+}
 
 FLAC__bool test_metadata_object()
 {
-	FLAC__StreamMetadata *block, *blockcopy, *vorbiscomment, *cuesheet;
+	FLAC__StreamMetadata *block, *blockcopy, *vorbiscomment, *cuesheet, *picture;
 	FLAC__StreamMetadata_SeekPoint seekpoint_array[14];
 	FLAC__StreamMetadata_VorbisComment_Entry entry;
 	FLAC__StreamMetadata_CueSheet_Index index;
@@ -1996,5 +2029,253 @@
 	printf("OK\n");
 
 
+	printf("testing PICTURE\n");
+
+	printf("testing FLAC__metadata_object_new()... ");
+	block = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PICTURE);
+	if(0 == block) {
+		printf("FAILED, returned NULL\n");
+		return false;
+	}
+	expected_length = (
+		FLAC__STREAM_METADATA_PICTURE_TYPE_LEN +
+		FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN +
+		FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN +
+		FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN +
+		FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN +
+		FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN +
+		FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN
+	) / 8;
+	if(block->length != expected_length) {
+		printf("FAILED, bad length, expected %u, got %u\n", expected_length, block->length);
+		return false;
+	}
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_clone()... ");
+	picture = FLAC__metadata_object_clone(block);
+	if(0 == picture) {
+		printf("FAILED, returned NULL\n");
+		return false;
+	}
+	if(!mutils__compare_block(picture, block))
+		return false;
+	printf("OK\n");
+
+	pi_set_mime_type(picture, "image/png\t");
+	printf("testing FLAC__metadata_object_picture_set_mime_type(copy)...");
+	if(!FLAC__metadata_object_picture_set_mime_type(block, "image/png\t", /*copy=*/true)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!mutils__compare_block(picture, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_picture_is_legal()...");
+	{
+		const char *violation;
+		if(FLAC__metadata_object_picture_is_legal(block, &violation)) {
+			printf("FAILED, returned true when expecting false\n");
+			return false;
+		}
+		printf("returned false as expected, violation=\"%s\" OK\n", violation);
+	}
+
+	pi_set_mime_type(picture, "image/png");
+	printf("testing FLAC__metadata_object_picture_set_mime_type(copy)...");
+	if(!FLAC__metadata_object_picture_set_mime_type(block, "image/png", /*copy=*/true)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!mutils__compare_block(picture, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_picture_is_legal()...");
+	{
+		const char *violation;
+		if(!FLAC__metadata_object_picture_is_legal(block, &violation)) {
+			printf("FAILED, returned false, violation=\"%s\"\n", violation);
+			return false;
+		}
+		printf("OK\n");
+	}
+
+	pi_set_description(picture, (const FLAC__byte *)"DESCRIPTION\xff");
+	printf("testing FLAC__metadata_object_picture_set_description(copy)...");
+	if(!FLAC__metadata_object_picture_set_description(block, (FLAC__byte *)"DESCRIPTION\xff", /*copy=*/true)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!mutils__compare_block(picture, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_picture_is_legal()...");
+	{
+		const char *violation;
+		if(FLAC__metadata_object_picture_is_legal(block, &violation)) {
+			printf("FAILED, returned true when expecting false\n");
+			return false;
+		}
+		printf("returned false as expected, violation=\"%s\" OK\n", violation);
+	}
+
+	pi_set_description(picture, (const FLAC__byte *)"DESCRIPTION");
+	printf("testing FLAC__metadata_object_picture_set_description(copy)...");
+	if(!FLAC__metadata_object_picture_set_description(block, (FLAC__byte *)"DESCRIPTION", /*copy=*/true)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!mutils__compare_block(picture, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_picture_is_legal()...");
+	{
+		const char *violation;
+		if(!FLAC__metadata_object_picture_is_legal(block, &violation)) {
+			printf("FAILED, returned false, violation=\"%s\"\n", violation);
+			return false;
+		}
+		printf("OK\n");
+	}
+
+
+	pi_set_data(picture, (const FLAC__byte*)"PNGDATA", strlen("PNGDATA"));
+	printf("testing FLAC__metadata_object_picture_set_data(copy)...");
+	if(!FLAC__metadata_object_picture_set_data(block, (FLAC__byte*)"PNGDATA", strlen("PNGDATA"), /*copy=*/true)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!mutils__compare_block(picture, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_clone()... ");
+	blockcopy = FLAC__metadata_object_clone(block);
+	if(0 == blockcopy) {
+		printf("FAILED, returned NULL\n");
+		return false;
+	}
+	if(!mutils__compare_block(block, blockcopy))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_delete()... ");
+	FLAC__metadata_object_delete(blockcopy);
+	printf("OK\n");
+
+	pi_set_mime_type(picture, "image/png\t");
+	printf("testing FLAC__metadata_object_picture_set_mime_type(own)...");
+	if(!FLAC__metadata_object_picture_set_mime_type(block, strdup("image/png\t"), /*copy=*/false)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!mutils__compare_block(picture, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_picture_is_legal()...");
+	{
+		const char *violation;
+		if(FLAC__metadata_object_picture_is_legal(block, &violation)) {
+			printf("FAILED, returned true when expecting false\n");
+			return false;
+		}
+		printf("returned false as expected, violation=\"%s\" OK\n", violation);
+	}
+
+	pi_set_mime_type(picture, "image/png");
+	printf("testing FLAC__metadata_object_picture_set_mime_type(own)...");
+	if(!FLAC__metadata_object_picture_set_mime_type(block, strdup("image/png"), /*copy=*/false)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!mutils__compare_block(picture, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_picture_is_legal()...");
+	{
+		const char *violation;
+		if(!FLAC__metadata_object_picture_is_legal(block, &violation)) {
+			printf("FAILED, returned false, violation=\"%s\"\n", violation);
+			return false;
+		}
+		printf("OK\n");
+	}
+
+	pi_set_description(picture, (const FLAC__byte *)"DESCRIPTION\xff");
+	printf("testing FLAC__metadata_object_picture_set_description(own)...");
+	if(!FLAC__metadata_object_picture_set_description(block, (FLAC__byte *)strdup("DESCRIPTION\xff"), /*copy=*/false)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!mutils__compare_block(picture, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_picture_is_legal()...");
+	{
+		const char *violation;
+		if(FLAC__metadata_object_picture_is_legal(block, &violation)) {
+			printf("FAILED, returned true when expecting false\n");
+			return false;
+		}
+		printf("returned false as expected, violation=\"%s\" OK\n", violation);
+	}
+
+	pi_set_description(picture, (const FLAC__byte *)"DESCRIPTION");
+	printf("testing FLAC__metadata_object_picture_set_description(own)...");
+	if(!FLAC__metadata_object_picture_set_description(block, (FLAC__byte *)strdup("DESCRIPTION"), /*copy=*/false)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!mutils__compare_block(picture, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_picture_is_legal()...");
+	{
+		const char *violation;
+		if(!FLAC__metadata_object_picture_is_legal(block, &violation)) {
+			printf("FAILED, returned false, violation=\"%s\"\n", violation);
+			return false;
+		}
+		printf("OK\n");
+	}
+
+	pi_set_data(picture, (const FLAC__byte*)"PNGDATA", strlen("PNGDATA"));
+	printf("testing FLAC__metadata_object_picture_set_data(own)...");
+	if(!FLAC__metadata_object_picture_set_data(block, (FLAC__byte*)strdup("PNGDATA"), strlen("PNGDATA"), /*copy=*/false)) {
+		printf("FAILED, returned false\n");
+		return false;
+	}
+	if(!mutils__compare_block(picture, block))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_clone()... ");
+	blockcopy = FLAC__metadata_object_clone(block);
+	if(0 == blockcopy) {
+		printf("FAILED, returned NULL\n");
+		return false;
+	}
+	if(!mutils__compare_block(block, blockcopy))
+		return false;
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_delete()... ");
+	FLAC__metadata_object_delete(blockcopy);
+	printf("OK\n");
+
+	printf("testing FLAC__metadata_object_delete()... ");
+	FLAC__metadata_object_delete(picture);
+	FLAC__metadata_object_delete(block);
+	printf("OK\n");
+
+
 	return true;
 }
diff --git a/src/test_libOggFLAC++/decoders.cpp b/src/test_libOggFLAC++/decoders.cpp
index 0776d0b..9a91ab9 100644
--- a/src/test_libOggFLAC++/decoders.cpp
+++ b/src/test_libOggFLAC++/decoders.cpp
@@ -58,8 +58,8 @@
 	"Filename"
 };
 
-static ::FLAC__StreamMetadata streaminfo_, padding_, seektable_, application1_, application2_, vorbiscomment_, cuesheet_, unknown_;
-static ::FLAC__StreamMetadata *expected_metadata_sequence_[8];
+static ::FLAC__StreamMetadata streaminfo_, padding_, seektable_, application1_, application2_, vorbiscomment_, cuesheet_, picture_, unknown_;
+static ::FLAC__StreamMetadata *expected_metadata_sequence_[9];
 static unsigned num_expected_;
 static const char *flacfilename_ = "metadata.ogg";
 static off_t flacfilesize_;
@@ -90,12 +90,12 @@
 
 static void init_metadata_blocks_()
 {
-	mutils__init_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &unknown_);
+	mutils__init_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &picture_, &unknown_);
 }
 
 static void free_metadata_blocks_()
 {
-	mutils__free_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &unknown_);
+	mutils__free_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &picture_, &unknown_);
 }
 
 static bool generate_file_()
@@ -109,6 +109,7 @@
 	expected_metadata_sequence_[num_expected_++] = &application2_;
 	expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
 	expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+	expected_metadata_sequence_[num_expected_++] = &picture_;
 	expected_metadata_sequence_[num_expected_++] = &unknown_;
 	/* WATCHOUT: the encoder should move the VORBIS_COMMENT block to the front, right after STREAMINFO */
 
@@ -723,6 +724,7 @@
 	expected_metadata_sequence_[num_expected_++] = &application1_;
 	expected_metadata_sequence_[num_expected_++] = &application2_;
 	expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+	expected_metadata_sequence_[num_expected_++] = &picture_;
 	expected_metadata_sequence_[num_expected_++] = &unknown_;
 
 	if(!(layer < LAYER_FILE? dynamic_cast<StreamDecoder*>(decoder)->test_respond() : dynamic_cast<FileDecoder*>(decoder)->test_respond()))
@@ -769,6 +771,7 @@
 	expected_metadata_sequence_[num_expected_++] = &application1_;
 	expected_metadata_sequence_[num_expected_++] = &application2_;
 	expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+	expected_metadata_sequence_[num_expected_++] = &picture_;
 	expected_metadata_sequence_[num_expected_++] = &unknown_;
 
 	if(!(layer < LAYER_FILE? dynamic_cast<StreamDecoder*>(decoder)->test_respond() : dynamic_cast<FileDecoder*>(decoder)->test_respond()))
@@ -798,6 +801,7 @@
 	expected_metadata_sequence_[num_expected_++] = &padding_;
 	expected_metadata_sequence_[num_expected_++] = &seektable_;
 	expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+	expected_metadata_sequence_[num_expected_++] = &picture_;
 	expected_metadata_sequence_[num_expected_++] = &unknown_;
 
 	if(!(layer < LAYER_FILE? dynamic_cast<StreamDecoder*>(decoder)->test_respond() : dynamic_cast<FileDecoder*>(decoder)->test_respond()))
@@ -828,6 +832,7 @@
 	expected_metadata_sequence_[num_expected_++] = &seektable_;
 	expected_metadata_sequence_[num_expected_++] = &application2_;
 	expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+	expected_metadata_sequence_[num_expected_++] = &picture_;
 	expected_metadata_sequence_[num_expected_++] = &unknown_;
 
 	if(!(layer < LAYER_FILE? dynamic_cast<StreamDecoder*>(decoder)->test_respond() : dynamic_cast<FileDecoder*>(decoder)->test_respond()))
@@ -864,6 +869,7 @@
 	expected_metadata_sequence_[num_expected_++] = &padding_;
 	expected_metadata_sequence_[num_expected_++] = &seektable_;
 	expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+	expected_metadata_sequence_[num_expected_++] = &picture_;
 	expected_metadata_sequence_[num_expected_++] = &unknown_;
 
 	if(!(layer < LAYER_FILE? dynamic_cast<StreamDecoder*>(decoder)->test_respond() : dynamic_cast<FileDecoder*>(decoder)->test_respond()))
@@ -1006,6 +1012,7 @@
 	expected_metadata_sequence_[num_expected_++] = &seektable_;
 	expected_metadata_sequence_[num_expected_++] = &application1_;
 	expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+	expected_metadata_sequence_[num_expected_++] = &picture_;
 	expected_metadata_sequence_[num_expected_++] = &unknown_;
 
 	if(!(layer < LAYER_FILE? dynamic_cast<StreamDecoder*>(decoder)->test_respond() : dynamic_cast<FileDecoder*>(decoder)->test_respond()))
diff --git a/src/test_libOggFLAC++/encoders.cpp b/src/test_libOggFLAC++/encoders.cpp
index d2c7f69..ce91c8e 100644
--- a/src/test_libOggFLAC++/encoders.cpp
+++ b/src/test_libOggFLAC++/encoders.cpp
@@ -42,8 +42,8 @@
 	"Filename"
 };
 
-static ::FLAC__StreamMetadata streaminfo_, padding_, seektable_, application1_, application2_, vorbiscomment_, cuesheet_, unknown_;
-static ::FLAC__StreamMetadata *metadata_sequence_[] = { &vorbiscomment_, &padding_, &seektable_, &application1_, &application2_, &cuesheet_, &unknown_ };
+static ::FLAC__StreamMetadata streaminfo_, padding_, seektable_, application1_, application2_, vorbiscomment_, cuesheet_, picture_, unknown_;
+static ::FLAC__StreamMetadata *metadata_sequence_[] = { &vorbiscomment_, &padding_, &seektable_, &application1_, &application2_, &cuesheet_, &picture_, &unknown_ };
 static const unsigned num_metadata_ = sizeof(metadata_sequence_) / sizeof(metadata_sequence_[0]);
 static const char *flacfilename_ = "metadata.ogg";
 
@@ -77,12 +77,12 @@
 
 static void init_metadata_blocks_()
 {
-	mutils__init_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &unknown_);
+	mutils__init_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &picture_, &unknown_);
 }
 
 static void free_metadata_blocks_()
 {
-	mutils__free_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &unknown_);
+	mutils__free_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &picture_, &unknown_);
 }
 
 class StreamEncoder : public OggFLAC::Encoder::Stream {
diff --git a/src/test_libOggFLAC/decoders.c b/src/test_libOggFLAC/decoders.c
index f02abbc..4eea85d 100644
--- a/src/test_libOggFLAC/decoders.c
+++ b/src/test_libOggFLAC/decoders.c
@@ -59,8 +59,8 @@
 	FLAC__bool error_occurred;
 } StreamDecoderClientData;
 
-static FLAC__StreamMetadata streaminfo_, padding_, seektable_, application1_, application2_, vorbiscomment_, cuesheet_, unknown_;
-static FLAC__StreamMetadata *expected_metadata_sequence_[8];
+static FLAC__StreamMetadata streaminfo_, padding_, seektable_, application1_, application2_, vorbiscomment_, cuesheet_, picture_, unknown_;
+static FLAC__StreamMetadata *expected_metadata_sequence_[9];
 static unsigned num_expected_;
 static const char *flacfilename_ = "metadata.ogg";
 static off_t flacfilesize_;
@@ -91,12 +91,12 @@
 
 static void init_metadata_blocks_()
 {
-	mutils__init_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &unknown_);
+	mutils__init_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &picture_, &unknown_);
 }
 
 static void free_metadata_blocks_()
 {
-	mutils__free_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &unknown_);
+	mutils__free_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &picture_, &unknown_);
 }
 
 static FLAC__bool generate_file_()
@@ -110,6 +110,7 @@
 	expected_metadata_sequence_[num_expected_++] = &application2_;
 	expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
 	expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+	expected_metadata_sequence_[num_expected_++] = &picture_;
 	expected_metadata_sequence_[num_expected_++] = &unknown_;
 	/* WATCHOUT: the encoder should move the VORBIS_COMMENT block to the front, right after STREAMINFO */
 
@@ -643,6 +644,7 @@
 	expected_metadata_sequence_[num_expected_++] = &application1_;
 	expected_metadata_sequence_[num_expected_++] = &application2_;
 	expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+	expected_metadata_sequence_[num_expected_++] = &picture_;
 	expected_metadata_sequence_[num_expected_++] = &unknown_;
 
 	if(!stream_decoder_test_respond_(decoder, &decoder_client_data))
@@ -683,6 +685,7 @@
 	expected_metadata_sequence_[num_expected_++] = &application1_;
 	expected_metadata_sequence_[num_expected_++] = &application2_;
 	expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+	expected_metadata_sequence_[num_expected_++] = &picture_;
 	expected_metadata_sequence_[num_expected_++] = &unknown_;
 
 	if(!stream_decoder_test_respond_(decoder, &decoder_client_data))
@@ -708,6 +711,7 @@
 	expected_metadata_sequence_[num_expected_++] = &padding_;
 	expected_metadata_sequence_[num_expected_++] = &seektable_;
 	expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+	expected_metadata_sequence_[num_expected_++] = &picture_;
 	expected_metadata_sequence_[num_expected_++] = &unknown_;
 
 	if(!stream_decoder_test_respond_(decoder, &decoder_client_data))
@@ -734,6 +738,7 @@
 	expected_metadata_sequence_[num_expected_++] = &seektable_;
 	expected_metadata_sequence_[num_expected_++] = &application2_;
 	expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+	expected_metadata_sequence_[num_expected_++] = &picture_;
 	expected_metadata_sequence_[num_expected_++] = &unknown_;
 
 	if(!stream_decoder_test_respond_(decoder, &decoder_client_data))
@@ -764,6 +769,7 @@
 	expected_metadata_sequence_[num_expected_++] = &padding_;
 	expected_metadata_sequence_[num_expected_++] = &seektable_;
 	expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+	expected_metadata_sequence_[num_expected_++] = &picture_;
 	expected_metadata_sequence_[num_expected_++] = &unknown_;
 
 	if(!stream_decoder_test_respond_(decoder, &decoder_client_data))
@@ -882,6 +888,7 @@
 	expected_metadata_sequence_[num_expected_++] = &seektable_;
 	expected_metadata_sequence_[num_expected_++] = &application1_;
 	expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+	expected_metadata_sequence_[num_expected_++] = &picture_;
 	expected_metadata_sequence_[num_expected_++] = &unknown_;
 
 	if(!stream_decoder_test_respond_(decoder, &decoder_client_data))
diff --git a/src/test_libOggFLAC/encoders.c b/src/test_libOggFLAC/encoders.c
index 871ead4..d7701a5 100644
--- a/src/test_libOggFLAC/encoders.c
+++ b/src/test_libOggFLAC/encoders.c
@@ -45,8 +45,8 @@
 	"Filename"
 };
 
-static FLAC__StreamMetadata streaminfo_, padding_, seektable_, application1_, application2_, vorbiscomment_, cuesheet_, unknown_;
-static FLAC__StreamMetadata *metadata_sequence_[] = { &vorbiscomment_, &padding_, &seektable_, &application1_, &application2_, &cuesheet_, &unknown_ };
+static FLAC__StreamMetadata streaminfo_, padding_, seektable_, application1_, application2_, vorbiscomment_, cuesheet_, picture_, unknown_;
+static FLAC__StreamMetadata *metadata_sequence_[] = { &vorbiscomment_, &padding_, &seektable_, &application1_, &application2_, &cuesheet_, &picture_, &unknown_ };
 static const unsigned num_metadata_ = sizeof(metadata_sequence_) / sizeof(metadata_sequence_[0]);
 static const char *flacfilename_ = "metadata.ogg";
 
@@ -80,12 +80,12 @@
 
 static void init_metadata_blocks_()
 {
-	mutils__init_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &unknown_);
+	mutils__init_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &picture_, &unknown_);
 }
 
 static void free_metadata_blocks_()
 {
-	mutils__free_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &unknown_);
+	mutils__free_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &picture_, &unknown_);
 }
 
 static OggFLAC__StreamEncoderReadStatus stream_encoder_read_callback_(const OggFLAC__StreamEncoder *encoder, FLAC__byte buffer[], unsigned *bytes, void *client_data)
diff --git a/src/test_libs_common/metadata_utils.c b/src/test_libs_common/metadata_utils.c
index 926a894..1c88251 100644
--- a/src/test_libs_common/metadata_utils.c
+++ b/src/test_libs_common/metadata_utils.c
@@ -289,6 +289,56 @@
 	return true;
 }
 
+FLAC__bool mutils__compare_block_data_picture(const FLAC__StreamMetadata_Picture *block, const FLAC__StreamMetadata_Picture *blockcopy)
+{
+	size_t len, lencopy;
+	if(blockcopy->type != block->type) {
+		printf("FAILED, type mismatch, expected %u, got %u\n", (unsigned)block->type, (unsigned)blockcopy->type);
+		return false;
+	}
+	len = strlen(block->mime_type);
+	lencopy = strlen(blockcopy->mime_type);
+	if(lencopy != len) {
+		printf("FAILED, mime_type length mismatch, expected %u, got %u\n", (unsigned)len, (unsigned)lencopy);
+		return false;
+	}
+	if(strcmp(blockcopy->mime_type, block->mime_type)) {
+		printf("FAILED, mime_type mismatch, expected %s, got %s\n", block->mime_type, blockcopy->mime_type);
+		return false;
+	}
+	len = strlen((const char *)block->description);
+	lencopy = strlen((const char *)blockcopy->description);
+	if(lencopy != len) {
+		printf("FAILED, description length mismatch, expected %u, got %u\n", (unsigned)len, (unsigned)lencopy);
+		return false;
+	}
+	if(strcmp((const char *)blockcopy->description, (const char *)block->description)) {
+		printf("FAILED, description mismatch, expected %s, got %s\n", block->description, blockcopy->description);
+		return false;
+	}
+	if(blockcopy->width != block->width) {
+		printf("FAILED, width mismatch, expected %u, got %u\n", block->width, blockcopy->width);
+		return false;
+	}
+	if(blockcopy->height != block->height) {
+		printf("FAILED, height mismatch, expected %u, got %u\n", block->height, blockcopy->height);
+		return false;
+	}
+	if(blockcopy->depth != block->depth) {
+		printf("FAILED, depth mismatch, expected %u, got %u\n", block->depth, blockcopy->depth);
+		return false;
+	}
+	if(blockcopy->data_length != block->data_length) {
+		printf("FAILED, data_length mismatch, expected %u, got %u\n", block->data_length, blockcopy->data_length);
+		return false;
+	}
+	if(memcmp(blockcopy->data, block->data, block->data_length)) {
+		printf("FAILED, data mismatch\n");
+		return false;
+	}
+	return true;
+}
+
 FLAC__bool mutils__compare_block_data_unknown(const FLAC__StreamMetadata_Unknown *block, const FLAC__StreamMetadata_Unknown *blockcopy, unsigned block_length)
 {
 	if(0 == block->data || 0 == blockcopy->data) {
@@ -341,10 +391,13 @@
 			return mutils__compare_block_data_vorbiscomment(&block->data.vorbis_comment, &blockcopy->data.vorbis_comment);
 		case FLAC__METADATA_TYPE_CUESHEET:
 			return mutils__compare_block_data_cuesheet(&block->data.cue_sheet, &blockcopy->data.cue_sheet);
+		case FLAC__METADATA_TYPE_PICTURE:
+			return mutils__compare_block_data_picture(&block->data.picture, &blockcopy->data.picture);
 		default:
 			return mutils__compare_block_data_unknown(&block->data.unknown, &blockcopy->data.unknown, block->length);
 	}
 }
+
 static void *malloc_or_die_(size_t size)
 {
 	void *x = malloc(size);
@@ -365,6 +418,16 @@
 	return x;
 }
 
+static char *strdup_or_die_(const char *s)
+{
+	char *x = strdup(s);
+	if(0 == x) {
+		fprintf(stderr, "ERROR: out of memory copying string \"%s\"\n", s);
+		exit(1);
+	}
+	return x;
+}
+
 void mutils__init_metadata_blocks(
 	FLAC__StreamMetadata *streaminfo,
 	FLAC__StreamMetadata *padding,
@@ -373,6 +436,7 @@
 	FLAC__StreamMetadata *application2,
 	FLAC__StreamMetadata *vorbiscomment,
 	FLAC__StreamMetadata *cuesheet,
+	FLAC__StreamMetadata *picture,
 	FLAC__StreamMetadata *unknown
 )
 {
@@ -503,6 +567,31 @@
 	cuesheet->data.cue_sheet.tracks[2].number = 170;
 	cuesheet->data.cue_sheet.tracks[2].num_indices = 0;
 
+	picture->is_last = false;
+	picture->type = FLAC__METADATA_TYPE_PICTURE;
+	picture->length =
+		(
+			FLAC__STREAM_METADATA_PICTURE_TYPE_LEN +
+			FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN + /* will add the length for the string later */
+			FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN + /* will add the length for the string later */
+			FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN +
+			FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN +
+			FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN +
+			FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN /* will add the length for the data later */
+		) / 8
+	;
+	picture->data.picture.type = FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER;
+	picture->data.picture.mime_type = strdup_or_die_("image/jpeg");
+	picture->length += strlen(picture->data.picture.mime_type);
+	picture->data.picture.description = (FLAC__byte*)strdup_or_die_("desc");
+	picture->length += strlen((const char *)picture->data.picture.description);
+	picture->data.picture.width = 300;
+	picture->data.picture.height = 300;
+	picture->data.picture.depth = 24;
+	picture->data.picture.data = (FLAC__byte*)strdup_or_die_("SOMEJPEGDATA");
+	picture->data.picture.data_length = strlen((const char *)picture->data.picture.data);
+	picture->length += picture->data.picture.data_length;
+
 	unknown->is_last = true;
 	unknown->type = 126;
 	unknown->length = 8;
@@ -518,6 +607,7 @@
 	FLAC__StreamMetadata *application2,
 	FLAC__StreamMetadata *vorbiscomment,
 	FLAC__StreamMetadata *cuesheet,
+	FLAC__StreamMetadata *picture,
 	FLAC__StreamMetadata *unknown
 )
 {
@@ -530,5 +620,8 @@
 	free(cuesheet->data.cue_sheet.tracks[0].indices);
 	free(cuesheet->data.cue_sheet.tracks[1].indices);
 	free(cuesheet->data.cue_sheet.tracks);
+	free(picture->data.picture.mime_type);
+	free(picture->data.picture.description);
+	free(picture->data.picture.data);
 	free(unknown->data.unknown.data);
 }