| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146 |
- 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
|