from krita import DockWidget from PyQt5.QtWidgets import QWidget, QDialog, QVBoxLayout, QHBoxLayout, QLabel, QLineEdit, QComboBox, QCheckBox, QPushButton DOCKER_TITLE = 'Page Slicer' class PageSlicer(DockWidget): def __init__(self): super().__init__() self.setWindowTitle(DOCKER_TITLE) widget = QWidget() layout = QVBoxLayout() widget.setLayout(layout) layout.addSpacing(10) layout.addWidget(QLabel('Slice up an image into segments using page guides.')) # Thresholds for ignoring segments. Defaults to 100px in both dimensions. # limitModes = ['<', '>'] self.widthInput = QLineEdit('100') # self.widthLimitMode = QComboBox() # self.widthLimitMode.addItems(limitModes) self.heightInput = QLineEdit('100') # self.heightLimitMode = QComboBox() # self.heightLimitMode.addItems(limitModes) layout.addWidget(QLabel('Segment-Ignore Thresholds:')) row1 = QHBoxLayout() row1.addWidget(QLabel('Width <')) # row1.addWidget(self.widthLimitMode) row1.addWidget(self.widthInput) row1.addWidget(QLabel('px')) layout.addLayout(row1) row2 = QHBoxLayout() row2.addWidget(QLabel('Height <')) # row2.addWidget(self.heightLimitMode) row2.addWidget(self.heightInput) row2.addWidget(QLabel('px')) layout.addLayout(row2) # Use image bounds or not self.useImageBoundsCheck = QCheckBox('Use Image Bounds') self.useImageBoundsCheck.setChecked(False) layout.addWidget(self.useImageBoundsCheck) # Button! layout.addSpacing(20) goButton = QPushButton("Slice") 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.slicePage ) # notifies when views are added or removed # 'pass' means do not do anything def canvasChanged(self, canvas): pass ########## # Slots ########## # Actually slices the page. def slicePage(self, e): # Get the current layer. doc = Krita.instance().activeDocument() root = doc.rootNode() layer = doc.activeNode() if layer.type() != 'paintlayer': dialog = QDialog() dialog.setWindowTitle("Paint Layer Required") layout = QVBoxLayout() layout.addWidget(QLabel('Page slicer only works on paint layers. Please select one.')) dialog.setLayout(layout) dialog.exec_() return # Get horizontal and vertical points. # Horizontal guides provide the Vertical y-axis points and vice versa. vPoints = doc.horizontalGuides() hPoints = doc.verticalGuides() # Add the edges of the image for segment calculation, if needed. useImageBounds = self.useImageBoundsCheck.checkState() if useImageBounds: vPoints.insert(0, 0) vPoints.append(doc.height()) hPoints.insert(0, 0) hPoints.append(doc.width()) # Sanitize points. Guide values are floats, and may contain unexpected # extra fractional values. vPoints = [round(v) for v in vPoints] vPoints.sort() hPoints = [round(h) for h in hPoints] hPoints.sort() # Check that there are enough vertical and horizontal points. # When using image bounds there must be at least 1 guide (V or H). # When not using image bounds, there must be at least 4 guides (2V, 2H). imageBoundsLimitFail = True if len(vPoints) + len(hPoints) < 5 else False nonImageBoundsLimitFail = True if len(vPoints) < 2 or len(hPoints) < 2 else False if (useImageBounds and imageBoundsLimitFail) or nonImageBoundsLimitFail: dialog = QDialog() dialog.setWindowTitle("Insufficient Guides!") layout = QVBoxLayout() if useImageBounds: layout.addWidget(QLabel('Have at least 1 horizontal or vertical guide.')) else: layout.addWidget(QLabel('Have at least 2 horizontal and 2 vertical guides.')) dialog.setLayout(layout) dialog.exec_() return # Find segments, row by row. startV = vPoints.pop(0) startH = hPoints.pop(0) prevV = startV count = 1 heightLimit = int(self.heightInput.text()) widthLimit = int(self.widthInput.text()) for v in vPoints: segHeight = v - prevV if segHeight >= heightLimit: prevH = startH for h in hPoints: segWidth = h - prevH if segWidth >= widthLimit: # Copy image data to new layer. segmentData = layer.pixelData(prevH, prevV, segWidth, segHeight) newLayer = doc.createNode('seg' + str(count), 'paintLayer') newLayer.setPixelData(segmentData, prevH, prevV, segWidth, segHeight) root.addChildNode(newLayer, None) count += 1 prevH = h prevV = v