...
 
Commits (13)
......@@ -22,7 +22,7 @@ ExternalProject_Add( ext_fftw3
PATCH_COMMAND ${PATCH_COMMAND} -p1 -i ${CMAKE_CURRENT_SOURCE_DIR}/patch_mingw.patch
INSTALL_DIR ${PREFIX_ext_fftw3}
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${PREFIX_ext_fftw3} -DCMAKE_BUILD_TYPE=${GLOBAL_BUILD_TYPE} ${GLOBAL_PROFILE} -DWITH_COMBINED_THREADS=ON -ENABLE_SSE=ON -ENABLE_SSE2=ON -DBUILD_TESTS=OFF
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${PREFIX_ext_fftw3} -DCMAKE_BUILD_TYPE=${GLOBAL_BUILD_TYPE} ${GLOBAL_PROFILE} -ENABLE_SSE=ON -ENABLE_SSE2=ON -DBUILD_TESTS=OFF
UPDATE_COMMAND ""
)
......
......@@ -6,9 +6,13 @@ ExternalProject_Add( ext_gmic_base
URL https://gmic.eu/files/source/gmic_2.5.6.tar.gz
URL_MD5 8deabebc29081657986ae6531e3fc1d7
PATCH_COMMAND ${PATCH_COMMAND} -p1 -i ${CMAKE_CURRENT_SOURCE_DIR}/cmake.diff
COMMAND ${PATCH_COMMAND} -p1 -i ${CMAKE_CURRENT_SOURCE_DIR}/no_threads.diff
SOURCE_DIR gmic
CONFIGURE_COMMAND ""
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${PREFIX_ext_gmic} -D -DCMAKE_BUILD_TYPE=Release ${GLOBAL_PROFILE}
BUILD_COMMAND ""
INSTALL_COMMAND ""
......
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 3df1f8a..0bee815 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -53,7 +53,7 @@
# knowledge of the CeCILL and CeCILL-C licenses and that you accept its terms.
#
-cmake_minimum_required(VERSION 3.9)
+cmake_minimum_required(VERSION 3.5)
cmake_policy(SET CMP0046 OLD)
if(CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR)
diff --git a/src/CImg.h b/src/CImg.h
index 9c116d2..afd8694 100644
--- a/src/CImg.h
+++ b/src/CImg.h
@@ -3137,7 +3137,7 @@ namespace cimg_library_suffixed {
#if defined(cimg_use_fftw3)
static struct FFTW3_info {
FFTW3_info() {
- fftw_init_threads();
+// fftw_init_threads();
}
} _FFTW3_info;
#endif
......@@ -114,6 +114,7 @@ xsi:schemaLocation="http://www.kde.org/standards/kxmlgui/1.0 http://www.kde.org
<text>&amp;Snap To</text>
<Action name="view_snap_to_guides"/>
<Action name="view_snap_to_grid"/>
<Action name="view_snap_to_pixel"/>
<Action name="view_snap_orthogonal" />
<Action name="view_snap_node" />
<Action name="view_snap_extension" />
......
......@@ -866,6 +866,17 @@
<statusTip></statusTip>
</Action>
<Action name="view_snap_to_pixel">
<icon></icon>
<text>Snap Pixel</text>
<whatsThis></whatsThis>
<toolTip>Snap Pixel</toolTip>
<iconText>Snap Pixel</iconText>
<activationFlags>1000</activationFlags>
<shortcut></shortcut>
<isCheckable>true</isCheckable>
<statusTip></statusTip>
</Action>
<Action name="view_snap_intersection">
<icon></icon>
<text>Snap Intersection</text>
......
......@@ -407,7 +407,7 @@ extern "C" int main(int argc, char **argv)
if (singleApplication && app.isRunning()) {
// only pass arguments to main instance if they are not for batch processing
// any batch processing would be done in this separate instance
const bool batchRun = args.exportAs();
const bool batchRun = args.exportAs() || args.exportSequence();
if (!batchRun) {
QByteArray ba = args.serialize();
......
......@@ -313,7 +313,7 @@ void KoPathShapeLoaderPrivate::parseSvg(const QString &s, bool process)
lastCommand = command;
if (*ptr == '+' || *ptr == '-' || (*ptr >= '0' && *ptr <= '9')) {
if (*ptr == '+' || *ptr == '-' || *ptr == '.' || (*ptr >= '0' && *ptr <= '9')) {
// there are still coords in this command
if (command == 'M')
command = 'L';
......
......@@ -69,7 +69,8 @@ public:
GuideLineSnapping = 0x40,
DocumentBoundsSnapping = 0x80,
DocumentCenterSnapping = 0x100,
CustomSnapping = 0x200
CustomSnapping = 0x200,
PixelSnapping = 0x400
};
Q_DECLARE_FLAGS(Strategies, Strategy)
......
......@@ -1348,8 +1348,33 @@ QList<KoShape*> SvgParser::parseSvg(const KoXmlElement &e, QSizeF *fragmentSize)
const QString w = e.attribute("width");
const QString h = e.attribute("height");
const qreal width = w.isEmpty() ? 666.0 : parseUnitX(w);
const qreal height = h.isEmpty() ? 555.0 : parseUnitY(h);
qreal width = w.isEmpty() ? 666.0 : parseUnitX(w);
qreal height = h.isEmpty() ? 555.0 : parseUnitY(h);
if (w.isEmpty() || h.isEmpty()) {
QRectF viewRect;
QTransform viewTransform_unused;
QRectF fakeBoundingRect(0.0, 0.0, 1.0, 1.0);
if (SvgUtil::parseViewBox(e, fakeBoundingRect,
&viewRect, &viewTransform_unused)) {
QSizeF estimatedSize = viewRect.size();
if (estimatedSize.isValid()) {
if (!w.isEmpty()) {
estimatedSize = QSizeF(width, width * estimatedSize.height() / estimatedSize.width());
} else if (!h.isEmpty()) {
estimatedSize = QSizeF(height * estimatedSize.width() / estimatedSize.height(), height);
}
width = estimatedSize.width();
height = estimatedSize.height();
}
}
}
QSizeF svgFragmentSize(QSizeF(width, height));
......@@ -1408,7 +1433,7 @@ void SvgParser::applyViewBoxTransform(const KoXmlElement &element)
QRectF viewRect = gc->currentBoundingBox;
QTransform viewTransform;
if (SvgUtil::parseViewBox(gc, element, gc->currentBoundingBox,
if (SvgUtil::parseViewBox(element, gc->currentBoundingBox,
&viewRect, &viewTransform)) {
gc->matrix = viewTransform * gc->matrix;
......
......@@ -144,12 +144,10 @@ void SvgUtil::writeTransformAttributeLazy(const QString &name, const QTransform
}
}
bool SvgUtil::parseViewBox(SvgGraphicsContext *gc, const KoXmlElement &e,
bool SvgUtil::parseViewBox(const KoXmlElement &e,
const QRectF &elementBounds,
QRectF *_viewRect, QTransform *_viewTransform)
{
Q_UNUSED(gc)
KIS_ASSERT(_viewRect);
KIS_ASSERT(_viewTransform);
......
......@@ -92,7 +92,7 @@ public:
static void writeTransformAttributeLazy(const QString &name, const QTransform &transform, KoXmlWriter &shapeWriter);
/// Parses a viewbox attribute into an rectangle
static bool parseViewBox(SvgGraphicsContext *gc, const KoXmlElement &e, const QRectF &elementBounds, QRectF *_viewRect, QTransform *_viewTransform);
static bool parseViewBox(const KoXmlElement &e, const QRectF &elementBounds, QRectF *_viewRect, QTransform *_viewTransform);
struct PreserveAspectRatioParser;
static void parseAspectRatio(const PreserveAspectRatioParser &p, const QRectF &elementBounds, const QRectF &viewRect, QTransform *_viewTransform);
......
......@@ -539,13 +539,13 @@ Node* Node::duplicate()
return new Node(d->image, d->node->clone());
}
bool Node::save(const QString &filename, double xRes, double yRes, const InfoObject &exportConfiguration)
bool Node::save(const QString &filename, double xRes, double yRes, const InfoObject &exportConfiguration, const QRect &exportRect)
{
if (!d->node) return false;
if (filename.isEmpty()) return false;
KisPaintDeviceSP projection = d->node->projection();
QRect bounds = d->node->exactBounds();
QRect bounds = (exportRect.isEmpty())? d->node->exactBounds() : exportRect;
QString mimeType = KisMimeDatabase::mimeTypeForFile(filename, false);
QScopedPointer<KisDocument> doc(KisPart::instance()->createDocument());
......
......@@ -481,10 +481,13 @@ public Q_SLOTS:
* @param xRes the horizontal resolution in pixels per pt (there are 72 pts in an inch)
* @param yRes the horizontal resolution in pixels per pt (there are 72 pts in an inch)
* @param exportConfiguration a configuration object appropriate to the file format.
* @param exportRect the export bounds for saving a node as a QRect
* If \p exportRect is empty, then save exactBounds() of the node. If you'd like to save the image-
* aligned area of the node, just pass image->bounds() there.
* See Document->exportImage for InfoObject details.
* @return true if saving succeeded, false if it failed.
*/
bool save(const QString &filename, double xRes, double yRes, const InfoObject &exportConfiguration);
bool save(const QString &filename, double xRes, double yRes, const InfoObject &exportConfiguration, const QRect &exportRect = QRect());
/**
* @brief mergeDown merges the given node with the first visible node underneath this node in the layerstack.
......
......@@ -43,6 +43,7 @@ set(kritaui_LIB_SRCS
canvas/kis_snap_config.cpp
canvas/kis_snap_line_strategy.cpp
canvas/KisSnapPointStrategy.cpp
canvas/KisSnapPixelStrategy.cpp
canvas/KisMirrorAxisConfig.cpp
dialogs/kis_about_application.cpp
dialogs/kis_dlg_adj_layer_props.cc
......
/*
* Copyright (c) 2019 Kuntal Majumder <hellozee@disroot.org>
*
* This library 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.1 of the License.
*
* This library 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 Lesser 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 "KisSnapPixelStrategy.h"
#include <QPainterPath>
#include "kis_global.h"
#include "kis_canvas2.h"
#include "KoSnapProxy.h"
KisSnapPixelStrategy::KisSnapPixelStrategy(KoSnapGuide::Strategy type):
KoSnapStrategy(type)
{
}
KisSnapPixelStrategy::~KisSnapPixelStrategy()
{
}
bool KisSnapPixelStrategy::snap(const QPointF &mousePosition, KoSnapProxy *proxy, qreal maxSnapDistance)
{
Q_UNUSED(maxSnapDistance);
KisCanvas2 *canvas2 = dynamic_cast<KisCanvas2*>(proxy->canvas());
KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(canvas2, false);
const QPointF imagePos = canvas2->coordinatesConverter()->documentToImage(mousePosition);
const QPointF alignedDocPoint = canvas2->coordinatesConverter()->imageToDocument(imagePos.toPoint());
setSnappedPosition(alignedDocPoint);
return true;
}
QPainterPath KisSnapPixelStrategy::decoration(const KoViewConverter &converter) const
{
QSizeF unzoomedSize = converter.viewToDocument(QSizeF(5, 5));
QPainterPath decoration;
decoration.moveTo(snappedPosition() - QPointF(unzoomedSize.width(), 0));
decoration.lineTo(snappedPosition() + QPointF(unzoomedSize.width(), 0));
decoration.moveTo(snappedPosition() - QPointF(0, unzoomedSize.height()));
decoration.lineTo(snappedPosition() + QPointF(0, unzoomedSize.height()));
return decoration;
}
/*
* Copyright (c) 2019 Kuntal Majumder <hellozee@disroot.org>
*
* 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_SNAP_PIXEL_STRATEGY_H
#define __KIS_SNAP_PIXEL_STRATEGY_H
#include <QScopedPointer>
#include "KoSnapStrategy.h"
class KisSnapPixelStrategy : public KoSnapStrategy
{
public:
KisSnapPixelStrategy(KoSnapGuide::Strategy type = KoSnapGuide::PixelSnapping);
~KisSnapPixelStrategy() override;
bool snap(const QPointF &mousePosition, KoSnapProxy * proxy, qreal maxSnapDistance) override;
QPainterPath decoration(const KoViewConverter &converter) const override;
};
#endif /* __KIS_SNAP_PIXEL_STRATEGY_H */
......@@ -97,6 +97,8 @@
#include "kis_algebra_2d.h"
#include "kis_image_signal_router.h"
#include "KisSnapPixelStrategy.h"
class Q_DECL_HIDDEN KisCanvas2::KisCanvas2Private
{
......@@ -207,6 +209,7 @@ KisCanvas2::KisCanvas2(KisCoordinatesConverter *coordConverter, KoCanvasResource
m_d->frameRenderStartCompressor.setDelay(1000 / config.fpsLimit());
m_d->frameRenderStartCompressor.setMode(KisSignalCompressor::FIRST_ACTIVE);
snapGuide()->overrideSnapStrategy(KoSnapGuide::PixelSnapping, new KisSnapPixelStrategy());
}
void KisCanvas2::setup()
......
......@@ -211,6 +211,7 @@ void KisGuidesManager::syncActionsStatus()
m_d->syncAction("view_snap_bounding_box", m_d->snapConfig.boundingBox());
m_d->syncAction("view_snap_image_bounds", m_d->snapConfig.imageBounds());
m_d->syncAction("view_snap_image_center", m_d->snapConfig.imageCenter());
m_d->syncAction("view_snap_to_pixel",m_d->snapConfig.toPixel());
}
void KisGuidesManager::Private::updateSnappingStatus(const KisGuidesConfig &value)
......@@ -236,6 +237,7 @@ void KisGuidesManager::Private::updateSnappingStatus(const KisGuidesConfig &valu
snapGuide->enableSnapStrategy(KoSnapGuide::BoundingBoxSnapping, snapConfig.boundingBox());
snapGuide->enableSnapStrategy(KoSnapGuide::DocumentBoundsSnapping, snapConfig.imageBounds());
snapGuide->enableSnapStrategy(KoSnapGuide::DocumentCenterSnapping, snapConfig.imageCenter());
snapGuide->enableSnapStrategy(KoSnapGuide::PixelSnapping, snapConfig.toPixel());
snapConfig.saveStaticData();
}
......@@ -332,6 +334,9 @@ void KisGuidesManager::setup(KisActionManager *actionManager)
action = actionManager->createAction("view_snap_image_center");
connect(action, SIGNAL(toggled(bool)), this, SLOT(setSnapImageCenter(bool)));
action = actionManager->createAction("view_snap_to_pixel");
connect(action, SIGNAL(toggled(bool)), this, SLOT(setSnapToPixel(bool)));
m_d->updateSnappingStatus(m_d->guidesConfig);
syncActionsStatus();
}
......@@ -746,6 +751,7 @@ void KisGuidesManager::slotShowSnapOptions()
menu.addSection(i18n("Snap to:"));
menu.addAction(m_d->createShortenedAction(i18n("Grid"), "view_snap_to_grid", &menu));
menu.addAction(m_d->createShortenedAction(i18n("Guides"), "view_snap_to_guides", &menu));
menu.addAction(m_d->createShortenedAction(i18n("Pixel"), "view_snap_to_pixel", &menu));
menu.addAction(m_d->createShortenedAction(i18n("Orthogonal"), "view_snap_orthogonal", &menu));
menu.addAction(m_d->createShortenedAction(i18n("Node"), "view_snap_node", &menu));
......@@ -800,3 +806,9 @@ void KisGuidesManager::setSnapImageCenter(bool value)
m_d->snapConfig.setImageCenter(value);
m_d->updateSnappingStatus(m_d->guidesConfig);
}
void KisGuidesManager::setSnapToPixel(bool value)
{
m_d->snapConfig.setToPixel(value);
m_d->updateSnappingStatus(m_d->guidesConfig);
}
......@@ -74,6 +74,7 @@ public Q_SLOTS:
void setSnapBoundingBox(bool value);
void setSnapImageBounds(bool value);
void setSnapImageCenter(bool value);
void setSnapToPixel(bool value);
void slotUploadConfigToDocument();
......
......@@ -27,7 +27,8 @@ KisSnapConfig::KisSnapConfig(bool loadValues)
m_intersection(false),
m_boundingBox(false),
m_imageBounds(true),
m_imageCenter(true)
m_imageCenter(true),
m_toPixel(false)
{
if (loadValues) {
loadStaticData();
......
......@@ -75,6 +75,13 @@ public:
m_imageCenter = value;
}
bool toPixel() const {
return m_toPixel;
}
void setToPixel(bool value) {
m_toPixel = value;
}
void saveStaticData() const;
void loadStaticData();
......@@ -86,6 +93,7 @@ private:
bool m_boundingBox;
bool m_imageBounds;
bool m_imageCenter;
bool m_toPixel;
};
#endif /* __KIS_SNAP_CONFIG_H */
......@@ -853,6 +853,7 @@ void KisConfig::loadSnapConfig(KisSnapConfig *config, bool defaultValue) const
config->setBoundingBox(m_cfg.readEntry("globalSnapBoundingBox", defaultConfig.boundingBox()));
config->setImageBounds(m_cfg.readEntry("globalSnapImageBounds", defaultConfig.imageBounds()));
config->setImageCenter(m_cfg.readEntry("globalSnapImageCenter", defaultConfig.imageCenter()));
config->setToPixel(m_cfg.readEntry("globalSnapToPixel", defaultConfig.toPixel()));
}
void KisConfig::saveSnapConfig(const KisSnapConfig &config)
......@@ -864,6 +865,7 @@ void KisConfig::saveSnapConfig(const KisSnapConfig &config)
m_cfg.writeEntry("globalSnapBoundingBox", config.boundingBox());
m_cfg.writeEntry("globalSnapImageBounds", config.imageBounds());
m_cfg.writeEntry("globalSnapImageCenter", config.imageCenter());
m_cfg.writeEntry("globalSnapToPixel", config.toPixel());
}
qint32 KisConfig::checkSize(bool defaultValue) const
......
......@@ -78,6 +78,7 @@ void KisShadeSelectorLineComboBox::showPopup()
void KisShadeSelectorLineComboBox::setConfiguration(const QString &stri)
{
m_currentLine->fromString(stri);
update();
}
QString KisShadeSelectorLineComboBox::configuration() const
......
......@@ -57,9 +57,10 @@ KisShadeSelectorLineComboBoxPopup::KisShadeSelectorLineComboBoxPopup(QWidget* pa
layout->addWidget(new KisShadeSelectorLine(0.0, 0.5, 0.5, m_parentProxy.data(), this, -0.04));
layout->addWidget(new KisShadeSelectorLine(0.0, 0.5, 0.5, m_parentProxy.data(), this, +0.04));
layout->addWidget(new KisShadeSelectorLine(0.0, -0.5, 0.5, m_parentProxy.data(), this, -0.04));
layout->addWidget(new KisShadeSelectorLine(0.0, -0.5, 0.5, m_parentProxy.data(), this, +0.04));
m_lineEditor = new KisShadeSelectorLineEditor(this);
KisShadeSelectorLine* preview = new KisShadeSelectorLine(0.0, -0.5, 0.5, m_parentProxy.data(), this, +0.04);
m_lineEditor = new KisShadeSelectorLineEditor(this, preview);
layout->addWidget(preview);
layout->addWidget(m_lineEditor);
connect(m_lineEditor, SIGNAL(requestActivateLine(QWidget*)), SLOT(activateItem(QWidget*)));
......@@ -155,16 +156,16 @@ void KisShadeSelectorLineComboBoxPopup::mousePressEvent(QMouseEvent* e)
m_lineEditor->fromString(m_lastSelectedItem->toString());
m_lineEditor->blockSignals(false);
}
updateSelectedArea(m_highlightedArea);
} else {
if (m_lastSelectedItem) {
KisShadeSelectorLineComboBox *parent = dynamic_cast<KisShadeSelectorLineComboBox*>(this->parent());
Q_ASSERT(parent);
parent->setConfiguration(m_lastSelectedItem->toString());
}
hide();
}
if (m_lastSelectedItem) {
KisShadeSelectorLineComboBox *parent = dynamic_cast<KisShadeSelectorLineComboBox*>(this->parent());
Q_ASSERT(parent);
parent->setConfiguration(m_lastSelectedItem->toString());
}
e->accept();
this->parentWidget()->update();
hide();
}
......@@ -17,12 +17,15 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "kis_shade_selector_line_editor.h"
#include <QMouseEvent>
#include "kis_shade_selector_line_editor.h"
#include "kis_double_parse_spin_box.h"
#include "kis_config.h"
KisShadeSelectorLineEditor::KisShadeSelectorLineEditor(QWidget* parent)
KisShadeSelectorLineEditor::KisShadeSelectorLineEditor(QWidget* parent, KisShadeSelectorLine* preview)
: KisShadeSelectorLineBase(parent)
, m_line_preview(preview)
{
QVBoxLayout* layout = new QVBoxLayout(this);
......@@ -70,6 +73,20 @@ KisShadeSelectorLineEditor::KisShadeSelectorLineEditor(QWidget* parent)
connect(m_saturationShift, SIGNAL(valueChanged(double)), SLOT(valueChanged()));
connect(m_valueShift, SIGNAL(valueChanged(double)), SLOT(valueChanged()));
KConfigGroup cfg = KSharedConfig::openConfig()->group("advancedColorSelector");
QString lineset = cfg.readEntry(
"minimalShadeSelectorLineConfig", "0|0.2|0|0|0|0|0;1|0|1|1|0|0|0;2|0|-1|1|0|0|0;").split(";").at(0);
fromString(lineset);
updatePreview();
}
void KisShadeSelectorLineEditor::updatePreview(){
m_line_preview->setParam(
m_hueDelta->value(), m_saturationDelta->value(), m_valueDelta->value(),
m_hueShift->value(), m_saturationShift->value(), m_valueShift->value()
);
this->parentWidget()->update(m_line_preview->geometry());
}
QString KisShadeSelectorLineEditor::toString() const
......@@ -98,5 +115,11 @@ void KisShadeSelectorLineEditor::fromString(const QString &string)
}
void KisShadeSelectorLineEditor::valueChanged() {
updatePreview();
emit requestActivateLine(this);
}
void KisShadeSelectorLineEditor::mousePressEvent(QMouseEvent* e) {
e->accept();
}
......@@ -34,11 +34,16 @@ class KisDoubleParseSpinBox;
class KisShadeSelectorLineEditor : public KisShadeSelectorLineBase {
Q_OBJECT
public:
KisShadeSelectorLineEditor(QWidget* parent);
KisShadeSelectorLineEditor(QWidget* parent, KisShadeSelectorLine *preview);
QString toString() const override;
void fromString(const QString &string) override;
void mousePressEvent(QMouseEvent* e) override;
private:
void updatePreview();
private Q_SLOTS:
void valueChanged();
......@@ -46,6 +51,8 @@ Q_SIGNALS:
void requestActivateLine(QWidget *widget);
private:
KisShadeSelectorLine* m_line_preview;
KisDoubleParseSpinBox* m_hueDelta;
KisDoubleParseSpinBox* m_saturationDelta;
KisDoubleParseSpinBox* m_valueDelta;
......
......@@ -56,7 +56,7 @@ public Q_SLOTS:
QPoint position() const;
bool remove();
Node *duplicate() /Factory/;
void save(const QString &filename, double xRes, double yRes, const InfoObject & exportConfiguration);
void save(const QString &filename, double xRes, double yRes, const InfoObject & exportConfiguration, const QRect &exportRect = QRect());
Node *mergeDown() /Factory/;
void scaleNode(QPointF origin, int width, int height, QString strategy);
void rotateNode(double radians);
......
......@@ -302,8 +302,13 @@ bool QGIFLibHandler::write ( const QImage & image )
qWarning("EGifPutImageDesc returned error %d", gif->Error);
int lc = toWrite.height();
int llen = toWrite.bytesPerLine();
// NOTE: we suppose that the pixel size is exactly 1 byte, right now we
// cannot save anything else
int llen = toWrite.width();
// qDebug("will write %d lines, %d bytes each", lc, llen);
for (int l = 0; l < lc; ++l)
{
uchar* line = toWrite.scanLine(l);
......@@ -315,6 +320,7 @@ bool QGIFLibHandler::write ( const QImage & image )
}
EGifCloseFile(gif, &err);
free(colorValues);
return true;
}
......
......@@ -37,6 +37,7 @@
#include <kis_paint_layer.h>
#include <kis_paint_device.h>
#include <kis_config.h>
#include "kis_layer_utils.h"
#include "kis_tiff_converter.h"
#include "kis_dlg_options_tiff.h"
......@@ -70,6 +71,15 @@ KisImportExportFilter::ConversionStatus KisTIFFExport::convert(KisDocument *docu
KisTIFFOptions options;
options.fromProperties(configuration);
if (!options.flatten) {
const bool hasGroupLayers =
KisLayerUtils::recursiveFindNode(document->savingImage()->root(),
[] (KisNodeSP node) {
return node->parent() && node->inherits("KisGroupLayer");
});
options.flatten = hasGroupLayers;
}
if ((cs->channels()[0]->channelValueType() == KoChannelInfo::FLOAT16
|| cs->channels()[0]->channelValueType() == KoChannelInfo::FLOAT32) && options.predictor == 2) {
// FIXME THIS IS AN HACK FIX THAT IN 2.0 !! (62456a7b47636548c6507593df3e2bdf440f7544, BUG:135649)
......@@ -112,7 +122,6 @@ KisConfigWidget *KisTIFFExport::createConfigurationWidget(QWidget *parent, const
void KisTIFFExport::initializeCapabilities()
{
addCapability(KisExportCheckRegistry::instance()->get("NodeTypeCheck/KisGroupLayer")->create(KisExportCheckBase::UNSUPPORTED));
addCapability(KisExportCheckRegistry::instance()->get("MultiLayerCheck")->create(KisExportCheckBase::SUPPORTED));
addCapability(KisExportCheckRegistry::instance()->get("sRGBProfileCheck")->create(KisExportCheckBase::SUPPORTED));
......
......@@ -13,7 +13,7 @@
# https://creativecommons.org/publicdomain/zero/1.0/legalcode
from . import exportlayersdialog
from PyQt5.QtCore import Qt
from PyQt5.QtCore import (Qt, QRect)
from PyQt5.QtWidgets import (QFormLayout, QListWidget, QHBoxLayout,
QDialogButtonBox, QVBoxLayout, QFrame,
QPushButton, QAbstractScrollArea, QLineEdit,
......@@ -29,10 +29,11 @@ class UIExportLayers(object):
self.mainDialog = exportlayersdialog.ExportLayersDialog()
self.mainLayout = QVBoxLayout(self.mainDialog)
self.formLayout = QFormLayout()
self.resSpinBoxLayout = QFormLayout()
self.documentLayout = QVBoxLayout()
self.directorySelectorLayout = QHBoxLayout()
self.optionsLayout = QVBoxLayout()
self.resolutionLayout = QHBoxLayout()
self.rectSizeLayout = QHBoxLayout()
self.refreshButton = QPushButton(i18n("Refresh"))
self.widgetDocuments = QListWidget()
......@@ -43,9 +44,13 @@ class UIExportLayers(object):
self.batchmodeCheckBox = QCheckBox(i18n("Export in batchmode"))
self.ignoreInvisibleLayersCheckBox = QCheckBox(
i18n("Ignore invisible layers"))
self.xResSpinBox = QSpinBox()
self.yResSpinBox = QSpinBox()
self.cropToImageBounds = QCheckBox(
i18n("Adjust export size to layer content"))
self.rectWidthSpinBox = QSpinBox()
self.rectHeightSpinBox = QSpinBox()
self.formatsComboBox = QComboBox()
self.resSpinBox = QSpinBox()
self.buttonBox = QDialogButtonBox(
QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
......@@ -60,6 +65,7 @@ class UIExportLayers(object):
self.refreshButton.clicked.connect(self.refreshButtonClicked)
self.buttonBox.accepted.connect(self.confirmButton)
self.buttonBox.rejected.connect(self.mainDialog.close)
self.cropToImageBounds.stateChanged.connect(self._toggleCropSize)
self.mainDialog.setWindowModality(Qt.NonModal)
self.widgetDocuments.setSizeAdjustPolicy(
......@@ -68,8 +74,9 @@ class UIExportLayers(object):
def initialize(self):
self.loadDocuments()
self.xResSpinBox.setRange(1, 10000)
self.yResSpinBox.setRange(1, 10000)
self.rectWidthSpinBox.setRange(1, 10000)
self.rectHeightSpinBox.setRange(1, 10000)
self.resSpinBox.setRange(20, 1200)
self.formatsComboBox.addItem(i18n("JPEG"))
self.formatsComboBox.addItem(i18n("PNG"))
......@@ -83,15 +90,19 @@ class UIExportLayers(object):
self.optionsLayout.addWidget(self.exportFilterLayersCheckBox)
self.optionsLayout.addWidget(self.batchmodeCheckBox)
self.optionsLayout.addWidget(self.ignoreInvisibleLayersCheckBox)
self.optionsLayout.addWidget(self.cropToImageBounds)
self.resSpinBoxLayout.addRow(i18n("dpi:"), self.resSpinBox)
self.resolutionLayout.addWidget(self.xResSpinBox)
self.resolutionLayout.addWidget(self.yResSpinBox)
self.rectSizeLayout.addWidget(self.rectWidthSpinBox)
self.rectSizeLayout.addWidget(self.rectHeightSpinBox)
self.rectSizeLayout.addLayout(self.resSpinBoxLayout)
self.formLayout.addRow(i18n("Documents:"), self.documentLayout)
self.formLayout.addRow(
i18n("Initial directory:"), self.directorySelectorLayout)
self.formLayout.addRow(i18n("Export options:"), self.optionsLayout)
self.formLayout.addRow(i18n("Resolution:"), self.resolutionLayout)
self.formLayout.addRow(i18n("Export size:"), self.rectSizeLayout)
self.formLayout.addRow(
i18n("Images extensions:"), self.formatsComboBox)
......@@ -188,11 +199,16 @@ class UIExportLayers(object):
elif '[png]' in nodeName:
_fileFormat = 'png'
if self.cropToImageBounds.isChecked():
bounds = QRect()
else:
bounds = QRect(0, 0, self.rectWidthSpinBox.value(), self.rectHeightSpinBox.value())
layerFileName = '{0}{1}/{2}.{3}'.format(
self.directoryTextField.text(),
parentDir, node.name(), _fileFormat)
node.save(layerFileName, self.xResSpinBox.value(),
self.yResSpinBox.value(), krita.InfoObject())
node.save(layerFileName, self.resSpinBox.value() / 72.,
self.resSpinBox.value() / 72., krita.InfoObject(), bounds)
if node.childNodes():
self._exportLayers(node, fileFormat, newDir)
......@@ -207,5 +223,11 @@ class UIExportLayers(object):
def _setResolution(self, index):
document = self.documentsList[index]
self.xResSpinBox.setValue(document.width())
self.yResSpinBox.setValue(document.height())
self.rectWidthSpinBox.setValue(document.width())
self.rectHeightSpinBox.setValue(document.height())
self.resSpinBox.setValue(document.resolution())
def _toggleCropSize(self):
cropToLayer = self.cropToImageBounds.isChecked()
self.rectWidthSpinBox.setDisabled(cropToLayer)
self.rectHeightSpinBox.setDisabled(cropToLayer)
......@@ -411,7 +411,6 @@ ToolTransformArgs ToolTransformArgs::fromXML(const QDomElement &e)
KisDomUtils::loadValue(freeEl, "transformedCenter", &args.m_transformedCenter) &&
KisDomUtils::loadValue(freeEl, "originalCenter", &args.m_originalCenter) &&
KisDomUtils::loadValue(freeEl, "rotationCenterOffset", &args.m_rotationCenterOffset) &&
KisDomUtils::loadValue(freeEl, "transformAroundRotationCenter", &args.m_transformAroundRotationCenter) &&
KisDomUtils::loadValue(freeEl, "aX", &args.m_aX) &&
KisDomUtils::loadValue(freeEl, "aY", &args.m_aY) &&
......@@ -427,9 +426,14 @@ ToolTransformArgs ToolTransformArgs::fromXML(const QDomElement &e)
KisDomUtils::loadValue(freeEl, "keepAspectRatio", &args.m_keepAspectRatio) &&
KisDomUtils::loadValue(freeEl, "flattenedPerspectiveTransform", &args.m_flattenedPerspectiveTransform) &&
KisDomUtils::loadValue(freeEl, "filterId", &filterId);
// transformAroundRotationCenter is a new parameter introduced in Krita 4.0,
// so it might be not present in older transform masks
if (!KisDomUtils::loadValue(freeEl, "transformAroundRotationCenter", &args.m_transformAroundRotationCenter)) {
args.m_transformAroundRotationCenter = false;
}
if (result) {
args.m_filter = KisFilterStrategyRegistry::instance()->value(filterId);
result = (bool) args.m_filter;
......@@ -452,9 +456,12 @@ ToolTransformArgs ToolTransformArgs::fromXML(const QDomElement &e)
KisDomUtils::loadValue(warpEl, "alpha", &args.m_alpha);
if(args.m_mode == CAGE){
result = result &&
KisDomUtils::loadValue(warpEl, "pixelPrecision", &args.m_pixelPrecision) &&
KisDomUtils::loadValue(warpEl, "previewPixelPrecision", &args.m_previewPixelPrecision);
// Pixel precision is a parameter introduced in Krita 4.2, so we should
// expect it not being present in older files. In case it is not found,
// just use the defalt value initialized by c-tor (that is, do nothing).
(void) KisDomUtils::loadValue(warpEl, "pixelPrecision", &args.m_pixelPrecision);
(void) KisDomUtils::loadValue(warpEl, "previewPixelPrecision", &args.m_previewPixelPrecision);
}
if (result && warpType >= 0 && warpType < KisWarpTransformWorker::N_MODES) {
......@@ -475,7 +482,7 @@ ToolTransformArgs ToolTransformArgs::fromXML(const QDomElement &e)
KIS_ASSERT_RECOVER_NOOP(0 && "Unknown transform mode");
}
if (!result) {
KIS_SAFE_ASSERT_RECOVER(result) {
args = ToolTransformArgs();
}
......