skip to Main Content

I made a html-site to upload an image and convert it into lines for a plotter. I use linedraw modified by evildmp. Unfortunately after uploading nothing happens. It should show me a "lines"-version (svg) of my image.

Therefor I created a function imagetosvg that returns a svg-file. I am new in pyscript and not able to find the problem.


<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>File System Examples</title>
    <link rel="stylesheet" href="https://pyscript.net/alpha/pyscript.css" />
    <script defer src="https://pyscript.net/alpha/pyscript.js"></script>
  </head>
  <body>
    <br />
    <label for="myfile">Select a file:</label>
    <input type="file" id="myfile" name="myfile">
    <div id="output"></div> 
    <br />
    <br />
    <p>Image:</p>
    <img id="image">

    <py-env>
        - numpy
        - Pillow
    </py-env>

    <py-script src="main.py">
    </py-script>
        
  </body>
</html>

main.py:

from random import *
import math
import argparse
import json
import time
import asyncio
import js
from js import document
from pyodide import create_proxy

from PIL import Image, ImageDraw, ImageOps

# file settings
export_path = "images/out.svg"
svg_folder = "images/"
json_folder = "images/"

# CV
no_cv = False

try:
    import numpy as np
    import cv2
except:
    print("Cannot import numpy/openCV. Switching to NO_CV mode.")
    no_cv = True



async def read_complete(event):
    # event is ProgressEvent
    # console.log('read_complete')
    print("ich habs")
    imageFile = event.target.result
    image = document.getElementById("image")
    image.src = image_to_svg(imageFile, draw_contours=2, draw_hatch=16)

async def process_file(x):
    fileList = document.getElementById('myfile').files

    for f in fileList:
        # reader is a pyodide.JsProxy
        reader = js.FileReader.new()

        # Create a Python proxy for the callback function
        onload_event = create_proxy(read_complete)

        reader.onload = onload_event

        reader.readAsDataURL(f)

    return

def setup():
    # Create a Python proxy for the callback function
    file_event = create_proxy(process_file)

    # Set the listener to the callback
    e = document.getElementById("myfile")
    e.addEventListener("change", file_event, False)

setup()


# -------------- output functions --------------


#My Own
def image_to_svg(image_filename, resolution=1024, draw_contours=False, repeat_contours=1, draw_hatch=False, repeat_hatch=1):
    lines = vectorise(image_filename, resolution, draw_contours, repeat_contours, draw_hatch, repeat_hatch)
    svg_data = makesvg(lines)
    return svg_data




def image_to_json(
    image_filename,
    resolution=1024,
    draw_contours=False,
    repeat_contours=1,
    draw_hatch=False,
    repeat_hatch=1,
):

    lines = vectorise(
        image_filename,
        resolution,
        draw_contours,
        repeat_contours,
        draw_hatch,
        repeat_hatch,
    )

    filename = json_folder + image_filename + ".json"
    lines_to_file(lines, filename)


def makesvg(lines):
    print("Generating svg file...")
    width = math.ceil(max([max([p[0] * 0.5 for p in l]) for l in lines]))
    height = math.ceil(max([max([p[1] * 0.5 for p in l]) for l in lines]))
    out = '<svg xmlns="http://www.w3.org/2000/svg" height="%spx" width="%spx" version="1.1">' % (
        height,
        width,
    )

    for l in lines:
        l = ",".join([str(p[0] * 0.5) + "," + str(p[1] * 0.5) for p in l])
        out += '<polyline points="' + l + '" stroke="black" stroke-width="1" fill="none" />n'
    out += "</svg>"
    return out

... see https://raw.githubusercontent.com/evildmp/BrachioGraph/master/linedraw.py

2

Answers


  1. Chosen as BEST ANSWER

    Now I changed the code and the image is converted into lines but I don't know how to show my svg-image after saving it.

    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>File System Examples</title>
        <link rel="stylesheet" href="https://pyscript.net/alpha/pyscript.css" />
        <script defer src="https://pyscript.net/alpha/pyscript.js"></script>
      </head>
      <body>
      <div style="border:2px inset #AAA;cursor:text;height:120px;overflow:auto;width:600px; resize:both">
      <div id="content">
      </div>
      <py-env>
          - Pillow
      </py-env>
      <label for="Upload a PNG image"></label><input type="file" id="file-upload-pillow">
      <div id="output_upload_pillow"></div>
      <py-script>
    from js import document, console, Uint8Array, window, File
    from pyodide import create_proxy
    import asyncio
    import io
    import math
    import argparse
    
    from PIL import Image, ImageFilter, ImageOps
    
    # CV
    no_cv = False
    
    try:
        import numpy as np
        import cv2
    except:
        print("Cannot import numpy/openCV. Switching to NO_CV mode.")
        no_cv = True
    
    async def _upload_change_and_show(e):
        #Get the first file from upload
        file_list = e.target.files
        first_item = file_list.item(0)
    
        #Get the data from the files arrayBuffer as an array of unsigned bytes
        array_buf = Uint8Array.new(await first_item.arrayBuffer())
    
        #BytesIO wants a bytes-like object, so convert to bytearray first
        bytes_list = bytearray(array_buf)
        my_bytes = io.BytesIO(bytes_list) 
    
        #Create PIL image from np array
        my_image = Image.open(my_bytes)
    
        #Log some of the image data for testing
        console.log(f"{my_image.format= } {my_image.width= } {my_image.height= }")
    
        # Now that we have the image loaded with PIL, we can use all the tools it makes available. 
        my_image = my_image.convert("L")
    
        my_image = ImageOps.autocontrast(my_image, 5, preserve_tone=True)
    
        resolution=1024
        draw_contours=2
        repeat_contours=1
        draw_hatch=16
        repeat_hatch=1
    
        lines = []
    
        if draw_contours and repeat_contours:
            contours = getcontours(resize_image(my_image, resolution, draw_contours), draw_contours)
            contours = sortlines(contours)
            contours = join_lines(contours)
            for r in range(repeat_contours):
                lines += contours
    
        if draw_hatch and repeat_hatch:
            hatches = hatch(resize_image(my_image, resolution), line_spacing=draw_hatch)
            hatches = sortlines(hatches)
            hatches = join_lines(hatches)
            for r in range(repeat_hatch):
                lines += hatches
    
        segments = 0
        for line in lines:
            segments = segments + len(line) - 1
        print(len(lines), "lines,", segments, "segments.")
    
        f = open("plotter.svg", "w")
        f.write(makesvg(lines))
        f.close()
    
        #Convert Pillow object array back into File type that createObjectURL will take
        my_stream = io.BytesIO()
        my_image.save(my_stream, format="PNG")
    
        #Create a JS File object with our data and the proper mime type
        image_file = File.new([Uint8Array.new(my_stream.getvalue())], "new_image_file.png", {type: "image/svg"})
    
        #Create new tag and insert into page
        new_image = document.createElement('img')
        new_image.src = window.URL.createObjectURL(image_file)
        document.getElementById("output_upload_pillow").appendChild(new_image)
    
    ###Linedraw Functions
    
    def makesvg(lines):
        print("generating svg file...")
        out = '<svg xmlns="http://www.w3.org/2000/svg" version="1.1">'
        for l in lines:
            l = ",".join([str(p[0]*0.5)+","+str(p[1]*0.5) for p in l])
            out += '<polyline points="'+l+'" stroke="black" stroke-width="2" fill="none" />n'
        out += '</svg>'
        return out
    
    #Other linedraw-functions...
    

  2. Following your expanded answer – if you have your SVG as a string of HTML, you can set the innerHTML property of a DOM element to that source:

    <div id="dest"></div>
    <py-script>
        import js
    
        svg_as_string = """<svg>Your data here</dvg>"""
    
        dest_elem = js.document.getElementById("dest")
        dest_elem.innerHTML = svg_as_string
    </py-script>
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search