Moinsen Allerseits,
ich habe mir mit "reportlab.pdfgen" ein pdf mit Schrift und Bildern erstellt. Diese Datei ist aber zig MB groß.
Wenn ich sie im Acrobat-Reader öffne und als komprimierte Datei abspeichere ist sie nur noch etwa 1 MB groß, was auch mein Ziel war.
Wie kann ich mittels Python dies auch erreichen?
Am liebsten würde ich meine Datei mit "reportlab" erstellen und anschließend mit einem weiteren Tool direkt in meinem Programmcode verkleinern.
Hat Jemand von Euch eine Idee, wie ich das hinbekommen kann?
LG Andi
pdf verkleinern
- __blackjack__
- User
- Beiträge: 14078
- Registriert: Samstag 2. Juni 2018, 10:21
- Wohnort: 127.0.0.1
- Kontaktdaten:
Sicherstellen, das komprimiert wird und ansonsten vermute ich stark, dass es an den Bildern liegt, das die vom Acrobat-Reader in schlechterer Qualität und damit halt auch kleiner, gespeichert werden.
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
- noisefloor
- User
- Beiträge: 4196
- Registriert: Mittwoch 17. Oktober 2007, 21:40
- Wohnort: WW
- Kontaktdaten:
Hallo,
wie groß sind denn die Bilder und wie viel DPI haben die? ReportLab komprimiert die ja beim Einbauen ins PDF nichts, sondern skaliert "nur". Das ist dann normalerweise der 1. Punkt, wo PDF Komprimierer ansetzen - Bildgröße verkleinern und / oder Auslösung des Bilds runter.
Kannst du im Skript z.B. mit Pillow machen, bevor du das Bild ns PDF einbaust.
Gruß, noisefloor
wie groß sind denn die Bilder und wie viel DPI haben die? ReportLab komprimiert die ja beim Einbauen ins PDF nichts, sondern skaliert "nur". Das ist dann normalerweise der 1. Punkt, wo PDF Komprimierer ansetzen - Bildgröße verkleinern und / oder Auslösung des Bilds runter.
Kannst du im Skript z.B. mit Pillow machen, bevor du das Bild ns PDF einbaust.
Gruß, noisefloor
sorry, leider hatte ich keine Emailbenachrichtigung über die Antworten erhalten.
Hier mal mein Code mit dem ich das pdf erzeuge:
Ich hatte es so verstanden, dass wenn ich den Ursprung und die Breite und die Höhe in Pixel angebe, dass reportlab die Bilder dann in genau diesen Pixeln speichert?
LG Andi
Hier mal mein Code mit dem ich das pdf erzeuge:
Code: Alles auswählen
def pdf_empf_header(self, pdfcontainer):
from reportlab.lib.colors import black, HexColor
from datetime import datetime
from reportlab.lib.units import cm
from reportlab.lib.pagesizes import A4
logo = "Logo-2800.png"
seitenbreite, seitenhoehe = A4
pdfcontainer.setPageCompression(1)
# Logo
pdfcontainer.drawImage(icopath + logo, seitenbreite - (14 * cm), seitenhoehe - (4 * cm), 12 * cm, 3 * cm, mask='auto', preserveAspectRatio=True)
# Logo Unterzeile
pdfcontainer.setFont('Helvetica', 16)
pdfcontainer.setFillColor(black)
pdfcontainer.drawString(seitenbreite - (8 * cm), seitenhoehe - (4.5 * cm), ' GmbH')
# Ueberschrift
pdfcontainer.setFont('Helvetica-Bold', 14)
pdfcontainer.drawString(2 * cm, seitenhoehe - (7 * cm), 'Empfehlungen Aquarientiere')
pdfcontainer.setFillColor(HexColor('#64a1d5'))
pdfcontainer.setFont('Helvetica', 14)
pdfcontainer.drawString(2 * cm, seitenhoehe - (7.5 * cm), "für KW " + format(int(datetime.today().strftime('%V')) + 1, '02d') + " und KW " + format(int(datetime.today().strftime('%V')) + 2, '02d'))
pdfcontainer.setFillColor(HexColor('#64a1d5'), alpha=0.25)
breite = seitenbreite * 1.25
hoehe = seitenbreite * 0.85
anfangx = breite * 0.25
anfangy = -hoehe * 0.4
pdfcontainer.ellipse(anfangx, anfangy, anfangx + breite, anfangy + hoehe, fill=1, stroke=0)
return pdfcontainer
def pdf_empf_bild(self, pdfcontainer, dateinamepfad, dateibeschriftung, xpos, ypos, bildbreite, bildhoehe, index=0):
from reportlab.lib.colors import Color, black, HexColor, white
from reportlab.lib.units import cm
from reportlab.pdfbase.pdfmetrics import stringWidth
from reportlab.lib.pagesizes import A4
seitenbreite, seitenhoehe = A4
pdfcontainer.setPageCompression(1)
pdfcontainer.setFillColor(HexColor('#eeeeee'), alpha=0.75)
pdfcontainer.setStrokeColor(HexColor('#cccccc'), alpha=0.5)
pdfcontainer.setLineWidth(3)
pdfcontainer.roundRect(xpos - (0.25 * cm)+2, ypos - (0.25 * cm)-2, bildbreite + (0.5 * cm), bildhoehe + (0.5 * cm), 3, stroke=1, fill=1) # draw rectangle
pdfcontainer.setLineWidth(1)
pdfcontainer.setStrokeColor(HexColor('#cccccc'), alpha=1)
pdfcontainer.roundRect(xpos - (0.25 * cm), ypos - (0.25 * cm), bildbreite + (0.5 * cm), bildhoehe + (0.5 * cm), 3, stroke=1, fill=1) # draw rectangle
pdfcontainer.setStrokeColor(HexColor('#aaaaaa'), alpha=0.75)
pdfcontainer.setLineWidth(1)
pdfcontainer.roundRect(xpos+2, ypos-2, bildbreite-1, bildhoehe-1, 0, stroke=1, fill=0) # draw rectangle
pdfcontainer.setStrokeColor(HexColor('#aaaaaa'), alpha=1)
pdfcontainer.setFillColor(black, alpha=1)
pdfcontainer.drawImage(dateinamepfad, xpos, ypos, bildbreite, bildhoehe, preserveAspectRatio=True)
pdfcontainer.setStrokeColor(HexColor('#cccccc'), alpha=1)
pdfcontainer.setLineWidth(1)
pdfcontainer.roundRect(xpos, ypos, bildbreite, bildhoehe, 0, stroke=1, fill=0) # draw rectangle
pdfcontainer.setFillColor(HexColor('#64a1d5'), alpha=0.85)
pdfcontainer.setStrokeColor(HexColor('#64a1d5'), alpha=1)
wortbreite = stringWidth(dateibeschriftung, 'Helvetica-Bold', 16)
pdfcontainer.roundRect((3.5 * cm) + (index * (seitenbreite - wortbreite*1.1 - (7 * cm))), ypos + (0.25 * cm) - (0.75 * cm), wortbreite * 1.1, 1.25 * cm, 8, stroke=1, fill=1) # draw rectangle
pdfcontainer.setFillColor(white)
pdfcontainer.setFont('Helvetica-Bold', 16)
pdfcontainer.drawString((0.5 * cm) + (3.5 * cm) + (index * (seitenbreite - wortbreite*1.1 - (7 * cm))), ypos + (0.7 * cm) - (0.75 * cm), dateibeschriftung)
return pdfcontainer
def writetopdf(self, exppfad, empdf, pdfdatei):
'''
'''
from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import A4
from reportlab.lib.units import cm
seitenbreite, seitenhoehe = A4
bildbreite = 12 * cm
bildhoehe = 9 * cm
tmp = pdfdatei.split(".")
pdf = canvas.Canvas(exppfad + pdfdatei, pagesize=A4, pageCompression=1)
pdf.setTitle(tmp[0])
pdf.setPageCompression(1)
pdf.setCreator('andi')
for index, zeile in empdf.iterrows():
if (index % 2 == 0): # oberes Bild
pdf = self.pdf_empf_header(pdf)
pdf = self.pdf_empf_bild(pdf, zeile["DATEINAME"], zeile["ARTNR"] + " " + zeile["SUCHBEGRIFF"] + " " + zeile["GROESSE"], (seitenbreite-bildbreite)/2, seitenhoehe - 2 * bildhoehe + 1 * cm, bildbreite, bildhoehe,0)
else:
pdf = self.pdf_empf_bild(pdf, zeile["DATEINAME"], zeile["ARTNR"] + " " + zeile["SUCHBEGRIFF"] + " " + zeile["GROESSE"], (seitenbreite-bildbreite)/2, seitenhoehe - (10 * cm) - 2 * bildhoehe, bildbreite, bildhoehe,1)
pdf.showPage()
pdf.save()
hmm, naja, die Auflösung dürfte doch irrelevant sein, da es sich ja nur um ein künstliches Konstrukt handelt.wie groß sind denn die Bilder und wie viel DPI haben die? ReportLab komprimiert die ja beim Einbauen ins PDF nichts, sondern skaliert "nur". Das ist dann normalerweise der 1. Punkt, wo PDF Komprimierer ansetzen - Bildgröße verkleinern und / oder Auslösung des Bilds runter.
Ich hatte es so verstanden, dass wenn ich den Ursprung und die Breite und die Höhe in Pixel angebe, dass reportlab die Bilder dann in genau diesen Pixeln speichert?
LG Andi
Du hast falsch verstanden. Nur weil ein Bild an eine Stelle skaliert und verschoben wird, ändert sich doch nicht die Menge der Ursprungsdaten. Oder wird dein PDF kleiner, weil es als thumbnail im explorer dargestellt wird?
Du musst die also entsprechend selbst verkleinern.
Du musst die also entsprechend selbst verkleinern.
Benutze keine kryptisch Abkürzungen. Was ist ein `empf`?
Importe stehen alle am Anfang der Datei, nicht innerhalb von Funktionen, zumal Du da die Importe in jeder Funktion wiederholst.
`pdf_empf_header` und `pdf_empf_bild` bekommen pdfcontainer als Argument und geben es wieder zurück. Das ist wenig sinnvoll, da die Stelle, die die Methode aufruft, ja schon den pdfcontainer kennt, also mit dem Rückgabewert nichts anfangen kann.
Keine Deiner Methoden benutzt `self`. Es scheint also so, dass Du ganz normale Funktionen in eine Klasse gestopft hast, wo sie nicht hinein gehören. Klassen sind keine Selbstzweck für sich.
Das was Du da mit `format` machst, ist sehr umständlich. `format` benutzt man nicht als Funktion, sondern heutzutage via f-Strings.
Du rufst mehrfach `today` auf, was dazu führen kann, dass der erste Aufruf ein Tag früher stattfindet als der zweite, Du bekommst also ein PDF das in sich inkonsistent ist. Man erzeugt nicht einen String aus einem datetime-Objekt, um es danach wieder in ein int umzuwandeln.
Dateipfade sind keine einfachen Strings, die verarbeitet man also nicht mit split oder +.
Heutzutage benutzt man dafür pathlib.Path.
Importe stehen alle am Anfang der Datei, nicht innerhalb von Funktionen, zumal Du da die Importe in jeder Funktion wiederholst.
`pdf_empf_header` und `pdf_empf_bild` bekommen pdfcontainer als Argument und geben es wieder zurück. Das ist wenig sinnvoll, da die Stelle, die die Methode aufruft, ja schon den pdfcontainer kennt, also mit dem Rückgabewert nichts anfangen kann.
Keine Deiner Methoden benutzt `self`. Es scheint also so, dass Du ganz normale Funktionen in eine Klasse gestopft hast, wo sie nicht hinein gehören. Klassen sind keine Selbstzweck für sich.
Das was Du da mit `format` machst, ist sehr umständlich. `format` benutzt man nicht als Funktion, sondern heutzutage via f-Strings.
Du rufst mehrfach `today` auf, was dazu führen kann, dass der erste Aufruf ein Tag früher stattfindet als der zweite, Du bekommst also ein PDF das in sich inkonsistent ist. Man erzeugt nicht einen String aus einem datetime-Objekt, um es danach wieder in ein int umzuwandeln.
Dateipfade sind keine einfachen Strings, die verarbeitet man also nicht mit split oder +.
Heutzutage benutzt man dafür pathlib.Path.
Code: Alles auswählen
from datetime import datetime
from reportlab.pdfgen import canvas
from reportlab.pdfbase.pdfmetrics import stringWidth
from reportlab.lib.pagesizes import A4
from reportlab.lib.units import cm
from reportlab.lib.colors import Color, black, HexColor, white
def pdf_empf_header(pdfcontainer, date):
logo = "Logo-2800.png"
seitenbreite, seitenhoehe = A4
pdfcontainer.setPageCompression(1)
# Logo
pdfcontainer.drawImage(icopath + logo, seitenbreite - (14 * cm), seitenhoehe - (4 * cm), 12 * cm, 3 * cm, mask='auto', preserveAspectRatio=True)
# Logo Unterzeile
pdfcontainer.setFont('Helvetica', 16)
pdfcontainer.setFillColor(black)
pdfcontainer.drawString(seitenbreite - (8 * cm), seitenhoehe - (4.5 * cm), ' GmbH')
# Ueberschrift
pdfcontainer.setFont('Helvetica-Bold', 14)
pdfcontainer.drawString(2 * cm, seitenhoehe - (7 * cm), 'Empfehlungen Aquarientiere')
pdfcontainer.setFillColor(HexColor('#64a1d5'))
pdfcontainer.setFont('Helvetica', 14)
week_number = date.isocalendar()[1]
pdfcontainer.drawString(2 * cm, seitenhoehe - (7.5 * cm), f"für KW {week_number + 1:02d} und KW {week_number + 2:02d}")
pdfcontainer.setFillColor(HexColor('#64a1d5'), alpha=0.25)
breite = seitenbreite * 1.25
hoehe = seitenbreite * 0.85
anfangx = breite * 0.25
anfangy = -hoehe * 0.4
pdfcontainer.ellipse(anfangx, anfangy, anfangx + breite, anfangy + hoehe, fill=1, stroke=0)
def pdf_empf_bild(pdfcontainer, dateinamepfad, dateibeschriftung, xpos, ypos, bildbreite, bildhoehe, index=0):
seitenbreite, seitenhoehe = A4
pdfcontainer.setPageCompression(1)
pdfcontainer.setFillColor(HexColor('#eeeeee'), alpha=0.75)
pdfcontainer.setStrokeColor(HexColor('#cccccc'), alpha=0.5)
pdfcontainer.setLineWidth(3)
pdfcontainer.roundRect(xpos - (0.25 * cm)+2, ypos - (0.25 * cm)-2, bildbreite + (0.5 * cm), bildhoehe + (0.5 * cm), 3, stroke=1, fill=1) # draw rectangle
pdfcontainer.setLineWidth(1)
pdfcontainer.setStrokeColor(HexColor('#cccccc'), alpha=1)
pdfcontainer.roundRect(xpos - (0.25 * cm), ypos - (0.25 * cm), bildbreite + (0.5 * cm), bildhoehe + (0.5 * cm), 3, stroke=1, fill=1) # draw rectangle
pdfcontainer.setStrokeColor(HexColor('#aaaaaa'), alpha=0.75)
pdfcontainer.setLineWidth(1)
pdfcontainer.roundRect(xpos+2, ypos-2, bildbreite-1, bildhoehe-1, 0, stroke=1, fill=0) # draw rectangle
pdfcontainer.setStrokeColor(HexColor('#aaaaaa'), alpha=1)
pdfcontainer.setFillColor(black, alpha=1)
pdfcontainer.drawImage(dateinamepfad, xpos, ypos, bildbreite, bildhoehe, preserveAspectRatio=True)
pdfcontainer.setStrokeColor(HexColor('#cccccc'), alpha=1)
pdfcontainer.setLineWidth(1)
pdfcontainer.roundRect(xpos, ypos, bildbreite, bildhoehe, 0, stroke=1, fill=0) # draw rectangle
pdfcontainer.setFillColor(HexColor('#64a1d5'), alpha=0.85)
pdfcontainer.setStrokeColor(HexColor('#64a1d5'), alpha=1)
wortbreite = stringWidth(dateibeschriftung, 'Helvetica-Bold', 16)
pdfcontainer.roundRect((3.5 * cm) + (index * (seitenbreite - wortbreite*1.1 - (7 * cm))), ypos + (0.25 * cm) - (0.75 * cm), wortbreite * 1.1, 1.25 * cm, 8, stroke=1, fill=1) # draw rectangle
pdfcontainer.setFillColor(white)
pdfcontainer.setFont('Helvetica-Bold', 16)
pdfcontainer.drawString((0.5 * cm) + (3.5 * cm) + (index * (seitenbreite - wortbreite*1.1 - (7 * cm))), ypos + (0.7 * cm) - (0.75 * cm), dateibeschriftung)
def writetopdf(pdf_path, empdf):
pdf = canvas.Canvas(str(pdf_path), pagesize=A4, pageCompression=1)
pdf.setTitle(pdf_path.stem)
pdf.setPageCompression(1)
pdf.setCreator('andi')
seitenbreite, seitenhoehe = A4
bildbreite = 12 * cm
bildhoehe = 9 * cm
date = datetime.today()
for index, zeile in empdf.iterrows():
position = index % 2
if position == 0: # oberes Bild
pdf = self.pdf_empf_header(pdf, date)
pdf = self.pdf_empf_bild(pdf,
zeile["DATEINAME"],
f'{zeile["ARTNR"]} {zeile["SUCHBEGRIFF"]} {zeile["GROESSE"]}'
(seitenbreite-bildbreite)/2,
seitenhoehe - 2 * bildhoehe + (1 if position == 0 else -10) * cm,
bildbreite, bildhoehe, position)
if position == 1:
pdf.showPage()
pdf.save()
Danke. Ich hatte das echt so verstanden, dass drawImage das Bild mit den angegeben Pixel neu "malt".__deets__ hat geschrieben: Sonntag 6. Februar 2022, 10:16 Du hast falsch verstanden. Nur weil ein Bild an eine Stelle skaliert und verschoben wird, ändert sich doch nicht die Menge der Ursprungsdaten. Oder wird dein PDF kleiner, weil es als thumbnail im explorer dargestellt wird?
Du musst die also entsprechend selbst verkleinern.
Mit
pdfBild = ImageOps.fit(orgBild, (1200, 900))
pdfBild.save(root + pdfverzeichnis + "\\" + filename + file_extension, optimize=True, quality=30)
erreiche ich das gewünschte.
ok, die Datei heisst Empfehlungen, ich versuche halt immer zuuuuu lange Begriffe zu vermeiden.Sirius3 hat geschrieben: Sonntag 6. Februar 2022, 11:18 Benutze keine kryptisch Abkürzungen. Was ist ein `empf`?
ok, ich dachte, dass die so nur beim Aufruf der Methode geladen werden, ich brauche sie ja nicht in jeder Funtkion.Sirius3 hat geschrieben: Sonntag 6. Februar 2022, 11:18 Importe stehen alle am Anfang der Datei, nicht innerhalb von Funktionen, zumal Du da die Importe in jeder Funktion wiederholst.
naja, ich komme halt aus der prozeduralen Programmierung. Hatte mich mit Klassen nie näher auseinandergesetzt.Sirius3 hat geschrieben: Sonntag 6. Februar 2022, 11:18 `pdf_empf_header` und `pdf_empf_bild` bekommen pdfcontainer als Argument und geben es wieder zurück. Das ist wenig sinnvoll, da die Stelle, die die Methode aufruft, ja schon den pdfcontainer kennt, also mit dem Rückgabewert nichts anfangen kann.
Keine Deiner Methoden benutzt `self`. Es scheint also so, dass Du ganz normale Funktionen in eine Klasse gestopft hast, wo sie nicht hinein gehören. Klassen sind keine Selbstzweck für sich.
Danke, ich bin bei python ein Quereinsteiger und arbeite mich in ein vorhandenes Projekt rein und erweitere es. Vieles war schon so vorhanden und ich habe es dann so weitergeführt.Sirius3 hat geschrieben: Sonntag 6. Februar 2022, 11:18 Das was Du da mit `format` machst, ist sehr umständlich. `format` benutzt man nicht als Funktion, sondern heutzutage via f-Strings.
Guter Einwand, sollte zwar keine Auswirkungen haben, da hast Du recht, das ist so sicherer!Sirius3 hat geschrieben: Sonntag 6. Februar 2022, 11:18 Du rufst mehrfach `today` auf, was dazu führen kann, dass der erste Aufruf ein Tag früher stattfindet als der zweite, Du bekommst also ein PDF das in sich inkonsistent ist. Man erzeugt nicht einen String aus einem datetime-Objekt, um es danach wieder in ein int umzuwandeln.
Danke und LG
Andi
Sirius3 hat geschrieben: Sonntag 6. Februar 2022, 11:18 Dateipfade sind keine einfachen Strings, die verarbeitet man also nicht mit split oder +.
Heutzutage benutzt man dafür pathlib.Path.