diff --git a/TutorialMaker/Lib/Annotations.py b/TutorialMaker/Lib/Annotations.py index 85e767c..f6deeca 100644 --- a/TutorialMaker/Lib/Annotations.py +++ b/TutorialMaker/Lib/Annotations.py @@ -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"] @@ -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): @@ -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: @@ -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: @@ -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"] diff --git a/TutorialMaker/Lib/TutorialPainter.py b/TutorialMaker/Lib/TutorialPainter.py index 00d6e4b..7d8d539 100644 --- a/TutorialMaker/Lib/TutorialPainter.py +++ b/TutorialMaker/Lib/TutorialPainter.py @@ -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): """ @@ -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 diff --git a/TutorialMaker/Lib/TutorialUtils.py b/TutorialMaker/Lib/TutorialUtils.py index e79bbb1..0755fbf 100644 --- a/TutorialMaker/Lib/TutorialUtils.py +++ b/TutorialMaker/Lib/TutorialUtils.py @@ -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: @@ -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: