Commit 2638194b authored by Michael Pyne's avatar Michael Pyne
Browse files

Add support for loading more types of covers to JuK trunk. Fixes bug 103118. ...

Add support for loading more types of covers to JuK trunk.  Fixes bug 103118.  Now JuK will pull covers
from files named cover.jpg or cover.png in the same directory as the music file, or from embedded cover art
if present in .mp3 files.

BUG:103118

svn path=/trunk/KDE/kdemultimedia/juk/; revision=807472
parent 1b37be4b
/***************************************************************************
copyright : (C) 2004 Nathan Toone
: (C) 2005 Michael Pyne <michael.pyne@kdemail.net>
: (C) 2005, 2008 Michael Pyne <michael.pyne@kdemail.net>
email : nathan@toonetown.com
***************************************************************************/
......@@ -29,13 +29,21 @@
#include <QHBoxLayout>
#include <QEvent>
#include <QFile>
#include <QFileInfo>
#include <QDesktopWidget>
#include <taglib/mpegfile.h>
#include <taglib/tstring.h>
#include <taglib/id3v2tag.h>
#include <taglib/attachedpictureframe.h>
#include "collectionlist.h"
#include "playlistsearch.h"
#include "playlistitem.h"
#include "tag.h"
using namespace TagLib;
struct CoverPopup : public QWidget
{
CoverPopup(const QPixmap &image, const QPoint &p) :
......@@ -64,6 +72,7 @@ struct CoverPopup : public QWidget
CoverInfo::CoverInfo(const FileHandle &file) :
m_file(file),
m_hasCover(false),
m_hasAttachedCover(false),
m_haveCheckedForCover(false),
m_coverKey(CoverManager::NoMatch),
m_needsConverting(false)
......@@ -74,7 +83,7 @@ CoverInfo::CoverInfo(const FileHandle &file) :
bool CoverInfo::hasCover()
{
if(m_haveCheckedForCover)
return m_hasCover;
return m_hasCover || m_hasAttachedCover;
m_haveCheckedForCover = true;
......@@ -98,15 +107,39 @@ bool CoverInfo::hasCover()
m_needsConverting = true;
}
// Check if it's embedded in the file itself.
QByteArray filePath = QFile::encodeName(m_file.absFilePath());
MPEG::File mpegFile(filePath.constData(), true, AudioProperties::Accurate);
ID3v2::Tag *id3tag = mpegFile.ID3v2Tag(false);
if(!id3tag)
return m_hasCover;
// Look for attached picture frames.
ID3v2::FrameList frames = id3tag->frameListMap()["APIC"];
m_hasAttachedCover = !frames.isEmpty();
if(m_hasAttachedCover)
return true;
// Look for cover.jpg or cover.png in the directory.
if(QFile::exists(m_file.fileInfo().absolutePath() + "/cover.jpg") ||
QFile::exists(m_file.fileInfo().absolutePath() + "/cover.png"))
{
m_hasCover = true;
}
return m_hasCover;
}
void CoverInfo::clearCover()
{
m_hasCover = false;
m_hasAttachedCover = false;
// Yes, we have checked, and we don't have it. ;)
m_haveCheckedForCover = true;
// Re-search for cover since we may still have a different type of cover.
m_haveCheckedForCover = false;
m_needsConverting = false;
......@@ -186,13 +219,86 @@ QPixmap CoverInfo::pixmap(CoverSize size) const
if(m_needsConverting)
convertOldStyleCover();
if(m_coverKey == CoverManager::NoMatch)
if(m_hasCover && m_coverKey != CoverManager::NoMatch) {
return CoverManager::coverFromId(m_coverKey,
size == Thumbnail
? CoverManager::Thumbnail
: CoverManager::FullSize);
}
// If m_hasCover is still true we must have a directory cover image.
if(m_hasCover) {
QString fileName = m_file.fileInfo().absolutePath() + "/cover.jpg";
QImage cover;
if(!cover.load(fileName)) {
fileName = m_file.fileInfo().absolutePath() + "/cover.png";
if(!cover.load(fileName))
return QPixmap();
}
if(size == Thumbnail)
cover = scaleCoverToThumbnail(cover);
return QPixmap::fromImage(cover);
}
// If we get here, see if there is an embedded cover.
QByteArray filePath = QFile::encodeName(m_file.absFilePath());
MPEG::File mpegFile(filePath.constData(), true, AudioProperties::Accurate);
ID3v2::Tag *id3tag = mpegFile.ID3v2Tag(false);
if(!id3tag)
return QPixmap();
// Look for attached picture frames.
ID3v2::FrameList frames = id3tag->frameListMap()["APIC"];
if(frames.isEmpty())
return QPixmap();
// According to the spec attached picture frames have different types.
// So we should look for the corresponding picture depending on what
// type of image (i.e. front cover, file info) we want. If only 1
// frame, just return that (scaled if necessary).
ID3v2::AttachedPictureFrame *selectedFrame = 0;
if(frames.size() != 1) {
ID3v2::FrameList::Iterator it = frames.begin();
for(; it != frames.end(); ++it) {
ID3v2::AttachedPictureFrame *frame =
static_cast<ID3v2::AttachedPictureFrame *>(*it);
// Both thumbnail and full size should use FrontCover, as
// FileIcon may be too small even for thumbnail.
if(frame->type() != ID3v2::AttachedPictureFrame::FrontCover)
continue;
selectedFrame = frame;
break;
}
}
// If we get here we failed to pick a picture, or there was only one,
// so just use the first picture.
if(!selectedFrame)
selectedFrame = static_cast<ID3v2::AttachedPictureFrame *>(frames.front());
QByteArray pictureData = QByteArray(selectedFrame->picture().data(),
selectedFrame->picture().size());
QImage attachedImage = QImage::fromData(pictureData);
kDebug() << "Embedded cover art of size" << attachedImage.size();
if(size == Thumbnail)
return CoverManager::coverFromId(m_coverKey, CoverManager::Thumbnail);
else
return CoverManager::coverFromId(m_coverKey, CoverManager::FullSize);
attachedImage = scaleCoverToThumbnail(attachedImage);
QPixmap returnValue = QPixmap::fromImage(attachedImage);
return QPixmap::fromImage(attachedImage);
}
void CoverInfo::popup() const
......@@ -225,6 +331,11 @@ void CoverInfo::popup() const
new CoverPopup(image, QPoint(x, y));
}
QImage CoverInfo::scaleCoverToThumbnail(const QImage &image) const
{
return image.scaled(80, 80, Qt::KeepAspectRatio, Qt::SmoothTransformation);
}
/**
* DEPRECATED
*/
......
/***************************************************************************
copyright : (C) 2004 Nathan Toone
email : nathan@toonetown.com
copyright : (C) 2008 Michael Pyne
email : michael.pyne@kdemail.net
***************************************************************************/
/***************************************************************************
......@@ -15,13 +18,12 @@
#ifndef COVERINFO_H
#define COVERINFO_H
#include <qimage.h>
//Added by qt3to4:
#include <QPixmap>
#include "filehandle.h"
#include "covermanager.h"
class QImage;
class QPixmap;
class CoverInfo
{
friend class FileHandle;
......@@ -58,9 +60,11 @@ public:
private:
QString coverLocation(CoverSize size) const;
bool convertOldStyleCover() const;
QImage scaleCoverToThumbnail(const QImage &image) const;
FileHandle m_file;
bool m_hasCover;
bool m_hasAttachedCover;
bool m_haveCheckedForCover;
mutable coverKey m_coverKey;
mutable bool m_needsConverting;
......
......@@ -2161,8 +2161,12 @@ void Playlist::slotShowRMBMenu(Q3ListViewItem *item, const QPoint &point, int co
m_rmbEdit->setEnabled(file.fileInfo().isWritable() || selectedItems().count() > 1);
// View cover is based on if there is a cover to see. We should only have
// the remove cover option if the cover is in our database (and not directly
// embedded in the file, for instance).
action("viewCover")->setEnabled(file.coverInfo()->hasCover());
action("removeCover")->setEnabled(file.coverInfo()->hasCover());
action("removeCover")->setEnabled(file.coverInfo()->coverId() != CoverManager::NoMatch);
m_rmbMenu->popup(point);
m_currentColumn = column + columnOffset();
......
......@@ -21,10 +21,12 @@
#include <QPixmap>
#include <QFileInfo>
#include "collectionlist.h"
#include "musicbrainzquery.h"
#include "tag.h"
#include "coverinfo.h"
#include "covermanager.h"
#include "tagtransactionmanager.h"
PlaylistItemList PlaylistItem::m_playingItems; // static
......@@ -89,8 +91,15 @@ const QPixmap *PlaylistItem::pixmap(int column) const
int offset = playlist()->columnOffset();
if((column - offset) == CoverColumn && d->fileHandle.coverInfo()->hasCover())
// Don't use hasCover here because that may dig into the track itself.
// Besides, we really just want to know if the cover manager has a cover
// for the track.
if((column - offset) == CoverColumn &&
d->fileHandle.coverInfo()->coverId() != CoverManager::NoMatch)
{
return &image;
}
if(column == playlist()->leftColumn() &&
m_playingItems.contains(const_cast<PlaylistItem *>(this)))
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment