浏览代码

Change Bleed Generator to a docker

Previously an extension that had to be called through the `Tools >
Scripts` menu. A docker makes more sense for this function, since it
does not require a very complicated UI, and is an action that a user
might want to repeat quickly.
cinaeco 4 年之前
父节点
当前提交
6f6c033334

+ 0 - 24
bleed_generator/Manual.html

@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!DOCTYPE html>
-
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head><title>Bleed Generator Documentation</title>
-</head>
-<body>
-<h3>Bleed Generator Documentation</h3>
-
-This extension creates artificial "bleed" on the edges of a given layer, by
-simply cloning the edges outward. This is mainly used for preparing images for
-double sided printing, such as print and play card games.
-
-Defaults to 2mm bleed on all sides, which is sufficient leeway for most
-printers.
-
-<h3>Usage</h3>
-
-Run the generator while having a paint layer selected. Bleed amount can be
-specified in millimetres, inches and pixels. "Offset" allows the use of pixel
-lines other than the edge. A "-1" offset means bleed will be copied from 1 line
-just inside the edge, "-2" means 2 lines in, etc.
-</body>
-</html>

+ 0 - 3
bleed_generator/__init__.py

@@ -1,3 +0,0 @@
-from .bleed_generator_extension import BleedGenerator
-
-Krita.instance().addExtension(BleedGenerator(Krita.instance()))

二进制
bleed_generator/__pycache__/__init__.cpython-38.pyc


二进制
bleed_generator/__pycache__/bleed_generator_extension.cpython-38.pyc


+ 0 - 154
bleed_generator/bleed_generator_extension.py

@@ -1,154 +0,0 @@
-from krita import *
-from PyQt5.QtWidgets import QDialog, QVBoxLayout, QHBoxLayout, QLabel, QLineEdit, QComboBox, QCheckBox, QPushButton
-from PyQt5.QtCore import *
-
-class BleedGenerator(Extension):
-
-    def __init__(self, parent):
-        super().__init__(parent)
-
-    # Krita.instance() exists, so do any setup work
-    def setup(self):
-        pass
-
-    # called after setup(self)
-    def createActions(self, window):
-        # Create menu item in Tools > Scripts.
-        action = window.createAction("bleedgen", "Bleed Generator")
-        action.triggered.connect(self.bleed_generator)
-
-    def bleed_generator(self):
-        # Get the current selected layer, called a 'node'
-        self.doc = Krita.instance().activeDocument()
-        self.layer = self.doc.activeNode()
-
-        # Create dialog.
-        newDialog = QDialog()
-        newDialog.setWindowTitle("Bleed Generator!")
-
-        desc = QLabel('Adds bleed to the active paint layer')
-        desc.setAlignment(Qt.AlignCenter)
-
-        # Count and unit inputs. Default to 2mm.
-        self.countInput = QLineEdit('2')
-        self.unitInput = QComboBox()
-        self.unitInput.addItems( ['mm', 'inch', 'px'] )
-        self.unitIndex = 0 # track current unit.
-        self.offsetInput = QLineEdit('0')
-
-        # Side selection
-        self.topCheck = QCheckBox('Top')
-        self.topCheck.setChecked(True)
-        self.botCheck = QCheckBox('Bottom')
-        self.botCheck.setChecked(True)
-        self.leftCheck = QCheckBox('Left')
-        self.leftCheck.setChecked(True)
-        self.rightCheck = QCheckBox('Right')
-        self.rightCheck.setChecked(True)
-
-        # Button!
-        goButton = QPushButton("Add Bleed")
-        goButton.setIcon( Krita.instance().icon('animation_play') )
-
-        # create layouts
-        row0 = QHBoxLayout()
-        row1 = QHBoxLayout()
-        row2 = QHBoxLayout()
-        row3 = QHBoxLayout()
-        row0.addWidget(desc)
-        row1.addWidget(QLabel('How much bleed:'))
-        row1.addWidget(self.countInput)
-        row1.addWidget(self.unitInput)
-        row1.addWidget(QLabel('Offset (0 = use edge):'))
-        row1.addWidget(self.offsetInput)
-        row2.addWidget(QLabel('Sides to bleed:'))
-        row2.addWidget(self.topCheck)
-        row2.addWidget(self.botCheck)
-        row2.addWidget(self.leftCheck)
-        row2.addWidget(self.rightCheck)
-
-        if self.layer.type() != 'paintlayer':
-            desc.setText('Please select a paint layer!')
-        else:
-            row3.addWidget(goButton)
-
-        layoutMain = QVBoxLayout()
-        layoutMain.addLayout(row0)
-        layoutMain.addLayout(row1)
-        layoutMain.addLayout(row2)
-        layoutMain.addLayout(row3)
-        newDialog.setLayout(layoutMain)
-
-        # hook up the actions.
-        goButton.clicked.connect( self.generateBleed )
-        # self.unitInput.currentIndexChanged.connect( self.convertCount )
-
-        # show the dialog.
-        newDialog.exec_()
-
-
-    ##########
-    # Slots
-    ##########
-
-    # Actually generates the bleed!
-    def generateBleed(self, e):
-
-        # Calculate how many lines of pixels to copy.
-        unit = self.unitInput.currentIndex()
-        count = float(self.countInput.text())
-        ppi = self.doc.resolution()
-        if unit == 0: # mm
-            count = count * (ppi / 24.5)
-        if unit == 1: # inch
-            count = count * ppi
-        offset = round(float(self.offsetInput.text()))
-        count = round(count) - offset
-        print("Pixel bleed amount: ", count)
-        print("Edge offset: ", offset)
-
-        # Copy lines for selected sides.
-        if self.topCheck.checkState():
-            bds = self.layer.bounds()
-            xpos = bds.left()
-            ypos = bds.top() - offset
-            len = bds.width()
-            bleedline = self.layer.pixelData(xpos, ypos, len, 1)
-            for c in range(1, count+1):
-                self.layer.setPixelData(bleedline, xpos, (ypos - c), len, 1)
-            print("Top lines cloned: ", count)
-        if self.botCheck.checkState():
-            bds = self.layer.bounds()
-            xpos = bds.left()
-            ypos = bds.bottom() + offset
-            len = bds.width()
-            bleedline = self.layer.pixelData(xpos, ypos, len, 1)
-            for c in range(1, count+1):
-                self.layer.setPixelData(bleedline, xpos, (ypos + c), len, 1)
-            print("Bottom lines cloned: ", count)
-        if self.leftCheck.checkState():
-            bds = self.layer.bounds()
-            xpos = bds.left() - offset
-            ypos = bds.top()
-            len = bds.height()
-            bleedline = self.layer.pixelData(xpos, ypos, 1, len)
-            for c in range(1, count+1):
-                self.layer.setPixelData(bleedline, (xpos - c), ypos, 1, len)
-            print("Left lines cloned: ", count)
-        if self.rightCheck.checkState():
-            bds = self.layer.bounds()
-            xpos = bds.right() + offset
-            ypos = bds.top()
-            len = bds.height()
-            bleedline = self.layer.pixelData(xpos, ypos, 1, len)
-            for c in range(1, count+1):
-                self.layer.setPixelData(bleedline, (xpos + c), ypos, 1, len)
-            print("Right lines cloned: ", count)
-
-
-        self.doc.refreshProjection()
-
-    # Convert count input values to relevant units
-    def convertCount():
-        unitIndex = unitInput.currentIndex()
-        print("Updated unit index: ", unitIndex)

+ 8 - 8
bleed_generator.desktop → bleed_generator_docker.desktop

@@ -1,8 +1,8 @@
-[Desktop Entry]
-Type=Service
-ServiceTypes=Krita/PythonPlugin
-X-KDE-Library=bleed_generator
-X-Python-2-Compatible=false
-X-Krita-Manual=Manual.html
-Name=Bleed Generator
-Comment=Creates bleed on image layers by cloning the pixels on the edges.
+[Desktop Entry]
+Type=Service
+ServiceTypes=Krita/PythonPlugin
+X-KDE-Library=bleed_generator_docker
+X-Python-2-Compatible=false
+X-Krita-Manual=Manual.html
+Name=Bleed Generator Docker
+Comment=Creates bleed on image layers by cloning the pixels on the edges.

+ 39 - 0
bleed_generator_docker/Manual.html

@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html>
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head><title>Bleed Generator Documentation</title>
+</head>
+<body>
+<h3>Bleed Generator Documentation</h3>
+
+<p>
+This docker creates artificial "bleed" on the edges of a given layer, by
+simply cloning the edges outward. This is mainly used for preparing images -
+such as playing cards - for double sided printing.
+</p>
+
+<p>
+Defaults to 24px (~2mm) bleed on all sides, which is sufficient leeway for most
+printers.
+</p>
+
+<h3>Usage</h3>
+
+<p>
+Select a paint layer, and press the "Add Bleed" button. Bleed amount can be
+specified in millimetres, inches and pixels. "Offset" allows the use of pixel
+lines other than the edge. A "-1" offset means bleed will be copied from 1 line
+just inside the edge, "-2" means 2 lines in, etc.
+</p>
+
+<h4>Warning!</h4>
+
+<p>
+Bleed Generator does not presently add Undo History entries! It is best to save
+before performing bleed operations, or be prepared to manually remove
+wrongly-applied bleed.
+</p>
+
+</body>
+</html>

+ 10 - 0
bleed_generator_docker/__init__.py

@@ -0,0 +1,10 @@
+from krita import DockWidgetFactory, DockWidgetFactoryBase
+from .bleed_generator_docker import BleedGenerator
+
+DOCKER_ID = 'bleed_generator'
+instance = Krita.instance()
+dock_widget_factory = DockWidgetFactory(DOCKER_ID,
+                                        DockWidgetFactoryBase.DockRight,
+                                        BleedGenerator)
+
+instance.addDockWidgetFactory(dock_widget_factory)

+ 198 - 0
bleed_generator_docker/bleed_generator_docker.py

@@ -0,0 +1,198 @@
+from krita import DockWidget
+from PyQt5.QtWidgets import QWidget, QDialog, QVBoxLayout, QHBoxLayout, QLabel, QLineEdit, QComboBox, QCheckBox, QPushButton
+
+DOCKER_TITLE = 'Bleed Generator'
+
+class BleedGenerator(DockWidget):
+
+    def __init__(self):
+        super().__init__()
+        self.setWindowTitle(DOCKER_TITLE)
+        widget = QWidget()
+        layout = QVBoxLayout()
+        widget.setLayout(layout)
+
+        layout.addSpacing(10)
+        layout.addWidget(QLabel('Adds bleed to the active paint layer.'))
+
+        # Count and unit inputs. Default to 24px (2mm at 300dpi).
+        self.countInput = QLineEdit('24')
+        self.unitInput = QComboBox()
+        self.unitInput.addItems( ['px', 'mm', 'inch'] )
+        row1 = QHBoxLayout()
+        row1.addWidget(QLabel('Bleed amount:'))
+        row1.addWidget(self.countInput)
+        row1.addWidget(self.unitInput)
+        layout.addLayout(row1)
+
+        # Option to bleed to boundaries.
+        self.bleedToBoundsCheck = QCheckBox('Bleed to nearest guides/boundaries')
+        self.bleedToBoundsCheck.setChecked(False)
+        layout.addWidget(self.bleedToBoundsCheck)
+
+        # Offset input i.e. how far from edge to start copying lines.
+        self.offsetInput = QLineEdit('0')
+        row2 = QHBoxLayout()
+        row2.addWidget(QLabel('Offset (0 = use edge):'))
+        row2.addWidget(self.offsetInput)
+        row2.addWidget(QLabel('px'))
+        layout.addLayout(row2)
+
+        # Side selection
+        self.topCheck = QCheckBox('Top')
+        self.topCheck.setChecked(True)
+        self.botCheck = QCheckBox('Bottom')
+        self.botCheck.setChecked(True)
+        self.leftCheck = QCheckBox('Left')
+        self.leftCheck.setChecked(True)
+        self.rightCheck = QCheckBox('Right')
+        self.rightCheck.setChecked(True)
+        layout.addWidget(QLabel('Sides to bleed:'))
+        row3 = QHBoxLayout()
+        row3.addWidget(self.topCheck)
+        row3.addWidget(self.botCheck)
+        row3.addWidget(self.leftCheck)
+        row3.addWidget(self.rightCheck)
+        layout.addLayout(row3)
+
+        # Button!
+        layout.addSpacing(20)
+        goButton = QPushButton("Add Bleed")
+        goButton.setIcon( Krita.instance().icon('animation_play') )
+        layout.addWidget(goButton)
+
+        # Add a stretch to prevent the rest of the content from stretching.
+        layout.addStretch()
+
+        # Add widget to the docker.
+        self.setWidget(widget)
+
+        # Hook up the action to the button.
+        goButton.clicked.connect( self.generateBleed )
+
+
+    # notifies when views are added or removed
+    # 'pass' means do not do anything
+    def canvasChanged(self, canvas):
+        pass
+
+
+    ##########
+    # Slots
+    ##########
+
+    # Actually generates the bleed.
+    def generateBleed(self, e):
+
+        # Get the current layer
+        self.doc = Krita.instance().activeDocument()
+        self.layer = self.doc.activeNode()
+        if self.layer.type() != 'paintlayer':
+            dialog = QDialog()
+            dialog.setWindowTitle("Paint Layer Required")
+            layout = QVBoxLayout()
+            layout.addWidget(QLabel('Bleed generator only works on paint layers. Please select one.'))
+            dialog.setLayout(layout)
+            dialog.exec_()
+            return
+        self.offset = round(float(self.offsetInput.text()))
+
+        # Calculate how many lines of pixels to copy for each side
+        amounts = self.calculateBleedAmounts()
+
+        # Copy lines for selected sides.
+        # Bounds are fetched each time as layer dimensions change.
+        if self.topCheck.checkState():
+            bds = self.layer.bounds()
+            xpos = bds.left()
+            ypos = bds.top() - self.offset
+            len = bds.width()
+            bleedline = self.layer.pixelData(xpos, ypos, len, 1)
+            for c in range(1, amounts['top']+1):
+                self.layer.setPixelData(bleedline, xpos, (ypos - c), len, 1)
+        if self.botCheck.checkState():
+            bds = self.layer.bounds()
+            xpos = bds.left()
+            ypos = bds.bottom() + self.offset
+            len = bds.width()
+            bleedline = self.layer.pixelData(xpos, ypos, len, 1)
+            for c in range(1, amounts['bottom']+1):
+                self.layer.setPixelData(bleedline, xpos, (ypos + c), len, 1)
+        if self.leftCheck.checkState():
+            bds = self.layer.bounds()
+            xpos = bds.left() - self.offset
+            ypos = bds.top()
+            len = bds.height()
+            bleedline = self.layer.pixelData(xpos, ypos, 1, len)
+            for c in range(1, amounts['left']+1):
+                self.layer.setPixelData(bleedline, (xpos - c), ypos, 1, len)
+        if self.rightCheck.checkState():
+            bds = self.layer.bounds()
+            xpos = bds.right() + self.offset
+            ypos = bds.top()
+            len = bds.height()
+            bleedline = self.layer.pixelData(xpos, ypos, 1, len)
+            for c in range(1, amounts['right']+1):
+                self.layer.setPixelData(bleedline, (xpos + c), ypos, 1, len)
+
+        # Refresh the view, or the cloned pixels will not be immediately shown.
+        self.doc.refreshProjection()
+
+
+    def calculateBleedAmounts(self):
+        amounts = {}
+        if self.bleedToBoundsCheck.checkState():
+            # Bleed amounts determined from boundaries.
+
+            # Get all boundaries.
+            vPoints = self.doc.horizontalGuides()
+            hPoints = self.doc.verticalGuides()
+            vPoints.insert(0, 0)
+            vPoints.append(self.doc.height())
+            vPoints.sort()
+            hPoints.insert(0, 0)
+            hPoints.append(self.doc.width())
+            hPoints.sort()
+            bds = self.layer.bounds()
+
+            # Calculate bleed from layer's edge to next relevant boundary.
+            prevV = 0
+            top = bds.top()
+            bottom = bds.bottom() + 1
+            for v in vPoints:
+                v = round(v)
+                if 'top' not in amounts and v >= top:
+                    amounts['top'] = top - prevV
+                if 'bottom' not in amounts and v > bottom:
+                    amounts['bottom'] = v - bottom
+                    break
+                prevV = v
+
+            prevH = 0
+            left = bds.left()
+            right = bds.right() + 1
+            for h in hPoints:
+                h = round(h)
+                if 'left' not in amounts and h >= left:
+                    amounts['left'] = left - prevH
+                if 'right' not in amounts and h > right:
+                    amounts['right'] = h - right
+                prevH = h
+
+        else:
+            # Bleed amounts based on the user's input.
+            unit = self.unitInput.currentIndex()
+            count = float(self.countInput.text())
+            ppi = self.doc.resolution()
+            if unit == 1: # mm
+                count = count * (ppi / 24.5)
+            if unit == 2: # inch
+                count = count * ppi
+            count = round(count) - self.offset
+            amounts['top'] = count
+            amounts['bottom'] = count
+            amounts['left'] = count
+            amounts['right'] = count
+
+        return amounts
+