0

I would like to get the canvas coordinate of every pixel of a line that is drawn with a given width in tkinter canvas.

There was a previous post on this question and the answer given is that it is not possible to get the inform from tkinter.[1]Tkinter: save coordinates of a drawn line of a given width

However, tkinter provides users the ability tag any drawn items on canvas and furthermore the ability to delete the tagged items. Should this not mean that tkinter must have created an array variable for a tagged item to store the canvas coordinates of every pixel of the tagged item so that a user can remove/hide/show the tagged item when the need arises? If this reasoning is correct, theoretically speaking a user should be able to extract the canvas coordinate of every pixel of a tagged drawn item if a user has access to the tkinter array variable.

I would like to ask the following questions:

  1. Is my reasoning mentioned above correct?
  2. Does someone knows how to extract the canvas coordinate of every pixel associated to a tagged canvas line using tkinter commands or otherwise?
Community
  • 1
  • 1
Sun Bear
  • 7,594
  • 11
  • 56
  • 102
  • Check this http://stackoverflow.com/questions/30104270/tkinter-number-of-pixels-of-a-line-oval – Kenly Dec 28 '15 at 09:33
  • Deleting an item means redrawing everything on the canvas without the deleted item. There is no need to know which pixels were occupied by the deleted item to do this. – BlackJack Dec 28 '15 at 18:25

2 Answers2

1

There is no way to get the pixel information of an item on a tkinter canvas. To get at the information you would need to implement a new canvas item method (in C), and recompile tk and tkinter for your own use. Even then, I'm not sure you can do what you want. Ultimately, the canvas code calls X11 drawing primitives -- specifically, XDrawLines in the case of lines -- which I don't think returns the actual pixels that were drawn.

Here's a link to the trunk of the tk source tree, if you're wanting to modify the canvas source code: http://core.tcl.tk/tk/dir?ci=trunk&name=generic. The file you'll probably need to modify it tkCanvLine.c, and within that you should look for the function DisplayLine

Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685
  • Thanks Bryan. It looks quite beyond my skill set. In tkCanvLine.c, in the section of DisplayLine, I think the array numPoints holds the pixel's screen coordinate information of the line. – Sun Bear Feb 02 '16 at 00:31
0

Without going into the details of X11 drawing primitives, I coded a method in my python & tkinter code to capture the canvas coordinate of every pixel of a tkinter canvas line created with a known width. It's lacking formal proof but visual inspections seems to indicates it works. I share my research and code below. Hope it helps tkinter users. Suggestions on improvement or feedback on it's use are appreciated.

Assumptions:

  1. Line width has odd number of pixels.
  2. Three types of pixel representation are used to draw the line width pixels: (a) vertical type (|), (b) horizontal type (_) & (c) diagonal types (/) & (). I observed these line width representations when tk.canvas.create_line is active.
  3. The criteria to determine the type of line width pixel representation are based on the gradient of the relative position between the two points of a line.

Line Width Pixel Representation Criteria:

Examples:

Code:

def linewidthpixels(self, width, Acol, Arow, Bcol, Brow):
    """
    This method attempts to replicate how tk.canvas.createline creates a
    line with a given width on tk.canvas. The line width's orientation is a
    function of the gradient of the line. Verification was done by visual 
    comparison; formal proof lacking.

    Input Mandatory Argument:
    -------------------------
    width - width of line including its center pixel (in pixel units).
    Acol  - line 1st point column coordinate (x-axis).
    Arow  - line 1st point row coordinate (y-axis).
    Bcol  - line 2nd point column coordinate (x-axis).
    Brow  - line 2nd point row coordinate (y-axis).

    Internal Variables:
    -------------------------
    swidth - half the width of line excluding its center pixel (in pixel units).

    Return Variable:
    ----------------
    linepixels - a numpy 1D array consisting the (col,row) position [] of every pixel
                 used to represent a line with a given width.

    Created: 20th Jan 2016
    Amended: 21st Jan 2016

    Acknowledgement: Kindly acknowledge author when using this code (with or without modifications).
    """
        print('def linewidthpixels(self, width, Acol, Arow, Bcol, Brow):')
        print ('width, Acol, Arow, Bcol, Brow =', width, Acol, Arow, Bcol, Brow)
        # 1. Initialise return variable
        linepixels = np.array([], dtype=np.uint16)
        # 2. Calculate the number of side pixels given to the line
        swidth = int(abs((width-1)/2))
        print('swidth =', swidth)
        # 3. Calculate gradient (m) of the line (B: endpoint, A: startpoint)
        if (Bcol - Acol) != 0: # When m is finite
            m = (Brow - Arow) / (Bcol - Acol)
        else: # when m is infinite
            m = float('Infinity')
        print ('m =', m)
        # 4. Store A: starpoint, it is the centre pixel of the line width
        linepixels = np.array([Acol, Arow])
        # 5. Determine and store the coordinates of the pixels of the line width
        if width != 1: # line width > 1 pixel wide
            if m > -0.5 and m < 0.5: # Linewidth type = |
                print('Linetype = |')
                for k in range(1,swidth+1,1):
                    linepixels = np.append(linepixels, [[Acol, Arow+k], [Acol, Arow-k]])
            elif m >= 0.5 and m < 2.0: # Linewidth type = /
                print('Linetype = /')
                for k in range(1,swidth+1,1):
                    linepixels = np.append(linepixels, [[Acol+k, Arow-k], [Acol-k, Arow+k]])
            elif m > -2.0 and m <= -0.5: # Linewidth type = \
                print('Linetype = \\')
                for k in range(1,swidth+1,1):
                    linepixels = np.append(linepixels, [[Acol-k, Arow-k], [Acol+k, Arow+k]])
            else: # Linewidth type = --
                print('Linetype = --')
                for k in range(1,swidth+1,1):
                    linepixels = np.append(linepixels, [[Acol+k, Arow], [Acol-k, Arow]])
        print ('linepixels =', linepixels)
        print ('Size of linepixels =', linepixels.size)
        return linepixels
Sun Bear
  • 7,594
  • 11
  • 56
  • 102