Forum Archive

Could use help with image resize glitch

donnieh

I would appreciate some help. I have a modified pythonista example. It is a sketch view. I have added the ability to insert a picture and then sketch on top of it.

The issue is after I sketch on top of a picture, the image resizes and become distorted. The script sketches fine if no picture is inserted though so the inserted picture is screwing things up. If you run the code below you will see.

I have narrowed down the issue to the function path_action() but cannot succeed in fixing it.

# coding: utf-8

# Sketch
# A very simple drawing 'app' that demonstrates # custom views and saving images to the camera roll.

import ui
import photos
import console

# The PathView class is responsible for tracking # touches and drawing the current stroke.
# It is used by SketchView.

class PathView (ui.View):
    def __init__(self, frame):
        self.frame = frame
        self.flex = 'WH'
        self.path = None
        self.action = None

    def touch_began(self, touch):
        x, y = touch.location
        self.path = ui.Path()
        self.path.line_width = 3
        self.path.line_join_style = ui.LINE_JOIN_ROUND
        self.path.line_cap_style = ui.LINE_CAP_ROUND
        self.path.move_to(x, y)

    def touch_moved(self, touch):
        x, y = touch.location
        self.path.line_to(x, y)
        self.set_needs_display()

    def touch_ended(self, touch):
        # Send the current path to the SketchView:
        if callable(self.action):
            self.action(self)
        # Clear the view (the path has now been rendered
        # into the SketchView's image view):
        self.path = None
        self.set_needs_display()

    def draw(self):
        if self.path:
            self.path.stroke()

# The main SketchView contains a PathView for the current # line and an ImageView for rendering completed strokes.
# It also manages the 'Clear' and 'Save' ButtonItems that # are shown in the title bar.

class SketchView (ui.View):
    def __init__(self, width=1024, height=1024):
        self.bg_color = 'white'
        iv = ui.ImageView(frame=(0, 0, width, height))
        pv = PathView(frame=self.bounds)
        pv.action = self.path_action
        self.add_subview(iv)
        self.add_subview(pv)
        save_button = ui.ButtonItem()
        save_button.title = 'Save'
        save_button.action = self.save_action
        clear_button = ui.ButtonItem()
        clear_button.title = 'New    '
        clear_button.tint_color = 'red'
        clear_button.action = self.clear_action
        view_button = ui.ButtonItem()
        view_button.title = '    Files'
        view_button.action = self.view_action
        self.right_button_items = [save_button, clear_button]
        self.left_button_items = [view_button]
        self.image_view = iv

    def path_action(self, sender):
        path = sender.path
        old_img = self.image_view.image
        width, height = self.image_view.width, self.image_view.height
        #width, height = ui.get_screen_size()
        with ui.ImageContext(width, height) as ctx:
            if old_img:
                old_img.draw()
            path.stroke()
            self.image_view.image = ctx.get_image()


    def clear_action(self, sender):
        self.image_view.image = None

    @ui.in_background
    def view_action(self, sender):
        self.image_view.image = ui.Image.from_data(photos.pick_image(raw_data=True))

    def save_action(self, sender):
        if self.image_view.image:
            # We draw a new image here, so that it has the current
            # orientation (the canvas is quadratic).
            with ui.ImageContext(self.width, self.height) as ctx:
                self.image_view.image.draw()
                img = ctx.get_image()
                photos.save_image(img)
                console.hud_alert('Saved to Photos')
        else:
            console.hud_alert('No Image to Save', 'error')


def load(self):
    # We use a quadratic canvas, so that the same image
    # can be used in portrait and landscape orientation.
    w, h = ui.get_screen_size()
    canvas_size = max(w, h)

    sv = SketchView(canvas_size, canvas_size)
    sv.name = 'Sketch Pad'
    sv.present('fullscreen')

load(None)
JonB

image_view has a default content mode which is scaling the image as displayed, but not actually scaling the underlying image. set iv.content_mode=ui.CONTENT_TOP_LEFT to prevent that.

You maybe ought to scale the image in view_action before you set the imageview. Though doing so causes you to lose resolution.

Or better yet, keep the full rez image, but set

    iv.content_mode=ui.CONTENT_SCALE_ASPECT_FIT

this requires you to set the width,height=old_img.size, but then also requires you to scale the path, or scale your touches perhaps.

Another problem: pathview defaults to flex=WH. Thus when presenting fullscreen, you no longer end up with a square canvas. Also, you might consider using canvas_size=min(w,h) so the entire canvas fits on screen.

finally...it seems somewhat inefficient to convert the path to an image every time. Perhaps it would be better to do that only once,when saving, instead storing a list of Paths.

donnieh

Thank you @JonB . I appreciate your explanation. I have not fully succeeded in getting it to work as expected but hope to get your suggestions working soon.