diff --git a/krita/data/templates/animation/.directory b/krita/data/templates/animation/.directory
index 1a0a291be1..a0b53cf46f 100644
--- a/krita/data/templates/animation/.directory
+++ b/krita/data/templates/animation/.directory
@@ -1,27 +1,27 @@
[Desktop Entry]
Name=Animation Templates
Name[ca]=Plantilles d'animació
Name[ca@valencia]=Plantilles d'animació
Name[cs]=Šablony animací:
Name[de]=Animations-Vorlagen
Name[en_GB]=Animation Templates
Name[es]=Plantillas de animación
Name[et]=Animatsioonimallid
Name[eu]=Animazio-txantiloiak
Name[fi]=Animaatiopohjat
Name[fr]=Modèles pour animation
Name[gl]=Modelos de animación
Name[it]=Modelli di animazioni
Name[ko]=애니메이션 템플릿
Name[nl]=Animatiesjablonen
Name[nn]=Animasjonsmalar
Name[pl]=Szablony animacji
-Name[pt]=Modelos de Animação
+Name[pt]=Modelos de Animações
Name[pt_BR]=Modelos de animação
Name[sv]=Animeringsmallar
Name[tr]=Canlandırma Şablonları
Name[uk]=Шаблони анімацій
Name[x-test]=xxAnimation Templatesxx
Name[zh_CN]=动画模板
Name[zh_TW]=動畫範本
X-KDE-DefaultTab=true
diff --git a/krita/pics/svg/dark_python.svg b/krita/pics/svg/dark_python.svg
new file mode 100644
index 0000000000..72fbb7f2e9
--- /dev/null
+++ b/krita/pics/svg/dark_python.svg
@@ -0,0 +1,88 @@
+
+
diff --git a/krita/pics/svg/light_python.svg b/krita/pics/svg/light_python.svg
new file mode 100644
index 0000000000..9617a92a0c
--- /dev/null
+++ b/krita/pics/svg/light_python.svg
@@ -0,0 +1,92 @@
+
+
diff --git a/krita/pics/svg/svg-icons.qrc b/krita/pics/svg/svg-icons.qrc
index 5d6418703d..168d1734e9 100644
--- a/krita/pics/svg/svg-icons.qrc
+++ b/krita/pics/svg/svg-icons.qrc
@@ -1,157 +1,159 @@
broken-preset.svgzdark_addblankframe.svgdark_addcolor.svgdark_addduplicateframe.svgdark_deletekeyframe.svgdark_docker_lock_a.svgdark_docker_lock_b.svgdark_layer-locked.svgdark_layer-unlocked.svgdark_nextframe.svgdark_nextkeyframe.svgdark_lastframe.svgdark_prevkeyframe.svgdark_firstframe.svgdark_pallete_librarysvg.svgdark_passthrough-disabled.svgdark_passthrough-enabled.svgdark_prevframe.svgdark_selection-mode_ants.svgdark_selection-mode_invisible.svgdark_selection-mode_mask.svgdark_transparency-disabled.svgdark_transparency-enabled.svgdark_trim-to-image.svgdark_warning.svgdelete.svgzlayer-style-disabled.svglayer-style-enabled.svglight_addblankframe.svglight_addcolor.svglight_addduplicateframe.svglight_deletekeyframe.svglight_docker_lock_a.svglight_docker_lock_b.svglight_layer-locked.svglight_layer-unlocked.svglight_nextframe.svglight_pallete_library.svglight_passthrough-disabled.svgzlight_passthrough-enabled.svgzlight_prevframe.svglight_nextkeyframe.svglight_lastframe.svglight_prevkeyframe.svglight_firstframe.svglight_selection-mode_ants.svglight_selection-mode_invisible.svglight_selection-mode_mask.svglight_timeline_keyframe.svglight_transparency-disabled.svglight_transparency-enabled.svglight_trim-to-image.svglight_warning.svgpaintop_presets_disabled.svgzpaintop_settings_01.svgzselection-info.svgselection-mode_invisible.svgsvg-icons.qrctransparency-locked.svgtransparency-unlocked.svgworkspace-chooser.svglight_lazyframeOn.svglight_lazyframeOff.svgdark_lazyframeOn.svgdark_lazyframeOff.svgdark_mirror-view.svglight_mirror-view.svgdark_rotation-reset.svglight_rotation-reset.svglight_smoothing-basic.svglight_smoothing-no.svglight_smoothing-stabilizer.svglight_smoothing-weighted.svgdark_smoothing-basic.svgdark_smoothing-no.svgdark_smoothing-stabilizer.svgdark_smoothing-weighted.svglight_merge-layer-below.svgdark_merge-layer-below.svglight_rotate-canvas-left.svglight_rotate-canvas-right.svgdark_rotate-canvas-left.svgdark_rotate-canvas-right.svglight_gmic.svgdark_gmic.svglight_split-layer.svgdark_split-layer.svglight_color-to-alpha.svgdark_color-to-alpha.svglight_preset-switcher.svgdark_preset-switcher.svgdark_animation_play.svgdark_animation_stop.svgdark_dropframe.svgdark_droppedframes.svglight_animation_play.svglight_animation_stop.svglight_dropframe.svglight_droppedframes.svgdark_landscape.svgdark_portrait.svglight_landscape.svglight_portrait.svgdark_interpolation_constant.svgdark_interpolation_linear.svgdark_interpolation_bezier.svgdark_interpolation_sharp.svgdark_interpolation_smooth.svglight_interpolation_bezier.svglight_interpolation_constant.svglight_interpolation_linear.svglight_interpolation_sharp.svglight_interpolation_smooth.svgdark_audio-none.svgdark_audio-volume-high.svgdark_audio-volume-mute.svgdark_keyframe-add.svgdark_keyframe-remove.svgdark_zoom-fit.svgdark_zoom-horizontal.svgdark_zoom-vertical.svglight_audio-none.svglight_audio-volume-high.svglight_audio-volume-mute.svglight_keyframe-add.svglight_keyframe-remove.svglight_zoom-fit.svglight_zoom-horizontal.svglight_zoom-vertical.svgdark_showColoring.svgdark_showMarks.svgdark_showColoringOff.svgdark_showMarksOff.svgdark_updateColorize.svglight_showColoring.svglight_showMarks.svglight_showColoringOff.svglight_showMarksOff.svglight_updateColorize.svglight_wheel-light.svglight_wheel-rings.svglight_wheel-sectors.svgdark_wheel-light.svgdark_wheel-rings.svgdark_wheel-sectors.svgdark_infinity.svglight_infinity.svgdark_gamut-mask-on.svgdark_gamut-mask-off.svglight_gamut-mask-off.svglight_gamut-mask-on.svgdark_ratio.svglight_ratio.svg
+ dark_python.svg
+ light_python.svg
diff --git a/libs/image/kis_convolution_painter.h b/libs/image/kis_convolution_painter.h
index 2db38414a7..0911bec934 100644
--- a/libs/image/kis_convolution_painter.h
+++ b/libs/image/kis_convolution_painter.h
@@ -1,104 +1,109 @@
/*
* Copyright (c) 2005 Cyrille Berger
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef KIS_CONVOLUTION_PAINTER_H_
#define KIS_CONVOLUTION_PAINTER_H_
#include "kis_types.h"
#include "kis_painter.h"
#include "kis_image.h"
#include "kritaimage_export.h"
template class KisConvolutionWorker;
enum KisConvolutionBorderOp {
BORDER_IGNORE = 0, // read the pixels outside of the application rect
BORDER_REPEAT = 1 // Use the border for the missing pixels
};
/**
* @brief The KisConvolutionPainter class applies a convolution kernel to a paint device.
*
*
* Note: https://bugs.kde.org/show_bug.cgi?id=220310 shows that there's something here
* that we need to fix...
*/
class KRITAIMAGE_EXPORT KisConvolutionPainter : public KisPainter
{
public:
KisConvolutionPainter();
KisConvolutionPainter(KisPaintDeviceSP device);
KisConvolutionPainter(KisPaintDeviceSP device, KisSelectionSP selection);
enum TestingEnginePreference {
NONE,
SPATIAL,
FFTW
};
KisConvolutionPainter(KisPaintDeviceSP device, TestingEnginePreference enginePreference);
/**
* Convolve all channels in src using the specified kernel; there is only one kernel for all
- * channels possible. By default the border pixels are not convolved, that is, convolving
- * starts with at (x + kernel.width/2, y + kernel.height/2) and stops at w - (kernel.width/2)
- * and h - (kernel.height/2)
+ * channels possible.
+ *
+ * WARNING: The painter will read **more** pixels than you pass in \p areaSize.
+ * The actual processing area will be:
+ * QRect(x - kernel.width() / 2,
+ * y - kernel.height() / 2,
+ * w + 2 * (kernel.width() / 2),
+ * h + 2 * (kernel.height() / 2))
*
* The border op decides what to do with pixels too close to the edge of the rect as defined above.
*
* The channels flag determines which set out of color channels, alpha channels.
* channels we convolve.
*
* Note that we do not (currently) support different kernels for
* different channels _or_ channel types.
*
* If you want to convolve a subset of the channels in a pixel,
* set those channels with KisPainter::setChannelFlags();
*/
void applyMatrix(const KisConvolutionKernelSP kernel, const KisPaintDeviceSP src, QPoint srcPos, QPoint dstPos, QSize areaSize,
KisConvolutionBorderOp borderOp = BORDER_REPEAT);
/**
* The caller should ask if the painter needs an explicit transaction iff
* the source and destination devices coincide. Otherwise, the transaction is
* just not needed.
*/
bool needsTransaction(const KisConvolutionKernelSP kernel) const;
static bool supportsFFTW();
protected:
friend class KisConvolutionPainterTest;
private:
template
KisConvolutionWorker* createWorker(const KisConvolutionKernelSP kernel,
KisPainter *painter,
KoUpdater *progress);
bool useFFTImplementation(const KisConvolutionKernelSP kernel) const;
private:
TestingEnginePreference m_enginePreference;
};
#endif //KIS_CONVOLUTION_PAINTER_H_
diff --git a/libs/image/kis_edge_detection_kernel.cpp b/libs/image/kis_edge_detection_kernel.cpp
index 2596140852..15ed4fc938 100644
--- a/libs/image/kis_edge_detection_kernel.cpp
+++ b/libs/image/kis_edge_detection_kernel.cpp
@@ -1,428 +1,414 @@
/*
* Copyright (c) 2017 Wolthera van Hövell tot Westerflier
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "kis_edge_detection_kernel.h"
#include "kis_global.h"
#include "kis_convolution_kernel.h"
#include
#include
#include
#include
#include
#include
KisEdgeDetectionKernel::KisEdgeDetectionKernel()
{
}
/*
* This code is very similar to the gaussian kernel code, except unlike the gaussian code,
* edge-detection kernels DO use the diagonals.
* Except for the simple mode. We implement the simple mode because it is an analog to
* the old sobel filter.
*/
Eigen::Matrix KisEdgeDetectionKernel::createHorizontalMatrix(qreal radius,
FilterType type,
bool reverse)
{
int kernelSize = kernelSizeFromRadius(radius);
Eigen::Matrix matrix(kernelSize, kernelSize);
KIS_ASSERT_RECOVER_NOOP(kernelSize & 0x1);
const int center = kernelSize / 2;
if (type==Prewit) {
for (int x = 0; x < kernelSize; x++) {
for (int y=0; y KisEdgeDetectionKernel::createVerticalMatrix(qreal radius,
FilterType type,
bool reverse)
{
int kernelSize = kernelSizeFromRadius(radius);
Eigen::Matrix matrix(kernelSize, kernelSize);
KIS_ASSERT_RECOVER_NOOP(kernelSize & 0x1);
const int center = kernelSize / 2;
if (type==Prewit) {
for (int y = 0; y < kernelSize; y++) {
for (int x=0; x matrix = createHorizontalMatrix(radius, type, reverse);
if (denormalize) {
return KisConvolutionKernel::fromMatrix(matrix, 0.5, 1);
} else {
return KisConvolutionKernel::fromMatrix(matrix, 0, matrix.sum());
}
}
KisConvolutionKernelSP KisEdgeDetectionKernel::createVerticalKernel(qreal radius,
KisEdgeDetectionKernel::FilterType type,
bool denormalize,
bool reverse)
{
Eigen::Matrix matrix = createVerticalMatrix(radius, type, reverse);
if (denormalize) {
return KisConvolutionKernel::fromMatrix(matrix, 0.5, 1);
} else {
return KisConvolutionKernel::fromMatrix(matrix, 0, matrix.sum());
}
}
int KisEdgeDetectionKernel::kernelSizeFromRadius(qreal radius)
{
return qMax((int)(2 * ceil(sigmaFromRadius(radius)) + 1), 3);
}
qreal KisEdgeDetectionKernel::sigmaFromRadius(qreal radius)
{
return 0.3 * radius + 0.3;
}
void KisEdgeDetectionKernel::applyEdgeDetection(KisPaintDeviceSP device,
const QRect &rect,
qreal xRadius,
qreal yRadius,
KisEdgeDetectionKernel::FilterType type,
const QBitArray &channelFlags,
KoUpdater *progressUpdater,
FilterOutput output,
bool writeToAlpha)
{
QPoint srcTopLeft = rect.topLeft();
KisPainter finalPainter(device);
finalPainter.setChannelFlags(channelFlags);
finalPainter.setProgress(progressUpdater);
if (output == pythagorean || output == radian) {
KisPaintDeviceSP x_denormalised = new KisPaintDevice(device->colorSpace());
KisPaintDeviceSP y_denormalised = new KisPaintDevice(device->colorSpace());
x_denormalised->prepareClone(device);
y_denormalised->prepareClone(device);
KisConvolutionKernelSP kernelHorizLeftRight = KisEdgeDetectionKernel::createHorizontalKernel(xRadius, type);
KisConvolutionKernelSP kernelVerticalTopBottom = KisEdgeDetectionKernel::createVerticalKernel(yRadius, type);
- qreal horizontalCenter = qreal(kernelHorizLeftRight->width()) / 2.0;
- qreal verticalCenter = qreal(kernelVerticalTopBottom->height()) / 2.0;
-
KisConvolutionPainter horizPainterLR(x_denormalised);
horizPainterLR.setChannelFlags(channelFlags);
horizPainterLR.setProgress(progressUpdater);
horizPainterLR.applyMatrix(kernelHorizLeftRight, device,
- srcTopLeft - QPoint(0, ceil(horizontalCenter)),
- srcTopLeft - QPoint(0, ceil(horizontalCenter)),
- rect.size() + QSize(0, 2 * ceil(horizontalCenter)), BORDER_REPEAT);
+ srcTopLeft,
+ srcTopLeft,
+ rect.size(), BORDER_REPEAT);
KisConvolutionPainter verticalPainterTB(y_denormalised);
verticalPainterTB.setChannelFlags(channelFlags);
verticalPainterTB.setProgress(progressUpdater);
verticalPainterTB.applyMatrix(kernelVerticalTopBottom, device,
- srcTopLeft - QPoint(0, ceil(verticalCenter)),
- srcTopLeft - QPoint(0, ceil(verticalCenter)),
- rect.size() + QSize(0, 2 * ceil(verticalCenter)), BORDER_REPEAT);
+ srcTopLeft,
+ srcTopLeft,
+ rect.size(), BORDER_REPEAT);
KisSequentialIterator yItterator(y_denormalised, rect);
KisSequentialIterator xItterator(x_denormalised, rect);
KisSequentialIterator finalIt(device, rect);
const int pixelSize = device->colorSpace()->pixelSize();
const int channels = device->colorSpace()->channelCount();
const int alphaPos = device->colorSpace()->alphaPos();
KIS_SAFE_ASSERT_RECOVER_RETURN(alphaPos >= 0);
QVector yNormalised(channels);
QVector xNormalised(channels);
QVector finalNorm(channels);
while(yItterator.nextPixel() && xItterator.nextPixel() && finalIt.nextPixel()) {
device->colorSpace()->normalisedChannelsValue(yItterator.rawData(), yNormalised);
device->colorSpace()->normalisedChannelsValue(xItterator.rawData(), xNormalised);
device->colorSpace()->normalisedChannelsValue(finalIt.rawData(), finalNorm);
if (output == pythagorean) {
for (int c = 0; ccolorSpace());
qreal alpha = 0;
for (int c = 0; c<(channels-1); c++) {
alpha = alpha+finalNorm[c];
}
alpha = qMin(alpha/(channels-1), col.opacityF());
col.setOpacity(alpha);
memcpy(finalIt.rawData(), col.data(), pixelSize);
} else {
quint8* f = finalIt.rawData();
finalNorm[alphaPos] = 1.0;
device->colorSpace()->fromNormalisedChannelsValue(f, finalNorm);
memcpy(finalIt.rawData(), f, pixelSize);
}
}
} else {
KisConvolutionKernelSP kernel;
- qreal center = 0;
bool denormalize = !writeToAlpha;
if (output == xGrowth) {
kernel = KisEdgeDetectionKernel::createHorizontalKernel(xRadius, type, denormalize);
- center = qreal(kernel->width()) / 2.0;
} else if (output == xFall) {
kernel = KisEdgeDetectionKernel::createHorizontalKernel(xRadius, type, denormalize, true);
- center = qreal(kernel->width()) / 2.0;
} else if (output == yGrowth) {
kernel = KisEdgeDetectionKernel::createVerticalKernel(yRadius, type, denormalize);
- center = qreal(kernel->height()) / 2.0;
} else { //yFall
kernel = KisEdgeDetectionKernel::createVerticalKernel(yRadius, type, denormalize, true);
- center = qreal(kernel->height()) / 2.0;
}
if (writeToAlpha) {
KisPaintDeviceSP denormalised = new KisPaintDevice(device->colorSpace());
denormalised->prepareClone(device);
KisConvolutionPainter kernelP(denormalised);
kernelP.setChannelFlags(channelFlags);
kernelP.setProgress(progressUpdater);
kernelP.applyMatrix(kernel, device,
- srcTopLeft - QPoint(0, ceil(center)),
- srcTopLeft - QPoint(0, ceil(center)),
- rect.size() + QSize(0, 2 * ceil(center)), BORDER_REPEAT);
+ srcTopLeft, srcTopLeft,
+ rect.size(), BORDER_REPEAT);
KisSequentialIterator iterator(denormalised, rect);
KisSequentialIterator finalIt(device, rect);
const int pixelSize = device->colorSpace()->pixelSize();
const int channels = device->colorSpace()->colorChannelCount();
QVector normalised(channels);
while (iterator.nextPixel() && finalIt.nextPixel()) {
device->colorSpace()->normalisedChannelsValue(iterator.rawData(), normalised);
KoColor col(finalIt.rawData(), device->colorSpace());
qreal alpha = 0;
for (int c = 0; ccolorSpace()->setOpacity(finalIt.rawData(), 1.0, numConseqPixels);
}
}
}
}
void KisEdgeDetectionKernel::convertToNormalMap(KisPaintDeviceSP device,
const QRect &rect,
qreal xRadius,
qreal yRadius,
KisEdgeDetectionKernel::FilterType type,
int channelToConvert,
QVector channelOrder,
QVector channelFlip,
const QBitArray &channelFlags,
KoUpdater *progressUpdater)
{
QPoint srcTopLeft = rect.topLeft();
KisPainter finalPainter(device);
finalPainter.setChannelFlags(channelFlags);
finalPainter.setProgress(progressUpdater);
KisPaintDeviceSP x_denormalised = new KisPaintDevice(device->colorSpace());
KisPaintDeviceSP y_denormalised = new KisPaintDevice(device->colorSpace());
x_denormalised->prepareClone(device);
y_denormalised->prepareClone(device);
KisConvolutionKernelSP kernelHorizLeftRight = KisEdgeDetectionKernel::createHorizontalKernel(yRadius, type, true, !channelFlip[1]);
KisConvolutionKernelSP kernelVerticalTopBottom = KisEdgeDetectionKernel::createVerticalKernel(xRadius, type, true, !channelFlip[0]);
- qreal horizontalCenter = qreal(kernelHorizLeftRight->width()) / 2.0;
- qreal verticalCenter = qreal(kernelVerticalTopBottom->height()) / 2.0;
-
KisConvolutionPainter horizPainterLR(y_denormalised);
horizPainterLR.setChannelFlags(channelFlags);
horizPainterLR.setProgress(progressUpdater);
horizPainterLR.applyMatrix(kernelHorizLeftRight, device,
- srcTopLeft - QPoint(ceil(horizontalCenter), 0),
- srcTopLeft - QPoint(ceil(horizontalCenter), 0),
- rect.size() + QSize(2 * ceil(horizontalCenter), 0), BORDER_REPEAT);
+ srcTopLeft, srcTopLeft,
+ rect.size(), BORDER_REPEAT);
KisConvolutionPainter verticalPainterTB(x_denormalised);
verticalPainterTB.setChannelFlags(channelFlags);
verticalPainterTB.setProgress(progressUpdater);
verticalPainterTB.applyMatrix(kernelVerticalTopBottom, device,
- srcTopLeft - QPoint(0, ceil(verticalCenter)),
- srcTopLeft - QPoint(0, ceil(verticalCenter)),
- rect.size() + QSize(0, 2 * ceil(verticalCenter)), BORDER_REPEAT);
+ srcTopLeft,
+ srcTopLeft,
+ rect.size(), BORDER_REPEAT);
KisSequentialIterator yItterator(y_denormalised, rect);
KisSequentialIterator xItterator(x_denormalised, rect);
KisSequentialIterator finalIt(device, rect);
const int pixelSize = device->colorSpace()->pixelSize();
const int channels = device->colorSpace()->channelCount();
const int alphaPos = device->colorSpace()->alphaPos();
KIS_SAFE_ASSERT_RECOVER_RETURN(alphaPos >= 0);
QVector yNormalised(channels);
QVector xNormalised(channels);
QVector finalNorm(channels);
while(yItterator.nextPixel() && xItterator.nextPixel() && finalIt.nextPixel()) {
device->colorSpace()->normalisedChannelsValue(yItterator.rawData(), yNormalised);
device->colorSpace()->normalisedChannelsValue(xItterator.rawData(), xNormalised);
qreal z = 1.0;
if (channelFlip[2]==true){
z=-1.0;
}
QVector3D normal = QVector3D((xNormalised[channelToConvert]-0.5)*2, (yNormalised[channelToConvert]-0.5)*2, z);
normal.normalize();
finalNorm.fill(1.0);
for (int c = 0; c<3; c++) {
finalNorm[device->colorSpace()->channels().at(channelOrder[c])->displayPosition()] = (normal[channelOrder[c]]/2)+0.5;
}
finalNorm[alphaPos]= 1.0;
quint8* pixel = finalIt.rawData();
device->colorSpace()->fromNormalisedChannelsValue(pixel, finalNorm);
memcpy(finalIt.rawData(), pixel, pixelSize);
}
}
diff --git a/libs/ui/opengl/kis_opengl_canvas2.cpp b/libs/ui/opengl/kis_opengl_canvas2.cpp
index dce0f530b5..cf48d4bc55 100644
--- a/libs/ui/opengl/kis_opengl_canvas2.cpp
+++ b/libs/ui/opengl/kis_opengl_canvas2.cpp
@@ -1,1119 +1,1119 @@
/* This file is part of the KDE project
* Copyright (C) Boudewijn Rempt , (C) 2006-2013
* Copyright (C) 2015 Michael Abrahams
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#define GL_GLEXT_PROTOTYPES
#include "opengl/kis_opengl_canvas2.h"
#include "opengl/kis_opengl_canvas2_p.h"
#include "kis_algebra_2d.h"
#include "opengl/kis_opengl_shader_loader.h"
#include "opengl/kis_opengl_canvas_debugger.h"
#include "canvas/kis_canvas2.h"
#include "canvas/kis_coordinates_converter.h"
#include "canvas/kis_display_filter.h"
#include "canvas/kis_display_color_converter.h"
#include "kis_config.h"
#include "kis_config_notifier.h"
#include "kis_debug.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "KisOpenGLModeProber.h"
#include
#if !defined(Q_OS_MACOS) && !defined(HAS_ONLY_OPENGL_ES)
#include
#endif
#define NEAR_VAL -1000.0
#define FAR_VAL 1000.0
#ifndef GL_CLAMP_TO_EDGE
#define GL_CLAMP_TO_EDGE 0x812F
#endif
#define PROGRAM_VERTEX_ATTRIBUTE 0
#define PROGRAM_TEXCOORD_ATTRIBUTE 1
static bool OPENGL_SUCCESS = false;
struct KisOpenGLCanvas2::Private
{
public:
~Private() {
delete displayShader;
delete checkerShader;
delete solidColorShader;
delete overlayInvertedShader;
Sync::deleteSync(glSyncObject);
}
bool canvasInitialized{false};
KisOpenGLImageTexturesSP openGLImageTextures;
KisOpenGLShaderLoader shaderLoader;
KisShaderProgram *displayShader{0};
KisShaderProgram *checkerShader{0};
KisShaderProgram *solidColorShader{0};
KisShaderProgram *overlayInvertedShader{0};
QScopedPointer canvasFBO;
bool displayShaderCompiledWithDisplayFilterSupport{false};
GLfloat checkSizeScale;
bool scrollCheckers;
QSharedPointer displayFilter;
KisOpenGL::FilterMode filterMode;
bool proofingConfigIsUpdated=false;
GLsync glSyncObject{0};
bool wrapAroundMode{false};
// Stores a quad for drawing the canvas
QOpenGLVertexArrayObject quadVAO;
QOpenGLBuffer quadBuffers[2];
// Stores data for drawing tool outlines
QOpenGLVertexArrayObject outlineVAO;
QOpenGLBuffer lineVertexBuffer;
QOpenGLBuffer lineTexCoordBuffer;
QVector3D vertices[6];
QVector2D texCoords[6];
#if !defined(Q_OS_MACOS) && !defined(HAS_ONLY_OPENGL_ES)
QOpenGLFunctions_2_1 *glFn201;
#endif
qreal pixelGridDrawingThreshold;
bool pixelGridEnabled;
QColor gridColor;
QColor cursorColor;
bool lodSwitchInProgress = false;
int xToColWithWrapCompensation(int x, const QRect &imageRect) {
int firstImageColumn = openGLImageTextures->xToCol(imageRect.left());
int lastImageColumn = openGLImageTextures->xToCol(imageRect.right());
int colsPerImage = lastImageColumn - firstImageColumn + 1;
int numWraps = floor(qreal(x) / imageRect.width());
int remainder = x - imageRect.width() * numWraps;
return colsPerImage * numWraps + openGLImageTextures->xToCol(remainder);
}
int yToRowWithWrapCompensation(int y, const QRect &imageRect) {
int firstImageRow = openGLImageTextures->yToRow(imageRect.top());
int lastImageRow = openGLImageTextures->yToRow(imageRect.bottom());
int rowsPerImage = lastImageRow - firstImageRow + 1;
int numWraps = floor(qreal(y) / imageRect.height());
int remainder = y - imageRect.height() * numWraps;
return rowsPerImage * numWraps + openGLImageTextures->yToRow(remainder);
}
};
KisOpenGLCanvas2::KisOpenGLCanvas2(KisCanvas2 *canvas,
KisCoordinatesConverter *coordinatesConverter,
QWidget *parent,
KisImageWSP image,
KisDisplayColorConverter *colorConverter)
: QOpenGLWidget(parent)
, KisCanvasWidgetBase(canvas, coordinatesConverter)
, d(new Private())
{
KisConfig cfg(false);
cfg.setCanvasState("OPENGL_STARTED");
d->openGLImageTextures =
KisOpenGLImageTextures::getImageTextures(image,
colorConverter->openGLCanvasSurfaceProfile(),
colorConverter->renderingIntent(),
colorConverter->conversionFlags());
connect(d->openGLImageTextures.data(),
SIGNAL(sigShowFloatingMessage(QString, int, bool)),
SLOT(slotShowFloatingMessage(QString, int, bool)));
setAcceptDrops(true);
setAutoFillBackground(false);
setFocusPolicy(Qt::StrongFocus);
setAttribute(Qt::WA_NoSystemBackground, true);
#ifdef Q_OS_MACOS
setAttribute(Qt::WA_AcceptTouchEvents, false);
#else
setAttribute(Qt::WA_AcceptTouchEvents, true);
#endif
setAttribute(Qt::WA_InputMethodEnabled, false);
setAttribute(Qt::WA_DontCreateNativeAncestors, true);
#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
// we should make sure the texture doesn't have alpha channel,
// otherwise blending will not work correctly.
if (KisOpenGLModeProber::instance()->useHDRMode()) {
setTextureFormat(GL_RGBA16F);
} else {
/**
* When in pure OpenGL mode, the canvas surface will have alpha
* channel. Therefore, if our canvas blending algorithm produces
* semi-transparent pixels (and it does), then Krita window itself
* will become transparent. Which is not good.
*
* In Angle mode, GL_RGB8 is not available (and the transparence effect
* doesn't exist at all).
*/
if (!KisOpenGL::hasOpenGLES()) {
setTextureFormat(GL_RGB8);
}
}
#endif
setDisplayFilterImpl(colorConverter->displayFilter(), true);
connect(KisConfigNotifier::instance(), SIGNAL(configChanged()), SLOT(slotConfigChanged()));
connect(KisConfigNotifier::instance(), SIGNAL(pixelGridModeChanged()), SLOT(slotPixelGridModeChanged()));
slotConfigChanged();
slotPixelGridModeChanged();
cfg.writeEntry("canvasState", "OPENGL_SUCCESS");
}
KisOpenGLCanvas2::~KisOpenGLCanvas2()
{
delete d;
}
void KisOpenGLCanvas2::setDisplayFilter(QSharedPointer displayFilter)
{
setDisplayFilterImpl(displayFilter, false);
}
void KisOpenGLCanvas2::setDisplayFilterImpl(QSharedPointer displayFilter, bool initializing)
{
bool needsInternalColorManagement =
!displayFilter || displayFilter->useInternalColorManagement();
bool needsFullRefresh = d->openGLImageTextures->setInternalColorManagementActive(needsInternalColorManagement);
d->displayFilter = displayFilter;
if (!initializing && needsFullRefresh) {
canvas()->startUpdateInPatches(canvas()->image()->bounds());
}
else if (!initializing) {
canvas()->updateCanvas();
}
}
void KisOpenGLCanvas2::notifyImageColorSpaceChanged(const KoColorSpace *cs)
{
// FIXME: on color space change the data is refetched multiple
// times by different actors!
if (d->openGLImageTextures->setImageColorSpace(cs)) {
canvas()->startUpdateInPatches(canvas()->image()->bounds());
}
}
void KisOpenGLCanvas2::setWrapAroundViewingMode(bool value)
{
d->wrapAroundMode = value;
update();
}
inline void rectToVertices(QVector3D* vertices, const QRectF &rc)
{
vertices[0] = QVector3D(rc.left(), rc.bottom(), 0.f);
vertices[1] = QVector3D(rc.left(), rc.top(), 0.f);
vertices[2] = QVector3D(rc.right(), rc.bottom(), 0.f);
vertices[3] = QVector3D(rc.left(), rc.top(), 0.f);
vertices[4] = QVector3D(rc.right(), rc.top(), 0.f);
vertices[5] = QVector3D(rc.right(), rc.bottom(), 0.f);
}
inline void rectToTexCoords(QVector2D* texCoords, const QRectF &rc)
{
texCoords[0] = QVector2D(rc.left(), rc.bottom());
texCoords[1] = QVector2D(rc.left(), rc.top());
texCoords[2] = QVector2D(rc.right(), rc.bottom());
texCoords[3] = QVector2D(rc.left(), rc.top());
texCoords[4] = QVector2D(rc.right(), rc.top());
texCoords[5] = QVector2D(rc.right(), rc.bottom());
}
void KisOpenGLCanvas2::initializeGL()
{
KisOpenGL::initializeContext(context());
initializeOpenGLFunctions();
#if !defined(Q_OS_MACOS) && !defined(HAS_ONLY_OPENGL_ES)
if (!KisOpenGL::hasOpenGLES()) {
d->glFn201 = context()->versionFunctions();
if (!d->glFn201) {
warnUI << "Cannot obtain QOpenGLFunctions_2_1, glLogicOp cannot be used";
}
} else {
d->glFn201 = nullptr;
}
#endif
KisConfig cfg(true);
d->openGLImageTextures->setProofingConfig(canvas()->proofingConfiguration());
d->openGLImageTextures->initGL(context()->functions());
d->openGLImageTextures->generateCheckerTexture(createCheckersImage(cfg.checkSize()));
initializeShaders();
// If we support OpenGL 3.2, then prepare our VAOs and VBOs for drawing
if (KisOpenGL::hasOpenGL3()) {
d->quadVAO.create();
d->quadVAO.bind();
glEnableVertexAttribArray(PROGRAM_VERTEX_ATTRIBUTE);
glEnableVertexAttribArray(PROGRAM_TEXCOORD_ATTRIBUTE);
// Create the vertex buffer object, it has 6 vertices with 3 components
d->quadBuffers[0].create();
d->quadBuffers[0].setUsagePattern(QOpenGLBuffer::StaticDraw);
d->quadBuffers[0].bind();
d->quadBuffers[0].allocate(d->vertices, 6 * 3 * sizeof(float));
glVertexAttribPointer(PROGRAM_VERTEX_ATTRIBUTE, 3, GL_FLOAT, GL_FALSE, 0, 0);
// Create the texture buffer object, it has 6 texture coordinates with 2 components
d->quadBuffers[1].create();
d->quadBuffers[1].setUsagePattern(QOpenGLBuffer::StaticDraw);
d->quadBuffers[1].bind();
d->quadBuffers[1].allocate(d->texCoords, 6 * 2 * sizeof(float));
glVertexAttribPointer(PROGRAM_TEXCOORD_ATTRIBUTE, 2, GL_FLOAT, GL_FALSE, 0, 0);
// Create the outline buffer, this buffer will store the outlines of
// tools and will frequently change data
d->outlineVAO.create();
d->outlineVAO.bind();
glEnableVertexAttribArray(PROGRAM_VERTEX_ATTRIBUTE);
glEnableVertexAttribArray(PROGRAM_TEXCOORD_ATTRIBUTE);
// The outline buffer has a StreamDraw usage pattern, because it changes constantly
d->lineVertexBuffer.create();
d->lineVertexBuffer.setUsagePattern(QOpenGLBuffer::StreamDraw);
d->lineVertexBuffer.bind();
glVertexAttribPointer(PROGRAM_VERTEX_ATTRIBUTE, 3, GL_FLOAT, GL_FALSE, 0, 0);
d->lineTexCoordBuffer.create();
d->lineTexCoordBuffer.setUsagePattern(QOpenGLBuffer::StreamDraw);
d->lineTexCoordBuffer.bind();
glVertexAttribPointer(PROGRAM_TEXCOORD_ATTRIBUTE, 2, GL_FLOAT, GL_FALSE, 0 ,0);
}
Sync::init(context());
d->canvasInitialized = true;
}
/**
* Loads all shaders and reports compilation problems
*/
void KisOpenGLCanvas2::initializeShaders()
{
KIS_SAFE_ASSERT_RECOVER_RETURN(!d->canvasInitialized);
delete d->checkerShader;
delete d->solidColorShader;
delete d->overlayInvertedShader;
d->checkerShader = 0;
d->solidColorShader = 0;
d->overlayInvertedShader = 0;
try {
d->checkerShader = d->shaderLoader.loadCheckerShader();
d->solidColorShader = d->shaderLoader.loadSolidColorShader();
d->overlayInvertedShader = d->shaderLoader.loadOverlayInvertedShader();
} catch (const ShaderLoaderException &e) {
reportFailedShaderCompilation(e.what());
}
initializeDisplayShader();
}
void KisOpenGLCanvas2::initializeDisplayShader()
{
KIS_SAFE_ASSERT_RECOVER_RETURN(!d->canvasInitialized);
bool useHiQualityFiltering = d->filterMode == KisOpenGL::HighQualityFiltering;
delete d->displayShader;
d->displayShader = 0;
try {
d->displayShader = d->shaderLoader.loadDisplayShader(d->displayFilter, useHiQualityFiltering);
d->displayShaderCompiledWithDisplayFilterSupport = d->displayFilter;
} catch (const ShaderLoaderException &e) {
reportFailedShaderCompilation(e.what());
}
}
/**
* Displays a message box telling the user that
* shader compilation failed and turns off OpenGL.
*/
void KisOpenGLCanvas2::reportFailedShaderCompilation(const QString &context)
{
KisConfig cfg(false);
qDebug() << "Shader Compilation Failure: " << context;
QMessageBox::critical(this, i18nc("@title:window", "Krita"),
i18n("Krita could not initialize the OpenGL canvas:\n\n%1\n\n Krita will disable OpenGL and close now.", context),
QMessageBox::Close);
cfg.disableOpenGL();
cfg.setCanvasState("OPENGL_FAILED");
}
void KisOpenGLCanvas2::resizeGL(int width, int height)
{
// The given size is the widget size but here we actually want to give
// KisCoordinatesConverter the viewport size aligned to device pixels.
if (KisOpenGL::supportsRenderToFBO()) {
- d->canvasFBO.reset(new QOpenGLFramebufferObject(QSize(width, height)));
+ d->canvasFBO.reset(new QOpenGLFramebufferObject(QSize(width * devicePixelRatio(), height * devicePixelRatio())));
}
coordinatesConverter()->setCanvasWidgetSize(widgetSizeAlignedToDevicePixel());
paintGL();
}
void KisOpenGLCanvas2::paintGL()
{
if (!OPENGL_SUCCESS) {
KisConfig cfg(false);
cfg.writeEntry("canvasState", "OPENGL_PAINT_STARTED");
}
KisOpenglCanvasDebugger::instance()->nofityPaintRequested();
if (d->canvasFBO) {
d->canvasFBO->bind();
}
renderCanvasGL();
if (d->canvasFBO) {
d->canvasFBO->release();
QOpenGLFramebufferObject::blitFramebuffer(nullptr, d->canvasFBO.data(), GL_COLOR_BUFFER_BIT, GL_NEAREST);
QOpenGLFramebufferObject::bindDefault();
}
if (d->glSyncObject) {
Sync::deleteSync(d->glSyncObject);
}
d->glSyncObject = Sync::getSync();
QPainter gc(this);
renderDecorations(&gc);
gc.end();
if (!OPENGL_SUCCESS) {
KisConfig cfg(false);
cfg.writeEntry("canvasState", "OPENGL_SUCCESS");
OPENGL_SUCCESS = true;
}
}
void KisOpenGLCanvas2::paintToolOutline(const QPainterPath &path)
{
if (!d->overlayInvertedShader->bind()) {
return;
}
QSizeF widgetSize = widgetSizeAlignedToDevicePixel();
// setup the mvp transformation
QMatrix4x4 projectionMatrix;
projectionMatrix.setToIdentity();
// FIXME: It may be better to have the projection in device pixel, but
// this requires introducing a new coordinate system.
projectionMatrix.ortho(0, widgetSize.width(), widgetSize.height(), 0, NEAR_VAL, FAR_VAL);
// Set view/projection & texture matrices
QMatrix4x4 modelMatrix(coordinatesConverter()->flakeToWidgetTransform());
modelMatrix.optimize();
modelMatrix = projectionMatrix * modelMatrix;
d->overlayInvertedShader->setUniformValue(d->overlayInvertedShader->location(Uniform::ModelViewProjection), modelMatrix);
d->overlayInvertedShader->setUniformValue(
d->overlayInvertedShader->location(Uniform::FragmentColor),
QVector4D(d->cursorColor.redF(), d->cursorColor.greenF(), d->cursorColor.blueF(), 1.0f));
// NOTE: Texture matrix transforms flake space -> widget space -> OpenGL UV texcoord space..
const QMatrix4x4 widgetToFBOTexCoordTransform = KisAlgebra2D::mapToRectInverse(QRect(QPoint(0, this->height()),
QSize(this->width(), -1 * this->height())));
const QMatrix4x4 textureMatrix = widgetToFBOTexCoordTransform *
QMatrix4x4(coordinatesConverter()->flakeToWidgetTransform());
d->overlayInvertedShader->setUniformValue(d->overlayInvertedShader->location(Uniform::TextureMatrix), textureMatrix);
// For the legacy shader, we should use old fixed function
// blending operations if available.
if (!KisOpenGL::hasOpenGL3() && !KisOpenGL::hasOpenGLES()) {
#ifndef HAS_ONLY_OPENGL_ES
glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
glEnable(GL_COLOR_LOGIC_OP);
#ifndef Q_OS_MACOS
if (d->glFn201) {
d->glFn201->glLogicOp(GL_XOR);
}
#else // Q_OS_MACOS
glLogicOp(GL_XOR);
#endif // Q_OS_MACOS
#else // HAS_ONLY_OPENGL_ES
KIS_ASSERT_X(false, "KisOpenGLCanvas2::paintToolOutline",
"Unexpected KisOpenGL::hasOpenGLES returned false");
#endif // HAS_ONLY_OPENGL_ES
}
// Paint the tool outline
if (KisOpenGL::hasOpenGL3()) {
d->outlineVAO.bind();
d->lineVertexBuffer.bind();
}
// Convert every disjointed subpath to a polygon and draw that polygon
QList subPathPolygons = path.toSubpathPolygons();
for (int polyIndex = 0; polyIndex < subPathPolygons.size(); polyIndex++) {
const QPolygonF& polygon = subPathPolygons.at(polyIndex);
QVector vertices;
QVector texCoords;
vertices.resize(polygon.count());
texCoords.resize(polygon.count());
for (int vertIndex = 0; vertIndex < polygon.count(); vertIndex++) {
QPointF point = polygon.at(vertIndex);
vertices[vertIndex].setX(point.x());
vertices[vertIndex].setY(point.y());
texCoords[vertIndex].setX(point.x());
texCoords[vertIndex].setY(point.y());
}
if (KisOpenGL::hasOpenGL3()) {
d->lineVertexBuffer.bind();
d->lineVertexBuffer.allocate(vertices.constData(), 3 * vertices.size() * sizeof(float));
d->lineTexCoordBuffer.bind();
d->lineTexCoordBuffer.allocate(texCoords.constData(), 2 * texCoords.size() * sizeof(float));
}
else {
d->overlayInvertedShader->enableAttributeArray(PROGRAM_VERTEX_ATTRIBUTE);
d->overlayInvertedShader->setAttributeArray(PROGRAM_VERTEX_ATTRIBUTE, vertices.constData());
d->overlayInvertedShader->enableAttributeArray(PROGRAM_TEXCOORD_ATTRIBUTE);
d->overlayInvertedShader->setAttributeArray(PROGRAM_TEXCOORD_ATTRIBUTE, texCoords.constData());
}
const bool usingLegacyShader = !((KisOpenGL::hasOpenGL3() || KisOpenGL::hasOpenGLES()) && KisOpenGL::supportsRenderToFBO());
if (usingLegacyShader){
glDrawArrays(GL_LINE_STRIP, 0, vertices.size());
} else {
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, d->canvasFBO->texture());
glDrawArrays(GL_LINE_STRIP, 0, vertices.size());
glBindTexture(GL_TEXTURE_2D, 0);
}
}
if (KisOpenGL::hasOpenGL3()) {
d->lineVertexBuffer.release();
d->outlineVAO.release();
}
if (!KisOpenGL::hasOpenGLES()) {
#ifndef HAS_ONLY_OPENGL_ES
glDisable(GL_COLOR_LOGIC_OP);
#else
KIS_ASSERT_X(false, "KisOpenGLCanvas2::paintToolOutline",
"Unexpected KisOpenGL::hasOpenGLES returned false");
#endif
} else {
glDisable(GL_BLEND);
}
d->overlayInvertedShader->release();
}
bool KisOpenGLCanvas2::isBusy() const
{
const bool isBusyStatus = Sync::syncStatus(d->glSyncObject) == Sync::Unsignaled;
KisOpenglCanvasDebugger::instance()->nofitySyncStatus(isBusyStatus);
return isBusyStatus;
}
void KisOpenGLCanvas2::setLodResetInProgress(bool value)
{
d->lodSwitchInProgress = value;
}
void KisOpenGLCanvas2::drawCheckers()
{
if (!d->checkerShader) {
return;
}
KisCoordinatesConverter *converter = coordinatesConverter();
QTransform textureTransform;
QTransform modelTransform;
QRectF textureRect;
QRectF modelRect;
QSizeF widgetSize = widgetSizeAlignedToDevicePixel();
QRectF viewportRect = !d->wrapAroundMode ?
converter->imageRectInViewportPixels() :
converter->widgetToViewport(QRectF(0, 0, widgetSize.width(), widgetSize.height()));
if (!canvas()->renderingLimit().isEmpty()) {
const QRect vrect = converter->imageToViewport(canvas()->renderingLimit()).toAlignedRect();
viewportRect &= vrect;
}
converter->getOpenGLCheckersInfo(viewportRect,
&textureTransform, &modelTransform, &textureRect, &modelRect, d->scrollCheckers);
textureTransform *= QTransform::fromScale(d->checkSizeScale / KisOpenGLImageTextures::BACKGROUND_TEXTURE_SIZE,
d->checkSizeScale / KisOpenGLImageTextures::BACKGROUND_TEXTURE_SIZE);
if (!d->checkerShader->bind()) {
qWarning() << "Could not bind checker shader";
return;
}
QMatrix4x4 projectionMatrix;
projectionMatrix.setToIdentity();
// FIXME: It may be better to have the projection in device pixel, but
// this requires introducing a new coordinate system.
projectionMatrix.ortho(0, widgetSize.width(), widgetSize.height(), 0, NEAR_VAL, FAR_VAL);
// Set view/projection matrices
QMatrix4x4 modelMatrix(modelTransform);
modelMatrix.optimize();
modelMatrix = projectionMatrix * modelMatrix;
d->checkerShader->setUniformValue(d->checkerShader->location(Uniform::ModelViewProjection), modelMatrix);
QMatrix4x4 textureMatrix(textureTransform);
d->checkerShader->setUniformValue(d->checkerShader->location(Uniform::TextureMatrix), textureMatrix);
//Setup the geometry for rendering
if (KisOpenGL::hasOpenGL3()) {
rectToVertices(d->vertices, modelRect);
d->quadBuffers[0].bind();
d->quadBuffers[0].write(0, d->vertices, 3 * 6 * sizeof(float));
rectToTexCoords(d->texCoords, textureRect);
d->quadBuffers[1].bind();
d->quadBuffers[1].write(0, d->texCoords, 2 * 6 * sizeof(float));
}
else {
rectToVertices(d->vertices, modelRect);
d->checkerShader->enableAttributeArray(PROGRAM_VERTEX_ATTRIBUTE);
d->checkerShader->setAttributeArray(PROGRAM_VERTEX_ATTRIBUTE, d->vertices);
rectToTexCoords(d->texCoords, textureRect);
d->checkerShader->enableAttributeArray(PROGRAM_TEXCOORD_ATTRIBUTE);
d->checkerShader->setAttributeArray(PROGRAM_TEXCOORD_ATTRIBUTE, d->texCoords);
}
// render checkers
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, d->openGLImageTextures->checkerTexture());
glDrawArrays(GL_TRIANGLES, 0, 6);
glBindTexture(GL_TEXTURE_2D, 0);
d->checkerShader->release();
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
void KisOpenGLCanvas2::drawGrid()
{
if (!d->solidColorShader->bind()) {
return;
}
QSizeF widgetSize = widgetSizeAlignedToDevicePixel();
QMatrix4x4 projectionMatrix;
projectionMatrix.setToIdentity();
// FIXME: It may be better to have the projection in device pixel, but
// this requires introducing a new coordinate system.
projectionMatrix.ortho(0, widgetSize.width(), widgetSize.height(), 0, NEAR_VAL, FAR_VAL);
// Set view/projection matrices
QMatrix4x4 modelMatrix(coordinatesConverter()->imageToWidgetTransform());
modelMatrix.optimize();
modelMatrix = projectionMatrix * modelMatrix;
d->solidColorShader->setUniformValue(d->solidColorShader->location(Uniform::ModelViewProjection), modelMatrix);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
d->solidColorShader->setUniformValue(
d->solidColorShader->location(Uniform::FragmentColor),
QVector4D(d->gridColor.redF(), d->gridColor.greenF(), d->gridColor.blueF(), 0.5f));
if (KisOpenGL::hasOpenGL3()) {
d->outlineVAO.bind();
d->lineVertexBuffer.bind();
}
QRectF widgetRect(0,0, widgetSize.width(), widgetSize.height());
QRectF widgetRectInImagePixels = coordinatesConverter()->documentToImage(coordinatesConverter()->widgetToDocument(widgetRect));
QRect wr = widgetRectInImagePixels.toAlignedRect();
if (!d->wrapAroundMode) {
wr &= d->openGLImageTextures->storedImageBounds();
}
QPoint topLeftCorner = wr.topLeft();
QPoint bottomRightCorner = wr.bottomRight() + QPoint(1, 1);
QVector grid;
for (int i = topLeftCorner.x(); i <= bottomRightCorner.x(); ++i) {
grid.append(QVector3D(i, topLeftCorner.y(), 0));
grid.append(QVector3D(i, bottomRightCorner.y(), 0));
}
for (int i = topLeftCorner.y(); i <= bottomRightCorner.y(); ++i) {
grid.append(QVector3D(topLeftCorner.x(), i, 0));
grid.append(QVector3D(bottomRightCorner.x(), i, 0));
}
if (KisOpenGL::hasOpenGL3()) {
d->lineVertexBuffer.allocate(grid.constData(), 3 * grid.size() * sizeof(float));
}
else {
d->solidColorShader->enableAttributeArray(PROGRAM_VERTEX_ATTRIBUTE);
d->solidColorShader->setAttributeArray(PROGRAM_VERTEX_ATTRIBUTE, grid.constData());
}
glDrawArrays(GL_LINES, 0, grid.size());
if (KisOpenGL::hasOpenGL3()) {
d->lineVertexBuffer.release();
d->outlineVAO.release();
}
d->solidColorShader->release();
glDisable(GL_BLEND);
}
void KisOpenGLCanvas2::drawImage()
{
if (!d->displayShader) {
return;
}
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
KisCoordinatesConverter *converter = coordinatesConverter();
d->displayShader->bind();
QSizeF widgetSize = widgetSizeAlignedToDevicePixel();
QMatrix4x4 projectionMatrix;
projectionMatrix.setToIdentity();
// FIXME: It may be better to have the projection in device pixel, but
// this requires introducing a new coordinate system.
projectionMatrix.ortho(0, widgetSize.width(), widgetSize.height(), 0, NEAR_VAL, FAR_VAL);
// Set view/projection matrices
QMatrix4x4 modelMatrix(converter->imageToWidgetTransform());
modelMatrix.optimize();
modelMatrix = projectionMatrix * modelMatrix;
d->displayShader->setUniformValue(d->displayShader->location(Uniform::ModelViewProjection), modelMatrix);
QMatrix4x4 textureMatrix;
textureMatrix.setToIdentity();
d->displayShader->setUniformValue(d->displayShader->location(Uniform::TextureMatrix), textureMatrix);
QRectF widgetRect(0,0, widgetSize.width(), widgetSize.height());
QRectF widgetRectInImagePixels = converter->documentToImage(converter->widgetToDocument(widgetRect));
const QRect renderingLimit = canvas()->renderingLimit();
if (!renderingLimit.isEmpty()) {
widgetRectInImagePixels &= renderingLimit;
}
qreal scaleX, scaleY;
converter->imagePhysicalScale(&scaleX, &scaleY);
d->displayShader->setUniformValue(d->displayShader->location(Uniform::ViewportScale), (GLfloat) scaleX);
d->displayShader->setUniformValue(d->displayShader->location(Uniform::TexelSize), (GLfloat) d->openGLImageTextures->texelSize());
QRect ir = d->openGLImageTextures->storedImageBounds();
QRect wr = widgetRectInImagePixels.toAlignedRect();
if (!d->wrapAroundMode) {
// if we don't want to paint wrapping images, just limit the
// processing area, and the code will handle all the rest
wr &= ir;
}
int firstColumn = d->xToColWithWrapCompensation(wr.left(), ir);
int lastColumn = d->xToColWithWrapCompensation(wr.right(), ir);
int firstRow = d->yToRowWithWrapCompensation(wr.top(), ir);
int lastRow = d->yToRowWithWrapCompensation(wr.bottom(), ir);
int minColumn = d->openGLImageTextures->xToCol(ir.left());
int maxColumn = d->openGLImageTextures->xToCol(ir.right());
int minRow = d->openGLImageTextures->yToRow(ir.top());
int maxRow = d->openGLImageTextures->yToRow(ir.bottom());
int imageColumns = maxColumn - minColumn + 1;
int imageRows = maxRow - minRow + 1;
for (int col = firstColumn; col <= lastColumn; col++) {
for (int row = firstRow; row <= lastRow; row++) {
int effectiveCol = col;
int effectiveRow = row;
QPointF tileWrappingTranslation;
if (effectiveCol > maxColumn || effectiveCol < minColumn) {
int translationStep = floor(qreal(col) / imageColumns);
int originCol = translationStep * imageColumns;
effectiveCol = col - originCol;
tileWrappingTranslation.rx() = translationStep * ir.width();
}
if (effectiveRow > maxRow || effectiveRow < minRow) {
int translationStep = floor(qreal(row) / imageRows);
int originRow = translationStep * imageRows;
effectiveRow = row - originRow;
tileWrappingTranslation.ry() = translationStep * ir.height();
}
KisTextureTile *tile =
d->openGLImageTextures->getTextureTileCR(effectiveCol, effectiveRow);
if (!tile) {
warnUI << "OpenGL: Trying to paint texture tile but it has not been created yet.";
continue;
}
/*
* We create a float rect here to workaround Qt's
* "history reasons" in calculation of right()
* and bottom() coordinates of integer rects.
*/
QRectF textureRect;
QRectF modelRect;
if (renderingLimit.isEmpty()) {
textureRect = tile->tileRectInTexturePixels();
modelRect = tile->tileRectInImagePixels().translated(tileWrappingTranslation.x(), tileWrappingTranslation.y());
} else {
const QRect limitedTileRect = tile->tileRectInImagePixels() & renderingLimit;
textureRect = tile->imageRectInTexturePixels(limitedTileRect);
modelRect = limitedTileRect.translated(tileWrappingTranslation.x(), tileWrappingTranslation.y());
}
//Setup the geometry for rendering
if (KisOpenGL::hasOpenGL3()) {
rectToVertices(d->vertices, modelRect);
d->quadBuffers[0].bind();
d->quadBuffers[0].write(0, d->vertices, 3 * 6 * sizeof(float));
rectToTexCoords(d->texCoords, textureRect);
d->quadBuffers[1].bind();
d->quadBuffers[1].write(0, d->texCoords, 2 * 6 * sizeof(float));
}
else {
rectToVertices(d->vertices, modelRect);
d->displayShader->enableAttributeArray(PROGRAM_VERTEX_ATTRIBUTE);
d->displayShader->setAttributeArray(PROGRAM_VERTEX_ATTRIBUTE, d->vertices);
rectToTexCoords(d->texCoords, textureRect);
d->displayShader->enableAttributeArray(PROGRAM_TEXCOORD_ATTRIBUTE);
d->displayShader->setAttributeArray(PROGRAM_TEXCOORD_ATTRIBUTE, d->texCoords);
}
if (d->displayFilter) {
glActiveTexture(GL_TEXTURE0 + 1);
glBindTexture(GL_TEXTURE_3D, d->displayFilter->lutTexture());
d->displayShader->setUniformValue(d->displayShader->location(Uniform::Texture1), 1);
}
glActiveTexture(GL_TEXTURE0);
const int currentLodPlane = tile->bindToActiveTexture(d->lodSwitchInProgress);
if (d->displayShader->location(Uniform::FixedLodLevel) >= 0) {
d->displayShader->setUniformValue(d->displayShader->location(Uniform::FixedLodLevel),
(GLfloat) currentLodPlane);
}
if (currentLodPlane > 0) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
} else if (SCALE_MORE_OR_EQUAL_TO(scaleX, scaleY, 2.0)) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
} else {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
switch(d->filterMode) {
case KisOpenGL::NearestFilterMode:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
break;
case KisOpenGL::BilinearFilterMode:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
break;
case KisOpenGL::TrilinearFilterMode:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
break;
case KisOpenGL::HighQualityFiltering:
if (SCALE_LESS_THAN(scaleX, scaleY, 0.5)) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
} else {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
}
break;
}
}
glDrawArrays(GL_TRIANGLES, 0, 6);
}
}
glBindTexture(GL_TEXTURE_2D, 0);
d->displayShader->release();
glBindBuffer(GL_ARRAY_BUFFER, 0);
glDisable(GL_BLEND);
}
QSize KisOpenGLCanvas2::viewportDevicePixelSize() const
{
// This is how QOpenGLCanvas sets the FBO and the viewport size. If
// devicePixelRatioF() is non-integral, the result is truncated.
int viewportWidth = static_cast(width() * devicePixelRatioF());
int viewportHeight = static_cast(height() * devicePixelRatioF());
return QSize(viewportWidth, viewportHeight);
}
QSizeF KisOpenGLCanvas2::widgetSizeAlignedToDevicePixel() const
{
QSize viewportSize = viewportDevicePixelSize();
qreal scaledWidth = viewportSize.width() / devicePixelRatioF();
qreal scaledHeight = viewportSize.height() / devicePixelRatioF();
return QSizeF(scaledWidth, scaledHeight);
}
void KisOpenGLCanvas2::slotConfigChanged()
{
KisConfig cfg(true);
d->checkSizeScale = KisOpenGLImageTextures::BACKGROUND_TEXTURE_CHECK_SIZE / static_cast(cfg.checkSize());
d->scrollCheckers = cfg.scrollCheckers();
d->openGLImageTextures->generateCheckerTexture(createCheckersImage(cfg.checkSize()));
d->openGLImageTextures->updateConfig(cfg.useOpenGLTextureBuffer(), cfg.numMipmapLevels());
d->filterMode = (KisOpenGL::FilterMode) cfg.openGLFilteringMode();
d->cursorColor = cfg.getCursorMainColor();
notifyConfigChanged();
}
void KisOpenGLCanvas2::slotPixelGridModeChanged()
{
KisConfig cfg(true);
d->pixelGridDrawingThreshold = cfg.getPixelGridDrawingThreshold();
d->pixelGridEnabled = cfg.pixelGridEnabled();
d->gridColor = cfg.getPixelGridColor();
update();
}
void KisOpenGLCanvas2::slotShowFloatingMessage(const QString &message, int timeout, bool priority)
{
canvas()->imageView()->showFloatingMessage(message, QIcon(), timeout, priority ? KisFloatingMessage::High : KisFloatingMessage::Medium);
}
QVariant KisOpenGLCanvas2::inputMethodQuery(Qt::InputMethodQuery query) const
{
return processInputMethodQuery(query);
}
void KisOpenGLCanvas2::inputMethodEvent(QInputMethodEvent *event)
{
processInputMethodEvent(event);
}
void KisOpenGLCanvas2::renderCanvasGL()
{
{
// Draw the border (that is, clear the whole widget to the border color)
QColor widgetBackgroundColor = borderColor();
const KoColorSpace *finalColorSpace =
KoColorSpaceRegistry::instance()->colorSpace(RGBAColorModelID.id(),
d->openGLImageTextures->updateInfoBuilder().destinationColorSpace()->colorDepthId().id(),
d->openGLImageTextures->monitorProfile());
KoColor convertedBackgroudColor = KoColor(widgetBackgroundColor, KoColorSpaceRegistry::instance()->rgb8());
convertedBackgroudColor.convertTo(finalColorSpace);
QVector channels = QVector(4);
convertedBackgroudColor.colorSpace()->normalisedChannelsValue(convertedBackgroudColor.data(), channels);
// Data returned by KoRgbU8ColorSpace comes in the order: blue, green, red.
glClearColor(channels[2], channels[1], channels[0], 1.0);
}
glClear(GL_COLOR_BUFFER_BIT);
if ((d->displayFilter && d->displayFilter->updateShader()) ||
(bool(d->displayFilter) != d->displayShaderCompiledWithDisplayFilterSupport)) {
KIS_SAFE_ASSERT_RECOVER_NOOP(d->canvasInitialized);
d->canvasInitialized = false; // TODO: check if actually needed?
initializeDisplayShader();
d->canvasInitialized = true;
}
if (KisOpenGL::hasOpenGL3()) {
d->quadVAO.bind();
}
drawCheckers();
drawImage();
if ((coordinatesConverter()->effectiveZoom() > d->pixelGridDrawingThreshold - 0.00001) && d->pixelGridEnabled) {
drawGrid();
}
if (KisOpenGL::hasOpenGL3()) {
d->quadVAO.release();
}
}
void KisOpenGLCanvas2::renderDecorations(QPainter *painter)
{
QRect boundingRect = coordinatesConverter()->imageRectInWidgetPixels().toAlignedRect();
drawDecorations(*painter, boundingRect);
}
void KisOpenGLCanvas2::setDisplayColorConverter(KisDisplayColorConverter *colorConverter)
{
d->openGLImageTextures->setMonitorProfile(colorConverter->openGLCanvasSurfaceProfile(),
colorConverter->renderingIntent(),
colorConverter->conversionFlags());
}
void KisOpenGLCanvas2::channelSelectionChanged(const QBitArray &channelFlags)
{
d->openGLImageTextures->setChannelFlags(channelFlags);
}
void KisOpenGLCanvas2::finishResizingImage(qint32 w, qint32 h)
{
if (d->canvasInitialized) {
d->openGLImageTextures->slotImageSizeChanged(w, h);
}
}
KisUpdateInfoSP KisOpenGLCanvas2::startUpdateCanvasProjection(const QRect & rc, const QBitArray &channelFlags)
{
d->openGLImageTextures->setChannelFlags(channelFlags);
if (canvas()->proofingConfigUpdated()) {
d->openGLImageTextures->setProofingConfig(canvas()->proofingConfiguration());
canvas()->setProofingConfigUpdated(false);
}
return d->openGLImageTextures->updateCache(rc, d->openGLImageTextures->image());
}
QRect KisOpenGLCanvas2::updateCanvasProjection(KisUpdateInfoSP info)
{
// See KisQPainterCanvas::updateCanvasProjection for more info
bool isOpenGLUpdateInfo = dynamic_cast(info.data());
if (isOpenGLUpdateInfo) {
d->openGLImageTextures->recalculateCache(info, d->lodSwitchInProgress);
}
return QRect(); // FIXME: Implement dirty rect for OpenGL
}
QVector KisOpenGLCanvas2::updateCanvasProjection(const QVector &infoObjects)
{
#ifdef Q_OS_MACOS
/**
* On OSX openGL different (shared) contexts have different execution queues.
* It means that the textures uploading and their painting can be easily reordered.
* To overcome the issue, we should ensure that the textures are uploaded in the
* same openGL context as the painting is done.
*/
QOpenGLContext *oldContext = QOpenGLContext::currentContext();
QSurface *oldSurface = oldContext ? oldContext->surface() : 0;
this->makeCurrent();
#endif
QVector result = KisCanvasWidgetBase::updateCanvasProjection(infoObjects);
#ifdef Q_OS_MACOS
if (oldContext) {
oldContext->makeCurrent(oldSurface);
} else {
this->doneCurrent();
}
#endif
return result;
}
bool KisOpenGLCanvas2::callFocusNextPrevChild(bool next)
{
return focusNextPrevChild(next);
}
KisOpenGLImageTexturesSP KisOpenGLCanvas2::openGLImageTextures() const
{
return d->openGLImageTextures;
}
diff --git a/plugins/extensions/pykrita/plugin/pyqtpluginsettings.cpp b/plugins/extensions/pykrita/plugin/pyqtpluginsettings.cpp
index d0e3e0b5c1..314ab30ba5 100644
--- a/plugins/extensions/pykrita/plugin/pyqtpluginsettings.cpp
+++ b/plugins/extensions/pykrita/plugin/pyqtpluginsettings.cpp
@@ -1,112 +1,112 @@
/*
* Copyright (c) 2014 Boudewijn Rempt
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "pyqtpluginsettings.h"
#include "ui_manager.h"
#include
#include
#include
#include
#include
#include
-#include
#include "kis_config.h"
+#include "kis_icon_utils.h"
#include "PythonPluginManager.h"
PyQtPluginSettings::PyQtPluginSettings(PythonPluginManager *pluginManager, QWidget *parent)
: KisPreferenceSet(parent)
, m_pluginManager(pluginManager)
, m_page(new Ui::ManagerPage)
{
m_page->setupUi(this);
QSortFilterProxyModel* const proxy_model = new QSortFilterProxyModel(this);
proxy_model->setSourceModel(pluginManager->model());
m_page->pluginsList->setModel(proxy_model);
m_page->pluginsList->resizeColumnToContents(0);
m_page->pluginsList->sortByColumn(0, Qt::AscendingOrder);
const bool is_enabled = bool(pluginManager);
const bool is_visible = !is_enabled;
m_page->errorLabel->setVisible(is_visible);
m_page->pluginsList->setEnabled(is_enabled);
m_page->textBrowser->setEnabled(is_enabled);
connect(m_page->pluginsList, SIGNAL(clicked(QModelIndex)), SLOT(updateManual(QModelIndex)));
}
PyQtPluginSettings::~PyQtPluginSettings()
{
delete m_page;
}
QString PyQtPluginSettings::id()
{
return QString("pykritapluginmanager");
}
QString PyQtPluginSettings::name()
{
return header();
}
QString PyQtPluginSettings::header()
{
return QString(i18n("Python Plugin Manager"));
}
QIcon PyQtPluginSettings::icon()
{
- return koIcon("applications-development");
+ return KisIconUtils::loadIcon("python");
}
void PyQtPluginSettings::savePreferences() const
{
Q_EMIT(settingsChanged());
}
void PyQtPluginSettings::loadPreferences()
{
}
void PyQtPluginSettings::loadDefaultPreferences()
{
}
void PyQtPluginSettings::updateManual(const QModelIndex &index)
{
QModelIndex unsortedIndex = static_cast(m_page->pluginsList->model())->mapToSource(index);
PythonPlugin *plugin = m_pluginManager->model()->plugin(unsortedIndex);
if (plugin && !plugin->manual().isEmpty()) {
QString manual = plugin->manual();
if (manual.startsWith("textBrowser->setHtml(manual);
}
else {
m_page->textBrowser->setText(manual);
}
}
else {
m_page->textBrowser->setHtml("
No Manual Available");
}
}
diff --git a/plugins/python/assignprofiledialog/kritapykrita_assignprofiledialog.desktop b/plugins/python/assignprofiledialog/kritapykrita_assignprofiledialog.desktop
index f6ce4c5fad..25bc3b11b9 100644
--- a/plugins/python/assignprofiledialog/kritapykrita_assignprofiledialog.desktop
+++ b/plugins/python/assignprofiledialog/kritapykrita_assignprofiledialog.desktop
@@ -1,54 +1,54 @@
[Desktop Entry]
Type=Service
ServiceTypes=Krita/PythonPlugin
X-KDE-Library=assignprofiledialog
X-Python-2-Compatible=true
X-Krita-Manual=Manual.html
Name=Assign Profile to Image
Name[ca]=Assigna un perfil a una imatge
Name[ca@valencia]=Assigna un perfil a una imatge
Name[cs]=Přiřadit obrázku profil
Name[en_GB]=Assign Profile to Image
Name[es]=Asignar perfil a imagen
Name[et]=Pildile profiili omistamine
Name[eu]=Esleitu profila irudiari
Name[fi]=Liitä kuvaan profiili
Name[fr]=Attribuer un profil à l'image
Name[gl]=Asignar un perfil á imaxe
Name[it]=Assegna profilo a immagine
Name[ko]=이미지에 프로필 할당
Name[nl]=Profiel aan afbeelding toewijzen
Name[nn]=Tildel profil til bilete
Name[pl]=Przypisz profil do obrazu
Name[pt]=Atribuir um Perfil à Imagem
Name[pt_BR]=Atribuir perfil a imagem
Name[sk]=Priradiť profil obrázku
Name[sv]=Tilldela profil till bild
Name[tr]=Görüntüye Profil Ata
Name[uk]=Призначити профіль до зображення
Name[x-test]=xxAssign Profile to Imagexx
Name[zh_CN]=为图像指定特性文件
Name[zh_TW]=指定設定檔到圖像
Comment=Assign a profile to an image without converting it.
Comment[ca]=Assigna un perfil a una imatge sense convertir-la.
Comment[ca@valencia]=Assigna un perfil a una imatge sense convertir-la.
Comment[en_GB]=Assign a profile to an image without converting it.
Comment[es]=Asignar un perfil a una imagen sin convertirla.
Comment[et]=Pildile profiili omistamine ilma seda teisendamata.
Comment[eu]=Esleitu profil bat irudi bati hura bihurtu gabe.
Comment[fi]=Liitä kuvaan profiili muuntamatta kuvaa
Comment[fr]=Attribuer un profil à une image sans la convertir.
Comment[gl]=Asignar un perfil a unha imaxe sen convertela.
Comment[it]=Assegna un profilo a un'immagine senza convertirla.
Comment[ko]=프로필을 변환하지 않고 이미지에 할당합니다.
Comment[nl]=Een profiel aan een afbeelding toewijzen zonder het te converteren.
Comment[nn]=Tildel fargeprofil til eit bilete utan å konvertera det til profilen
Comment[pl]=Przypisz profil do obrazu bez jego przekształcania.
-Comment[pt]=Atribuir um perfil a uma imagem sem a converter.
+Comment[pt]=Atribui um perfil à imagem sem a converter.
Comment[pt_BR]=Atribui um perfil para uma imagem sem convertê-la.
Comment[sv]=Tilldela en profil till en bild utan att konvertera den.
Comment[tr]=Bir görüntüye, görüntüyü değiştirmeden bir profil ata.
Comment[uk]=Призначити профіль до зображення без його перетворення.
Comment[x-test]=xxAssign a profile to an image without converting it.xx
Comment[zh_CN]=仅为图像指定特性文件,不转换其色彩空间
Comment[zh_TW]=將設定檔指定給圖像,而不進行轉換。
diff --git a/plugins/python/batch_exporter/kritapykrita_batch_exporter.desktop b/plugins/python/batch_exporter/kritapykrita_batch_exporter.desktop
index 660074a33b..5b5e8e1e58 100644
--- a/plugins/python/batch_exporter/kritapykrita_batch_exporter.desktop
+++ b/plugins/python/batch_exporter/kritapykrita_batch_exporter.desktop
@@ -1,26 +1,30 @@
[Desktop Entry]
Type=Service
ServiceTypes=Krita/PythonPlugin
X-KDE-Library=batch_exporter
X-Krita-Manual=Manual.html
X-Python-2-Compatible=false
Name=Batch Exporter
Name[ca]=Exportador per lots
+Name[en_GB]=Batch Exporter
Name[es]=Exportador por lotes
Name[et]=Hulgieksport
Name[nl]=Exportprogramma voor bulk
Name[nn]=Fleirbileteksport
+Name[pt]=Exportação em Lote
Name[pt_BR]=Exportador em lote
Name[sv]=Bakgrundsexport
Name[uk]=Пакетне експортування
Name[x-test]=xxBatch Exporterxx
Comment=Smart export tool that uses layer names to scale and (re-)export art assets in batches fast
Comment[ca]=Eina d'exportació intel·ligent que usa els noms de les capes per escalar i (re)exportar elements d'art en lots ràpidament
+Comment[en_GB]=Smart export tool that uses layer names to scale and (re-)export art assets in batches fast
Comment[es]=Herramienta de exportación inteligente que usa nombres de capas para escalar y (volver a) exportar recursos artísticos por lotes de un modo rápido
Comment[et]=Nutikas eksporditööriist, mid kasutab kihtide nimesid kunstiresursside kiireks hulgiskaleerimiseks ja -(taas)eksportimiseks
Comment[nl]=Slim hulpmiddel voor exporteren die lagennamen gebruikt om snel kunstbezittingen te schalen en (opnieuw) te exporteren in bulk
Comment[nn]=Smart eksportverktøy som brukar lagnamn til å skalera og (re)eksportera til fleire bilete
+Comment[pt]=Uma ferramenta inteligente de exportação em lote que usa os nomes das camadas para definir a escala e (re-)exportar os itens gráficos em lote de forma rápida
Comment[pt_BR]=Ferramenta de exportação inteligente que usa nomes de camada para dimensionar e (re)exportar ativos de arte em lotes rapidamente
Comment[sv]=Smart exportverktyg som använder lagernamn för att snabbt skala och exportera om grafiktillgångar i bakgrunden
Comment[uk]=Інструмент пакетного експортування, який використовує назви шарів для масштабування і швидкого (повторного) пакетного експортування художніх елементів
Comment[x-test]=xxSmart export tool that uses layer names to scale and (re-)export art assets in batches fastxx
diff --git a/plugins/python/channels2layers/kritapykrita_channels2layers.desktop b/plugins/python/channels2layers/kritapykrita_channels2layers.desktop
index 46a36be439..6ce6331805 100644
--- a/plugins/python/channels2layers/kritapykrita_channels2layers.desktop
+++ b/plugins/python/channels2layers/kritapykrita_channels2layers.desktop
@@ -1,26 +1,30 @@
[Desktop Entry]
Type=Service
ServiceTypes=Krita/PythonPlugin
X-KDE-Library=channels2layers
X-Python-2-Compatible=false
X-Krita-Manual=Manual.html
Name=Channels to layers
Name[ca]=Canals a capes
+Name[en_GB]=Channels to layers
Name[es]=Canales a capas
Name[et]=Kanalid kihtideks
Name[nl]=Kanalen naar lagen
Name[nn]=Kanalar til lag
+Name[pt]=Canais para camadas
Name[pt_BR]=Canais para camadas
Name[sv]=Kanaler till lager
Name[uk]=Канали у шари
Name[x-test]=xxChannels to layersxx
Comment=Extract channels as color layers
Comment[ca]=Extreu canals com a capes de color
+Comment[en_GB]=Extract channels as colour layers
Comment[es]=Extraer canales como capas de color
Comment[et]=Kanalite ekstraktimine värvikihtidena
Comment[nl]=Kanalen als kleurlagen extraheren
Comment[nn]=Hent ut kanalar som fargelag
+Comment[pt]=Extrair os canais como camadas de cores
Comment[pt_BR]=Extraia canais como camadas de cores
Comment[sv]=Extrahera kanaler som färglager
Comment[uk]=Видобування каналів як колірних шарів
Comment[x-test]=xxExtract channels as color layersxx
diff --git a/plugins/python/colorspace/kritapykrita_colorspace.desktop b/plugins/python/colorspace/kritapykrita_colorspace.desktop
index 733d2dcd55..708cab4d28 100644
--- a/plugins/python/colorspace/kritapykrita_colorspace.desktop
+++ b/plugins/python/colorspace/kritapykrita_colorspace.desktop
@@ -1,56 +1,56 @@
[Desktop Entry]
Type=Service
ServiceTypes=Krita/PythonPlugin
X-KDE-Library=colorspace
X-Python-2-Compatible=true
X-Krita-Manual=Manual.html
Name=Color Space
Name[ca]=Espai de color
Name[ca@valencia]=Espai de color
Name[cs]=Barevný prostor
Name[de]=Farbraum
Name[en_GB]=Colour Space
Name[es]=Espacio de color
Name[et]=Värviruum
Name[eu]=Kolore-espazioa
Name[fi]=Väriavaruus
Name[fr]=Espace colorimétrique
Name[gl]=Espazo de cores
Name[it]=Spazio dei colori
Name[ko]=색상 공간
Name[nl]=Kleurruimte
Name[nn]=Fargerom
Name[pl]=Przestrzeń barw
Name[pt]=Espaço de Cores
Name[pt_BR]=Espaço de cores
Name[sk]=Farebný priestor
Name[sv]=Färgrymd
Name[tr]=Renk Aralığı
Name[uk]=Простір кольорів
Name[x-test]=xxColor Spacexx
Name[zh_CN]=色彩空间
Name[zh_TW]=色彩空間
Comment=Plugin to change color space to selected documents
Comment[ca]=Un connector per a canviar l'espai de color dels documents seleccionats
Comment[ca@valencia]=Un connector per a canviar l'espai de color dels documents seleccionats
Comment[cs]=Modul pro změnu rozsahu barvy pro vybrané dokumenty
Comment[en_GB]=Plugin to change colour space to selected documents
Comment[es]=Complemento para cambiar el espacio de color de los documentos seleccionados
Comment[et]=Plugin valitud dokumentide värviruumi muutmiseks
Comment[eu]=Hautatutako dokumentuei kolore-espazioa aldatzeko plugina
Comment[fi]=Liitännäinen valittujen tiedostojen väriavaruuden muuttamiseksi
Comment[fr]=Module externe pour l'espace de couleurs des documents sélectionnés
Comment[gl]=Complemento para cambiar o espazo de cores dos documentos seleccionados.
Comment[it]=Estensione per cambiare lo spazio dei colori ai documenti selezionati
Comment[ko]=선택한 문서로 색상 공간을 변경하는 플러그인
Comment[nl]=Plug-in om kleurruimte te wijzigen aan geselecteerde documenten
Comment[nn]=Programtillegg for å byta fargerom på utvalde dokument
Comment[pl]=Wtyczka do zmiany przestrzeni barw dla wybranych dokumentów
-Comment[pt]='Plugin' para mudar o espaço de cores para os documentos seleccionados
+Comment[pt]='Plugin' para mudar o espaço de cores do documento seleccionado
Comment[pt_BR]=Plugin para alterar o espaço de cores em documentos selecionados
Comment[sv]=Insticksprogram för att ändra färgrymd för valda dokument
Comment[tr]=Seçili belgede renk aralığını değiştirmek için eklenti
Comment[uk]=Додаток для зміни простору кольорів у позначених документах
Comment[x-test]=xxPlugin to change color space to selected documentsxx
Comment[zh_CN]=用于更改选定文档色彩空间的插件
Comment[zh_TW]=用於變更色彩空間為選定檔案的外掛程式
diff --git a/plugins/python/highpass/kritapykrita_highpass.desktop b/plugins/python/highpass/kritapykrita_highpass.desktop
index 93d8b71672..784008029f 100644
--- a/plugins/python/highpass/kritapykrita_highpass.desktop
+++ b/plugins/python/highpass/kritapykrita_highpass.desktop
@@ -1,53 +1,53 @@
[Desktop Entry]
Type=Service
ServiceTypes=Krita/PythonPlugin
X-KDE-Library=highpass
X-Python-2-Compatible=false
Name=Highpass Filter
Name[ca]=Filtre passaalt
Name[ca@valencia]=Filtre passaalt
Name[cs]=Filtr s horní propustí
Name[de]=Hochpassfilter
Name[en_GB]=Highpass Filter
Name[es]=Filtro paso alto
Name[et]=Kõrgpääsfilter
Name[eu]=Goi-igaropeneko iragazkia
Name[fr]=Filtre passe-haut
Name[gl]=Filtro de paso alto
Name[it]=Filtro di accentuazione passaggio
Name[ko]=고대역 통과 필터
Name[nl]=Hoogdoorlaatfilter
Name[nn]=Høgpass-filter
Name[pl]=Filtr górnoprzepustowy
Name[pt]=Filtro Passa-Alto
Name[pt_BR]=Filtro passa alta
Name[sv]=Högpassfilter
Name[tr]=Yüksek Geçirgen Süzgeç
Name[uk]=Високочастотний фільтр
Name[x-test]=xxHighpass Filterxx
Name[zh_CN]=高通滤镜
Name[zh_TW]=高通濾鏡
Comment=Highpass Filter, based on http://registry.gimp.org/node/7385
Comment[ca]=Filtre passaalt, basat en el http://registry.gimp.org/node/7385
Comment[ca@valencia]=Filtre passaalt, basat en el http://registry.gimp.org/node/7385
Comment[cs]=Filtr s horní propustí založený na http://registry.gimp.org/node/7385
Comment[de]=Hochpassfilter, Grundlage ist http://registry.gimp.org/node/7385
Comment[en_GB]=Highpass Filter, based on http://registry.gimp.org/node/7385
Comment[es]=Filtro paso alto, basado en http://registry.gimp.org/node/7385
Comment[et]=Kõrgpääsfilter, mille aluseks on http://registry.gimp.org/node/7385
Comment[eu]=Goi-igaropeneko iragazkia, honetan oinarritua http://registry.gimp.org/node/7385
Comment[fr]=Filtre passe-haut, fondé sur http://registry.gimp.org/node/7385
Comment[gl]=Filtro de paso alto, baseado en http://registry.gimp.org/node/7385.
Comment[it]=Filtro di accentuazione passaggio, basato su http://registry.gimp.org/node/7385
Comment[ko]=http://registry.gimp.org/node/7385에 기반한 고대역 통과 필터
Comment[nl]=Hoogdoorlatfilter, gebaseerd op http://registry.gimp.org/node/7385
Comment[nn]=Høgpass-filter, basert på http://registry.gimp.org/node/7385
Comment[pl]=Filtr górnoprzepustowy, oparty na http://registry.gimp.org/node/7385
-Comment[pt]=Filtro Passa-Alto, baseado no http://registry.gimp.org/node/7385
+Comment[pt]=Filtro passa-alto, baseado em http://registry.gimp.org/node/7385
Comment[pt_BR]=Filtro passa alta, baseado em http://registry.gimp.org/node/7385
Comment[sv]=Högpassfilter, baserat på http://registry.gimp.org/node/7385
Comment[tr]=http://registry.gimp.org/node/7385 tabanlı Yüksek Geçirgen Süzgeç
Comment[uk]=Високочастотний фільтр, засновано на on http://registry.gimp.org/node/7385
Comment[x-test]=xxHighpass Filter, based on http://registry.gimp.org/node/7385xx
Comment[zh_CN]=高通滤镜,基于 http://registry.gimp.org/node/7385
Comment[zh_TW]=高通濾鏡,基於 http://registry.gimp.org/node/7385
diff --git a/plugins/python/krita_script_starter/kritapykrita_krita_script_starter.desktop b/plugins/python/krita_script_starter/kritapykrita_krita_script_starter.desktop
index 71aeeb4c89..df0e586aee 100644
--- a/plugins/python/krita_script_starter/kritapykrita_krita_script_starter.desktop
+++ b/plugins/python/krita_script_starter/kritapykrita_krita_script_starter.desktop
@@ -1,51 +1,51 @@
[Desktop Entry]
Type=Service
ServiceTypes=Krita/PythonPlugin
X-KDE-Library=krita_script_starter
X-Python-2-Compatible=false
X-Krita-Manual=Manual.html
Name=Krita Script Starter
Name[ca]=Iniciador de scripts del Krita
Name[ca@valencia]=Iniciador de scripts del Krita
Name[cs]=Spouštěč skriptů Krita
Name[en_GB]=Krita Script Starter
Name[es]=Iniciador de guiones de Krita
Name[et]=Krita skriptialustaja
Name[eu]=Krita-ren script abiarazlea
Name[fr]=Lanceur de scripts Krita
Name[gl]=Iniciador de scripts de Krita
Name[it]=Iniziatore di script per Krita
Name[ko]=Krita 스크립트 시작 도구
Name[nl]=Script-starter van Krita
Name[nn]=Krita skriptbyggjar
Name[pl]=Starter skryptów Krity
-Name[pt]=Introdução ao Programa do Krita
+Name[pt]=Inicialização do Programa do Krita
Name[pt_BR]=Inicializador de script do Krita
Name[sv]=Krita skriptstart
Name[tr]=Krita Betik Başlatıcı
Name[uk]=Створення скрипту Krita
Name[x-test]=xxKrita Script Starterxx
Name[zh_CN]=Krita 空脚本生成器
Name[zh_TW]=Krita 指令啟動器
Comment=Create the metadata and file structure for a new Krita script
Comment[ca]=Crea les metadades i l'estructura de fitxers d'un script nou del Krita
Comment[ca@valencia]=Crea les metadades i l'estructura de fitxers d'un script nou del Krita
Comment[en_GB]=Create the metadata and file structure for a new Krita script
Comment[es]=Crear los metadatos y la estructura de archivos para un nuevo guion de Krita
Comment[et]=Uue Krita skripti metaandmete ja failistruktuuri loomine
Comment[eu]=Sortu Krita-script berri baterako meta-datuak eta fitxategi egitura
Comment[fr]=Créer les métadonnées et la structure du fichier pour le nouveau script Krita
Comment[gl]=Crear os metadatos e a estrutura de ficheiros para un novo script de Krita.
Comment[it]=Crea i metadati e la struttura dei file per un nuovo script di Krita
Comment[ko]=새 Krita 스크립트에 대한 메타데이터 및 파일 구조 생성
Comment[nl]=Maak de metagegevens en bestandsstructuur voor een nieuw Krita-script
Comment[nn]=Generer metadata og filstruktur for nye Krita-skript
Comment[pl]=Utwórz metadane i strukturę plików dla nowego skryptu Krity
-Comment[pt]=Cria os meta-dados e estrutura de ficheiros de um novo programa do Krita
+Comment[pt]=Cria os meta-dados e a estrutura de ficheiros para um novo programa do Krita
Comment[pt_BR]=Cria os metadados e a estrutura de arquivos para um novo script do Krita
Comment[sv]=Skapa metadata och filstruktur för ett nytt Krita-skript
Comment[tr]=Yeni Krita betiği için üstveri ve dosya yapısı oluştur
Comment[uk]=Створення метаданих і структури файлів для нового скрипту Krita
Comment[x-test]=xxCreate the metadata and file structure for a new Krita scriptxx
Comment[zh_CN]=为新的 Krita 脚本创建元数据及文件结构
Comment[zh_TW]=為新的 Krita 指令稿建立中繼資料和檔案建構體
diff --git a/plugins/python/lastdocumentsdocker/kritapykrita_lastdocumentsdocker.desktop b/plugins/python/lastdocumentsdocker/kritapykrita_lastdocumentsdocker.desktop
index 15d1c57a04..f64e957ea2 100644
--- a/plugins/python/lastdocumentsdocker/kritapykrita_lastdocumentsdocker.desktop
+++ b/plugins/python/lastdocumentsdocker/kritapykrita_lastdocumentsdocker.desktop
@@ -1,52 +1,52 @@
[Desktop Entry]
Type=Service
ServiceTypes=Krita/PythonPlugin
X-KDE-Library=lastdocumentsdocker
X-Python-2-Compatible=false
X-Krita-Manual=Manual.html
Name=Last Documents Docker
Name[ca]=Acoblador Darrers documents
Name[ca@valencia]=Acoblador Darrers documents
Name[en_GB]=Last Documents Docker
Name[es]=Panel de últimos documentos
Name[et]=Viimaste dokumentide dokk
Name[eu]=Azken dokumentuen panela
Name[fi]=Viimeisimpien tiedostojen telakka
Name[fr]=Récemment ouverts
Name[gl]=Doca dos últimos documentos
Name[it]=Area di aggancio Ultimi documenti
Name[ko]=마지막 문서 도킹 패널
Name[nl]=Laatste documenten verankering
Name[nn]=Dokkpanel for nyleg opna dokument
Name[pl]=Dok ostatnich dokumentów
Name[pt]=Área dos Últimos Documentos
Name[pt_BR]=Área dos últimos documentos
Name[sv]=Dockningsfönster för senaste dokument
Name[tr]=Son Belgeler Doku
Name[uk]=Бічна панель останніх документів
Name[x-test]=xxLast Documents Dockerxx
Name[zh_CN]=最近文档工具面板
Name[zh_TW]=「最後檔案」面板
Comment=A Python-based docker for show thumbnails to last ten documents
Comment[ca]=Un acoblador basat en Python per a mostrar miniatures dels darrers deu documents
Comment[ca@valencia]=Un acoblador basat en Python per a mostrar miniatures dels darrers deu documents
Comment[en_GB]=A Python-based docker for show thumbnails to last ten documents
Comment[es]=Un panel basado en Python para mostrar miniaturas de los últimos diez documentos
Comment[et]=Pythoni-põhine dokk viimase kümne dokumendi pisipildi näitamiseks
Comment[eu]=Azken hamar dokumentuen koadro-txikiak erakusteko Python-oinarridun panel bat
Comment[fi]=Python-pohjainen telakka viimeisimpien kymmenen tiedoston pienoiskuvien näyttämiseen
Comment[fr]=Panneau en Python pour afficher les vignettes des dix derniers documents
Comment[gl]=Unha doca baseada en Python para mostrar as miniaturas dos últimos dez documentos.
Comment[it]=Un'area di aggancio basata su Python per mostrare miniature degli ultimi dieci documenti.
Comment[ko]=문서 10개를 표시할 수 있는 Python 기반 도킹 패널
Comment[nl]=Een op Python gebaseerde vastzetter om miniaturen van de laatste tien documenten te tonen
Comment[nn]=Python-basert dokkpanel for vising av miniatyrbilete av dei siste ti dokumenta
Comment[pl]=Dok oparty na Pythonie do pokazywania miniatur dziesięciu ostatnio otwieranych dokumentów
-Comment[pt]=Uma área acoplável em Python para mostrar miniaturas dos últimos dez documentos
+Comment[pt]=Uma área acoplável, feita em Python, para mostrar as miniaturas dos últimos dez documentos
Comment[pt_BR]=Uma área acoplável feita em Python para mostrar as miniaturas dos últimos dez documentos
Comment[sv]=Ett Python-baserat dockningsfönster för att visa miniatyrbilder för de tio senaste dokumenten
Comment[tr]=Son on belgenin küçük resmini göstermek için Python-tabanlı bir dok
Comment[uk]=Бічна панель на основі Python для показу мініатюр останніх десяти документів
Comment[x-test]=xxA Python-based docker for show thumbnails to last ten documentsxx
Comment[zh_CN]=这是一个基于 Python 的工具面板插件,它可以显示最近十个文档的缩略图
Comment[zh_TW]=基於 Python 的面板,用於顯示最後 10 個檔案縮圖
diff --git a/plugins/python/palette_docker/kritapykrita_palette_docker.desktop b/plugins/python/palette_docker/kritapykrita_palette_docker.desktop
index e0de9a1581..89caa2544d 100644
--- a/plugins/python/palette_docker/kritapykrita_palette_docker.desktop
+++ b/plugins/python/palette_docker/kritapykrita_palette_docker.desktop
@@ -1,54 +1,54 @@
[Desktop Entry]
Type=Service
ServiceTypes=Krita/PythonPlugin
X-KDE-Library=palette_docker
X-Python-2-Compatible=true
X-Krita-Manual=Manual.html
Name=Palette docker
Name[ca]=Acoblador Paleta
Name[ca@valencia]=Acoblador Paleta
Name[cs]=Dok palet
Name[de]=Paletten-Docker
Name[en_GB]=Palette docker
Name[es]=Panel de paleta
Name[et]=Paletidokk
Name[eu]=Paleta-panela
Name[fi]=Palettitelakka
Name[fr]=Panneau de palette
Name[gl]=Doca de paleta
Name[it]=Area di aggancio della tavolozza
Name[ko]=팔레트 도킹 패널
Name[nl]=Vastzetter van palet
Name[nn]=Palett-dokkpanel
Name[pl]=Dok palety
-Name[pt]=Área da Paleta
+Name[pt]=Área acoplável da paleta
Name[pt_BR]=Área da paleta
Name[sv]=Dockningsfönster för palett
Name[tr]=Palet doku
Name[uk]=Панель палітри
Name[x-test]=xxPalette dockerxx
Name[zh_CN]=色板工具面板
Name[zh_TW]=「調色盤」面板
Comment=A Python-based docker to edit color palettes.
Comment[ca]=Un acoblador basat en Python per editar paletes de colors.
Comment[ca@valencia]=Un acoblador basat en Python per editar paletes de colors.
Comment[en_GB]=A Python-based docker to edit colour palettes.
Comment[es]=Un panel basado en Python para editar paletas de colores.
Comment[et]=Pythoni-põhine dokk värvipalettide muutmiseks.
Comment[eu]=Kolore-paletak editatzeko Python-oinarridun paleta bat.
Comment[fi]=Python-pohjainen telakka väripalettien muokkaamiseen.
Comment[fr]=Panneau en Python pour éditer les palettes de couleurs.
Comment[gl]=Unha doca baseada en Python para editar paletas de cores.
Comment[it]=Un'area di aggancio per modificare le tavolozze di colori basata su Python.
Comment[ko]=색상 팔레트를 편집할 수 있는 Python 기반 도킹 패널입니다.
Comment[nl]=Een op Python gebaseerde vastzetter om kleurpaletten te bewerken.
Comment[nn]=Python-basert dokkpanel for redigering av fargepalettar
Comment[pl]=Dok oparty na Pythonie do edytowania palet kolorów.
-Comment[pt]=Um área acoplável em Python para editar as paletas de cores.
+Comment[pt]=Uma área acoplável, feita em Python, para editar paletas de cores.
Comment[pt_BR]=Uma área acoplável feita em Python para editar paletas de cores.
Comment[sv]=Ett Python-baserat dockningsfönster för att redigera färgpaletter.
Comment[tr]=Renk paletlerini düzenlemek için Python-tabanlı bir dok.
Comment[uk]=Бічна панель для редагування палітр кольорів на основі Python.
Comment[x-test]=xxA Python-based docker to edit color palettes.xx
Comment[zh_CN]=基于 Python 的色板编辑器面板
Comment[zh_TW]=基於 Python 的面板,用於編輯調色盤。
diff --git a/plugins/python/plugin_importer/kritapykrita_plugin_importer.desktop b/plugins/python/plugin_importer/kritapykrita_plugin_importer.desktop
index f03d30ae48..615d567750 100644
--- a/plugins/python/plugin_importer/kritapykrita_plugin_importer.desktop
+++ b/plugins/python/plugin_importer/kritapykrita_plugin_importer.desktop
@@ -1,51 +1,51 @@
[Desktop Entry]
Type=Service
ServiceTypes=Krita/PythonPlugin
X-KDE-Library=plugin_importer
X-Python-2-Compatible=false
X-Krita-Manual=manual.html
Name=Python Plugin Importer
Name[ca]=Importador de connectors en Python
Name[ca@valencia]=Importador de connectors en Python
Name[cs]=Importér modulů pro Python
Name[en_GB]=Python Plugin Importer
Name[es]=Importador de complementos de Python
Name[et]=Pythoni plugina importija
Name[eu]=Python plugin inportatzaile bat
Name[fr]=Importateur de modules externes Python
Name[gl]=Importador de complementos de Python
Name[it]=Importatore estensioni Python
Name[ko]=Python 플러그인 가져오기 도구
Name[nl]=Importeur van Plugin voor Python
Name[nn]=Importering av Python-tillegg
Name[pl]=Import wtyczek Pythona
-Name[pt]=Importador de 'Plugins' em Python
+Name[pt]=Importador de 'Plugins' do Python
Name[pt_BR]=Importador de plugins em Python
Name[sk]=Importér zásuvných modulov Python
Name[sv]=Python-insticksimport
Name[uk]=Засіб імпортування додатків Python
Name[x-test]=xxPython Plugin Importerxx
Name[zh_CN]=Python 插件导入器
Name[zh_TW]=Python 外掛程式匯入工具
Comment=Imports Python plugins from zip files.
Comment[ca]=Importa connectors en Python a partir de fitxers «zip».
Comment[ca@valencia]=Importa connectors en Python a partir de fitxers «zip».
Comment[cs]=Importuje moduly Pythonu ze souborů zip.
Comment[en_GB]=Imports Python plugins from zip files.
Comment[es]=Importa complementos de Python desde archivos zip.
Comment[et]=Pythoni pluginate import zip-failidest.
Comment[eu]=Python pluginak inportatzen ditu zip fitxategietatik.
Comment[fr]=Importe les modules externes Python à partir des fichiers « ZIP ».
Comment[gl]=Importa complementos de Python de ficheiros zip.
Comment[it]=Importa le estensioni Python dai file compressi.
Comment[ko]=ZIP 파일에서 Python 플러그인을 가져옵니다.
Comment[nl]=Importeert Python plug-ins uit zip-bestanden.
Comment[nn]=Importerer Python-baserte programtillegg frå .zip-filer
Comment[pl]=Importuj wtyczki Pythona z plików zip.
-Comment[pt]=Importa 'plugins' em Python a partir de ficheiros ZIP.
+Comment[pt]=Importa os 'plugins' em Python a partir de ficheiros Zip.
Comment[pt_BR]=Importa plugins em Python a partir de arquivos zip.
Comment[sv]=Importerar Python-insticksprogram från zip-filer.
Comment[uk]=Імпортує додатки Python з файлів zip.
Comment[x-test]=xxImports Python plugins from zip files.xx
Comment[zh_CN]=从 zip 文件导入 Python 插件。
Comment[zh_TW]=匯入 Zip 檔案中的 Python 外掛程式。
diff --git a/plugins/python/quick_settings_docker/kritapykrita_quick_settings_docker.desktop b/plugins/python/quick_settings_docker/kritapykrita_quick_settings_docker.desktop
index c10a39b1da..a6c3699010 100644
--- a/plugins/python/quick_settings_docker/kritapykrita_quick_settings_docker.desktop
+++ b/plugins/python/quick_settings_docker/kritapykrita_quick_settings_docker.desktop
@@ -1,53 +1,53 @@
[Desktop Entry]
Type=Service
ServiceTypes=Krita/PythonPlugin
X-KDE-Library=quick_settings_docker
X-Python-2-Compatible=true
X-Krita-Manual=Manual.html
Name=Quick Settings Docker
Name[ca]=Acoblador Arranjament ràpid
Name[ca@valencia]=Acoblador Arranjament ràpid
Name[cs]=Dok pro rychlé nastavení
Name[en_GB]=Quick Settings Docker
Name[es]=Panel de ajustes rápidos
Name[eu]=Ezarpen azkarren panela
Name[fi]=Pika-asetustelakka
Name[fr]=Réglages rapides
Name[gl]=Doca de configuración rápida
Name[it]=Area di aggancio delle impostazioni rapide
Name[ko]=빠른 설정 도킹 패널
Name[nl]=Verankering voor snelle instellingen
Name[nn]=Snøgginnstillingar-dokkpanel
Name[pl]=Dok szybkich ustawień
Name[pt]=Área de Configuração Rápida
Name[pt_BR]=Área de configuração rápida
Name[sk]=Panel rýchlych nastavení
Name[sv]=Dockningspanel med snabbinställningar
Name[tr]=Hızlı Ayarlar Doku
Name[uk]=Панель швидких параметрів
Name[x-test]=xxQuick Settings Dockerxx
Name[zh_CN]=快速设置工具面板
Name[zh_TW]=「快速設定」面板
Comment=A Python-based docker for quickly changing brush size and opacity.
Comment[ca]=Un acoblador basat en Python per a canviar ràpidament la mida i l'opacitat del pinzell.
Comment[ca@valencia]=Un acoblador basat en Python per a canviar ràpidament la mida i l'opacitat del pinzell.
Comment[en_GB]=A Python-based docker for quickly changing brush size and opacity.
Comment[es]=Un panel basado en Python para cambiar rápidamente el tamaño y la opacidad del pincel.
Comment[et]=Pythoni-põhine dokk pintsli suuruse ja läbipaistmatuse kiireks muutmiseks.
Comment[eu]=Isipu-neurria eta -opakotasuna aldatzeko Python-oinarridun panel bat.
Comment[fi]=Python-pohjainen telakka siveltimen koon ja läpikuultavuuden nopean muuttamiseen.
Comment[fr]=Panneau en python pour modifier rapidement la taille et l'opacité des brosses.
Comment[gl]=Unha doca baseada en Python para cambiar rapidamente a opacidade e o tamaño dos pinceis.
Comment[it]=Un'area di aggancio basata su Python per cambiare rapidamente la dimensione del pennello e l'opacità.
Comment[ko]=브러시 크기와 불투명도를 빠르게 변경할 수 있는 Python 기반 도킹 패널입니다.
Comment[nl]=Een op Python gebaseerde vastzetter om snel penseelgrootte en dekking te wijzigen.
Comment[nn]=Python-basert dokkpanel for kjapp endring av penselstorleik/-tettleik
Comment[pl]=Dok oparty na Pythonie do szybkiej zmiany rozmiaru i nieprzezroczystości pędzli.
-Comment[pt]=Um área acoplável em Python para mudar rapidamente o tamanho e opacidade do pincel.
+Comment[pt]=Uma área acoplável em Python para mudar rapidamente o tamanho e opacidade do pincel.
Comment[pt_BR]=Uma área acoplável em Python para mudar rapidamente o tamanho e opacidade do pincel.
Comment[sv]=En Python-baserad dockningspanel för att snabbt ändra penselstorlek och ogenomskinlighet.
Comment[tr]=Fırça boyutunu ve matlığını hızlıca değiştirmek için Python-tabanlı bir dok.
Comment[uk]=Панель на основі мови програмування Python для швидкої зміни розміру та непрозорості пензля.
Comment[x-test]=xxA Python-based docker for quickly changing brush size and opacity.xx
Comment[zh_CN]=这是一个基于 Python 的工具面板,用于快速更改笔刷尺寸和透明度。
Comment[zh_TW]=基於 Python 的面板,用於快速變更筆刷尺寸和不透明度。
diff --git a/plugins/python/scriptdocker/kritapykrita_scriptdocker.desktop b/plugins/python/scriptdocker/kritapykrita_scriptdocker.desktop
index f805b4d073..4f96d68192 100644
--- a/plugins/python/scriptdocker/kritapykrita_scriptdocker.desktop
+++ b/plugins/python/scriptdocker/kritapykrita_scriptdocker.desktop
@@ -1,52 +1,52 @@
[Desktop Entry]
Type=Service
ServiceTypes=Krita/PythonPlugin
X-KDE-Library=scriptdocker
X-Python-2-Compatible=false
Name=Script Docker
Name[ca]=Acoblador Script
Name[ca@valencia]=Acoblador Script
Name[cs]=Dok skriptu
Name[de]=Skript-Docker
Name[en_GB]=Script Docker
Name[es]=Panel de guiones
Name[eu]=Script-panela
Name[fi]=Skriptitelakka
Name[fr]=Panneau de script
Name[gl]=Doca de scripts
Name[it]=Area di aggancio degli script
Name[ko]=스크립트 도킹 패널
Name[nl]=Vastzetten van scripts
Name[nn]=Skript-dokkpanel
Name[pl]=Dok skryptów
Name[pt]=Área de Programas
Name[pt_BR]=Área de scripts
Name[sk]=Panel skriptov
Name[sv]=Dockningsfönster för skript
Name[tr]=Betik Doku
Name[uk]=Бічна панель скриптів
Name[x-test]=xxScript Dockerxx
Name[zh_CN]=脚本工具面板
Name[zh_TW]=「指令稿」面板
Comment=A Python-based docker for create actions and point to Python scripts
Comment[ca]=Un acoblador basat en Python per a crear accions i apuntar a scripts en Python
Comment[ca@valencia]=Un acoblador basat en Python per a crear accions i apuntar a scripts en Python
Comment[en_GB]=A Python-based docker for create actions and point to Python scripts
Comment[es]=Un panel basado en Python para crear y apuntar a guiones de Python
Comment[et]=Pythoni-põhine dokk toimingute loomiseks ja viitamiseks Pythoni skriptidele
Comment[eu]=Python-oinarridun panel bat.
Comment[fr]=Un panneau réalisé en Python pour créer des actions et s'interfacer avec des scripts Python
Comment[gl]=Unha doca escrita en Python para crear accións e apuntar a scripts escritos en Python.
Comment[it]=Un'area di aggancio basata su Python per creare azioni e scegliere script Python
Comment[ko]=작업 생성 및 Python 스크립트를 가리키는 Python 기반 도킹 패널
Comment[nl]=Een op Python gebaseerde vastzetter om acties te maken en naar Python scripts te wijzen
Comment[nn]=Python-basert dokkpanel for å laga handlingar og peika til Python-skript
Comment[pl]=Dok oparty na Pythonie do tworzenia działań i punktów dla skryptów Pythona
-Comment[pt]=Um área acoplável em Python para criar acções e apontar para programas em Python
+Comment[pt]=Uma área acoplável, feita em Python, para criar acções e apontar para programas em Python
Comment[pt_BR]=Uma área acoplável feita em Python para criar ações e apontar para scripts em Python
Comment[sv]=Ett Python-baserat dockningsfönster för att skapa åtgärder och peka ut Python-skript
Comment[tr]=Eylemler oluşturmak ve Python betiklerine yönlendirmek için Python-tabanlı bir dok
Comment[uk]=Бічна панель для створення дій і керування скриптами на основі Python.
Comment[x-test]=xxA Python-based docker for create actions and point to Python scriptsxx
Comment[zh_CN]=这是一个基于 Python 的工具面板,用于创建操作,并将他们指向 Python 脚本。
Comment[zh_TW]=基於 Python 的面板,用於建立動作並指向 Python 指令稿
diff --git a/plugins/python/selectionsbagdocker/kritapykrita_selectionsbagdocker.desktop b/plugins/python/selectionsbagdocker/kritapykrita_selectionsbagdocker.desktop
index 29f4b32e12..ba5611347d 100644
--- a/plugins/python/selectionsbagdocker/kritapykrita_selectionsbagdocker.desktop
+++ b/plugins/python/selectionsbagdocker/kritapykrita_selectionsbagdocker.desktop
@@ -1,51 +1,51 @@
[Desktop Entry]
Type=Service
ServiceTypes=Krita/PythonPlugin
X-KDE-Library=selectionsbagdocker
X-Python-2-Compatible=false
Name=Selections Bag Docker
Name[ca]=Acoblador Bossa de seleccions
Name[ca@valencia]=Acoblador Bossa de seleccions
Name[en_GB]=Selections Bag Docker
Name[es]=Panel de selecciones
Name[et]=Valikukarbi dokk
Name[eu]=Hautapen-zakua panela
Name[fr]=Outils de sélection
Name[gl]=Doca de bolsa das seleccións
Name[it]=Area di raccolta selezioni
Name[ko]=선택 가방 도킹 패널
Name[nl]=Vastzetter van zak met selecties
Name[nn]=Utvalssamlings-dokkpanel
Name[pl]=Dok worka zaznaczeń
-Name[pt]=Área da Lista de Selecções
+Name[pt]=Área de Selecções
Name[pt_BR]=Área de seleções
Name[sv]=Dockningspanel med markeringspåse
Name[tr]=Seçim Çantası Doku
Name[uk]=Бічна панель позначеного
Name[x-test]=xxSelections Bag Dockerxx
Name[zh_CN]=选区列表工具面板
Name[zh_TW]=「選取範圍收藏」面板
Comment=A docker that allow to store a list of selections
Comment[ca]=Un acoblador que permet emmagatzemar una llista de seleccions
Comment[ca@valencia]=Un acoblador que permet emmagatzemar una llista de seleccions
Comment[cs]=Dok umožňující uložit seznam výběrů
Comment[en_GB]=A docker that allow to store a list of selections
Comment[es]=Un panel que permite guardar una lista de selecciones
Comment[et]=Dokk valikute salvestamiseks
Comment[eu]=Hautapen zerrenda bat biltegiratzen uzten duen panel bat
Comment[fi]=Telakka, joka sallii tallentaa valintaluettelon
Comment[fr]=Panneau permettant de conserver une liste de sélections
Comment[gl]=Unha doca que permite almacenar unha lista de seleccións.
Comment[it]=Un'area di aggancio che consente di memorizzare un elenco di selezioni
Comment[ko]=선택 목록을 저장할 수 있는 도킹 패널
Comment[nl]=Een vastzetter die een lijst met selecties laat opslaan
Comment[nn]=Dokkpanel for lagring av ei liste med utval
Comment[pl]=Dok, który umożliwia przechowywanie listy zaznaczeń
Comment[pt]=Uma área acoplável que permite guardar uma lista de selecções
Comment[pt_BR]=Uma área acoplável que permite armazenar uma lista de seleções
Comment[sv]=En dockningspanel som gör det möjligt att lagra en lista över markeringar
Comment[tr]=Seçimlerin bir listesini saklamayı sağlayan bir dok
Comment[uk]=Бічна панель, на якій можна зберігати список позначеного
Comment[x-test]=xxA docker that allow to store a list of selectionsxx
Comment[zh_CN]=用于保存一组选区的工具面板
Comment[zh_TW]=允許儲存選取範圍列表的面板
diff --git a/plugins/python/tenbrushes/kritapykrita_tenbrushes.desktop b/plugins/python/tenbrushes/kritapykrita_tenbrushes.desktop
index a96aefa58f..923f313a6c 100644
--- a/plugins/python/tenbrushes/kritapykrita_tenbrushes.desktop
+++ b/plugins/python/tenbrushes/kritapykrita_tenbrushes.desktop
@@ -1,54 +1,54 @@
[Desktop Entry]
Type=Service
ServiceTypes=Krita/PythonPlugin
X-KDE-Library=tenbrushes
X-Python-2-Compatible=true
X-Krita-Manual=Manual.html
Name=Ten Brushes
Name[ca]=Deu pinzells
Name[ca@valencia]=Deu pinzells
Name[cs]=Deset štětců
Name[en_GB]=Ten Brushes
Name[es]=Diez pinceles
Name[et]=Kümme pintslit
Name[eu]=Hamar isipu
Name[fi]=Kymmenen sivellintä
Name[fr]=Raccourcis des préréglages de brosses
Name[gl]=Dez pinceis
Name[it]=Dieci pennelli
Name[ko]=브러시 10개
Name[nl]=Tien penselen
Name[nn]=Ti penslar
Name[pl]=Dziesięć pędzli
Name[pt]=Dez Pincéis
Name[pt_BR]=Dez pincéis
Name[sk]=10 Štetcov
Name[sv]=Tio penslar
Name[tr]=On Fırça
Name[uk]=Десять пензлів
Name[x-test]=xxTen Brushesxx
Name[zh_CN]=常用笔刷快捷键
Name[zh_TW]=10 個筆刷
Comment=Assign a preset to ctrl-1 to ctrl-0
Comment[ca]=Assigna una predefinició des de Ctrl-1 a Ctrl-0
Comment[ca@valencia]=Assigna una predefinició des de Ctrl-1 a Ctrl-0
Comment[en_GB]=Assign a preset to ctrl-1 to ctrl-0
Comment[es]=Asignar una preselección a Ctrl-1 hasta Ctrl-0
Comment[et]=Valmisvaliku omistamine Ctrl+1 kuni Ctrl+0
Comment[eu]=Aurrezarpena ezarri ktrl-1'etik ktrl-0'ra arte
Comment[fi]=Kytke esiasetukset Ctrl-1:stä Ctrl-0:aan
Comment[fr]=Associer un préréglage à de la touche « CRTL - 1 » à « CTRL - 2 »
Comment[gl]=Asigne unha predefinición do Ctrl+1 ao Ctrl+0.
Comment[it]=Assegna una preimpostazione per ctrl-1 a ctrl-0
Comment[ko]=Ctrl+1부터 Ctrl+0까지 프리셋 할당
Comment[nl]=Een voorinstelling aan ctrl-1 tot ctrl-0 toekennen
Comment[nn]=Byt til ferdigpenslar med «Ctrl + 1» til «Ctrl + 0»
Comment[pl]=Przypisz nastawę do ctrl-1 lub ctrl-0
-Comment[pt]=Atribuir uma predefinição de Ctrl-1 até Ctrl-8
+Comment[pt]=Atribuir uma predefinição de Ctrl-1 a Ctrl-0
Comment[pt_BR]=Atribuir uma predefinição de Ctrl-1 a Ctrl-0
Comment[sv]=Tilldela en förinställning för Ctrl+1 till Ctrl+0
Comment[tr]= ctrl-1 ve ctrl-0 için ayar atama
Comment[uk]=Прив’язування наборів налаштувань до скорочень від ctrl-1 до ctrl-0
Comment[x-test]=xxAssign a preset to ctrl-1 to ctrl-0xx
Comment[zh_CN]=将预设分配给由 Ctrl+1 到 Ctrl+0 的快捷键
Comment[zh_TW]=將預設指定給 ctrl-1 至 ctrl-0
diff --git a/plugins/python/tenscripts/kritapykrita_tenscripts.desktop b/plugins/python/tenscripts/kritapykrita_tenscripts.desktop
index be00039ced..9cbab071a4 100644
--- a/plugins/python/tenscripts/kritapykrita_tenscripts.desktop
+++ b/plugins/python/tenscripts/kritapykrita_tenscripts.desktop
@@ -1,53 +1,53 @@
[Desktop Entry]
Type=Service
ServiceTypes=Krita/PythonPlugin
X-KDE-Library=tenscripts
X-Python-2-Compatible=true
X-Krita-Manual=Manual.html
Name=Ten Scripts
Name[ca]=Deu scripts
Name[ca@valencia]=Deu scripts
Name[en_GB]=Ten Scripts
Name[es]=Diez guiones
Name[et]=Kümme skripti
Name[eu]=Hamar script
Name[fi]=Kymmenen skriptiä
Name[fr]=Raccourcis des scripts
Name[gl]=Dez scripts
Name[it]=Dieci script
Name[ko]=스크립트 10개
Name[nl]=Tien scripts
Name[nn]=Ti skript
Name[pl]=Skrypty Ten
Name[pt]=Dez Programas
Name[pt_BR]=Dez scripts
Name[sk]=Desať skriptov
Name[sv]=Tio skript
Name[tr]=On Betik
Name[uk]=Десять скриптів
Name[x-test]=xxTen Scriptsxx
Name[zh_CN]=常用脚本快捷键
Name[zh_TW]=10 個指令稿
Comment=A Python-based plugin for creating ten actions and assign them to Python scripts
Comment[ca]=Un connector basat en Python per a crear deu accions i assignar-les a scripts en Python
Comment[ca@valencia]=Un connector basat en Python per a crear deu accions i assignar-les a scripts en Python
Comment[en_GB]=A Python-based plugin for creating ten actions and assign them to Python scripts
Comment[es]=Un complemento basado en Python para crear diez acciones y asignarlas a guiones de Python
Comment[et]=Pythoni-põhine plugin kümne toimingu loomiseks ja nende omistamiseks Pythoni skriptidele
Comment[eu]=Hamar ekintza sortu eta haiek Python-scriptei esleitzeko Python-oinarridun plugin bat
Comment[fi]=Python-pohjainen liitännäinen kymmenen toiminnon luomiseksi kytkemiseksi Python-skripteihin
Comment[fr]=Module externe développé à partir de Python pour créer dix actions et les assigner à des scripts Python
Comment[gl]=Un complemento escrito en Python para crear dez accións e asignalas a scripts escritos en Python.
Comment[it]=Un'estensione basata su Python per creare dieci azioni e assegnarle a script Python
Comment[ko]=작업 10개를 생성하고 이를 Python 스크립트에 할당하는 Python 기반 플러그인
Comment[nl]=Een op Python gebaseerde plug-in om tien acties te maken en ze aan Python scripts toe te wijzen
Comment[nn]=Python-basert tillegg som legg til ti handlingar du kan tildela til Python-skript
Comment[pl]=Dok oparty na Pythonie do tworzenia działań i przypisywania ich skryptom Pythona
-Comment[pt]=Um 'plugin' em Python para criar dez acções e atribuí-las a programas em Python
+Comment[pt]=Um 'plugin' feito em Python para criar dez acções e atribuí-las a programas em Python
Comment[pt_BR]=Um plugin feito em Python para criar dez ações e atribuí-las a scripts em Python
Comment[sv]=Ett Python-baserat insticksprogram för att skapa tio åtgärder och tilldela dem till Python-skript
Comment[tr]=On eylem oluşturmak ve Python betiklerine atamak için Python tabanlı bir eklenti
Comment[uk]=Скрипт на основі Python для створення десяти дій і прив'язування до них скриптів Python
Comment[x-test]=xxA Python-based plugin for creating ten actions and assign them to Python scriptsxx
Comment[zh_CN]=这是一个基于 Python 编写的插件,它可以创建十种操作,并将它们指定到特定 Python 脚本。
Comment[zh_TW]=基於 Python 的外掛程式,用於建立 10 個動作並且將它們指定給 Python 指令稿