Changeset View
Changeset View
Standalone View
Standalone View
src/embeddedimagedata.cpp
Show All 38 Lines | |||||
39 | #include <wavpackfile.h> | 39 | #include <wavpackfile.h> | ||
40 | #include <speexfile.h> | 40 | #include <speexfile.h> | ||
41 | #include <wavfile.h> | 41 | #include <wavfile.h> | ||
42 | #include <aifffile.h> | 42 | #include <aifffile.h> | ||
43 | #include <asffile.h> | 43 | #include <asffile.h> | ||
44 | #include <asfattribute.h> | 44 | #include <asfattribute.h> | ||
45 | #include <asfpicture.h> | 45 | #include <asfpicture.h> | ||
46 | 46 | | |||
47 | #include <QByteArray> | ||||
47 | #include <QMimeDatabase> | 48 | #include <QMimeDatabase> | ||
48 | 49 | | |||
49 | using namespace KFileMetaData; | 50 | using namespace KFileMetaData; | ||
50 | 51 | | |||
51 | class Q_DECL_HIDDEN EmbeddedImageData::Private | 52 | class Q_DECL_HIDDEN EmbeddedImageData::Private | ||
52 | { | 53 | { | ||
53 | public: | 54 | public: | ||
54 | QMimeDatabase mMimeDatabase; | 55 | QMimeDatabase mMimeDatabase; | ||
55 | QByteArray getFrontCover(const QString &fileUrl, const QString &mimeType) const; | 56 | QByteArray getFrontCover(const QString &fileUrl, const QString &mimeType) const; | ||
56 | QByteArray getFrontCoverFromID3(TagLib::ID3v2::Tag* Id3Tags) const; | 57 | QByteArray getFrontCoverFromID3(TagLib::ID3v2::Tag* Id3Tags) const; | ||
57 | QByteArray getFrontCoverFromFlacPicture(TagLib::List<TagLib::FLAC::Picture *> lstPic) const; | 58 | QByteArray getFrontCoverFromFlacPicture(TagLib::List<TagLib::FLAC::Picture *> lstPic) const; | ||
58 | QByteArray getFrontCoverFromMp4(TagLib::MP4::Tag* mp4Tags) const; | 59 | QByteArray getFrontCoverFromMp4(TagLib::MP4::Tag* mp4Tags) const; | ||
59 | QByteArray getFrontCoverFromApe(TagLib::APE::Tag* apeTags) const; | 60 | QByteArray getFrontCoverFromApe(TagLib::APE::Tag* apeTags) const; | ||
60 | QByteArray getFrontCoverFromAsf(TagLib::ASF::Tag* asfTags) const; | 61 | QByteArray getFrontCoverFromAsf(TagLib::ASF::Tag* asfTags) const; | ||
62 | void writeFrontCover(const QString &fileUrl, const QString &mimeType, const QByteArray &pictureData); | ||||
63 | void writeFrontCoverToID3(TagLib::ID3v2::Tag* Id3Tags, const QByteArray &pictureData); | ||||
64 | void writeFrontCoverToFlacPicture(TagLib::List<TagLib::FLAC::Picture *> lstPic, const QByteArray &pictureData); | ||||
65 | void writeFrontCoverToMp4(TagLib::MP4::Tag* mp4Tags, const QByteArray &pictureData); | ||||
66 | void writeFrontCoverToApe(TagLib::APE::Tag* apeTags, const QByteArray &pictureData); | ||||
67 | void writeFrontCoverToAsf(TagLib::ASF::Tag* asfTags, const QByteArray &pictureData); | ||||
68 | TagLib::String determineMimeType(const QByteArray &pictureData); | ||||
61 | static const QStringList mMimetypes; | 69 | static const QStringList mMimetypes; | ||
62 | }; | 70 | }; | ||
63 | 71 | | |||
64 | const QStringList EmbeddedImageData::Private::mMimetypes = | 72 | const QStringList EmbeddedImageData::Private::mMimetypes = | ||
65 | { | 73 | { | ||
66 | QStringLiteral("audio/flac"), | 74 | QStringLiteral("audio/flac"), | ||
67 | QStringLiteral("audio/mp4"), | 75 | QStringLiteral("audio/mp4"), | ||
68 | QStringLiteral("audio/mpeg"), | 76 | QStringLiteral("audio/mpeg"), | ||
Show All 28 Lines | |||||
97 | } | 105 | } | ||
98 | 106 | | |||
99 | QMap<EmbeddedImageData::ImageType, QByteArray> | 107 | QMap<EmbeddedImageData::ImageType, QByteArray> | ||
100 | EmbeddedImageData::imageData(const QString &fileUrl, | 108 | EmbeddedImageData::imageData(const QString &fileUrl, | ||
101 | const EmbeddedImageData::ImageTypes types) const | 109 | const EmbeddedImageData::ImageTypes types) const | ||
102 | { | 110 | { | ||
103 | QMap<EmbeddedImageData::ImageType, QByteArray> imageData; | 111 | QMap<EmbeddedImageData::ImageType, QByteArray> imageData; | ||
104 | 112 | | |||
105 | const auto &fileMimeType = d->mMimeDatabase.mimeTypeForFile(fileUrl); | 113 | const auto fileMimeType = d->mMimeDatabase.mimeTypeForFile(fileUrl); | ||
106 | if (fileMimeType.name().startsWith(QLatin1String("audio/"))) { | 114 | if (fileMimeType.name().startsWith(QLatin1String("audio/"))) { | ||
107 | if (types & EmbeddedImageData::FrontCover) { | 115 | if (types & EmbeddedImageData::FrontCover) { | ||
108 | imageData.insert(EmbeddedImageData::FrontCover, d->getFrontCover(fileUrl, fileMimeType.name())); | 116 | imageData.insert(EmbeddedImageData::FrontCover, d->getFrontCover(fileUrl, fileMimeType.name())); | ||
109 | } | 117 | } | ||
110 | } | 118 | } | ||
111 | 119 | | |||
112 | return imageData; | 120 | return imageData; | ||
113 | } | 121 | } | ||
114 | 122 | | |||
123 | void | ||||
124 | EmbeddedImageData::writeImageData(const QString &fileUrl, | ||||
125 | QMap<EmbeddedImageData::ImageType, QByteArray> &imageData) | ||||
126 | { | ||||
127 | const auto fileMimeType = d->mMimeDatabase.mimeTypeForFile(fileUrl); | ||||
128 | QMap<EmbeddedImageData::ImageType, QByteArray>::iterator frontCover = imageData.find(EmbeddedImageData::FrontCover); | ||||
129 | if (fileMimeType.name().startsWith(QLatin1String("audio/"))) { | ||||
130 | if (frontCover != imageData.end()) { | ||||
131 | d->writeFrontCover(fileUrl, fileMimeType.name(), frontCover.value()); | ||||
132 | } | ||||
133 | } | ||||
134 | } | ||||
135 | | ||||
115 | QByteArray | 136 | QByteArray | ||
116 | EmbeddedImageData::Private::getFrontCover(const QString &fileUrl, | 137 | EmbeddedImageData::Private::getFrontCover(const QString &fileUrl, | ||
117 | const QString &mimeType) const | 138 | const QString &mimeType) const | ||
118 | { | 139 | { | ||
119 | TagLib::FileStream stream(fileUrl.toUtf8().constData(), true); | 140 | TagLib::FileStream stream(fileUrl.toUtf8().constData(), true); | ||
120 | if (!stream.isOpen()) { | 141 | if (!stream.isOpen()) { | ||
121 | qCWarning(KFILEMETADATA_LOG) << "Unable to open file readonly: " << fileUrl; | 142 | qCWarning(KFILEMETADATA_LOG) << "Unable to open file readonly: " << fileUrl; | ||
122 | return QByteArray(); | 143 | return QByteArray(); | ||
▲ Show 20 Lines • Show All 87 Lines • ▼ Show 20 Line(s) | 228 | } else if (mimeType == QLatin1String("audio/speex") || mimeType == QLatin1String("audio/x-speex")) { | |||
210 | if (speexFile.tag()) { | 231 | if (speexFile.tag()) { | ||
211 | return getFrontCoverFromFlacPicture(speexFile.tag()->pictureList()); | 232 | return getFrontCoverFromFlacPicture(speexFile.tag()->pictureList()); | ||
212 | } | 233 | } | ||
213 | 234 | | |||
214 | } | 235 | } | ||
215 | return QByteArray(); | 236 | return QByteArray(); | ||
216 | } | 237 | } | ||
217 | 238 | | |||
239 | void | ||||
240 | EmbeddedImageData::Private::writeFrontCover(const QString &fileUrl, | ||||
241 | const QString &mimeType, const QByteArray &pictureData) | ||||
242 | { | ||||
243 | TagLib::FileStream stream(fileUrl.toUtf8().constData(), false); | ||||
244 | if (!stream.isOpen()) { | ||||
245 | qWarning() << "Unable to open file: " << fileUrl; | ||||
246 | return; | ||||
247 | } | ||||
248 | | ||||
249 | if ((mimeType == QLatin1String("audio/mpeg")) | ||||
250 | || (mimeType == QLatin1String("audio/mpeg3")) | ||||
251 | || (mimeType == QLatin1String("audio/x-mpeg"))) { | ||||
252 | | ||||
253 | // Handling multiple tags in mpeg files. | ||||
254 | TagLib::MPEG::File mpegFile(&stream, TagLib::ID3v2::FrameFactory::instance(), false); | ||||
255 | if (mpegFile.ID3v2Tag()) { | ||||
256 | writeFrontCoverToID3(mpegFile.ID3v2Tag(), pictureData); | ||||
257 | } | ||||
258 | mpegFile.save(); | ||||
259 | } else if (mimeType == QLatin1String("audio/x-aiff")) { | ||||
260 | | ||||
261 | TagLib::RIFF::AIFF::File aiffFile(&stream, false); | ||||
262 | if (aiffFile.hasID3v2Tag()) { | ||||
263 | writeFrontCoverToID3(aiffFile.tag(), pictureData); | ||||
264 | } | ||||
265 | aiffFile.save(); | ||||
266 | } else if ((mimeType == QLatin1String("audio/wav")) | ||||
267 | || (mimeType == QLatin1String("audio/x-wav"))) { | ||||
268 | | ||||
269 | TagLib::RIFF::WAV::File wavFile(&stream, false); | ||||
270 | if (wavFile.hasID3v2Tag()) { | ||||
271 | writeFrontCoverToID3(wavFile.ID3v2Tag(), pictureData); | ||||
272 | } | ||||
273 | wavFile.save(); | ||||
274 | } else if (mimeType == QLatin1String("audio/mp4")) { | ||||
275 | | ||||
276 | TagLib::MP4::File mp4File(&stream, false); | ||||
277 | if (mp4File.tag()) { | ||||
278 | writeFrontCoverToMp4(mp4File.tag(), pictureData); | ||||
279 | } | ||||
280 | mp4File.save(); | ||||
281 | } else if (mimeType == QLatin1String("audio/x-musepack")) { | ||||
282 | | ||||
283 | TagLib::MPC::File mpcFile(&stream, false); | ||||
284 | if (mpcFile.APETag()) { | ||||
285 | writeFrontCoverToApe(mpcFile.APETag(), pictureData); | ||||
286 | } | ||||
287 | mpcFile.save(); | ||||
288 | } else if (mimeType == QLatin1String("audio/x-ape")) { | ||||
289 | | ||||
290 | TagLib::APE::File apeFile(&stream, false); | ||||
291 | if (apeFile.hasAPETag()) { | ||||
292 | writeFrontCoverToApe(apeFile.APETag(), pictureData); | ||||
293 | } | ||||
294 | apeFile.save(); | ||||
295 | } else if (mimeType == QLatin1String("audio/x-wavpack")) { | ||||
296 | | ||||
297 | TagLib::WavPack::File wavpackFile(&stream, false); | ||||
298 | if (wavpackFile.hasAPETag()) { | ||||
299 | writeFrontCoverToApe(wavpackFile.APETag(), pictureData); | ||||
300 | } | ||||
301 | wavpackFile.save(); | ||||
302 | } else if (mimeType == QLatin1String("audio/x-ms-wma")) { | ||||
303 | | ||||
304 | TagLib::ASF::File asfFile(&stream, false); | ||||
305 | TagLib::ASF::Tag* asfTags = dynamic_cast<TagLib::ASF::Tag*>(asfFile.tag()); | ||||
306 | if (asfTags) { | ||||
307 | writeFrontCoverToAsf(asfTags, pictureData); | ||||
308 | } | ||||
309 | asfFile.save(); | ||||
310 | } else if (mimeType == QLatin1String("audio/flac")) { | ||||
311 | | ||||
312 | TagLib::FLAC::File flacFile(&stream, TagLib::ID3v2::FrameFactory::instance(), false); | ||||
313 | writeFrontCoverToFlacPicture(flacFile.pictureList(), pictureData); | ||||
314 | flacFile.save(); | ||||
315 | } else if ((mimeType == QLatin1String("audio/ogg")) | ||||
316 | || (mimeType == QLatin1String("audio/x-vorbis+ogg"))) { | ||||
317 | | ||||
318 | TagLib::Ogg::Vorbis::File oggFile(&stream, false); | ||||
319 | if (oggFile.tag()) { | ||||
320 | writeFrontCoverToFlacPicture(oggFile.tag()->pictureList(), pictureData); | ||||
321 | } | ||||
322 | oggFile.save(); | ||||
323 | } | ||||
324 | else if ((mimeType == QLatin1String("audio/opus")) | ||||
325 | || (mimeType == QLatin1String("audio/x-opus+ogg"))) { | ||||
326 | | ||||
327 | TagLib::Ogg::Opus::File opusFile(&stream, false); | ||||
328 | if (opusFile.tag()) { | ||||
329 | writeFrontCoverToFlacPicture(opusFile.tag()->pictureList(), pictureData); | ||||
330 | } | ||||
331 | opusFile.save(); | ||||
332 | } else if (mimeType == QLatin1String("audio/speex") || mimeType == QLatin1String("audio/x-speex")) { | ||||
333 | | ||||
334 | TagLib::Ogg::Speex::File speexFile(&stream, false); | ||||
335 | if (speexFile.tag()) { | ||||
336 | writeFrontCoverToFlacPicture(speexFile.tag()->pictureList(), pictureData); | ||||
337 | } | ||||
338 | speexFile.save(); | ||||
339 | } | ||||
340 | } | ||||
341 | | ||||
218 | QByteArray | 342 | QByteArray | ||
219 | EmbeddedImageData::Private::getFrontCoverFromID3(TagLib::ID3v2::Tag* Id3Tags) const | 343 | EmbeddedImageData::Private::getFrontCoverFromID3(TagLib::ID3v2::Tag* Id3Tags) const | ||
220 | { | 344 | { | ||
221 | TagLib::ID3v2::FrameList lstID3v2; | 345 | TagLib::ID3v2::FrameList lstID3v2; | ||
222 | // Attached Front Picture. | 346 | // Attached Front Picture. | ||
223 | lstID3v2 = Id3Tags->frameListMap()["APIC"]; | 347 | lstID3v2 = Id3Tags->frameListMap()["APIC"]; | ||
224 | for (const auto& frame : qAsConst(lstID3v2)) | 348 | for (const auto& frame : qAsConst(lstID3v2)) | ||
225 | { | 349 | { | ||
226 | const auto *frontCoverFrame = static_cast<TagLib::ID3v2::AttachedPictureFrame *>(frame); | 350 | const auto *frontCoverFrame = static_cast<TagLib::ID3v2::AttachedPictureFrame *>(frame); | ||
227 | if (frontCoverFrame->type() == frontCoverFrame->FrontCover) { | 351 | if (frontCoverFrame->type() == frontCoverFrame->FrontCover) { | ||
228 | return QByteArray(frontCoverFrame->picture().data(), frontCoverFrame->picture().size()); | 352 | return QByteArray(frontCoverFrame->picture().data(), frontCoverFrame->picture().size()); | ||
229 | } | 353 | } | ||
230 | } | 354 | } | ||
231 | return QByteArray(); | 355 | return QByteArray(); | ||
232 | } | 356 | } | ||
233 | 357 | | |||
358 | void | ||||
359 | EmbeddedImageData::Private::writeFrontCoverToID3(TagLib::ID3v2::Tag* Id3Tags, const QByteArray &pictureData) | ||||
360 | { | ||||
361 | // Try to update existing front cover frame first | ||||
362 | TagLib::ID3v2::FrameList lstID3v2; | ||||
363 | lstID3v2 = Id3Tags->frameListMap()["APIC"]; | ||||
364 | for (auto& frame : qAsConst(lstID3v2)) | ||||
365 | { | ||||
366 | auto *frontCoverFrame = static_cast<TagLib::ID3v2::AttachedPictureFrame *>(frame); | ||||
367 | if (frontCoverFrame->type() == frontCoverFrame->FrontCover) { | ||||
368 | frontCoverFrame->setPicture(TagLib::ByteVector(static_cast<const char *>(pictureData.data()), pictureData.size())); | ||||
369 | frontCoverFrame->setMimeType(determineMimeType(pictureData)); | ||||
370 | return; | ||||
371 | } | ||||
372 | } | ||||
373 | auto pictureFrame = new TagLib::ID3v2::AttachedPictureFrame; | ||||
374 | pictureFrame->setPicture(TagLib::ByteVector(pictureData.data(), pictureData.size())); | ||||
375 | pictureFrame->setType(pictureFrame->FrontCover); | ||||
376 | pictureFrame->setMimeType(determineMimeType(pictureData)); | ||||
377 | Id3Tags->addFrame(pictureFrame); | ||||
378 | } | ||||
379 | | ||||
234 | QByteArray | 380 | QByteArray | ||
235 | EmbeddedImageData::Private::getFrontCoverFromFlacPicture(TagLib::List<TagLib::FLAC::Picture *> lstPic) const | 381 | EmbeddedImageData::Private::getFrontCoverFromFlacPicture(TagLib::List<TagLib::FLAC::Picture *> lstPic) const | ||
236 | { | 382 | { | ||
237 | for (const auto &picture : qAsConst(lstPic)) { | 383 | for (const auto &picture : qAsConst(lstPic)) { | ||
238 | if (picture->type() == picture->FrontCover) { | 384 | if (picture->type() == picture->FrontCover) { | ||
239 | return QByteArray(picture->data().data(), picture->data().size()); | 385 | return QByteArray(picture->data().data(), picture->data().size()); | ||
240 | } | 386 | } | ||
241 | } | 387 | } | ||
242 | return QByteArray(); | 388 | return QByteArray(); | ||
243 | } | 389 | } | ||
244 | 390 | | |||
391 | void | ||||
392 | EmbeddedImageData::Private::writeFrontCoverToFlacPicture(TagLib::List<TagLib::FLAC::Picture *> lstPic, const QByteArray &pictureData) | ||||
393 | { | ||||
394 | for (const auto &picture : qAsConst(lstPic)) { | ||||
395 | if (picture->type() == picture->FrontCover) { | ||||
396 | picture->setData(TagLib::ByteVector(pictureData.data(), pictureData.size())); | ||||
397 | picture->setMimeType(determineMimeType(pictureData)); | ||||
398 | return ; | ||||
399 | } | ||||
400 | } | ||||
401 | auto flacPicture = new TagLib::FLAC::Picture; | ||||
402 | flacPicture->setMimeType(determineMimeType(pictureData)); | ||||
403 | flacPicture->setData(TagLib::ByteVector(pictureData.data(), pictureData.size())); | ||||
404 | lstPic.append(flacPicture); | ||||
405 | } | ||||
406 | | ||||
245 | QByteArray | 407 | QByteArray | ||
246 | EmbeddedImageData::Private::getFrontCoverFromMp4(TagLib::MP4::Tag* mp4Tags) const | 408 | EmbeddedImageData::Private::getFrontCoverFromMp4(TagLib::MP4::Tag* mp4Tags) const | ||
247 | { | 409 | { | ||
248 | TagLib::MP4::Item coverArtItem = mp4Tags->item("covr"); | 410 | TagLib::MP4::Item coverArtItem = mp4Tags->item("covr"); | ||
249 | if (coverArtItem.isValid()) | 411 | if (coverArtItem.isValid()) | ||
250 | { | 412 | { | ||
251 | TagLib::MP4::CoverArtList coverArtList = coverArtItem.toCoverArtList(); | 413 | TagLib::MP4::CoverArtList coverArtList = coverArtItem.toCoverArtList(); | ||
252 | TagLib::MP4::CoverArt& frontCover = coverArtList.front(); | 414 | TagLib::MP4::CoverArt& frontCover = coverArtList.front(); | ||
253 | return QByteArray(frontCover.data().data(), frontCover.data().size()); | 415 | return QByteArray(frontCover.data().data(), frontCover.data().size()); | ||
254 | } | 416 | } | ||
255 | return QByteArray(); | 417 | return QByteArray(); | ||
256 | } | 418 | } | ||
257 | 419 | | |||
420 | void | ||||
421 | EmbeddedImageData::Private::writeFrontCoverToMp4(TagLib::MP4::Tag* mp4Tags, const QByteArray &pictureData) | ||||
422 | { | ||||
423 | TagLib::MP4::Item coverArtItem = mp4Tags->item("covr"); | ||||
424 | TagLib::MP4::CoverArtList coverArtList; | ||||
425 | TagLib::MP4::CoverArt coverArt(TagLib::MP4::CoverArt::Format::Unknown, TagLib::ByteVector(pictureData.data(), pictureData.size())); | ||||
426 | if (coverArtItem.isValid()) | ||||
427 | { | ||||
428 | coverArtList = coverArtItem.toCoverArtList(); | ||||
429 | coverArtList.clear(); | ||||
430 | } | ||||
431 | coverArtList.append(coverArt); | ||||
432 | mp4Tags->setItem("covr", coverArtList); | ||||
433 | } | ||||
434 | | ||||
258 | QByteArray | 435 | QByteArray | ||
259 | EmbeddedImageData::Private::getFrontCoverFromApe(TagLib::APE::Tag* apeTags) const | 436 | EmbeddedImageData::Private::getFrontCoverFromApe(TagLib::APE::Tag* apeTags) const | ||
260 | { | 437 | { | ||
261 | TagLib::APE::ItemListMap lstApe = apeTags->itemListMap(); | 438 | TagLib::APE::ItemListMap lstApe = apeTags->itemListMap(); | ||
262 | TagLib::APE::ItemListMap::ConstIterator itApe; | 439 | TagLib::APE::ItemListMap::ConstIterator itApe; | ||
263 | 440 | | |||
264 | /* The cover art tag for APEv2 tags starts with the filename as string | 441 | /* The cover art tag for APEv2 tags starts with the filename as string | ||
265 | * with zero termination followed by the actual picture data */ | 442 | * with zero termination followed by the actual picture data */ | ||
266 | itApe = lstApe.find("COVER ART (FRONT)"); | 443 | itApe = lstApe.find("COVER ART (FRONT)"); | ||
267 | if (itApe != lstApe.end()) { | 444 | if (itApe != lstApe.end()) { | ||
268 | TagLib::ByteVector pictureData = (*itApe).second.binaryData(); | 445 | TagLib::ByteVector pictureData = (*itApe).second.binaryData(); | ||
269 | int position = pictureData.find('\0'); | 446 | int position = pictureData.find('\0'); | ||
270 | if (position >= 0) { | 447 | if (position >= 0) { | ||
271 | position += 1; | 448 | position += 1; | ||
272 | return QByteArray(pictureData.data() + position, pictureData.size() - position); | 449 | return QByteArray(pictureData.data() + position, pictureData.size() - position); | ||
273 | } | 450 | } | ||
274 | } | 451 | } | ||
275 | return QByteArray(); | 452 | return QByteArray(); | ||
276 | } | 453 | } | ||
454 | | ||||
455 | void | ||||
456 | EmbeddedImageData::Private::writeFrontCoverToApe(TagLib::APE::Tag* apeTags, const QByteArray &pictureData) | ||||
457 | { | ||||
458 | /* The cover art tag for APEv2 tags starts with the filename as string | ||||
459 | * with zero termination followed by the actual picture data */ | ||||
460 | TagLib::ByteVector imageData; | ||||
461 | TagLib::String name; | ||||
462 | if (determineMimeType(pictureData) == TagLib::String("image/png")) { | ||||
463 | name = "frontCover.png"; | ||||
464 | } else { | ||||
465 | name = "frontCover.jpeg"; | ||||
466 | } | ||||
467 | imageData.append(name.data(TagLib::String::UTF8)); | ||||
468 | imageData.append('\0'); | ||||
469 | imageData.append(TagLib::ByteVector(pictureData.constData(), pictureData.size())); | ||||
470 | apeTags->setData("COVER ART (FRONT)", imageData); | ||||
471 | } | ||||
472 | | ||||
277 | QByteArray | 473 | QByteArray | ||
278 | EmbeddedImageData::Private::getFrontCoverFromAsf(TagLib::ASF::Tag* asfTags) const | 474 | EmbeddedImageData::Private::getFrontCoverFromAsf(TagLib::ASF::Tag* asfTags) const | ||
279 | { | 475 | { | ||
280 | TagLib::ASF::AttributeList lstASF = asfTags->attribute("WM/Picture"); | 476 | TagLib::ASF::AttributeList lstASF = asfTags->attribute("WM/Picture"); | ||
281 | for (const auto& attribute : qAsConst(lstASF)) { | 477 | for (const auto& attribute : qAsConst(lstASF)) { | ||
282 | TagLib::ASF::Picture picture = attribute.toPicture(); | 478 | TagLib::ASF::Picture picture = attribute.toPicture(); | ||
283 | if (picture.type() == TagLib::ASF::Picture::FrontCover) { | 479 | if (picture.type() == TagLib::ASF::Picture::FrontCover) { | ||
284 | TagLib::ByteVector pictureData = picture.picture(); | 480 | TagLib::ByteVector pictureData = picture.picture(); | ||
285 | return QByteArray(pictureData.data(), pictureData.size()); | 481 | return QByteArray(pictureData.data(), pictureData.size()); | ||
286 | } | 482 | } | ||
287 | } | 483 | } | ||
288 | return QByteArray(); | 484 | return QByteArray(); | ||
289 | } | 485 | } | ||
486 | | ||||
487 | void | ||||
488 | EmbeddedImageData::Private::writeFrontCoverToAsf(TagLib::ASF::Tag* asfTags, const QByteArray &pictureData) | ||||
489 | { | ||||
490 | TagLib::ASF::AttributeList lstASF = asfTags->attribute("WM/Picture"); | ||||
491 | for (const auto& attribute : qAsConst(lstASF)) { | ||||
492 | TagLib::ASF::Picture picture = attribute.toPicture(); | ||||
493 | if (picture.type() == TagLib::ASF::Picture::FrontCover) { | ||||
494 | picture.setPicture(TagLib::ByteVector(pictureData.constData(), pictureData.size())); | ||||
495 | picture.setMimeType(determineMimeType(pictureData)); | ||||
496 | TagLib::ByteVector pictureData = picture.picture(); | ||||
497 | return; | ||||
498 | } | ||||
499 | } | ||||
500 | TagLib::ASF::Picture picture; | ||||
501 | picture.setPicture(TagLib::ByteVector(pictureData.constData(), pictureData.size())); | ||||
502 | picture.setType(TagLib::ASF::Picture::FrontCover); | ||||
503 | lstASF.append(picture); | ||||
504 | } | ||||
505 | | ||||
506 | | ||||
507 | TagLib::String EmbeddedImageData::Private::determineMimeType(const QByteArray &pictureData) | ||||
508 | { | ||||
509 | if (pictureData.startsWith(QByteArray::fromHex("89504E470D0A1A0A"))) { | ||||
510 | return TagLib::String("image/png"); | ||||
511 | } else if (pictureData.startsWith(QByteArray::fromHex("FFD8FFDB")) || | ||||
512 | pictureData.startsWith(QByteArray::fromHex("FFD8FFE000104A4649460001")) || | ||||
513 | pictureData.startsWith(QByteArray::fromHex("FFD8FFEE")) || | ||||
514 | pictureData.startsWith(QByteArray::fromHex("FFD8FFE1"))) { | ||||
515 | return TagLib::String("image/jpeg"); | ||||
516 | } else { | ||||
517 | return TagLib::String(); | ||||
518 | } | ||||
519 | } | ||||
520 | |