screenshot als Bild in PDF speichern

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
UniversalBastler
User
Beiträge: 17
Registriert: Samstag 1. August 2020, 12:08

Okay, das mit dem Zwischenspeichern war vielleicht von mir falsch ausgedrückt.
Natürlich muss der screenshot bzw. das Objekt oder Bild irgendwo im Speicher landen sonst könnte man es ja nicht in die PDF Schreiben.
Es ging aber darum, das nicht jedes mal auf die Festplatte zu schreiben.

@Sirius3
vielen Dank für die weitere Bereinigung des Codes. Zumindest das erste sleep(1) hätte ich gedacht, das es gebraucht wird weil angeblich der screenshot durchaus mehrere hundert Millisekunden brauchen kann. Aber es scheint auch so zu gehen :D
Dass ich die Variable screenshot1 gar nicht brauche erscheint mir (hinterher) auch klar.
Auf jeden Fall wieder was dazu gelernt :geek:
__deets__
User
Beiträge: 14540
Registriert: Mittwoch 14. Oktober 2015, 14:29

Du *schreibst* das doch jetzt auf die Festplatte. Du instruierst pyautogui das fuer dich zu machen, aber das ist auch der einzige Unterschied. Das wird *immer* noch auf die Platte geschrieben. Und vor allem auch in einen relativen Pfad, das heisst, dass die Datein irgendwo landen - und nicht kontrolliert zB im TEMP-Verzeichnis. Wenigstens dahingehend wuerde ich das Programm noch ueberarbeiten.
UniversalBastler
User
Beiträge: 17
Registriert: Samstag 1. August 2020, 12:08

Du *schreibst* das doch jetzt auf die Festplatte.
Ich habe es gerade auch festgestellt. :o
Aber das macht dann doch pyautogui.screenshot() selbstständig oder?
Na gut, dann soll es halt so sein :cry:
Wo das hingeschrieben wird habe ich im Griff, da kann ich einfach den Pfad mit angeben.
Sirius3
User
Beiträge: 17750
Registriert: Sonntag 21. Oktober 2012, 17:20

Wie schon geschrieben, muss man tief in die Klasse eingreifen, um das zu ändern.

Code: Alles auswählen

import pyautogui
from io import BytesIO
from fpdf import FPDF

class Fpdf(FPDF):
    def load_resource(self, reason, file):
        if hasattr(file, "read"):
            return file
        return FPDF.load_resource(self, reason, file)

pdf = Fpdf()
image = BytesIO()
screenshot1 = pyautogui.screenshot(region=(80,48, 880, 960))#screeshot der ersten Seite
screenshot1.save(inage, fornat="png")
image.seek(0)
pdf.add_page() #Seite wird dem PDF zugefügt
pdf.image(image,10, 40, 200, type="png") #screenshot wird auf der PDF Seite positioniert

pdf.output("PDF-Test3.pdf", "F") #fertiges PDF wird gespeichert
print("Fertig")
[/quote]
UniversalBastler
User
Beiträge: 17
Registriert: Samstag 1. August 2020, 12:08

Sorry, soweit bin ich noch nicht.
Trotzdem Danke :mrgreen:
Benutzeravatar
noisefloor
User
Beiträge: 3856
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

ReportLab ist mächtiger, weil es (viel) mehr Möglichkeiten hat. Aber deswegen ist es nicht wirklich komplizierter:

Code: Alles auswählen

>>> import pyautogui
>>> from reportlab.platypus import SimpleDocTemplate, Image
>>> from reportlab.lib.pagesizes import A4
>>> from io import BytesIO
>>> image = BytesIO()
>>> screenshot1 = pyautogui.screenshot(region=(80,48, 200, 200))
>>> screenshot1.save(image, format='png')
>>> doc = SimpleDocTemplate("image.pdf", pagesize=A4)
>>> story=[]
>>> story.append(Image(image))
>>> doc.build(story)
Das PDF mit den Screenshot ist dann im Verzeichnis, wo das Skript liegt, als "image.pdf" gespeichert.

Gruß, noisefloor
Benutzeravatar
__blackjack__
User
Beiträge: 13107
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@noisefloor: Kleine Korrektur: Das PDF ist dann im aktuellen Arbeitsverszeichnis gespeichert. Ob das das gleiche ist in dem das Skript liegt, hängt davon ab wie/von wo man das startet.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
UniversalBastler
User
Beiträge: 17
Registriert: Samstag 1. August 2020, 12:08

Hallo,
Vielen Dank aber ihr bringt mich an meine Grenzen :oops:
Also mit BytesIO und reportlap muss ich mich dann doch mal beschäftigen.
Ich bin eigentlich davon ausgegangen, dass mit screenshot1.save(image, format='png') das png Bild auf die Festplatte gespeichert wird, finde es aber nicht.
Oder liegt das an dem BytesIO ? Gut, muss ich mich erst einarbeiten.
Das reportlab muss ich auch tiefer eintauchen, das Bild (Screenshot eines halben Bildschirm's) kann sicher auch hier so skaliert werden, dass es auf eine A4 Seite passt.
Benutzeravatar
noisefloor
User
Beiträge: 3856
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,
Ich bin eigentlich davon ausgegangen, dass mit screenshot1.save(image, format='png') das png Bild auf die Festplatte gespeichert wird, finde es aber nicht.
Tut's auch. Das Bild sollte da liegen, wo das aktuelle Arbeitsverzeichnis des Skripts ist.
Oder liegt das an dem BytesIO ? Gut, muss ich mich erst einarbeiten.
Nein. Mit BytesIO erzeugst du ein "file-like object", also ein Objekt, was sich wie eine Datei verhält (aber nicht unbedingt eine ist). Mit BytesIO sparst du dir den Zwischenschritt des Speicherns auf ein Laufwerk, das Bild bzw. die "Datei" wird im Speicher gehalten.
Das reportlab muss ich auch tiefer eintauchen, das Bild (Screenshot eines halben Bildschirm's) kann sicher auch hier so skaliert werden, dass es auf eine A4 Seite passt.
Ja, aber nicht über ReportLab. Die Platypus.Image Klasse kennt keine Größenangaben. Das musst du vorher machen. PyAutoGUI.screenshot liefert dir ja ein PIL Objekt, das hat Methoden, um das Bild zu skalieren:

Code: Alles auswählen

>> from pyautogui import screenshot
>>> image = screenshot()
>>> image
<PIL.PngImagePlugin.PngImageFile image mode=RGB size=1366x768 at 0x7F6286F1C610>
>>> image.size
(1366, 768)
>>> image = image.resize((800, 450))
>>> image.size
(800, 450)
Gruß, noisefloor
Sirius3
User
Beiträge: 17750
Registriert: Sonntag 21. Oktober 2012, 17:20

@UniversalBastler: image ist ein BytesIO-Objekt, `save` speichert also nur was im Speicher und nicht auf Festplatte. Das ist doch das, was Du möchtest.

@noisefloor: resize verändert doch nur die Pixelanzahl und hat erstmal nichts damit zu tun, wie groß das Bild dann auf der PDF-Seite dargestellt wird.
Benutzeravatar
noisefloor
User
Beiträge: 3856
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

was ich oben bzgl. des Skalierens in `platypus.Image`gesagt habe ist auch nicht korrekt. Die Objekt-Klasse vom Image kennt Größenangaben:

Code: Alles auswählen

>>> story.append(Image(image, 800, 600))
skaliert das Bild direkt. Wobei man auch direkt auf eine bestimmte Größe in z.B. cm skalieren kann:

Code: Alles auswählen

...
from reportlab.lib.units import cm
from reportlab.platypus import Image
...
story.append(Image(image, 5*cm, 3*cm))
...
würde das Bild auf 5x3cm im PDF skalieren.

Gruß, noisefloor
UniversalBastler
User
Beiträge: 17
Registriert: Samstag 1. August 2020, 12:08

skaliert das Bild direkt. Wobei man auch direkt auf eine bestimmte Größe in z.B. cm skalieren kann:
Danke, das hilft mir ein ganzes Stück weiter.
In Verbindung mit bytesIO habe ich mein Programm jetzt fast komplett umgeschrieben und es funktioniert bis hierhin.
Jetzt muss ich nur noch beide Bildschirmhälften nacheinander scannen, und das in eine Schleife einbauen damit es mehrere Bildschirme/Seiten nacheinander bearbeitet.
Dazu muss ich aber erst in reportlab etwas tiefer eintauchen. Ich habe mich schon mal umgeschaut, aber nicht wirklich viel gefunden was ich mit meinen nur rudimentären Englischkenntnissen problemlos erfassen könnte. Hat jemand eine Quelle, ein Buch oder eine Webseite wo reportlab gut und möglichst in deutsch beschrieben ist? fpdf habe ich zum Beispiel im Buch "Routineaufgaben mit Python automatisieren" kennengelernt und daher auch anfangs eingesetzt.

P.S. wiki.ubuntuusers.de/ReportLab/ kenne ich natürlich.
Benutzeravatar
noisefloor
User
Beiträge: 3856
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

also ich kenne kein Buch. Die Doku von ReportLab ist sehr umfangreich und es gibt im Netz sehr sehr viele Beispiele und Codeschnipsel zu Reportlab.

Platypus, was ja die "high level" API zum Bauen von PDFs mit ReporLab ist, nutzt man normalerweise so, dass man eine Liste (in vielen Beispielen "story" benannt) hat, in die man alle Elemente, die das PDF haben soll, packt. "Elemente" sind hier die Klassen, die Platypus so kennt, also Paragraphen, Bilder, etc. Die Elemente sind im Jargon von Platypus als "Flowables" bezeichnet.

Ein 2-seitiges PDF baust du so:

Code: Alles auswählen

>>> import pyautogui
>>> from reportlab.platypus import SimpleDocTemplate, Image, PageBreak
>>> from reportlab.lib.pagesizes import A4
>>> from io import BytesIO
>>> image_left = BytesIO()
>>> image_right = BytesIO()
>>> screenshot_left = pyautogui.screenshot(region=(80,48, 200, 200))
>>> screenshot_right = pyautogui.screenshot(region=(300,300, 200, 200))
>>> screenshot_left.save(image_left, format='png')
>>> screenshot_right.save(image_rigth, format='png')
>>> doc = SimpleDocTemplate("image.pdf", pagesize=A4)
>>> story=[]
>>> story.append(Image(image_left, 150, 150))
>>> story.append(PageBreak())
>>> story.append(Image(image_right, 150, 150))
>>> doc.build(story)
Den `PageBreak`kannst / solltest du sicherheitshalber einbauen, damit garantiert eine da ist. enn Das 1. Bild so groß ist, dass das 2. Bild nicht mehr auf die 1. Seite des PDFs passt, dann wird natürlich automatisch ein Seitenumbruch eingebaut.

Den obigen, linearen Code solltest du dann natürlich sinnvoll in Funktionen packen, wenn du Screenshots von mehreren Bildschirmen brauchst.

Gruß, noisefloor
Sirius3
User
Beiträge: 17750
Registriert: Sonntag 21. Oktober 2012, 17:20

@noisefloor: statt Code zu kopieren und nur leicht zu ändern, schreibt man sich eine Funktion. Bei einer fixen Anzahl an Elementen für eine Liste schreibt man diese gleich in die eckigen Klammern:

Code: Alles auswählen

import pyautogui
from reportlab.platypus import SimpleDocTemplate, Image, PageBreak
from reportlab.lib.pagesizes import A4
from io import BytesIO

def create_screenshot(region):
    screenshot = pyautogui.screenshot(region=region)
    image = BytesIO()
    screenshot.save(image, format='png')
    return Image(image, 150, 150)

story = [
    create_screenshot(region=(80,48, 200, 200)),
    PageBreak(),
    create_screenshot(region=(300,300, 200, 200)),
]
doc = SimpleDocTemplate("image.pdf", pagesize=A4)
doc.build(story)
Benutzeravatar
noisefloor
User
Beiträge: 3856
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

@Sirius3: genau das habe ich ja auch im letzten Satz im vorherigen Post geschrieben... Basierend auf dem, was der TE geschrieben hat, kann es durchaus auch Sinn machen, das Bauen des PDFs in eine Funktion zu packen.

Gruß, noisefloor
Benutzeravatar
noisefloor
User
Beiträge: 3856
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

passend zum Thema: der aktuelle Real Python Podcast behandelt Python, PDFs und ReportLab (https://realpython.com/podcasts/rpp/20/). Und es gibt doch ein (englischsprachiges) ReportLab Buch (https://leanpub.com/reportlab). Habe mal virtuell die ersten 54 Seiten durchgeblättert, die man kostenlos als Demo anschauen kann. Das sieht eher so aus, als wäre das ein Re-Write der ReportLab Doku, womit das Buch.. na ja nur semi-sinnvoll wäre. Das Kapitel zu Platypus kann man in der kostenlosen Ansicht leider nicht anschauen.

Gruß, noisefloor
Antworten