card_grid_generator_extension.py 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. from krita import Extension
  2. from PyQt5.QtWidgets import QDialog, QVBoxLayout, QHBoxLayout, QLabel, QLineEdit, QComboBox, QCheckBox, QPushButton
  3. from PyQt5.QtCore import Qt, QByteArray
  4. from math import floor
  5. class CardGridGenerator(Extension):
  6. def __init__(self, parent):
  7. super().__init__(parent)
  8. # Krita.instance() exists, so do any setup work
  9. def setup(self):
  10. pass
  11. # called after setup(self)
  12. def createActions(self, window):
  13. # Create menu item in Tools > Scripts.
  14. action = window.createAction("cardgridgen", "Card Grid Generator")
  15. action.triggered.connect(self.card_grid_generator)
  16. def card_grid_generator(self):
  17. # Dialog creation.
  18. newDialog = QDialog()
  19. newDialog.setWindowTitle("Card Grid Generator")
  20. layout = QVBoxLayout()
  21. newDialog.setLayout(layout)
  22. # Description row.
  23. desc = QLabel('Creates a grid of guides and cropmarks for a given card size.')
  24. desc.setAlignment(Qt.AlignCenter)
  25. row0 = QHBoxLayout()
  26. row0.addWidget(desc)
  27. layout.addLayout(row0)
  28. # Card dimension row.
  29. self.widthInput = QLineEdit('750')
  30. self.heightInput = QLineEdit('1050')
  31. self.unitInput = QComboBox()
  32. self.unitInput.addItems( ['px', 'mm', 'inch'] )
  33. row1 = QHBoxLayout()
  34. row1.addWidget(QLabel('Card size: W:'))
  35. row1.addWidget(self.widthInput)
  36. row1.addWidget(QLabel(' x H:'))
  37. row1.addWidget(self.heightInput)
  38. row1.addWidget(self.unitInput)
  39. layout.addLayout(row1)
  40. # Bleed dimension row. Also, guides or cropmarks selection.
  41. self.bleedInput = QLineEdit('24')
  42. self.guidesCheck = QCheckBox('Guides')
  43. self.guidesCheck.setChecked(True)
  44. self.cropmarksCheck = QCheckBox('Cropmarks')
  45. self.cropmarksCheck.setChecked(True)
  46. row2 = QHBoxLayout()
  47. row2.addWidget(QLabel('Bleed size:'))
  48. row2.addWidget(self.bleedInput)
  49. row2.addWidget(self.guidesCheck)
  50. row2.addWidget(self.cropmarksCheck)
  51. layout.addLayout(row2)
  52. # How many cards row.
  53. self.rowsInput = QLineEdit('0')
  54. self.colsInput = QLineEdit('0')
  55. self.maxCheck = QCheckBox('Max Possible')
  56. self.maxCheck.setChecked(True)
  57. row3 = QHBoxLayout()
  58. row3.addWidget(QLabel('Grid: Columns:'))
  59. row3.addWidget(self.colsInput)
  60. row3.addWidget(QLabel('Rows:'))
  61. row3.addWidget(self.rowsInput)
  62. row3.addWidget(self.maxCheck)
  63. layout.addLayout(row3)
  64. # Do It row.
  65. goButton = QPushButton("Create Card Grid")
  66. goButton.setIcon( Krita.instance().icon('animation_play') )
  67. row4 = QHBoxLayout()
  68. row4.addWidget(goButton)
  69. layout.addLayout(row4)
  70. # Hook up the actions.
  71. goButton.clicked.connect( self.generateCardGrid )
  72. # Show the dialog.
  73. newDialog.exec_()
  74. ##########
  75. # Slots
  76. ##########
  77. # Actually generates the card grid!
  78. def generateCardGrid(self, e):
  79. doc = Krita.instance().activeDocument()
  80. # If there is no open document, create a new one (A4 300ppi).
  81. if not doc:
  82. doc = Krita.instance().createDocument(3508, 2480, "Card Grid", "RGBA", "U8", "", 300.0)
  83. Krita.instance().activeWindow().addView(doc)
  84. # Document dimensions.
  85. docWidth = doc.width()
  86. docHeight = doc.height()
  87. # Card dimensions with bleed.
  88. bleedSize = int(self.bleedInput.text())
  89. cardWidth = int(self.widthInput.text())
  90. cardHeight = int(self.heightInput.text())
  91. cardBledWidth = cardWidth + bleedSize * 2
  92. cardBledHeight = cardHeight + bleedSize * 2
  93. # Determine layout.
  94. colCount = 0
  95. rowCount = 0
  96. if self.maxCheck.checkState():
  97. # Create the maximum-possible card layout
  98. colCount = floor(docWidth / cardBledWidth)
  99. rowCount = floor(docHeight / cardBledHeight)
  100. else:
  101. # Create card layout according to user specified rows and columns.
  102. colCount = int(self.colsInput.text())
  103. rowCount = int(self.rowsInput.text())
  104. # Calculate offset for centering.
  105. # Remainder pixels of row and column, divide by 2.
  106. # Bias odd pixel calculations to top left via floor.
  107. widthOffset = floor((docWidth - colCount * cardBledWidth) / 2)
  108. heightOffset = floor((docHeight - rowCount * cardBledHeight) / 2)
  109. # Create xSet and ySet (remember, both bleed + edge dimensions).
  110. # Also create Cards-Only sets for cropmarks.
  111. xSet = [widthOffset]
  112. ySet = [heightOffset]
  113. xSetCardsOnly = []
  114. ySetCardsOnly = []
  115. for i in range(colCount):
  116. base = widthOffset + i * cardBledWidth
  117. bleed1 = base + bleedSize
  118. card = bleed1 + cardWidth
  119. bleed2 = card + bleedSize
  120. # Cut down the number of guides if there is no bleed.
  121. xSet += [bleed1, card, bleed2] if bleedSize > 0 else [card]
  122. xSetCardsOnly += [bleed1, card] if bleedSize > 0 else [card]
  123. for i in range(rowCount):
  124. base = heightOffset + i * cardBledHeight
  125. bleed1 = base + bleedSize
  126. card = bleed1 + cardHeight
  127. bleed2 = card + bleedSize
  128. # Cut down the number of guides if there is no bleed.
  129. ySet +=[bleed1, card, bleed2] if bleedSize > 0 else [card]
  130. ySetCardsOnly += [bleed1, card] if bleedSize > 0 else [card]
  131. xSet.sort()
  132. ySet.sort()
  133. # Create guides. dump xSet ySet into guide functions.
  134. if self.guidesCheck.checkState():
  135. vList = doc.verticalGuides()
  136. hList = doc.horizontalGuides()
  137. vList.clear()
  138. hList.clear()
  139. doc.setVerticalGuides(xSet)
  140. doc.setHorizontalGuides(ySet)
  141. doc.setGuidesLocked(True)
  142. doc.setGuidesVisible(True)
  143. # Create cropmarks.
  144. if self.cropmarksCheck.checkState():
  145. # Cropmarks will be on a new layer.
  146. layer = doc.createNode('CardGridCropmarks', 'paintLayer')
  147. root = doc.rootNode()
  148. root.addChildNode(layer, None)
  149. # Create vertical cropmarks.
  150. blackPixel = b'\x00\x00\x00\xff'
  151. cropMarkWidth = 2
  152. cropMarkHeight = 48
  153. cropMark = QByteArray(blackPixel * cropMarkWidth * cropMarkHeight)
  154. for x in xSetCardsOnly:
  155. # top
  156. y = ySet[0] - cropMarkHeight
  157. layer.setPixelData(cropMark, x - 1, y, cropMarkWidth, cropMarkHeight)
  158. # bottom
  159. layer.setPixelData(cropMark, x - 1, ySet[-1], cropMarkWidth, cropMarkHeight)
  160. # Create horizontal cropmarks.
  161. cropMarkWidth = 48
  162. cropMarkHeight = 2
  163. cropMark = QByteArray(blackPixel * cropMarkWidth * cropMarkHeight)
  164. for y in ySetCardsOnly:
  165. # left
  166. x = xSet[0] - cropMarkWidth
  167. layer.setPixelData(cropMark, x, y - 1, cropMarkWidth, cropMarkHeight)
  168. # right
  169. layer.setPixelData(cropMark, xSet[-1], y - 1, cropMarkWidth, cropMarkHeight)
  170. # Refresh the view, or the cropmarks will not be immediately shown.
  171. doc.refreshProjection()