1
0
mirror of https://github.com/clementine-player/Clementine synced 2024-12-16 19:31:02 +01:00

Add an option to blur background image.

Fixes issue 3266.
This commit is contained in:
Mateusz Kowalczyk 2012-11-09 20:17:26 +01:00 committed by Arnaud Bienner
parent 5825768f36
commit c4796564ea
5 changed files with 142 additions and 4 deletions

View File

@ -1017,16 +1017,19 @@ void PlaylistView::ReloadSettings() {
}
}
QString background_image_filename = s.value(kSettingBackgroundImageFilename).toString();
int blur_radius = s.value("blur_radius").toInt();
// Check if background properties have changed.
// We change properties only if they have actually changed, to avoid to call
// set_background_image when it is not needed, as this will cause the fading
// animation to start again. This also avoid to do useless
// "force_background_redraw".
if (background_image_filename != background_image_filename_
|| background_type != background_image_type_) {
|| background_type != background_image_type_ ||
blur_radius_ != blur_radius) {
// Store background properties
background_image_type_ = background_type;
background_image_filename_ = background_image_filename;
blur_radius_ = blur_radius;
if (background_image_type_ == Custom) {
set_background_image(QImage(background_image_filename));
} else if (background_image_type_ == AlbumCover) {
@ -1190,18 +1193,93 @@ void PlaylistView::set_background_image(const QImage& image) {
else
background_image_ = image;
// Apply opacity filter
uchar* bits = background_image_.bits();
for (int i = 0; i < background_image_.height() * background_image_.bytesPerLine(); i+=4) {
bits[i+3] = kBackgroundOpacity * 255;
}
if (blur_radius_ != 0)
background_image_ = blur_background_image(background_image_, blur_radius_, false);
if (isVisible()) {
previous_background_image_opacity_ = 1.0;
fade_animation_->start();
}
}
QImage PlaylistView::blur_background_image(const QImage& image, int radius, bool alphaOnly = false)
{
int tab[] = { 14, 10, 8, 6, 5, 5, 4, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2 };
int alpha = (radius < 1) ? 16 : (radius > 17) ? 1 : tab[radius-1];
QImage result = image.convertToFormat(QImage::Format_ARGB32_Premultiplied);
QRect rect = image.rect();
int r1 = rect.top();
int r2 = rect.bottom();
int c1 = rect.left();
int c2 = rect.right();
int bpl = result.bytesPerLine();
int rgba[4];
unsigned char* p;
int i1 = 0;
int i2 = 3;
if (alphaOnly)
i1 = i2 = (QSysInfo::ByteOrder == QSysInfo::BigEndian ? 0 : 3);
for (int col = c1; col <= c2; col++) {
p = result.scanLine(r1) + col * 4;
for (int i = i1; i <= i2; i++)
rgba[i] = p[i] << 4;
p += bpl;
for (int j = r1; j < r2; j++, p += bpl)
for (int i = i1; i <= i2; i++)
p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4;
}
for (int row = r1; row <= r2; row++) {
p = result.scanLine(row) + c1 * 4;
for (int i = i1; i <= i2; i++)
rgba[i] = p[i] << 4;
p += 4;
for (int j = c1; j < c2; j++, p += 4)
for (int i = i1; i <= i2; i++)
p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4;
}
for (int col = c1; col <= c2; col++) {
p = result.scanLine(r2) + col * 4;
for (int i = i1; i <= i2; i++)
rgba[i] = p[i] << 4;
p -= bpl;
for (int j = r1; j < r2; j++, p -= bpl)
for (int i = i1; i <= i2; i++)
p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4;
}
for (int row = r1; row <= r2; row++) {
p = result.scanLine(row) + c2 * 4;
for (int i = i1; i <= i2; i++)
rgba[i] = p[i] << 4;
p -= 4;
for (int j = c1; j < c2; j++, p -= 4)
for (int i = i1; i <= i2; i++)
p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4;
}
return result;
}
void PlaylistView::FadePreviousBackgroundImage(qreal value) {
previous_background_image_opacity_ = value;
if (qFuzzyCompare(previous_background_image_opacity_, qreal(0.0))) {

View File

@ -73,6 +73,7 @@ class PlaylistView : public QTreeView {
// Constants for settings: are persistent, values should not be changed
static const char* kSettingBackgroundImageType;
static const char* kSettingBackgroundImageFilename;
static const int kSettingBackgroundBlurLevel;
static ColumnAlignmentMap DefaultColumnAlignment();
@ -166,6 +167,7 @@ class PlaylistView : public QTreeView {
// Save image as the background_image_ after applying some modifications (opacity, ...).
// Should be used instead of modifying background_image_ directly
void set_background_image(const QImage& image);
QImage blur_background_image(const QImage& image, int radius, bool alphaOnly);
private:
static const int kGlowIntensitySteps;
@ -173,7 +175,7 @@ class PlaylistView : public QTreeView {
static const int kDropIndicatorWidth;
static const int kDropIndicatorGradientWidth;
static const qreal kBackgroundOpacity;
QList<int> GetEditableColumns();
QModelIndex NextEditableIndex(const QModelIndex& current);
QModelIndex PrevEditableIndex(const QModelIndex& current);
@ -194,6 +196,7 @@ class PlaylistView : public QTreeView {
// particular (in terms of format, opacity), you should probably use
// set_background_image_type instead of modifying background_image_ directly
QImage background_image_;
int blur_radius_;
// Used if background image is a filemane
QString background_image_filename_;
QImage current_song_cover_art_;

View File

@ -56,6 +56,7 @@ AppearanceSettingsPage::AppearanceSettingsPage(SettingsDialog* dialog)
connect(ui_->select_foreground_color, SIGNAL(pressed()), SLOT(SelectForegroundColor()));
connect(ui_->select_background_color, SIGNAL(pressed()), SLOT(SelectBackgroundColor()));
connect(ui_->use_a_custom_color_set, SIGNAL(toggled(bool)), SLOT(UseCustomColorSetOptionChanged(bool)));
connect(ui_->blur_slider, SIGNAL(valueChanged(int)), SLOT(BlurLevelChanged(int)));
connect(ui_->select_background_image_filename_button, SIGNAL(pressed()), SLOT(SelectBackgroundImage()));
connect(ui_->use_custom_background_image, SIGNAL(toggled(bool)),
@ -114,6 +115,7 @@ void AppearanceSettingsPage::Load() {
ui_->use_default_background->setChecked(true);
}
ui_->background_image_filename->setText(playlist_view_background_image_filename_);
s.endGroup();
// Moodbar settings
@ -154,7 +156,8 @@ void AppearanceSettingsPage::Save() {
playlist_view_background_image_filename_);
}
s.setValue(PlaylistView::kSettingBackgroundImageType,
playlist_view_background_image_type_);
playlist_view_background_image_type_);
s.setValue("blur_radius", ui_->blur_slider->value());
s.endGroup();
// Moodbar settings
@ -230,6 +233,12 @@ void AppearanceSettingsPage::SelectBackgroundImage() {
ui_->background_image_filename->setText(playlist_view_background_image_filename_);
}
void AppearanceSettingsPage::BlurLevelChanged(int value) {
background_blur_radius_ = value;
ui_->background_blur_radius_label->setText(QString("%1px").arg(value));
}
void AppearanceSettingsPage::InitMoodbarPreviews() {
#ifdef HAVE_MOODBAR
if (initialised_moodbar_previews_)

View File

@ -42,6 +42,7 @@ private slots:
void SelectBackgroundColor();
void UseCustomColorSetOptionChanged(bool);
void SelectBackgroundImage();
void BlurLevelChanged(int);
private:
static const int kMoodbarPreviewWidth;
@ -62,7 +63,8 @@ private:
QColor current_background_color_;
PlaylistView::BackgroundImageType playlist_view_background_image_type_;
QString playlist_view_background_image_filename_;
int background_blur_radius_;
bool initialised_moodbar_previews_;
};

View File

@ -155,6 +155,52 @@
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_6">
<item>
<widget class="QLabel" name="select_background_blur_label">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text">
<string>Select blur radius:</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="background_blur_radius_label">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text">
<string>0px</string>
</property>
</widget>
</item>
<item>
<widget class="QSlider" name="blur_slider">
<property name="minimum">
<number>0</number>
</property>
<property name="maximum">
<number>10</number>
</property>
<property name="value">
<number>0</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="tickPosition">
<enum>QSlider::TicksBelow</enum>
</property>
<property name="tickInterval">
<number>1</number>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>