2

So I got .txt file with around 200 lines, each contains a (x,y) location ranging from 0 to 255. I want to draw dot, or "," at each location.. so (0,5) will draw 5 spaces in first line and then the ",".

Using python, is there a way to print it to the terminal that way? if not, is there a way to create .txt file with the "image" or any other way to view the resulting "image" (its just bunch of ","'s) thanks.

EDIT:

The .txt file is something I extracted from challenge. The challenege was to decode the output of given binary file. This is the original file: https://elbitcareer.hunterhrms.com/wp-content/uploads/elbitsystems.elbit

This is the .txt coords I managed to extract from the file: https://easyupload.io/imtbdn

And this is what it looks like when I print it to the terminal: enter image description here

It looks like the right direction (SYSCO..?) but something is off.. Any ideas on what is the problem?

EDIT2: So my .txt file was missing some points and my terminal window needed some resizing.. now it kinda workds! thanks all.

Gal Birka
  • 581
  • 6
  • 16
  • Load the coordinates into a set of tuples (or, for performance, a dict of y coordinates to a set of x coordinates), then iterate over each row and format a string to represent that line? – AKX Jan 08 '21 at 10:29
  • Can you tell something more about how you specify your data? Maybe instead of x,y location you should use smth like : (row, spaces, dots, spaces,dots.... 'new_line'), because if you will draw 5 spaces and 1 ',' and turn to another line there will be no option to print something in this line anymore. If you got point like (10,10) it will be 10 enters , 10 spaces and 1 "." Its gona be poor pic :P – Raxodius Jan 08 '21 at 11:00
  • Can you upload your .txt file and picture sample? – Raxodius Jan 08 '21 at 11:02
  • I edited the original post with more information.. There is still some problem. (Mabye I extracted the data wrong?..) – Gal Birka Jan 08 '21 at 11:14
  • 1
    This print_at func works for you? I got only smth like this :←[25;92H, at the output.... – Raxodius Jan 08 '21 at 11:43
  • @Raxodius yeah it acually does :) I'm using Windows 10 with Windows Terminal running the CMD.. Since you asked I checked running it with the "old" cmd without Windows Terminal.. and like you said, it did not work. But again, windows 10 using Windows Terminal, it does. – Gal Birka Jan 08 '21 at 12:47

3 Answers3

1

Here is a little function using ANSI escape codes to do that.

def print_at(x, y, txt):
    """
    Print txt on a specific coordinate of the terminal screen.
    """
    print(f"\033[{y};{x}H{txt}")
alec_djinn
  • 10,104
  • 8
  • 46
  • 71
  • Note that this might not work very well at all on Windows or other platforms that don't have 100% support for ANSI escape codes. – AKX Jan 08 '21 at 10:27
  • I believe from Windows 10 onward the terminal has an option to accept ANSI escape codes. I am not a Windows user so I can't guarantee that, please check here for more info https://stackoverflow.com/questions/16755142/how-to-make-win32-console-recognize-ansi-vt100-escape-sequences – alec_djinn Jan 08 '21 at 10:33
  • Thank you for the reply, I edited the original post with more information.. There is still some problem. (Mabye I extracted the data wrong?..) – Gal Birka Jan 08 '21 at 11:14
  • @Birkagal I get a similar output, the code looks correct, I think you need to adjust the size of your terminal, some of the x coordinates are to big otherwise and they will fall on the next line. – alec_djinn Jan 08 '21 at 12:22
  • 1
    @alec_djinn Thank you for the help my friend. Yeah I needed to resize the terminal window and add some more points from the "challenge". Anyway I now solved it, thanks alot and the print_at function works perfectly and I learned something new today. THANKS AGAIN! – Gal Birka Jan 08 '21 at 12:50
1

I wrote some code and the output seems to be just like yours but a little more. So the problem must be in the console size. I used out.txt file and this code:

import numpy as np

xmax = 0
ymax = 0
with open('out.txt', 'r') as f:
    while f.readline() !='':
        line = f.readline()
        if line and "," in line:
            x, y = line.split(',')
        x = int(x)
        y = int(y)
        if x > xmax:
            xmax = x
        if y > ymax:
            ymax = y
f.close()

pic = np.zeros((xmax+1,ymax+1))

with open('out.txt', 'r') as f:
    while f.readline() !='':
        line = f.readline()
        if line and "," in line:
            x, y = line.split(',')
        x = int(x)
        y = int(y)
        pic[x][y] = 1
        
print(xmax,ymax)

with open('picture.txt', 'w') as f:
    for y in range(ymax):
        for x in range(xmax):
            if pic[x][y] == 1:
                f.write('.')
            else:
                f.write(' ')
        f.write('\n')

This code works in 4 steps:

  1. Looking for max values of the picture.
  2. Creates matrix filled with zeros with this size.
  3. Fill the matrix with ones according to x,y coordinates from out.txt
  4. Iterate through the matrix and write to picture.txt dot '.' if there is 1 and spaces if 0.

The output file is picture.txt and looks like this: enter image description here

try to change size of your terminal console and will be good :)

Raxodius
  • 109
  • 8
  • Oh, and i deleted " ( ) " signs from out.txt file when runing this code. – Raxodius Jan 08 '21 at 12:01
  • Thank you for the reply! this is acually work, and apperantly my original code was working as well I just needed to add some more points from the "challenge". Anyway I really appriciate your help and explanation, THANKS AGAIN! – Gal Birka Jan 08 '21 at 12:49
1

Updated Answer

Now that your file has the format:

colourIndex, x, y

you can make a PNG image like this:

#!/usr/bin/env python3

import numpy as np
from PIL import Image

# Unpack CSV into three Numpy arrays
colour, x, y = np.loadtxt('out.txt', dtype=np.int, delimiter=',', unpack=True)

# Find height and width of "image", i.e. maximum y and x
h = np.max(y)
w = np.max(x)
print(f'Width: {w}, height: {h}')

# Make empty (black) 3-channel RGB image right size
im = np.zeros((h,w,3), dtype=np.uint8)

# Choose some colours for the colour indices
colmap = {0:[255,0,255],    # 0 -> magenta
          1:[128,128,128]}  # 1 -> grey

# Fill in points in colour
for col,thisx,thisy in zip(colour,x,y):
    im[thisy-1, thisx-1] = colmap[col]

# Make into "PIL Image" and save
Image.fromarray(im).save('result.png')

enter image description here

Original Answer

As your question mentions "or other way", I thought I'd make a PNG image from your data:

#!/usr/bin/env python3

import re
import numpy as np
from PIL import Image

# Open file with rather pesky parentheses, carriage returns and linefeeds
with open('out.txt', 'r') as f:
    c = f.read()

# Find all things that look like numbers and make into Numnpy array of 2 columns
points = np.array(re.findall('\d+',c), dtype=np.int).reshape(-1,2)

# Find height and width of "image", i.e. maximum x and y
w, h = np.max(points, axis=0)
print(f'Width: {w}, height: {h}')

# Make empty (black) image right size
im = np.zeros((h,w), dtype=np.uint8)

# Fill in white points
im[points[...,1]-1,points[...,0]-1] = 255

# Make into "PIL Image" and save
Image.fromarray(im).save('result.png')

Note that the code is twice as long as it needs to be as a result of all the unnecessary parentheses and Windows-y CR+LF at the line ends (Carriage Return and Linefeeds) in your input file.

enter image description here

Note that I scaled the image vertically because characters in a Terminal are generally taller than they are wide - unlike bitmapped images where pixels are square.

Mark Setchell
  • 191,897
  • 31
  • 273
  • 432
  • hey Mark, this is pretty cool! I edited the original post since I kinda solve the poblem and provided the "resulting" image.. as you can tell I only had one part of the solution the first time.. Turn out it acually use 2 colors. The PNG method is kinda cool.. You think there is simple way to change it so it will support both colors? The new .txt file is formatted such that : [color], [x], [y], (without pesky parentheses) and color is just either 1 or 0 since there are only 2 colors in this "image". I already submitted my answer but I think it will look "cooler" as a PNG image rather then '10' – Gal Birka Jan 08 '21 at 15:02
  • 1
    I have updated my answer for the new format - please have another look. – Mark Setchell Jan 08 '21 at 17:46
  • Yeah thats perfect! really awesome, but when I tried to run it myself the result was a bit "crushed". On your original answer you mentioned scaling since charachter in Terminal are taller.. but how exactly you did it? I mean, how did you fixed the scale? – Gal Birka Jan 08 '21 at 17:57
  • I actually used **ImageMagick** in the Terminal because I am quickest with that `magick result.png -scale 200%x400% rescaled.png` but you could add a line in Python. Wait one moment... – Mark Setchell Jan 08 '21 at 18:09
  • 1
    Delete last line in Python and add `res = Image.fromarray(im)` then `res = res.resize((400,100))` and `res.save('result.png')` – Mark Setchell Jan 08 '21 at 18:14
  • 1
    Amazing.. Looks perfect. Thank you so much friend, you really help me and I learned quite few things from this.! – Gal Birka Jan 08 '21 at 19:03