bs_pnp_tools_docker.py 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. from krita import DockWidget
  2. from PyQt5.QtWidgets import QWidget, QDialog, QVBoxLayout, QHBoxLayout, QLabel, QComboBox, QCheckBox, QPushButton
  3. from PyQt5.QtCore import QByteArray
  4. DOCKER_TITLE = 'Button Shy PNP Tools'
  5. class BsPnpTools(DockWidget):
  6. def __init__(self):
  7. super().__init__()
  8. self.setWindowTitle(DOCKER_TITLE)
  9. widget = QWidget()
  10. layout = QVBoxLayout()
  11. widget.setLayout(layout)
  12. layout.addSpacing(10)
  13. layout.addWidget(QLabel('Expand the Button Shy 6-card PNP layout to 8-cards'))
  14. # Expand Direction. Do we put the 2 new cards on the left or right?
  15. self.expandDir = QComboBox()
  16. dirs = ['Right', 'Left']
  17. self.expandDir.addItems(dirs)
  18. row0 = QHBoxLayout()
  19. row0.addWidget(QLabel('Expand Direction:'))
  20. row0.addWidget(self.expandDir)
  21. layout.addLayout(row0)
  22. # Button (Shy)!
  23. layout.addSpacing(20)
  24. goButton = QPushButton("Expand")
  25. goButton.setIcon( Krita.instance().icon('animation_play') )
  26. layout.addWidget(goButton)
  27. crop3Button = QPushButton("Create 3x2 Cropmarks")
  28. crop3Button.setIcon( Krita.instance().icon('animation_play') )
  29. layout.addWidget(crop3Button)
  30. crop4Button = QPushButton("Create 4x2 Cropmarks")
  31. crop4Button.setIcon( Krita.instance().icon('animation_play') )
  32. layout.addWidget(crop4Button)
  33. self.outerCheck = QCheckBox('Outer')
  34. self.outerCheck.setChecked(True)
  35. self.innerCheck = QCheckBox('Inner')
  36. self.innerCheck.setChecked(True)
  37. self.guidesCheck = QCheckBox('Guides')
  38. self.guidesCheck.setChecked(True)
  39. row1 = QHBoxLayout()
  40. row1.addWidget(self.outerCheck)
  41. row1.addWidget(self.innerCheck)
  42. row1.addWidget(self.guidesCheck)
  43. layout.addLayout(row1)
  44. # Add a stretch to prevent the rest of the content from stretching.
  45. layout.addStretch()
  46. # Add widget to the docker.
  47. self.setWidget(widget)
  48. # Hook up the action to the button.
  49. goButton.clicked.connect( self.expandBsPnp )
  50. crop3Button.clicked.connect( self.add3x2CropMarks )
  51. crop4Button.clicked.connect( self.add4x2CropMarks )
  52. # notifies when views are added or removed
  53. # 'pass' means do not do anything
  54. def canvasChanged(self, canvas):
  55. pass
  56. ##########
  57. # Slots
  58. ##########
  59. # Actually expands the PNP.
  60. def expandBsPnp(self, e):
  61. # dialog = QDialog()
  62. # dialog.setWindowTitle("DEBUG")
  63. # layout = QVBoxLayout()
  64. # dialog.setLayout(layout)
  65. # Get the current layer.
  66. doc = Krita.instance().activeDocument()
  67. layer = doc.activeNode()
  68. if layer.type() != 'paintlayer':
  69. dialog = QDialog()
  70. dialog.setWindowTitle("Paint Layer Required")
  71. layout = QVBoxLayout()
  72. layout.addWidget(QLabel('Expander only works on paint layers. Please select one.'))
  73. dialog.setLayout(layout)
  74. dialog.exec_()
  75. return
  76. direction = self.expandDir.currentText()
  77. layerPos = layer.position()
  78. # Move layer 411 pixels left or right, which is half a card and gap width: (752 + 70) / 2
  79. xDiff = 411 if direction == 'Left' else -411
  80. layer.move(layerPos.x() + xDiff, layerPos.y())
  81. # Fill in empty document area with white
  82. overlapHCrop = 341 # x-offset to overwrite old horizontal crop marks.
  83. whitePixel = b'\xff\xff\xff\xff'
  84. bds = layer.bounds()
  85. fillX = 0 if direction == 'Left' else bds.right() - overlapHCrop
  86. fillY = 0
  87. fillWidth = bds.left() + overlapHCrop if direction == 'Left' else doc.width() - fillX
  88. fillHeight = doc.height()
  89. whiteFill = QByteArray(whitePixel * fillWidth * fillHeight)
  90. layer.setPixelData(whiteFill, fillX, fillY, fillWidth, fillHeight)
  91. # Create horizontal cropmarks at image edges.
  92. # Vertical distances (px): 1047 (38 midY 37) 1048
  93. # 61px long.
  94. blackPixel = b'\x00\x00\x00\xff'
  95. cropMarkWidth = 61
  96. cropMarkHeight = 2
  97. cropMark = QByteArray(blackPixel * cropMarkWidth * cropMarkHeight)
  98. midX = int(doc.width() / 2)
  99. midY = int(doc.height() / 2)
  100. ySet = [ midY - 1085, midY - 38, midY + 37, midY + 1085 ]
  101. for x in [midX - 1706, midX + 1645]:
  102. for y in ySet:
  103. layer.setPixelData(cropMark, x, y - 1, cropMarkWidth, cropMarkHeight)
  104. # Create vertical cropmarks for new card spaces
  105. # Horizontal distances (px): 752 70 752 (35 midX 35) 752 70 752
  106. # For these marks, we only want either the first or last 2 positions.
  107. # 37px long.
  108. cropMarkWidth = 2
  109. cropMarkHeight = 37
  110. cropMark = QByteArray(blackPixel * cropMarkWidth * cropMarkHeight)
  111. xSet = [ midX - 1609, midX - 857 ] if direction == 'Left' else [ midX + 857, midX + 1609 ]
  112. for y in [ midY - 1192, midY + 1155 ]:
  113. for x in xSet:
  114. layer.setPixelData(cropMark, x - 1, y, cropMarkWidth, cropMarkHeight)
  115. # Place guides on crop marks for new card spaces
  116. vList = doc.verticalGuides()
  117. hList = doc.horizontalGuides()
  118. vList.clear()
  119. hList.clear()
  120. doc.setVerticalGuides(xSet)
  121. doc.setHorizontalGuides(ySet)
  122. doc.setGuidesLocked(True)
  123. doc.setGuidesVisible(True)
  124. # Refresh the view, or the moved will not be immediately reflected.
  125. doc.refreshProjection()
  126. # Add 3x2 Internal cropmarks.
  127. def add3x2CropMarks(self, e):
  128. self.addCropMarks(3)
  129. # Add 4x2 Internal cropmarks.
  130. def add4x2CropMarks(self, e):
  131. self.addCropMarks(4)
  132. def addCropMarks(self, gridSize):
  133. # Cropmarks will be on a new layer.
  134. doc = Krita.instance().activeDocument()
  135. layer = doc.createNode('BSCropmarks', 'paintLayer')
  136. root = doc.rootNode()
  137. root.addChildNode(layer, None)
  138. # Calculate grid dimensions, assuming page is in centre position.
  139. midX = int(doc.width() / 2)
  140. midY = int(doc.height() / 2)
  141. xSet = []
  142. ySet = []
  143. if gridSize == 3:
  144. # Horizontal distances (px): 752 70 (376 midX 376) 70 752
  145. # Vertical distances (px): 1047 (38 midY 37) 1048
  146. xSet = [ midX - 1198, midX - 446, midX - 376, midX + 376, midX + 446, midX + 1198 ]
  147. ySet = [ midY - 1085, midY - 38, midY + 37, midY + 1085 ]
  148. else:
  149. # Horizontal distances (px): 752 70 752 (35 midX 35) 752 70 752
  150. # Vertical distances (px): 1047 (38 midY 37) 1048
  151. xSet = [ midX - 1609, midX - 857, midX - 787, midX - 35, midX + 35, midX + 787, midX + 857, midX + 1609 ]
  152. ySet = [ midY - 1085, midY - 38, midY + 37, midY + 1085 ]
  153. # Create inner and outer cropmarks.
  154. blackPixel = b'\x00\x00\x00\xff'
  155. cropMarkWidth = 2
  156. if self.outerCheck.checkState():
  157. cropMarkHeight = 48
  158. cropMark = QByteArray(blackPixel * cropMarkWidth * cropMarkHeight)
  159. for x in xSet:
  160. layer.setPixelData(cropMark, x-1, ySet[0]-35-48, cropMarkWidth, cropMarkHeight) # top vertical line
  161. layer.setPixelData(cropMark, x-1, ySet[-1]+35, cropMarkWidth, cropMarkHeight) # bottom vertical line
  162. for y in ySet:
  163. layer.setPixelData(cropMark, xSet[0]-35-48, y-1, cropMarkHeight, cropMarkWidth) # left horizontal line
  164. layer.setPixelData(cropMark, xSet[-1]+35, y-1, cropMarkHeight, cropMarkWidth) # right horizontal line
  165. if self.innerCheck.checkState():
  166. cropMarkHeight = 36
  167. cropMark = QByteArray(blackPixel * cropMarkWidth * cropMarkHeight)
  168. for x in xSet:
  169. for y in ySet:
  170. layer.setPixelData(cropMark, x-1, int(y - cropMarkHeight/2), cropMarkWidth, cropMarkHeight) # vertical line
  171. layer.setPixelData(cropMark, int(x - cropMarkHeight/2), y-1, cropMarkHeight, cropMarkWidth) # horizontal line
  172. # Create guides.
  173. if self.guidesCheck.checkState():
  174. vList = doc.verticalGuides()
  175. hList = doc.horizontalGuides()
  176. vList.clear()
  177. hList.clear()
  178. doc.setVerticalGuides(xSet)
  179. doc.setHorizontalGuides(ySet)
  180. doc.setGuidesLocked(True)
  181. doc.setGuidesVisible(True)
  182. # Refresh the view, or the cropmarks will not be immediately shown.
  183. doc.refreshProjection()