🪟 Windows TippsMicrosoft bringt Emoji 17.0 auf Windows 11(31.08.2026 um 08:16 Uhr)
🕵️ SicherheitslückenDropbox-Hack: Tausende Konten kompromittiert(02.09.2026 um 11:02 Uhr)
⚠️ Malware / Trojaner / VirenAtombomben-Frage trickst KI-Malware-Scanner aus(02.09.2026 um 12:46 Uhr)
🪟 Windows TippsWindows 11: Diese Tastenkürzel sollten Sie kennen(03.09.2026 um 09:53 Uhr)
🪟 Windows TippsMicrosoft bringt Emoji 17.0 auf Windows 11(31.08.2026 um 08:16 Uhr)
🕵️ SicherheitslückenDropbox-Hack: Tausende Konten kompromittiert(02.09.2026 um 11:02 Uhr)
⚠️ Malware / Trojaner / VirenAtombomben-Frage trickst KI-Malware-Scanner aus(02.09.2026 um 12:46 Uhr)
🪟 Windows TippsWindows 11: Diese Tastenkürzel sollten Sie kennen(03.09.2026 um 09:53 Uhr)

26 🕛 kürzlich 6 Min Lesezeit CVE-RADAR
0

Create selectable PDF files with Lambda Python and ReportLab

↗ Quelle (dev.to)
🗣️ Stimme:
📑 Inhaltsübersicht




Motivation



There are times when I need to create PDF files for reporting from data points using an AWS Lambda function.



This blog post was inspired by



(Note: We want the text in the PDF files to be selectable and copyable, so we won't be using Matplotlib this time.)





Architecture






  • Create the SNS Topic




    • arn of the topic will be used later.

    • .



      You will use the arn of the layer later.






      Create Lambda function



      On the Lambda console, Create Lambda (Python).






      Configuration



      • General configuration



        • The default 3 sec timeout might be short. Change it a little longer, like 10 sec.




      • Environmental variables



        • SNS_ARN: arn of the topic you have

        • BUCKET_NAME: name of the bucket you have




      • IAM Policy



        • Select Permission, and Role name. Add an inline policy like the one below for sending SNS and uploading a file to S3. Change the arn of your SNS topic and S3 bucket name.

        • Make sure you don't change the IAM policy while your pre-singed URL will be used.



      CODE
      {
      "Version": "2012-10-17",
      "Statement": [
      {
      "Effect": "Allow",
      "Action": "sns:Publish",
      "Resource": "arn:aws:sns:REGION:ACCOUNT_ID:your-sns-topic-arn"
      },
      {
      "Effect": "Allow",
      "Action": [
      "s3:PutObject",
      "s3:GetObject",
      "s3:ListBucket"
      ],
      "Resource": [
      "arn:aws:s3:::your-bucket-name/*",
      "arn:aws:s3:::your-bucket-name"
      ]
      }
      ]
      }









      Code






      Add Lambda Layer


      In the Code tab, add the Layer you've created. Specify the ARN of the layer you've created.






      Write code


      • In this code

        • Percentage of the year passed and left days are calculated.

        • The gauge for the percentage is generated with draw_gauge().

        • Create an A4 PDF file. Upload it to the S3 bucket.

        • Set the pre-assigned URL to the file in the bucket

        • Send the URL with SNS.


      • As the unit I used mm. inch is available by changing unit = mm to inch, but some modifications are needed with x, y.


      • on_grid parameter in create_pdf_days_passed_left() is for designing layouts. (See Appendix)


      CODE
      import io
      import os
      import uuid
      from datetime import datetime

      import boto3
      from reportlab.lib import colors
      from reportlab.lib.pagesizes import A4, landscape
      from reportlab.lib.units import inch, mm
      from reportlab.pdfgen import canvas


      def percentage_of_year_passed(start_of_year, end_of_year, now):
      total_days = (end_of_year - start_of_year).days + 1
      days_passed = (now - start_of_year).days + 1
      percentage_passed = int((days_passed / total_days) * 100)
      return percentage_passed


      def calculate_days():
      now = datetime.now()
      start_of_year = datetime(now.year, 1, 1)
      end_of_year = datetime(now.year, 12, 31, 23, 59, 59)

      percentage_passed = percentage_of_year_passed(start_of_year, end_of_year, now)
      days_left = (end_of_year - now).days + 1

      return percentage_passed, days_left


      def draw_grid(c, width, height, unit):
      step = 25 if unit == mm else 1
      c.setLineWidth(1 / unit)
      c.setStrokeColor(colors.grey)
      c.setFont("Helvetica", 25 / unit)

      for i in range(0, int(height) + 1, step):
      c.line(0, i, width, i)
      c.drawString(0, i, f"{i}")

      for i in range(0, int(width) + 1, step):
      c.line(i, 0, i, height)
      c.drawString(i, 0, f"{i}")


      def draw_gauge(c, x, y, radius, percentage, base_color, fill_color):
      """
      Draw gauge with two arches: base 180 deg arch and filled with percentage.
      """

      # Draw base half-circle
      c.setLineWidth(15)
      c.setStrokeColor(base_color)
      c.arc(x - radius, y - radius, x + radius, y + radius, 180, -179.9)

      # Draw filled half-circle
      c.setStrokeColor(fill_color)
      gauge = -180 * percentage / 100 + 0.01
      c.arc(x - radius, y - radius, x + radius, y + radius, 180, gauge)


      def draw_str(c, x, y, item, font_size, font_color="black"):
      c.setFont("Helvetica", font_size)
      c.setFillColor(font_color)
      c.drawCentredString(x, y, f"{item}")


      def create_pdf_days_passed_left(page_size, x, y, radius, on_grid = False):

      unit = mm # mm or inch
      buffer = io.BytesIO()
      c = canvas.Canvas(buffer, pagesize=page_size)
      c.scale(unit, unit)

      if on_grid:
      width = page_size[0] / unit
      height = page_size[1] / unit
      draw_grid(c, width, height, unit)

      base_color = colors.HexColor("#c8c8c8") # light grey
      fill_color = colors.HexColor("#1f77b4") # light blue

      percentage_passed, days_left = calculate_days()

      message = f'Created at {datetime.now().strftime("%Y-%m-%d %H:%M:%S")}'
      draw_str(c, x + 50, y + 55, message, 8)
      draw_gauge(c, x, y, radius, percentage_passed, base_color, fill_color)
      draw_str(c, x, y, f"{percentage_passed}%", font_size=20)
      draw_str(c, x, y - 25, "This year passed", font_size=10)

      draw_str(c, x + 100, y, days_left, font_size=20, font_color="green")
      draw_str(c, x + 100, y - 25, "days left", font_size=10)

      c.showPage()
      c.save()
      buffer.seek(0)
      return buffer


      def generate_n_char_id(n: int):
      unique_id = uuid.uuid4()
      short_id = str(unique_id)[:n]
      return short_id


      def generate_presigned_url(bucket_name, object_name, expiration_sec=3600):
      s3_client = boto3.client("s3")
      response = s3_client.generate_presigned_url(
      "get_object",
      Params={"Bucket": bucket_name, "Key": object_name},
      ExpiresIn=expiration_sec,
      )

      return response


      def send_sns_message(topic_arn, message):
      sns_client = boto3.client("sns")
      response = sns_client.publish(
      TopicArn=topic_arn,
      Message=message,
      )

      return response


      def lambda_handler(event, context):
      s3 = boto3.client("s3")
      bucket_name = os.environ["BUCKET_NAME"]
      sns_topic_arn = os.environ["SNS_ARN"]

      dt = datetime.now().strftime("%Y%m%d-%H%M%S")
      uuid = generate_n_char_id(8)
      filename = f"demo-{dt}-{uuid}.pdf"

      page_size = landscape(A4)
      x, y = 100, 125 # Center of gauge. Use this point as anchoring
      radius = 40 # radius of gauge

      pdf_buffer = create_pdf_days_passed_left(page_size, x, y, radius)
      s3.upload_fileobj(pdf_buffer, bucket_name, filename)

      url = generate_presigned_url(bucket_name, filename, expiration_sec=3600)
      if url:
      print(f"Generated presigned URL: {url}")
      message = f"Download the PDF file here: {url}"
      send_sns_message(sns_topic_arn, message)
      else:
      print("Failed to generate presigned URL")

      return {
      "statusCode": 200,
      "body": "PDF created and uploaded to S3. Presigned url has sent with SNS.",
      }









      Result



      You'll receive an email to download URL.



      Vollständiger Original-Bericht
      Ausführliche Details, Code-Beispiele & Hersteller-Stellungnahme auf dev.to.
      ↗ Original-Artikel auf dev.to lesen
  • Wie bewertest du diesen Beitrag?
    1 Klick Feedback
    Teilen mit Netzwerk & Team:

    Community-Analysen & Experten-Meinungen 0

    Verfasse deine eigene Analyse, teile Workarounds oder diskutiere diesen Vorfall im Blog.
    Noch keine Community-Analyse verfasst. Markiere einen Textabschnitt oder klicke oben auf Eigene Analyse verfassen“!
    Community Pulse: Relevanz-Einschätzung
    1 Klick Experten-Votum
    🔴 Akute Relevanz 39%
    🟡 In Evaluierung 20%
    🟢 Keine Auswirkung 17%
    Spannende Innovation 24%
    Verwandte Story-Cluster & Quellen (Vektor-KI)
    Port 8095 Engine
    5 Quellen
    OpenAI’s new Astra model is finally here – why safety experts are worried
    1 Quelle
    Microsoft bringt Emoji 17.0 auf Windows 11
    1 Quelle
    Dropbox-Hack: Tausende Konten kompromittiert
    Ähnliche Beiträge
    🔍 Verwandte News

    Auch interessante Nachrichten Create selectable PDF files with Lambda Python and ReportLab

    Thematisch verwandte Begriffe: Create, selectable, files, with · 6 Treffer

    Laden...

    Videos werden geladen ...

    Laden...

    Beiträge werden geladen ...

    Laden...

    Videos werden geladen ...

    Laden...

    Beiträge werden geladen ...

    Laden...

    Videos werden geladen ...

    Laden...

    Beiträge werden geladen ...

    Laden...

    Videos werden geladen ...

    Laden...

    Beiträge werden geladen ...

    Laden...

    Videos werden geladen ...