Add nearest and bicubic filtering

This commit is contained in:
2023-12-18 15:54:15 +01:00
parent 0e9c980325
commit 2134f13b06
4 changed files with 114 additions and 2 deletions
+4
View File
@@ -14,6 +14,8 @@
#include <cmath> #include <cmath>
#include <QElapsedTimer> #include <QElapsedTimer>
int FILTERING = 1;
struct RawImageType struct RawImageType
{ {
QOpenGLTexture::PixelFormat pixelFormat; QOpenGLTexture::PixelFormat pixelFormat;
@@ -375,6 +377,8 @@ void ImageWidget::paintGL()
m_program->setUniformValue("bw", m_bwImg && !m_superpixel); m_program->setUniformValue("bw", m_bwImg && !m_superpixel);
m_program->setUniformValue("false_color", m_falseColor && m_bwImg); m_program->setUniformValue("false_color", m_falseColor && m_bwImg);
m_program->setUniformValue("invert", m_invert); m_program->setUniformValue("invert", m_invert);
m_program->setUniformValue("filtering", m_scale > 1.0f ? FILTERING : 1);
qDebug() << 1.0 / m_scale;
#ifdef COLOR_MANAGMENT #ifdef COLOR_MANAGMENT
m_program->setUniformValue("srgb", m_srgb); m_program->setUniformValue("srgb", m_srgb);
#endif #endif
+9
View File
@@ -8,6 +8,7 @@
extern int DEFAULT_WIDTH; extern int DEFAULT_WIDTH;
extern double SATURATION; extern double SATURATION;
extern int FILTERING;
class EvenNumber : public QSpinBox class EvenNumber : public QSpinBox
{ {
@@ -59,10 +60,15 @@ SettingsDialog::SettingsDialog(QWidget *parent) : QDialog(parent)
m_useNativeDialog = new QCheckBox(tr("Don't use native file dialog"), this); m_useNativeDialog = new QCheckBox(tr("Don't use native file dialog"), this);
m_useNativeDialog->setChecked(QApplication::testAttribute(Qt::AA_DontUseNativeDialogs)); m_useNativeDialog->setChecked(QApplication::testAttribute(Qt::AA_DontUseNativeDialogs));
m_filtering = new QComboBox(this);
m_filtering->addItems({tr("Nearest"), tr("Bilinear"), tr("Bicubic")});
m_filtering->setCurrentIndex(FILTERING);
layout->addRow(tr("Image preload count"), m_preloadImages); layout->addRow(tr("Image preload count"), m_preloadImages);
layout->addRow(tr("Thumbnails size"), m_thumSize); layout->addRow(tr("Thumbnails size"), m_thumSize);
layout->addRow(tr("Saturation"), m_saturation); layout->addRow(tr("Saturation"), m_saturation);
layout->addRow(m_useNativeDialog); layout->addRow(m_useNativeDialog);
layout->addRow(tr("Image filtering"), m_filtering);
//layout->addRow(new QLabel(tr("Changes in settings will take effect after program restart."))); //layout->addRow(new QLabel(tr("Changes in settings will take effect after program restart.")));
QDialogButtonBox *buttonBox = new QDialogButtonBox(this); QDialogButtonBox *buttonBox = new QDialogButtonBox(this);
@@ -82,6 +88,7 @@ void SettingsDialog::loadSettings()
THUMB_SIZE_BORDER_Y = THUMB_SIZE + 30; THUMB_SIZE_BORDER_Y = THUMB_SIZE + 30;
DEFAULT_WIDTH = settings.value("settings/preloadimagecount", DEFAULT_WIDTH).toInt(); DEFAULT_WIDTH = settings.value("settings/preloadimagecount", DEFAULT_WIDTH).toInt();
SATURATION = settings.value("settings/saturation", 95.0).toDouble() / 100.0; SATURATION = settings.value("settings/saturation", 95.0).toDouble() / 100.0;
FILTERING = settings.value("settings/filtering", FILTERING).toInt();
QApplication::setAttribute(Qt::AA_DontUseNativeDialogs, settings.value("settings/dontusenativedialogs", false).toBool()); QApplication::setAttribute(Qt::AA_DontUseNativeDialogs, settings.value("settings/dontusenativedialogs", false).toBool());
} }
@@ -102,6 +109,8 @@ void SettingsDialog::saveSettings()
settings.setValue("settings/preloadimagecount", m_preloadImages->value()); settings.setValue("settings/preloadimagecount", m_preloadImages->value());
settings.setValue("settings/dontusenativedialogs", m_useNativeDialog->isChecked()); settings.setValue("settings/dontusenativedialogs", m_useNativeDialog->isChecked());
settings.setValue("settings/saturation", m_saturation->value()); settings.setValue("settings/saturation", m_saturation->value());
FILTERING = m_filtering->currentIndex();
settings.setValue("settings/filtering", FILTERING);
SATURATION = m_saturation->value() / 100.0; SATURATION = m_saturation->value() / 100.0;
QApplication::setAttribute(Qt::AA_DontUseNativeDialogs, m_useNativeDialog->isChecked()); QApplication::setAttribute(Qt::AA_DontUseNativeDialogs, m_useNativeDialog->isChecked());
if(DEFAULT_WIDTH != m_preloadImages->value()) if(DEFAULT_WIDTH != m_preloadImages->value())
+2
View File
@@ -4,6 +4,7 @@
#include <QDialog> #include <QDialog>
#include <QSpinBox> #include <QSpinBox>
#include <QCheckBox> #include <QCheckBox>
#include <QComboBox>
class SettingsDialog : public QDialog class SettingsDialog : public QDialog
{ {
@@ -21,6 +22,7 @@ private:
QSpinBox *m_thumSize; QSpinBox *m_thumSize;
QDoubleSpinBox *m_saturation; QDoubleSpinBox *m_saturation;
QCheckBox *m_useNativeDialog; QCheckBox *m_useNativeDialog;
QComboBox *m_filtering;
}; };
#endif // SETTINGSDIALOG_H #endif // SETTINGSDIALOG_H
+99 -2
View File
@@ -7,6 +7,7 @@ uniform bool bw;
uniform bool invert; uniform bool invert;
uniform bool srgb; uniform bool srgb;
uniform bool false_color; uniform bool false_color;
uniform int filtering;
in vec2 qt_TexCoord0; in vec2 qt_TexCoord0;
layout(location = 0) out vec4 color; layout(location = 0) out vec4 color;
@@ -35,7 +36,8 @@ vec3 falsecolor(float color)
vec3(1.0, 0.0, 0.0), vec3(1.0, 0.0, 0.0));//red vec3(1.0, 0.0, 0.0), vec3(1.0, 0.0, 0.0));//red
color *= 5.0; color *= 5.0;
int i = int(color); int i = int(color);
return mix(pallete[i], pallete[i+1], fract(color)); float f = fract(color);
return mix(pallete[i], pallete[i+1], f);// * (f * 0.5 + 0.5);
} }
vec3 checker() vec3 checker()
@@ -44,9 +46,104 @@ vec3 checker()
return vec3(step(pattern.x * pattern.y, 0.0) * 0.25 + 0.25); return vec3(step(pattern.x * pattern.y, 0.0) * 0.25 + 0.25);
} }
vec4 cubic(float v)
{
vec4 n = vec4(1.0, 2.0, 3.0, 4.0) - v;
vec4 s = n * n * n;
float x = s.x;
float y = s.y - 4.0 * s.x;
float z = s.z - 4.0 * s.y + 6.0 * s.x;
float w = 6.0 - x - y - z;
return vec4(x, y, z, w) * (1.0/6.0);
}
vec4 textureBicubic(sampler2D sampler, vec2 texCoords)
{
vec2 texSize = textureSize(sampler, 0);
vec2 invTexSize = 1.0 / texSize;
texCoords = texCoords * texSize - 0.5;
vec2 fxy = fract(texCoords);
texCoords -= fxy;
vec4 xcubic = cubic(fxy.x);
vec4 ycubic = cubic(fxy.y);
vec4 c = texCoords.xxyy + vec2 (-0.5, +1.5).xyxy;
vec4 s = vec4(xcubic.xz + xcubic.yw, ycubic.xz + ycubic.yw);
vec4 offset = c + vec4 (xcubic.yw, ycubic.yw) / s;
offset *= invTexSize.xxyy;
vec4 sample0 = texture(sampler, offset.xz);
vec4 sample1 = texture(sampler, offset.yz);
vec4 sample2 = texture(sampler, offset.xw);
vec4 sample3 = texture(sampler, offset.yw);
float sx = s.x / (s.x + s.y);
float sy = s.z / (s.z + s.w);
return mix(mix(sample3, sample2, sx), mix(sample1, sample0, sx), sy);
}
vec4 textureCatmul(sampler2D sampler, vec2 texCoords)
{
ivec2 texSize = textureSize(sampler, 0);
texCoords = texCoords * vec2(texSize) - 0.5;
ivec2 texel = ivec2(floor(texCoords));
vec2 fra = fract(texCoords);
texSize -= 1;
const mat4 CatMul = mat4(0, 1, 0, 0, -0.5, 0, 0.5, 0, 1, -2.5, 2, -0.5, -0.5, 1.5, -1.5, 0.5);
vec4 xx = CatMul * vec4(1.0, fra.x, fra.x*fra.x, fra.x*fra.x*fra.x);
vec4 yy = CatMul * vec4(1.0, fra.y, fra.y*fra.y, fra.y*fra.y*fra.y);
vec4 a00 = texelFetch(sampler, clamp(texel + ivec2(-1, -1), ivec2(0, 0), texSize), 0) * xx.x;
vec4 a01 = texelFetch(sampler, clamp(texel + ivec2( 0, -1), ivec2(0, 0), texSize), 0) * xx.y;
vec4 a02 = texelFetch(sampler, clamp(texel + ivec2( 1, -1), ivec2(0, 0), texSize), 0) * xx.z;
vec4 a03 = texelFetch(sampler, clamp(texel + ivec2( 2, -1), ivec2(0, 0), texSize), 0) * xx.w;
vec4 a10 = texelFetch(sampler, clamp(texel + ivec2(-1, 0), ivec2(0, 0), texSize), 0) * xx.x;
vec4 a11 = texelFetch(sampler, clamp(texel + ivec2( 0, 0), ivec2(0, 0), texSize), 0) * xx.y;
vec4 a12 = texelFetch(sampler, clamp(texel + ivec2( 1, 0), ivec2(0, 0), texSize), 0) * xx.z;
vec4 a13 = texelFetch(sampler, clamp(texel + ivec2( 2, 0), ivec2(0, 0), texSize), 0) * xx.w;
vec4 a20 = texelFetch(sampler, clamp(texel + ivec2(-1, 1), ivec2(0, 0), texSize), 0) * xx.x;
vec4 a21 = texelFetch(sampler, clamp(texel + ivec2( 0, 1), ivec2(0, 0), texSize), 0) * xx.y;
vec4 a22 = texelFetch(sampler, clamp(texel + ivec2( 1, 1), ivec2(0, 0), texSize), 0) * xx.z;
vec4 a23 = texelFetch(sampler, clamp(texel + ivec2( 2, 1), ivec2(0, 0), texSize), 0) * xx.w;
vec4 a30 = texelFetch(sampler, clamp(texel + ivec2(-1, 2), ivec2(0, 0), texSize), 0) * xx.x;
vec4 a31 = texelFetch(sampler, clamp(texel + ivec2( 0, 2), ivec2(0, 0), texSize), 0) * xx.y;
vec4 a32 = texelFetch(sampler, clamp(texel + ivec2( 1, 2), ivec2(0, 0), texSize), 0) * xx.z;
vec4 a33 = texelFetch(sampler, clamp(texel + ivec2( 2, 2), ivec2(0, 0), texSize), 0) * xx.w;
vec4 c = vec4(0.0);
c += (a00 + a01 + a02 + a03) * yy.x;
c += (a10 + a11 + a12 + a13) * yy.y;
c += (a20 + a21 + a22 + a23) * yy.z;
c += (a30 + a31 + a32 + a33) * yy.w;
return c;
}
void main(void) void main(void)
{ {
color = texture(qt_Texture0, qt_TexCoord0); switch(filtering)
{
case 0://nearest
color = texelFetch(qt_Texture0, ivec2(qt_TexCoord0 * textureSize(qt_Texture0, 0)), 0);
break;
default:
case 1://bilinear
color = texture(qt_Texture0, qt_TexCoord0);
break;
case 2://catmul bicubic
color = textureCatmul(qt_Texture0, qt_TexCoord0);
break;
}
color.rgb = color.rgb * unit_scale.x + unit_scale.y; color.rgb = color.rgb * unit_scale.x + unit_scale.y;
if(bw)color = color.rrra; if(bw)color = color.rrra;
color = MTF(color, vec4(mtf_param[0], 0.0), vec4(mtf_param[1], 0.5), vec4(mtf_param[2], 1.0)); color = MTF(color, vec4(mtf_param[0], 0.0), vec4(mtf_param[1], 0.5), vec4(mtf_param[2], 1.0));