Macro Snip/it

Snip

Descrizione
Macro per catturare facilmente screenshot di FreeCAD.

Versione macro: 1.07
Ultima modifica: 2019-08-05
Versione FreeCAD: Tutti
Download: ToolBar Icon
Autore: TheMarkster
Autore
TheMarkster
Download
ToolBar Icon
Link
Versione macro
1.07
Data ultima modifica
2019-08-05
Versioni di FreeCAD
Tutti
Scorciatoia
Su Windows: Windows Key + Shift + S

Su Mac: Command + Shift + 4
Su Linux: gnone-screenshot utility

Vedere anche
Macro Copia la vista 3D negli appunti
Macro Screen Wiki

Descrizione

Usare questa macro per pubblicare facilmente screenshot nel forum di FreeCAD.

Si può aggiungere questa macro alla barra degli strumenti delle macro personalizzate globali per un accesso rapido e semplice.

Quando si pubblica sul forum di FreeCAD, spesso è utile poter includere degli screenshot. Il problema è che si tratta di un compito un po' noioso. Questa macro mira quindi a semplificare un po' il compito.

Utilizzo

La macro può acquisire schermate oppure utilizzare schermate esistenti già copiate negli appunti di sistema. Per ignorare l'immagine già presente negli appunti, premere il tasto Shift mentre si richiama la macro. Per utilizzare la macro per acquisire la schermata, regolare le dimensioni e la posizione della finestra di dialogo che si apre, quindi fare clic su OK. Facendo clic su OK, la macro tenterà di acquisire una schermata dell'area dello schermo coperta dalla finestra di dialogo. La finestra di dialogo stessa è semitrasparente, quindi è possibile vederne il contenuto sottostante.

Notare come la finestra di dialogo sia semitrasparente. Verrà catturato solo il contenuto dello schermo sotto la finestra di dialogo.

Dopo aver cliccato su OK, la macro acquisisce lo screenshot e lo salva in un file temporaneo. Viene quindi aperta una finestra di dialogo per l'apertura del file nella posizione del file. È possibile trascinare il file da lì nel forum, nell'area di testo in cui si digita il testo per il post del forum. Annullando la finestra di dialogo, il file temporaneo dello screenshot viene eliminato automaticamente. È anche possibile aprire il file dello screenshot nell'applicazione predefinita installata per l'apertura di file .png (in Windows in genere è Paint). Questo può essere utile se si desidera aggiungere annotazioni allo screenshot o apportare modifiche aggiuntive, come il ritaglio.

Questa è la finestra di dialogo per aprire il file che appare automaticamente dopo aver acquisito lo screenshot. L'immagine può essere trascinata e rilasciata sul forum oppure aperta per un'ulteriore elaborazione nell'applicazione predefinita del sistema per l'apertura dei file PNG. In alternativa, si può fare clic con il pulsante destro del mouse sull'immagine e selezionare Apri con.. per utilizzare un'altra applicazione a scelta.

Se la macro per catturare screenshot non funziona sul sistema, può comunque essere utile per gli screenshot che sono stati catturati con altri strumenti. Copiare semplicemente lo screenshot negli appunti, quindi eseguire la macro. Verrà creato un file temporaneo e verrà aperta la cartella del file in una finestra di dialogo "Apri file". Altri strumenti per catturare screenshot:

Windows: Tasto Windows + Shift + S
MacOS: Command + Shift + 4
Linux: gnome-screenshot utility

Parametri

La macro supporta i parametri utente, che possono essere impostati tramite Strumenti → Modifica parametri... → Plugin → Snip_Macro

LastX, LastY, LastWidth, LastHeight: posizione e dimensione dell'ultimo utilizzo del riquardo di taglio
WindowOpacity (0.85): un valore compreso tra 0,0 (meno opaco) e 1,0 (più opaco)
SnipDelay (0.5): tempo (in secondi) di ritardo tra la chiusura del riquardo di ritaglio e il ritaglio
DesiredWidth (0): larghezza desiderata (in pixel), ignorata se 0 -- ridimensiona l'immagine alla dimensione desiderata mantenendo le proporzioni correnti
ScaleFactor (1.0): fattore di scala desiderato (sovrascrive DesiredWidth se ScaleFactor non è 1.0) -- ridimensiona l'immagine in base al fattore di scala

I parametri Last vengono reimpostati dalla macro ogni volta che viene eseguita. In questo modo, tiene traccia di dove posizionare il riquadro di cattura, ovvero l'ultima posizione in cui si trovava quando l'utente ha acquisito uno screenshot.

Il parametro WindowOpacity è l'opacità della casella di ritaglio.

Il parametro SnipDelay può essere regolato per velocizzare un po' le cose, ma se il valore è troppo piccolo, lo screenshot potrebbe includere la casella di ritaglio stessa, perché è necessario un intervallo di tempo per chiudere la finestra di dialogo prima di acquisire lo screenshot.

Il parametro DesiredWidth ridimensiona l'immagine alla larghezza desiderata, a meno che non sia 0 (impostazione predefinita), nel qual caso non viene effettuato alcun ridimensionamento. Ad esempio, se si imposta la larghezza desiderata a 800, si otterranno immagini larghe 800 pixel. L'altezza verrà ridimensionata automaticamente per mantenere le proporzioni correnti. Se l'immagine originale era 1600x1200 e DesiredWidth è 800, l'immagine risultante sarà 800x600.

Il parametro ScaleFactor ridimensiona l'immagine in base al rapporto desiderato, ad esempio 0,5. Il valore predefinito è 1,0, nel qual caso non viene eseguito alcun ridimensionamento. Questo valore sostituisce il parametro DesiredWidth se ScaleFactor non è 1,0.

È possibile ignorare tutti i ridimensionamenti tenendo premuto il tasto Ctrl mentre si fa clic sul pulsante Ok per acquisire lo screenshot.

Script

Icona della barra degli strumenti

Macro_Snip.FCMacro

# -*- coding: utf-8 -*-
"""
***************************************************************************
*   Copyright (c) 2019 <TheMarkster>                                      *
*                                                                         *
*   This file is a supplement to the FreeCAD CAx development system.      *
*                                                                         *
*   This program is free software; you can redistribute it and/or modify  *
*   it under the terms of the GNU Lesser General Public License (LGPL)    *
*   as published by the Free Software Foundation; either version 2 of     *
*   the License, or (at your option) any later version.                   *
*                                                                         *
*   This software is distributed in the hope that it will be useful,      *
*   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the          *
*   GNU Library General Public License at http://www.gnu.org/licenses     *
*   for more details.                                                     *
*                                                                         *
*   For more information about the GNU Library General Public License     *
*   write to the Free Software Foundation, Inc., 59 Temple Place,         *
*   Suite 330, Boston, MA  02111-1307 USA                                 *
*                                                                         *
***************************************************************************
"""



"""
Snip Macro

This is a macro to make it easier to post screenshots to the FreeCAD forum.

The forum supports a drag and drop interface -- just drag and drop an image to the
textarea where you type in your post. But it still requires many
tedious steps. This macro is to reduce some of those steps.

You should add the macro to your custom macro toolbar to save as many clicks as possible.

The first thing the macro does is to check if there is an image already saved to the
system clipboard, and if so, it uses that one. To bypass the clipboard, press Shift
while invoking the macro.

"""

__title__ = "Snip"
__author__ = "TheMarkster"
__url__ = ""
__Wiki__ = ""
__date__ = "2024.07.23"
__version__ = 1.3
import FreeCAD
from PySide import QtGui,QtCore
import uuid
import time
import tempfile, os, shutil

# class SnipBox(QtGui.QDialog):
#     def __init__(self, scale, desired_width):
#         QtGui.QDialog.__init__(self)
#         self.scale = scale
#         self.desired_width = desired_width
#
#         self.detailsTextEdit = QtGui.QTextEdit("Details")
#         self.Details = QtGui.QPushButton("Details")
#         self.Scaling = QtGui.QPushButton("Scaling")
#         self.Details.clicked.connect(self.onDetailsClicked)
#         self.Scaling.clicked.connect(self.onScalingClicked)
#         layout = QtGui.QVBoxLayout()
#         layout.addWidget(self.detailsTextEdit)
#         layout.addStretch()
#         buttons = QtGui.QDialogButtonBox(
#             QtGui.QDialogButtonBox.Ok,
#             QtCore.Qt.Horizontal, self)
#         buttons.accepted.connect(self.accept)
#         buttons.rejected.connect(self.reject)
#         buttons.addButton(self.Details, QtGui.QDialogButtonBox.ActionRole)
#         buttons.addButton(self.Scaling, QtGui.QDialogButtonBox.ActionRole)
#         buttons.setCenterButtons(True)
#         layout.addWidget(buttons)
#         self.setLayout(layout)
#         self.detailsTextEdit.setVisible(False)
#
#     def setDetailedText(self, txt):
#         self.detailsTextEdit.setText(txt)
#
#     def setTitle(self, rectwidth, rectheight):
#         if self.scale != 1.0:
#            out_width = rect.width()*scale_factor
#         elif self.desired_width != 0:
#             out_width = desired_width
#         self.setWindowTitle(f"Snip macro v{__version__} {rectwidth} x {rectheight} output width {out_width}")
#
#
#     def onDetailsClicked(self):
#         self.detailsTextEdit.setVisible(not self.detailsTextEdit.isVisible())
#
#     def onScalingClicked(self):
#         pass
#
#     def event(self, e): #credit serge_gubenko of stackoverflow for this
#         result = QtGui.QDialog.event(self, e)
#         self.setMinimumHeight(0)
#         self.setMaximumHeight(16777215)
#         self.setMinimumWidth(0)
#         self.setMaximumWidth(16777215)
#         self.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding)
#         textEdit = self.findChild(QtGui.QTextEdit)
#         if textEdit != None :
#             textEdit.setMinimumHeight(0)
#             textEdit.setMaximumHeight(16777215)
#             textEdit.setMinimumWidth(0)
#             textEdit.setMaximumWidth(16777215)
#             textEdit.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding)
# #thanks to mario52 for this
#         if result == True:
#             try:
#                 rect = mb.frameGeometry()
#                 rectwidth  = rect.width()
#                 rectheight = rect.height()
#                 mb.setTitle(rectwidth,rectheight)
#
#             except Exception:
#                 None
# ##############
#         return result
class SnipBox(QtGui.QDialog):
    def __init__(self, scale, desired_width):
        QtGui.QDialog.__init__(self)
        self.pg = FreeCAD.ParamGet("User parameter:Plugins/Snip_Macro")
        self.scale = scale
        self.desired_width = desired_width

        self.detailsTextEdit = QtGui.QTextEdit("Details")
        self.Details = QtGui.QPushButton("Details")
        self.Scaling = QtGui.QPushButton("Scaling")
        self.Details.clicked.connect(self.onDetailsClicked)
        self.Scaling.clicked.connect(self.onScalingClicked)

        layout = QtGui.QVBoxLayout()
        layout.addWidget(self.detailsTextEdit)
        layout.addStretch()

        # Scaling widgets
        self.scaleLabel = QtGui.QLabel("Scale:")
        self.scaleSpinBox = QtGui.QDoubleSpinBox()
        self.scaleSpinBox.setDecimals(2)
        self.scaleSpinBox.setSingleStep(0.1)
        self.scaleSpinBox.setValue(self.scale)
        self.scaleSpinBox.valueChanged.connect(self.updateScale)

        self.fixedWidthLabel = QtGui.QLabel("Fixed Width:")
        self.fixedWidthSpinBox = QtGui.QSpinBox()
        self.fixedWidthSpinBox.setRange(0, 10000)
        self.fixedWidthSpinBox.setValue(self.desired_width)
        self.fixedWidthSpinBox.valueChanged.connect(self.updateDesiredWidth)

        self.scaleLayout = QtGui.QVBoxLayout()
        self.scaleText = QtGui.QLabel("Scale values other than 1.0 will override fixed width setting")
        self.scaleLayout.addWidget(self.scaleText)
        scaleHBox1 = QtGui.QHBoxLayout()
        scaleHBox1.addWidget(self.scaleLabel)
        scaleHBox1.addWidget(self.scaleSpinBox)

        scaleHBox2 = QtGui.QHBoxLayout()
        scaleHBox2.addWidget(self.fixedWidthLabel)
        scaleHBox2.addWidget(self.fixedWidthSpinBox)

        self.scaleLayout.addLayout(scaleHBox1)
        self.scaleLayout.addLayout(scaleHBox2)

        self.scaleWidget = QtGui.QWidget()
        self.scaleWidget.setLayout(self.scaleLayout)
        self.scaleWidget.setVisible(False)

        layout.addWidget(self.scaleWidget)

        buttons = QtGui.QDialogButtonBox(
            QtGui.QDialogButtonBox.Ok,
            QtCore.Qt.Horizontal, self)
        buttons.accepted.connect(self.accept)
        buttons.rejected.connect(self.reject)
        buttons.addButton(self.Details, QtGui.QDialogButtonBox.ActionRole)
        buttons.addButton(self.Scaling, QtGui.QDialogButtonBox.ActionRole)
        buttons.setCenterButtons(True)
        layout.addWidget(buttons)
        self.setLayout(layout)
        self.detailsTextEdit.setVisible(False)

    def setDetailedText(self, txt):
        self.detailsTextEdit.setText(txt)

    def setTitle(self, rectwidth, rectheight):
        if self.scale != 1.0:
            out_width = rectwidth * self.scale
        elif self.desired_width != 0:
            out_width = self.desired_width
        self.setWindowTitle(f"Snip macro v{__version__} {rectwidth} x {rectheight} output width {out_width}")

    def onDetailsClicked(self):
        if self.scaleWidget.isVisible():
            self.scaleWidget.setVisible(False)
        self.detailsTextEdit.setVisible(not self.detailsTextEdit.isVisible())

    def onScalingClicked(self):
        if self.detailsTextEdit.isVisible():
            self.detailsTextEdit.setVisible(False)
        self.scaleWidget.setVisible(not self.scaleWidget.isVisible())

    def updateScale(self, value):
        self.scale = value
        self.pg.SetFloat("ScaleFactor", self.scale)

    def updateDesiredWidth(self, value):
        self.desired_width = value
        self.pg.SetInt("DesiredWidth", self.desired_width)

    def event(self, e): #credit serge_gubenko of stackoverflow for this
        result = QtGui.QDialog.event(self, e)
        self.setMinimumHeight(0)
        self.setMaximumHeight(16777215)
        self.setMinimumWidth(0)
        self.setMaximumWidth(16777215)
        self.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding)
        textEdit = self.findChild(QtGui.QTextEdit)
        if textEdit != None :
            textEdit.setMinimumHeight(0)
            textEdit.setMaximumHeight(16777215)
            textEdit.setMinimumWidth(0)
            textEdit.setMaximumWidth(16777215)
            textEdit.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding)
#thanks to mario52 for this
        if result == True:
            try:
                rect = mb.frameGeometry()
                rectwidth  = rect.width()
                rectheight = rect.height()
                mb.setTitle(rectwidth,rectheight)
            except Exception:
                None
##############
        return result

def get_screen_for_widget(widget):
    screen_geometry = widget.geometry()
    for screen in QtGui.QApplication.screens():
        if screen.geometry().contains(screen_geometry.center()):
            return screen
def get_widget_screen_coordinates(widget):
    screen = get_screen_for_widget(widget)
    widget_geometry = widget.geometry()
    screen_geometry = screen.geometry()
    return QtCore.QRect(widget_geometry.x() - screen_geometry.x(),
                        widget_geometry.y() - screen_geometry.y(),
                        widget_geometry.width(),
                        widget_geometry.height())


pg = FreeCAD.ParamGet("User parameter:Plugins/Snip_Macro")
#parameters were originally in BaseApp, but should be in Plugins, so relocate if necessary
if FreeCAD.ParamGet("User parameter:BaseApp/Preferences").HasGroup("Snip_Macro"):
    deprecated = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Snip_Macro")
    pg.SetInt("LastX",deprecated.GetInt("LastX",0))
    pg.SetInt("LastY",deprecated.GetInt("LastY",0))
    pg.SetInt("LastWidth",deprecated.GetInt("LastWidth",0))
    pg.SetInt("LastHeight",deprecated.GetInt("LastHeight",0))
    pg.SetFloat("WindowOpacity",deprecated.GetFloat("WindowOpacity",0.85))
    pg.SetFloat("SnipDelay",deprecated.GetFloat("SnipDelay",0.5))
    FreeCAD.ParamGet("User parameter:BaseApp/Preferences").RemGroup("Snip_Macro")

desired_width = pg.GetInt("DesiredWidth",0) #used for scaling to desired width, maintaining aspect ratio
pg.SetInt("DesiredWidth", desired_width)
scale_factor = pg.GetFloat("ScaleFactor", 1.0) #scale by scale factor instead of desired width
pg.SetFloat("ScaleFactor", scale_factor)

skipClipboard = False
modifiers = QtGui.QApplication.keyboardModifiers()
if modifiers == QtCore.Qt.ShiftModifier:
    skipClipboard = True

userCanceled = False
fname = "Snip macro screenshot-"+str(uuid.uuid4())[:6]+".png"
image = None
if not skipClipboard:
    clip = QtGui.QClipboard()
    image = clip.image(QtGui.QClipboard.Clipboard)
if not image:

    #use our own screen grabber
    mb = SnipBox(scale_factor, desired_width)
    details = """
Move and resize this box to cover the part of the screen you wish to grab.
If it succeeds an open file dialog will appear. Drag and drop the file
from the open file dialog to the forum. The file will be deleted after
you close the dialog.

If this fails you can still use this macro to handle screenshots you
copied to the clipboard using other tools:

Windows snip tool: Window Key + Shift + S
Mac snip tool: Command + Shift + 4
Linux: gnome-screenshot utility

If the macro finds there is already an image copied to the clipboard
it uses that image instead of bringing up this dialog. Press Shift
while invoking this macro to bypass the clipboard. Alternatively,
you can clear the image from the clipboard by copying some text to it.

The Open button will open the file in the system
default application for handling png files, e.g. Paint in windows. This
can be useful if you wish to annotate the screenshot. But most of the
time you will simply want to drag and drop the file to the forum, then
Cancel to close the open file dialog afterwards.

If you wish to open the screenshot file with another application, right-click
the file and select open with... option or drag/drop to that other application.

User Parameters: These can be accessed via Tools menu -> Edit Parameters in
Plugins -> Snip_Macro:

LastX, LastY, LastWidth, LastHeight -- location and size of snip box last use
WindowOpacity (0.85) -- value between 0.0 (less opaque) and 1.0 (more opaque)
SnipDelay (0.5) -- time (in seconds) delay between snip box close and snip
DesiredWidth -- image will be scaled to this width (unless it is 0) maintaining
current aspect ratio.
ScaleFactor -- float value, e.g. 0.5 -- image will be scaled to that scale factor.
Note: ScaleFactor (if not 1.0) will take precedence over DesiredWidth
Hold down Ctrl key to ignore scaling.

The SnipDelay parameter can be adjusted to speed things up a bit, but if it
is too small the screenshot taken might include the snip box itself because
we need to wait for it to close before taking the screenshot.

"""
   # mb.setWindowTitle("Snip macro v"+str(__version__))
    mb.setDetailedText(details)
    if pg.GetFloat("WindowOpacity",0.85) == 0.85:
        pg.SetFloat("WindowOpacity",0.85)
    mb.setWindowOpacity(pg.GetFloat("WindowOpacity",0.85))
    lastX = pg.GetInt("LastX",0)
    lastY = pg.GetInt("LastY",0)
    lastWidth = pg.GetInt("LastWidth",100)
    lastHeight = pg.GetInt("LastHeight",100)
    mb.setGeometry(lastX, lastY, lastWidth, lastHeight)
    mb.resize(lastWidth, lastHeight)
    mb.setWindowFlags(QtCore.Qt.Tool)
    result = mb.exec_()
    if not result:
        userCanceled = True
    if not userCanceled:
        clientRect = mb.geometry()
        scale_factor = mb.scale
        desired_width = mb.desired_width
        rect = get_widget_screen_coordinates(mb)
        diff = rect.height()-clientRect.height()
        pg.SetInt("LastX", rect.x())
        pg.SetInt("LastY", rect.y())
        pg.SetInt("LastWidth", rect.width())
        pg.SetInt("LastHeight", rect.height()-diff)
        QtGui.QApplication.processEvents()
        snipDelay = pg.GetFloat("SnipDelay", 0.5)
        if snipDelay == 0.5:
            pg.SetFloat("SnipDelay", 0.5)
        time.sleep(snipDelay) #give time for dialog to close before taking screenshot
        QtGui.QApplication.processEvents()
        if hasattr(QtGui.QApplication,"primaryScreen"):
            #screen = QtGui.QApplication.primaryScreen()
            screen = get_screen_for_widget(mb)
            image = screen.grabWindow(0,rect.x(),rect.y(),rect.width(),rect.height()).toImage()
        else:
            long_qdesktop_id = QtGui.QApplication.desktop().winId()
            image = QtGui.QPixmap.grabWindow(long_qdesktop_id, rect.x(), rect.y(), rect.width(), rect.height()).toImage()
        if not image:
            raise Exception("Snip Macro Error: Unable to grab screen image\n")
        modifiers = QtGui.QApplication.keyboardModifiers()
        skipScaling = False
        if modifiers == QtCore.Qt.ControlModifier:
            skipScaling = True
        if not skipScaling:
            if scale_factor != 1.0:
                image = image.smoothScaled(rect.width()*scale_factor, rect.height()*scale_factor)
            elif desired_width != 0:
                image = image.smoothScaled(desired_width, rect.height()*float(desired_width)/float(rect.width()))

if not userCanceled:
    dirPath = tempfile.mkdtemp()
    filePath = dirPath + os.path.sep + fname
    image.save(filePath)
    fileName = QtGui.QFileDialog.getOpenFileName(QtGui.QApplication.activeWindow(),
    "Drag the image to the forum, then Cancel will delete the temporary file", dirPath, "PNG (*.png)")
    if fileName[0]:  #user selected Open or double-clicked file
        import subprocess, os, platform
        if platform.system() == 'Darwin':       # macOS
            subprocess.call(('open', fileName[0]))
        elif platform.system() == 'Windows':    # Windows
            os.startfile(fileName[0])
        else:                                   # linux variants
            subprocess.call(('xdg-open', fileName[0]))
        QtGui.QApplication.processEvents() #allow some time for file to open before deleting temp folder and contents
        time.sleep(1)
        QtGui.QApplication.processEvents()
    shutil.rmtree(dirPath)

Link

La discussione sul forum Snip macro