Пример #1
0
  void testPicture()
  {
    ScopedFileCopy copy("empty", ".ogg");
    string newname = copy.fileName();

    {
      Vorbis::File f(newname.c_str());
      FLAC::Picture *newpic = new FLAC::Picture();
      newpic->setType(FLAC::Picture::BackCover);
      newpic->setWidth(5);
      newpic->setHeight(6);
      newpic->setColorDepth(16);
      newpic->setNumColors(7);
      newpic->setMimeType("image/jpeg");
      newpic->setDescription("new image");
      newpic->setData("JPEG data");
      f.tag()->addPicture(newpic);
      f.save();
    }
    {
      Vorbis::File f(newname.c_str());
      List<FLAC::Picture *> lst = f.tag()->pictureList();
      CPPUNIT_ASSERT_EQUAL((unsigned int)1, lst.size());
      CPPUNIT_ASSERT_EQUAL((int)5, lst[0]->width());
      CPPUNIT_ASSERT_EQUAL((int)6, lst[0]->height());
      CPPUNIT_ASSERT_EQUAL((int)16, lst[0]->colorDepth());
      CPPUNIT_ASSERT_EQUAL((int)7, lst[0]->numColors());
      CPPUNIT_ASSERT_EQUAL(String("image/jpeg"), lst[0]->mimeType());
      CPPUNIT_ASSERT_EQUAL(String("new image"), lst[0]->description());
      CPPUNIT_ASSERT_EQUAL(ByteVector("JPEG data"), lst[0]->data());
    }
  }
Пример #2
0
  void testReadPicture()
  {
    ScopedFileCopy copy("silence-44-s", ".flac");
    string newname = copy.fileName();

    FLAC::File f(newname.c_str());
    List<FLAC::Picture *> lst = f.pictureList();
    CPPUNIT_ASSERT_EQUAL((unsigned int)1, lst.size());

    FLAC::Picture *pic = lst.front();
    CPPUNIT_ASSERT_EQUAL(FLAC::Picture::FrontCover, pic->type());
    CPPUNIT_ASSERT_EQUAL(1, pic->width());
    CPPUNIT_ASSERT_EQUAL(1, pic->height());
    CPPUNIT_ASSERT_EQUAL(24, pic->colorDepth());
    CPPUNIT_ASSERT_EQUAL(0, pic->numColors());
    CPPUNIT_ASSERT_EQUAL(String("image/png"), pic->mimeType());
    CPPUNIT_ASSERT_EQUAL(String("A pixel."), pic->description());
    CPPUNIT_ASSERT_EQUAL((unsigned int)150, pic->data().size());
  }
Пример #3
0
void CTagLoaderTagLib::SetFlacArt(FLAC::File *flacFile, EmbeddedArt *art, CMusicInfoTag &tag)
{
  FLAC::Picture *cover[2] = {};
  List<FLAC::Picture *> pictures = flacFile->pictureList();
  for (List<FLAC::Picture *>::ConstIterator i = pictures.begin(); i != pictures.end(); ++i)
  {
    FLAC::Picture *picture = *i;
    if (picture->type() == FLAC::Picture::FrontCover)
      cover[0] = picture;
    else // anything else is taken as second priority
      cover[1] = picture;
  }
  for (unsigned int i = 0; i < 2; i++)
  {
    if (cover[i])
    {
      tag.SetCoverArtInfo(cover[i]->data().size(), cover[i]->mimeType().to8Bit(true));
      if (art)
        art->set((const uint8_t*)cover[i]->data().data(), cover[i]->data().size(), cover[i]->mimeType().to8Bit(true));
      return; // one is enough
    }
  }
}
Пример #4
0
bool TagEditor::save()
{
	if ( fRef )
	{
		bool mustSave = false, result = false;

		if ( !isChecked() )
			clearValues();

		File &file = *fRef->file();

		Tag &tag = getTag( *fRef, file );
		if ( titleE->text() != tag.title().toCString( true ) )
		{
			tag.setTitle( String( titleE->text().toUtf8().data(), String::UTF8 ) );
			mustSave = true;
		}
		if ( artistE->text() != tag.artist().toCString( true ) )
		{
			tag.setArtist( String( artistE->text().toUtf8().data(), String::UTF8 ) );
			mustSave = true;
		}
		if ( albumE->text() != tag.album().toCString( true ) )
		{
			tag.setAlbum( String( albumE->text().toUtf8().data(), String::UTF8 ) );
			mustSave = true;
		}
		if ( commentE->text() != tag.comment().toCString( true ) )
		{
			tag.setComment( String( commentE->text().toUtf8().data(), String::UTF8 ) );
			mustSave = true;
		}
		if ( genreE->text() != tag.genre().toCString( true ) )
		{
			tag.setGenre( String( genreE->text().toUtf8().data(), String::UTF8 ) );
			mustSave = true;
		}
		if ( ( uint )yearB->value() != tag.year() )
		{
			tag.setYear( yearB->value() );
			mustSave = true;
		}
		if ( ( uint )trackB->value() != tag.track() )
		{
			tag.setTrack( trackB->value() );
			mustSave = true;
		}

		if ( isChecked() && ( pictureModificated || pictureBChecked != pictureB->isChecked() ) )
		{
			const bool hasPicture = pictureB->isChecked() && !picture->isEmpty();
			if ( instanceOf( file, MPEG::File ) || instanceOf( file, RIFF::AIFF::File ) )
			{
				ID3v2::Tag *id3v2 = NULL;
				if ( instanceOf( file, MPEG::File ) )
					id3v2 = ( ( MPEG::File & )file ).ID3v2Tag( hasPicture );
				else if ( instanceOf( file, RIFF::AIFF::File ) )
					id3v2 = ( ( RIFF::AIFF::File & )file ).tag();
				if ( id3v2 )
				{
					id3v2->removeFrames( "APIC" );
					if ( hasPicture )
					{
						ID3v2::AttachedPictureFrame *pictureFrame = new ID3v2::AttachedPictureFrame;
						pictureFrame->setType( ID3v2::AttachedPictureFrame::FrontCover );
						pictureFrame->setMimeType( pictureMimeType.data() );
						pictureFrame->setPicture( *picture );
						id3v2->addFrame( pictureFrame );
					}
					mustSave = true;
				}
			}
			else if ( instanceOf( file, FLAC::File ) )
			{
				FLAC::File &flacF = ( FLAC::File & )file;
				flacF.removePictures();
				if ( hasPicture )
				{
					FLAC::Picture *flacPicture = new FLAC::Picture;
					flacPicture->setMimeType( pictureMimeType.data() );
					flacPicture->setType( FLAC::Picture::FrontCover );
					flacPicture->setData( *picture );
					flacF.addPicture( flacPicture );
				}
				mustSave = true;
			}
			else if ( instanceOf( file, MP4::File ) )
			{
				MP4::ItemListMap &itemListMap = ( ( MP4::File & )file ).tag()->itemListMap();
				if ( itemListMap.contains( "covr" ) )
					itemListMap.erase( "covr" );
				if ( hasPicture )
				{
					MP4::CoverArt::Format format = ( MP4::CoverArt::Format )0;
					if ( pictureMimeType == "image/jpeg" )
						format = MP4::CoverArt::JPEG;
					else if ( pictureMimeType == "image/png" )
						format = MP4::CoverArt::PNG;
#if TAGLIB18
					else if ( pictureMimeType == "image/bmp" )
						format = MP4::CoverArt::BMP;
					else if ( pictureMimeType == "image/gif" )
						format = MP4::CoverArt::GIF;
#endif
					if ( format )
					{
						MP4::CoverArtList coverArtList;
						coverArtList.append( MP4::CoverArt( format, *picture ) );
						itemListMap.insert( "covr", coverArtList );
					}
				}
				mustSave = true;
			}
			else if ( isOgg( file ) )
			{
				Ogg::XiphComment *xiphComment = getXiphComment( file );
				if ( xiphComment )
				{
					xiphComment->removeField( "METADATA_BLOCK_PICTURE" );
					if ( hasPicture )
					{
						FLAC::Picture flacPicture;
						flacPicture.setMimeType( pictureMimeType.data() );
						flacPicture.setType( FLAC::Picture::FrontCover );
						flacPicture.setData( *picture );
						const ByteVector pict_data = flacPicture.render();
						xiphComment->addField( "METADATA_BLOCK_PICTURE", QByteArray::fromRawData( pict_data.data(), pict_data.size() ).toBase64().data() );
					}
					mustSave = true;
				}
			}
		}
		else if ( !isChecked() ) //Usuwanie wszystkich znanych tagów
		{
			mustSave = true;

			if ( instanceOf( file, MPEG::File ) )
				( ( MPEG::File & )file ).strip();
			else if ( instanceOf( file, MPC::File ) )
				( ( MPC::File & )file ).strip();
			else if ( instanceOf( file, WavPack::File ) )
				( ( WavPack::File & )file ).strip();
			else if ( instanceOf( file, TrueAudio::File ) )
				( ( TrueAudio::File & )file ).strip();
			else if ( instanceOf( file, APE::File ) )
				( ( APE::File & )file ).strip();
			else if ( instanceOf( file, MP4::File ) )
				( ( MP4::File & )file ).tag()->itemListMap().clear();
			else if ( instanceOf( file, ASF::File ) )
				( ( ASF::File & )file ).tag()->attributeListMap().clear();
			else if ( isOgg( file ) )
				removeXiphComment( getXiphComment( file ) );
			else if ( instanceOf( file, FLAC::File ) )
			{
				FLAC::File &flacF = ( FLAC::File & )file;
				flacF.removePictures();
#if TAGLIB19
				if ( flacF.hasXiphComment() )
#endif
					removeXiphComment( flacF.xiphComment() );
			}
			else if ( instanceOf( file, RIFF::AIFF::File ) )
			{
				ID3v2::Tag *id3v2 = ( ( RIFF::AIFF::File & )file ).tag();
				if ( id3v2 )
				{
					ID3v2::FrameList frameList = id3v2->frameList();
					for ( ID3v2::FrameList::ConstIterator it = frameList.begin() ; it != frameList.end() ; ++it )
						id3v2->removeFrame( *it );
				}
			}
#if TAGLIB18
			else if ( instanceOf( file, Mod::File ) || instanceOf( file, S3M::File ) || instanceOf( file, IT::File ) || instanceOf( file, XM::File ) )
			{
				Mod::Tag *modTag = NULL;
				if ( instanceOf( file, Mod::File ) )
					modTag = ( ( Mod::File & )file ).tag();
				else if ( instanceOf( file, S3M::File ) )
					modTag = ( ( S3M::File & )file ).tag();
				else if ( instanceOf( file, IT::File ) )
					modTag = ( ( IT::File & )file ).tag();
				else if ( instanceOf( file, XM::File ) )
					modTag = ( ( XM::File & )file ).tag();
				if ( modTag )
					modTag->setTrackerName( String::null );
			}
#endif
		}

		/* FLAC::File writer BUG workaround - remove ID3 tags */
		if ( mustSave && instanceOf( file, FLAC::File ) )
		{
			FLAC::File &flacF = ( FLAC::File & )file;
#if TAGLIB19
			if ( flacF.hasID3v1Tag() || flacF.hasID3v2Tag() )
#else
			if ( flacF.ID3v1Tag() || flacF.ID3v2Tag() )
#endif
			{
				const FileName fName = fRef->file()->name();
				result = fRef->save();
				delete fRef;
				fRef = NULL;
				if ( result )
					result = MPEG::File( fName, false ).save( MPEG::File::NoTags );
				mustSave = false;
			}
		}

#if TAGLIB19
		/* No ID3v2 in WAV, only InfoTag */
		if ( mustSave && instanceOf( file, RIFF::WAV::File ) )
		{
			RIFF::WAV::File &wavF = ( RIFF::WAV::File & )file;
			wavF.save( wavF.InfoTag()->isEmpty() ? RIFF::WAV::File::NoTags : RIFF::WAV::File::Info );
			mustSave = false;
		}
#endif

		return mustSave ? fRef->save() : ( fRef ? true : result );
	}
	return false;
}
Пример #5
0
bool TagEditor::open( const QString &fileName )
{
	clear();
#ifdef Q_OS_WIN
	fRef = new FileRef( ( const wchar_t * )fileName.utf16(), false );
#else
	fRef = new FileRef( fileName.toLocal8Bit(), false );
#endif
	if ( !fRef->isNull() && fRef->tag() )
	{
		File &file = *fRef->file();

#if TAGLIB19
		/* Copy ID3v2 to InfoTag */
		if ( instanceOf( file, RIFF::WAV::File ) )
		{
			const Tag &tag = *fRef->tag();
			RIFF::Info::Tag &infoTag = *( ( RIFF::WAV::File & )file ).InfoTag();
			if ( infoTag.isEmpty() && !tag.isEmpty() )
			{
				infoTag.setTitle( tag.title() );
				infoTag.setArtist( tag.artist() );
				infoTag.setAlbum( tag.album() );
				infoTag.setComment( tag.comment() );
				infoTag.setGenre( tag.genre() );
				infoTag.setYear( tag.year() );
				infoTag.setTrack( tag.track() );
			}
		}
#endif

		const Tag &tag = getTag( *fRef, file );
		bool hasTags = !tag.isEmpty();
		setChecked( true );
		if ( hasTags )
		{
			titleE->setText( tag.title().toCString( true ) );
			artistE->setText( tag.artist().toCString( true ) );
			albumE->setText( tag.album().toCString( true ) );
			commentE->setText( tag.comment().toCString( true ) );
			genreE->setText( tag.genre().toCString( true ) );
			yearB->setValue( tag.year() );
			trackB->setValue( tag.track() );
		}
		/* Covers */
		if ( instanceOf( file, MPEG::File ) || instanceOf( file, RIFF::AIFF::File ) )
		{
			pictureB->setEnabled( true );
			if ( hasTags )
			{
				ID3v2::Tag *id3v2 = NULL;
				if ( instanceOf( file, MPEG::File ) )
				{
					MPEG::File &mpegF = ( MPEG::File & )file;
#if TAGLIB19
					if ( mpegF.hasID3v2Tag() )
#endif
						id3v2 = mpegF.ID3v2Tag();
				}
				else if ( instanceOf( file, RIFF::AIFF::File ) )
					id3v2 = ( ( RIFF::AIFF::File & )file ).tag();
				if ( id3v2 )
				{
					const ID3v2::FrameList &frameList = id3v2->frameList( "APIC" );
					if ( !frameList.isEmpty() )
					{
						ID3v2::AttachedPictureFrame &pictureFrame = *( ID3v2::AttachedPictureFrame * )frameList.front();
						pictureMimeType = pictureFrame.mimeType().toCString();
						*picture = pictureFrame.picture();
						pictureB->setChecked( true );
						pictureW->update();
					}
				}
			}
		}
		else if ( instanceOf( file, FLAC::File ) )
		{
			pictureB->setEnabled( true );
			FLAC::File &flacF = ( FLAC::File & )file;
			if ( !flacF.pictureList().isEmpty() )
			{
				FLAC::Picture &flacPicture = *flacF.pictureList().front();
				pictureMimeType = flacPicture.mimeType().toCString();
				*picture = flacPicture.data();
				pictureB->setChecked( true );
				pictureW->update();
				hasTags = true;
			}
		}
		else if ( instanceOf( file, MP4::File ) )
		{
			MP4::ItemListMap &itemListMap = ( ( MP4::File & )file ).tag()->itemListMap();
			MP4::ItemListMap::ConstIterator it = itemListMap.find( "covr" );
			pictureB->setEnabled( true );
			if ( it != itemListMap.end() )
			{
				MP4::CoverArtList coverArtList = it->second.toCoverArtList();
				if ( !coverArtList.isEmpty() )
				{
					MP4::CoverArt coverArt = coverArtList.front();
					switch ( coverArt.format() )
					{
						case MP4::CoverArt::JPEG:
							pictureMimeType = "image/jpeg";
							break;
						case MP4::CoverArt::PNG:
							pictureMimeType = "image/png";
							break;
#if TAGLIB18
						case MP4::CoverArt::BMP:
							pictureMimeType = "image/bmp";
							break;
						case MP4::CoverArt::GIF:
							pictureMimeType = "image/gif";
							break;
#endif
						default:
							break;
					}
					if ( !pictureMimeType.isEmpty() )
					{
						*picture = coverArt.data();
						pictureB->setChecked( true );
						pictureW->update();
						hasTags = true;
					}
				}
			}
		}
		else if ( isOgg( file ) )
		{
			const Ogg::XiphComment *xiphComment = getXiphComment( file );
			if ( xiphComment )
			{
				const Ogg::FieldListMap &fieldListMap = xiphComment->fieldListMap();
				Ogg::FieldListMap::ConstIterator it = fieldListMap.find( "METADATA_BLOCK_PICTURE" );
				pictureB->setEnabled( true );
				if ( it != fieldListMap.end() && !it->second.isEmpty() )
				{
					/* OGG picture and FLAC picture are the same except OGG picture is encoded into Base64 */
					QByteArray pict_frame_decoded = QByteArray::fromBase64( it->second.front().toCString() );
					FLAC::Picture flacPicture;
					if ( flacPicture.parse( ByteVector( pict_frame_decoded.data(), pict_frame_decoded.size() ) ) )
					{
						pictureMimeType = flacPicture.mimeType().toCString();
						*picture = flacPicture.data();
						pictureB->setChecked( true );
						pictureW->update();
					}
				}
			}
		}
		pictureBChecked = pictureB->isChecked();
		setChecked( hasTags );
		return true;
	}
	delete fRef;
	fRef = NULL;
	return false;
}
Пример #6
0
void FLAC::File::scan()
{
  // Scan the metadata pages

  if(d->scanned)
    return;

  if(!isValid())
    return;

  long nextBlockOffset;

  if(d->hasID3v2)
    nextBlockOffset = find("fLaC", d->ID3v2Location + d->ID3v2OriginalSize);
  else
    nextBlockOffset = find("fLaC");

  if(nextBlockOffset < 0) {
    debug("FLAC::File::scan() -- FLAC stream not found");
    setValid(false);
    return;
  }

  nextBlockOffset += 4;
  d->flacStart = nextBlockOffset;

  seek(nextBlockOffset);

  ByteVector header = readBlock(4);

  // Header format (from spec):
  // <1> Last-metadata-block flag
  // <7> BLOCK_TYPE
  //    0 : STREAMINFO
  //    1 : PADDING
  //    ..
  //    4 : VORBIS_COMMENT
  //    ..
  // <24> Length of metadata to follow

  char blockType = header[0] & 0x7f;
  bool isLastBlock = (header[0] & 0x80) != 0;
  uint length = header.mid(1, 3).toUInt();

  // First block should be the stream_info metadata

  if(blockType != MetadataBlock::StreamInfo) {
    debug("FLAC::File::scan() -- invalid FLAC stream");
    setValid(false);
    return;
  }

  d->streamInfoData = readBlock(length);
  d->blocks.append(new UnknownMetadataBlock(blockType, d->streamInfoData));
  nextBlockOffset += length + 4;

  // Search through the remaining metadata
  while(!isLastBlock) {

    header = readBlock(4);
    blockType = header[0] & 0x7f;
    isLastBlock = (header[0] & 0x80) != 0;
    length = header.mid(1, 3).toUInt();

    ByteVector data = readBlock(length);
    if(data.size() != length || length == 0) {
      debug("FLAC::File::scan() -- FLAC stream corrupted");
      setValid(false);
      return;
    }

    MetadataBlock *block = 0;

    // Found the vorbis-comment
    if(blockType == MetadataBlock::VorbisComment) {
      if(!d->hasXiphComment) {
        d->xiphCommentData = data;
        d->hasXiphComment = true;
      }
      else {
        debug("FLAC::File::scan() -- multiple Vorbis Comment blocks found, using the first one");
      }
    }
    else if(blockType == MetadataBlock::Picture) {
      FLAC::Picture *picture = new FLAC::Picture();
      if(picture->parse(data)) {
        block = picture;
      }
      else {
        debug("FLAC::File::scan() -- invalid picture found, discarting");
        delete picture;
      }
    }

    if(!block) {
      block = new UnknownMetadataBlock(blockType, data);
    }
    if(block->code() != MetadataBlock::Padding) {
      d->blocks.append(block);
    }
    else {
      delete block;
    }

    nextBlockOffset += length + 4;

    if(nextBlockOffset >= File::length()) {
      debug("FLAC::File::scan() -- FLAC stream corrupted");
      setValid(false);
      return;
    }
    seek(nextBlockOffset);
  }

  // End of metadata, now comes the datastream

  d->streamStart = nextBlockOffset;
  d->streamLength = File::length() - d->streamStart;

  if(d->hasID3v1)
    d->streamLength -= 128;

  d->scanned = true;
}
Пример #7
0
QMPlay_Tag::QMPlay_Tag( const char *_fileName )
{
	using namespace TagLib;

	fileName = _fileName;
	isNull = true;
	canWriteID3 = false;
	dontUse = false;

	isFLAC = fileName.right( 5 ) == ".flac";
	if ( !isFLAC )
	{
		QByteArray r4 = fileName.right( 4 );
		if ( r4 == ".wav" )
		{
			dontUse = true;
			return;
		}
		if ( r4 == ".mp3" )
			canWriteID3 = true;
	}

	//General tags
	{
		Load_FileRef
		if ( !f->isNull() && f->tag() )
		{
			Tag *tag = f->tag();

			title = tag->title();
			artist = tag->artist();
			album = tag->album();
			comment = tag->comment();
			genre = tag->genre();
			year = tag->year();
			track = tag->track();

			isNull = false;
		}
		delete f;
	}

	//ID3v2 picture
	if ( canWriteID3 )
	{
		Load_MPEG_File
		ID3v2::Tag *id3v2 = f->ID3v2Tag();
		if ( id3v2 && !id3v2->isEmpty() )
		{
			ID3v2::FrameList pict = id3v2->frameList( "APIC" );
			if ( !pict.isEmpty() )
			{
				picture = ID3v2::AttachedPictureFrame( pict.front()->render() ).picture();
				isNull = false;
			}
		}
		delete f;
	}

	//FLAC picture
	if ( isFLAC )
	{
		Load_FLAC_File
		if ( f->pictureList().size() )
		{
			FLAC::Picture *p = f->pictureList().front();
			if ( p )
			{
				picture = p->data();
				isNull = false;
			}
		}
		delete f;
	}
}
Пример #8
0
void QMPlay_Tag::save( bool clearID3 )
{
	if ( dontUse )
		return;

	using namespace TagLib;

	//ID3v2
	{
		Load_MPEG_File
		if ( !canWriteID3 || clearID3 )
			f->save( MPEG::File::NoTags );
		else
		{
			ID3v2::Tag *id3v2 = f->ID3v2Tag();
			if ( id3v2 )
			{
				ID3v2::FrameList pict = id3v2->frameList( "APIC" );
				while ( pict.size() )
					id3v2->removeFrame( pict[ 0 ] );
				if ( !picture.isEmpty() )
				{
					ID3v2::AttachedPictureFrame *pictFrame = new ID3v2::AttachedPictureFrame;
					pictFrame->setPicture( picture );
					QString mimeType = "image/" + QImageReader( QDataStream( QByteArray( picture.data(), picture.size() ) ).device() ).format();
					pictFrame->setMimeType( mimeType.toAscii().data() );
					id3v2->addFrame( pictFrame );
				}
				f->save();
			}
		}
		delete f;
	}

	if ( isFLAC )
	{
		Load_FLAC_File
		if ( f->pictureList().size() )
			f->removePictures();
		if ( !picture.isEmpty() )
		{
			FLAC::Picture *pict = new FLAC::Picture;
			pict->setData( picture );
			QString mimeType = "image/" + QImageReader( QDataStream( QByteArray( picture.data(), picture.size() ) ).device() ).format();
			pict->setMimeType( mimeType.toAscii().data() );
			f->addPicture( pict );
		}
		f->save();
		delete f;
	}

	//General tag
	{
		Load_FileRef
		if ( !f->isNull() && f->tag() )
		{
			Tag *tag = f->tag();

			tag->setTitle( title );
			tag->setArtist( artist );
			tag->setAlbum( album );
			tag->setComment( comment );
			tag->setGenre( genre );
			tag->setYear( year );
			tag->setTrack( track );

			f->save();
		}
		delete f;
	}
}
Пример #9
0
  void testReplacePicture()
  {
    ScopedFileCopy copy("silence-44-s", ".flac");
    string newname = copy.fileName();

    {
      FLAC::File f(newname.c_str());
      List<FLAC::Picture *> lst = f.pictureList();
      CPPUNIT_ASSERT_EQUAL((unsigned int)1, lst.size());

      FLAC::Picture *newpic = new FLAC::Picture();
      newpic->setType(FLAC::Picture::BackCover);
      newpic->setWidth(5);
      newpic->setHeight(6);
      newpic->setColorDepth(16);
      newpic->setNumColors(7);
      newpic->setMimeType("image/jpeg");
      newpic->setDescription("new image");
      newpic->setData("JPEG data");
      f.removePictures();
      f.addPicture(newpic);
      f.save();
    }
    {
      FLAC::File f(newname.c_str());
      List<FLAC::Picture *> lst = f.pictureList();
      CPPUNIT_ASSERT_EQUAL((unsigned int)1, lst.size());

      FLAC::Picture *pic = lst[0];
      CPPUNIT_ASSERT_EQUAL(FLAC::Picture::BackCover, pic->type());
      CPPUNIT_ASSERT_EQUAL(5, pic->width());
      CPPUNIT_ASSERT_EQUAL(6, pic->height());
      CPPUNIT_ASSERT_EQUAL(16, pic->colorDepth());
      CPPUNIT_ASSERT_EQUAL(7, pic->numColors());
      CPPUNIT_ASSERT_EQUAL(String("image/jpeg"), pic->mimeType());
      CPPUNIT_ASSERT_EQUAL(String("new image"), pic->description());
      CPPUNIT_ASSERT_EQUAL(ByteVector("JPEG data"), pic->data());
    }
  }