Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
114 changes: 17 additions & 97 deletions TutorialMaker/Lib/Annotations.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,11 +113,9 @@ def penConfig(self, color, fontSize, thickness, brush = None, pen = None):
pass

def draw(self, painter : qt.QPainter = None, pen : qt.QPen = None, brush :qt.QBrush = None):
#Maybe we can organize this better
targetPos = [self.target["position"][0] - self.annotationOffset[0] + self.offsetX,
self.target["position"][1] - self.annotationOffset[1] + self.offsetY]

#Might as well do this then
targetSize = self.target["size"]


Expand Down Expand Up @@ -406,100 +404,8 @@ def __init__(self, BackgroundImage : qt.QPixmap, Metadata : dict, Annotations :
self.SlideLayout = "Screenshot"
self.SlideTitle = ""
self.SlideBody = ""
pass

def AddAnnotation(self, annotation : Annotation):
annotation.setOffset(self.windowOffset)
self.annotations.append(annotation)
pass

def FindWidgetsAtPos(self, posX, posY):
results = []

posX += self.windowOffset[0]
posY += self.windowOffset[1]

for widget in self.metadata:
rectX, rectY = widget["position"]
rectWidth, rectHeight = widget["size"]
if rectX <= posX <= rectX + rectWidth and rectY <= posY <= rectY + rectHeight:
results.append(widget)
return results

def FindAnnotationsAtPos(self, posX, posY):
results = []

for annotation in self.annotations:
rectX, rectY = annotation.boundingBoxTopLeft
rectWidth, rectHeight = annotation.getSelectionBoundingBoxSize()
if rectX <= posX <= rectX + rectWidth and rectY <= posY <= rectY + rectHeight:
results.append(annotation)

results.sort(reverse=True, key= lambda x: x.getSelectionBoundingBoxSize()[0]*x.getSelectionBoundingBoxSize()[1])
return results


def MapScreenToImage(self, qPos : qt.QPoint, qLabel : qt.QLabel):
imageSizeX = self.image.width()
imageSizeY = self.image.height()

labelWidth = qLabel.width
labelHeight = qLabel.height

x = Util.mapFromTo(qPos.x(), 0, labelWidth, 0, imageSizeX)
y = Util.mapFromTo(qPos.y(), 0, labelHeight, 0, imageSizeY)

return [x,y]

def MapImageToScreen(self, qPos : qt.QPoint, qLabel : qt.QLabel):
imageSizeX = self.image.width()
imageSizeY = self.image.height()

labelWidth = qLabel.width
labelHeight = qLabel.height

x = Util.mapFromTo(qPos.x(), 0, imageSizeX, 0, labelWidth)
y = Util.mapFromTo(qPos.y(), 0, imageSizeY, 0, labelHeight)

return [x,y]

def GetResized(self, resizeX : float = 0, resizeY : float = 0, keepAspectRatio=False) -> qt.QPixmap:
if resizeX <= 0 or resizeY <= 0:
return self.outputImage
if keepAspectRatio:
self.outputImage.scaled(resizeX, resizeY, qt.Qt.KeepAspectRatio, qt.Qt.SmoothTransformation)
return self.outputImage.scaled(resizeX, resizeY,qt.Qt.IgnoreAspectRatio, qt.Qt.SmoothTransformation)

def ReDraw(self):
del self.outputImage
self.outputImage = self.image.copy()
self.Draw()

def Draw(self):
painter = qt.QPainter(self.outputImage)
painter.setRenderHint(qt.QPainter.Antialiasing, True)
pen = qt.QPen()
brush = qt.QBrush()
for annotation in self.annotations:
annotation.draw(painter, pen, brush)
painter.end()

def __init__(self, BackgroundImage : qt.QPixmap, Metadata : dict, Annotations : list[Annotation] = None, WindowOffset : list[int] = None):

self.image = BackgroundImage
self.outputImage = self.image.copy()
self.metadata = Metadata
if Annotations is None:
Annotations = []
if WindowOffset is None:
WindowOffset = [0,0]
self.windowOffset = WindowOffset
self.annotations = Annotations
self.Active = True

self.SlideLayout = "Screenshot"
self.SlideTitle = ""
self.SlideBody = ""

self.devicePixelRatio = 1.0
pass

def AddAnnotation(self, annotation : Annotation):
Expand Down Expand Up @@ -616,10 +522,12 @@ def LoadAnnotatedTutorial(path):
slideImage : qt.QImage = None

tsParser = TutorialScreenshot()
devicePixelRatio = 1.0 # Default for backward compatibility
if slideData["SlideLayout"] == "Screenshot":
try:
tsParser.metadata = rawStepPath + ".json"
slideMetadata = tsParser.getWidgets()
devicePixelRatio = tsParser.getDevicePixelRatio()

slideImage = qt.QImage(rawStepPath + ".png")
except FileNotFoundError:
Expand All @@ -631,6 +539,9 @@ def LoadAnnotatedTutorial(path):
continue
tsParser.metadata = f"{stepPath}/{content}"
slideMetadata.extend(tsParser.getWidgets())
# Get DPR from the first metadata file found
if devicePixelRatio == 1.0:
devicePixelRatio = tsParser.getDevicePixelRatio()

slideImage = qt.QImage(f"{outputFolder}/Annotations/{slideData['ImagePath']}")
else:
Expand Down Expand Up @@ -660,7 +571,16 @@ def LoadAnnotatedTutorial(path):
)
annotation.PERSISTENT = True
annotations.append(annotation)
annotatedSlide = AnnotatorSlide(qt.QPixmap.fromImage(slideImage), slideMetadata, annotations)

pixmap = qt.QPixmap.fromImage(slideImage)
if devicePixelRatio > 1.0:
logicalWidth = int(pixmap.width() / devicePixelRatio)
logicalHeight = int(pixmap.height() / devicePixelRatio)
pixmap = pixmap.scaled(logicalWidth, logicalHeight, qt.Qt.KeepAspectRatio, qt.Qt.SmoothTransformation)
pixmap.setDevicePixelRatio(1.0)

annotatedSlide = AnnotatorSlide(pixmap, slideMetadata, annotations)
annotatedSlide.devicePixelRatio = 1.0
annotatedSlide.SlideTitle = textDict.get(slideData["SlideTitle"], "")
annotatedSlide.SlideBody = textDict.get(slideData["SlideDesc"], "")
annotatedSlide.SlideLayout = slideData["SlideLayout"]
Expand Down
10 changes: 4 additions & 6 deletions TutorialMaker/Lib/TutorialPainter.py
Original file line number Diff line number Diff line change
Expand Up @@ -517,8 +517,6 @@ def save_to_png(self, filename):
else:
print("Error: No view to save.")

# TODO: In that moment we will remove the translation and only show in English
# after define the infrastructre with Weblate or GitHub we will use community translation
def painter(self, metadata, screenshotData, language):

"""
Expand Down Expand Up @@ -619,13 +617,13 @@ def StartPaint(path,ListPositionWhite, ListoTotalImages):
if(cont < len(ListPositionWhite)-1):
cont = cont + 1
else:
screenshot = tutorial.steps[ListoTotalImages[i]].getImage()
screenshotData = tutorial.steps[ListoTotalImages[i]].getWidgets()
# Load the image
tutorialStep = tutorial.steps[ListoTotalImages[i]]
screenshot = tutorialStep.getImage()
screenshotData = tutorialStep.getWidgets()

image_drawer.load_image(screenshot)
image_drawer.painter(OutputAnnotator[annotateSteps], screenshotData, 'es')

# Save the view to a PNG file with a dynamic path
image_drawer.save_to_png(TutorialUtils.get_module_basepath("TutorialMaker") + '/Outputs/Translation/output_image_' + str(i) + '.png')

imgSS = imgSS + 1
Expand Down
30 changes: 28 additions & 2 deletions TutorialMaker/Lib/TutorialUtils.py
Original file line number Diff line number Diff line change
Expand Up @@ -727,6 +727,7 @@ def saveScreenshot(self, filename, window):

def saveAllWidgetsData(self, filename, window):
data = {}
data["_devicePixelRatio"] = slicer.app.desktop().devicePixelRatioF()
widgets = Util.getOnScreenWidgets(window)
for index in range(len(widgets)):
try:
Expand Down Expand Up @@ -817,13 +818,38 @@ def __init__(self, screenshot="", metadata=""):

def getImage(self):
image = qt.QImage(self.screenshot)
return qt.QPixmap.fromImage(image)
pixmap = qt.QPixmap.fromImage(image)

dpr = self.getDevicePixelRatio()
if dpr > 1.0:
logicalWidth = int(pixmap.width() / dpr)
logicalHeight = int(pixmap.height() / dpr)
pixmap = pixmap.scaled(logicalWidth, logicalHeight, qt.Qt.KeepAspectRatio, qt.Qt.SmoothTransformation)

pixmap.setDevicePixelRatio(1.0)
return pixmap
def getWidgets(self):
widgets = []
nWidgets = JSONHandler.parseJSON(self.metadata)
dpr = self.getDevicePixelRatio()

for keys in nWidgets:
widgets.append(nWidgets[keys])
if isinstance(keys, str) and keys.startswith("_"):
continue

widget = nWidgets[keys].copy() if hasattr(nWidgets[keys], 'copy') else dict(nWidgets[keys])

if dpr > 1.0:
widget["position"] = [widget["position"][0] / dpr, widget["position"][1] / dpr]
widget["size"] = [widget["size"][0] / dpr, widget["size"][1] / dpr]

widgets.append(widget)
return widgets

def getDevicePixelRatio(self):
"""Get the device pixel ratio saved with this screenshot, defaults to 1.0"""
nWidgets = JSONHandler.parseJSON(self.metadata)
return nWidgets.get("_devicePixelRatio", 1.0)

# TODO: REMOVE THIS, DEPRECATED
class JSONHandler:
Expand Down
Loading