Re: [casetta] Important : Normalize function and strange behaviour...or not + NEW version of img_to_basic |
[ Thread Index |
Date Index
| More lists.tuxfamily.org/casetta Archives
]
- To: casetta@xxxxxxxxxxxxxxxxxxx
- Subject: Re: [casetta] Important : Normalize function and strange behaviour...or not + NEW version of img_to_basic
- From: "Florian Birée" <florian.biree@xxxxxxxxx>
- Date: Sat, 17 Mar 2007 17:21:55 +0100
- Dkim-signature: a=rsa-sha1; c=relaxed/relaxed; d=gmail.com; s=beta; h=domainkey-signature:received:received:message-id:date:from:to:subject:in-reply-to:mime-version:content-type:references; b=IWk/FP93DtoLItuO0jqltUhSlnI0f4krnaY4E9GCOAz4GbLvCFrBFxUheWF9LZINBrg1gqL9oAUwmOIkvnAiGusgHTsmupbnWMC7iXoyfxhM5WzDtWkRNFAHOBqPz9EmhOFpG34k2CX7eUmNv2KGdv1Spa1yLUxA30OdJ6etmvc=
- Domainkey-signature: a=rsa-sha1; c=nofws; d=gmail.com; s=beta; h=received:message-id:date:from:to:subject:in-reply-to:mime-version:content-type:references; b=S8B8mSjRCYJll36L4THHCw+ZpL4kuBXjQXG+QzJCuw6hEVhy+FciM9CUyWiIZoNoIC2gE+AMaQ8DGEXWP+b5z+YRkLGc1ifiHT7NRfR0ceQvr0r0gktgHt3ReIveJlLSnMzf5RD9fSZUT3tM2qUGCFXxVewexM5n0ClfplQDs14=
Hello,
2007/3/16, Florian Birée <florian.biree@xxxxxxxxx>:
Hi,
2007/3/16, Fabien ANDRE <fabien.andre.g@xxxxxxxxxx>:
Florian Birée a écrit :
Hello,
2007/3/15, Fabien ANDRE <fabien.andre.g@xxxxxxxxxx>:
Hello,
2 things :
1st: I have included the modifications you made in the
img_to_basic function old version and made that working for me :
The changelog until the last version I sent you is :
* Changed indent to 4-spaces and lines to 80-characters max.
* Changeg color constants to the system of dictionnaries/variables
* Included your special condition in the end F-line block : I didn't
understand what it is useful for but as
it didn't include new bugs, I included this
* Corrected the bug of a line not drawn if it goes to the end of a line
(Yes I know this is ugly)
I still don't know the problem there was in the modified version you
sent me. Maybe and indentation problem...
I succeded in transmitting my tux2.png on my calculator with your
pic2prog.py script. I hope this will work for you.
I will try it this week end, and send you if it work with me.
2nd: Sometimes, I
believe that the normalize function has a
strange behaviour. For example, the image in attachments contains white
(By Thesa).
And in the imagen variable sent to the img_to_basic function, there is
no white pixel (and of course on my calculator I get no white). I may
be wrong ;-)
Pixels are white only if the color is exactly (255,255,255), and not
values like (254, 255, 255). I know with issue, and I'll change the
color detection to be less strict.
I have also some feature
requests (not added in the wishlist, because I
want your opinion before : I don't know if it is easy of not !!!)
1- Could you make the dialog window in casetta (such as : "Mettez votre
calculatrice en réception et cliquez sur valider"), as it (traduction
incertaine de comme çà), you have just to press enter (yes, this is
another unimportant detail :-).
I'm currently writing a totally new transfer tool (so cafix and its
bug will ne longer be needed), and its almost ready to be added in the
repository. And I'll also rewrite the interface for it (when I'll work
on casetta_gtk, ie when casetta 0.3 will be almost finished).
2-For backups, could you add
the ability to casetta_gtk to show the
content ? (Name of programs, matrix,pictures etc ...)
It's an interesting idea, and not really to made (data is more or less
stored in the same way that it is send by the calculator). A function
which convert a backup into a casio file may just be a collection of
regular _expression_, each can extract a kind of data. (Its already do to
extract passwords from a backup).
But this function need to know how all data are stored in the casio
memory, and for the moment, I didn't know all types of data (you can
see
http://casetta.tuxfamily.org/formats/
for more information about formats). And I think the support of
all data is the first objective. So I prefer to work on a function like
this in a later version. But if you want to try to do this... ;-)
3-For image/screencapture
could you display them in casetta and add an
export function to export to png...
Yes, a picture editor is planned in casetta_gtk. For the png export, it
must already work in the svn version, as its only a casetta work, and
casetta can import/export all picture formats managed in the Python
Image Library (and there are a lot).
Normally, the img_to_basic
function is working and ready to be
integrated in the svn :-).
Ok, I'll see it this week-end.
"Longue vie à casetta"
Merci !
--
Thesa ~ Florian Birée
e-mail : florian.biree@xxxxxxxxx
Messagerie Instantanée Jabber/XMPP/Google Talk : florian.biree@xxxxxxxxx
Site web et blog : http://filyb.info/
"And I think the support of all data is the first objective. So I
prefer to work on a function like this in a later version. But if you
want to try to do this... ;-)"
Yes, you're right, support of all data is more important than these
secondary functions. But if we can get both that's better :-) So let's
go I'm trying to do that.A small revison of regexp will not be bad for
me !!
For the png, export it works with the svn version but when you click
save it proposes newcat as format and it is not obsvious for "simple"
user to change extension to PNG.
When you save a file, when you show the "other directory" panel, a list let you choice your format, and picture formats are already inside this list. The behaviour of the save as window follow the behaviour of all Gnome applications
"I'm currently writing a totally new transfer tool (so cafix and
its
bug will ne longer be needed), and its almost ready to be added in the
repository. And I'll also rewrite the interface for it (when I'll work
on casetta_gtk, ie when casetta 0.3 will be almost finished)."
Wow ! But why didn't you contact cafix author to ask him to correct the
bugs and to add support for new USB calculators ? He didn't answered ?
Cafix is no longer maintained ?
Yes, cafix is not maintained since 2002 or 2003. Add a lot of technical choice of the cafix project are very bad (the file format, details about how cafix work with the calculator) - in my opinion, of course. And cafix work only under GNU/Linux operating system, not my transfer tool which use the pyserial module.
--
Fabien ANDRE aka Xion345
Linux User
#418689
--
fabien.andre.g@xxxxxxxxxx --
xion345@xxxxxxxxxxxxx
When asked why he
called the new software, 'git,' British slang meaning 'a rotten
person,' he said. 'I'm an egotistical bastard, so I name all my
projects after myself. First Linux, now git.' ( Linus Torvalds, Not
dated )
I've test your function, the result is very good. Some details was bad (as the By Thesa in your picture) because of my normalize function. I've changed it, and now programs made by your functions display pictures perfectly. I've join the new
pictures.py file. It'll be uploaded in the svn repository soon.
Thank you for this great contribution!
(When I'll begin the work on casetta_gtk, I may move your function in the casetta_gtk code, since it's casetta_gtk which will used the function. For the moment, I don't know.)
--
Thesa ~ Florian Birée
e-mail : florian.biree@xxxxxxxxx
Messagerie Instantanée Jabber/XMPP/Google Talk :
florian.biree@xxxxxxxxx
Site web et blog : http://filyb.info/
# -*- coding: utf-8 -*-
#
############################################################################
#
# (c) 2006 Florian Birée aka Thesa <florian.biree@xxxxxxxxxxx>
# (c) 2006 Achraf Cherti aka Asher256 <achrafcherti@xxxxxxxxx>
# function img_to_basic is (c) 2007 Xion345 aka Fabien ANDRE
# <fabien.andre.g@xxxxxxxxxx>
#
# Website: <URL:http://casetta.tuxfamily.org>
#
# Version 0.3.0
#
# changelog:
#
# # 0.3.0 version:
#
# o First release
#
############################################################################
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# MA 02110-1301, USA.
#
# http://www.gnu.org/copyleft/gpl.html
#
############################################################################
"""Pictures manager for casetta"""
__author__ = "Florian Birée, Achraf Cherti"
__version__ = "0.3.0"
__copyright__ = "Copyright (c) 2006, Florian Birée, Achraf Cherti"
__license__ = "GPL"
__revision__ = "$Revision: $"
# $Source: $
__date__ = "$Date: $"
import Image
import os
import data as datacls
# Constants:
ORANGE = (255, 128, 0)
GREEN = (0, 128, 0)
BLUE = (0, 0, 128)
WHITE = (255, 255, 255)
CASIO_SIZE = (128, 64)
COLORS = (ORANGE, GREEN, BLUE, WHITE)
_COLOR_DIC = {'o' : ORANGE,
'g' : GREEN,
'b' : BLUE,
'w' : WHITE}
DEFAULT_PALLET = ['b', 'g', 'w', 'o']
WHITE_LIMIT = 210
# If all color of a pixel are superior of WHITE_LIMITE, they will be white.
# Conversion functions
def normalize(image, colors=COLORS):
"""Convert an image object in a casio-like format.
This will:
resize image to 128x64
convert color to 4-color mode
return a data list.
pal is a 4-color tuple.
"""
if image.size != CASIO_SIZE:
image = image.resize(CASIO_SIZE, Image.ANTIALIAS)
data = list(image.getdata())
out = []
# color conversion
for pixel in data:
red, green, blue = pixel[0], pixel[1], pixel[2]
if red > WHITE_LIMIT and green > WHITE_LIMIT and blue > WHITE_LIMIT:
pixel = colors[3] # white
elif red > green and red > blue:
pixel = colors[0] # orange
elif green > red and green > blue:
pixel = colors[1] # green
elif blue > green and blue > red:
pixel = colors[2] # blue
elif red == green and red > blue:
pixel = colors[1] # green
elif green == blue and green > red:
pixel = colors[2] # blue
elif red == blue and red > green:
pixel = colors[2] # blue
elif (red, green, blue) == (0, 0, 0):
pixel = colors[2] # blue
out.append(pixel)
return out
def data_to_sheets(data, wanted_pallet=DEFAULT_PALLET):
"""Make raw picture sheets from *normalized* data
wanted_pallet is a list of color id as 'b', 'g', 'w' or 'o'
Return a list of data sheets, sorted as wanted_pallet, with the
color byte at 0."""
sheets = []
for color_id in wanted_pallet :
color = _COLOR_DIC[color_id]
rev_sheet = '0' * (128 * 64)
for index in range(len(data)):
if data[index] == color:
line = index / 128
col = (index % 128) / 8
car = (index % 128) % 8
pos = car + line * 8 + col * (8 * 64)
rev_sheet = rev_sheet[:pos] + '1' + rev_sheet[pos + 1:]
# reverse and compact the rev_sheet
sheet = ''
for index in range(0, len(data), 8):
car = chr(int(rev_sheet[index : index + 8], 2))
sheet = car + sheet
sheets.append(chr(wanted_pallet.index(color_id) + 1) + sheet)
return sheets
def sheets_to_raw(sheets, headers = None):
"""Join sheets to make raw data
The function can add a sheet header form the headers list (one string by
sheet).
"""
raw_img = ''
for index in range(len(sheets)):
if headers != None:
raw_img += headers[index]
raw_img += sheets[index]
return raw_img
def data_to_raw(data, wanted_pallet=DEFAULT_PALLET, headers = None):
"""Work as sheets_to_raw(data_to_sheets(data)), with same arguments"""
return sheets_to_raw(data_to_sheets(data, wanted_pallet), headers)
def raw_to_data(raw_picture, color_byte=0, pal=DEFAULT_PALLET, \
colors=COLORS, background=WHITE):
"""Make image data from a raw picture
colors is a 4-color tuple,
color_byte is the index of the color_byte (last byte of a sheet header)
pal is the ordoned list of the color corresponding to each sheet
background is the default color of a pixel."""
#make color dic:
color_dic = { 'o' : colors[0],
'g' : colors[1],
'b' : colors[2],
'w' : colors[3]}
#extract raw sheets from raw_picture
raw_sheets = []
sh_len = 0x400 + color_byte + 1
for index in range(len(pal)):
offset = index * sh_len
raw_sheets.append(raw_picture[offset: offset + sh_len])
#convert raw sheets to list data
data = [background] * (CASIO_SIZE[0] * CASIO_SIZE[1])
for raw_sheet in raw_sheets:
color = ord(raw_sheet[color_byte]) - 1
raw_sheet = raw_sheet[color_byte + 1:]
for index in range(len(raw_sheet)):
byte = bin(ord(raw_sheet[index]))
col, line = (15 - ((index) / 64)) * 8, 63 - ((index) % 64)
data_pos = line * 128 + (col )
for bit_index in range(len(byte)):
if byte[bit_index] == '1':
bit_pos = data_pos + bit_index
data[bit_pos] = color_dic[pal[color]]
return data
def raw_to_sheets(raw_picture, color_byte = 0, sheet_number = 4):
"""Split raw data into sheets"""
raw_sheets = []
sh_len = 0x400 + color_byte + 1
for index in range(sheet_number):
offset = index * sh_len
raw_sheets.append(raw_picture[offset + color_byte: offset + sh_len])
return raw_sheets
def change_sheets_pallet(sheets, old_pallet, new_pallet):
"""Resort sheets from old_pallet to new_pallet
If a collor in new_pallet is not in old_pallet, a empty sheet
will be made for this color.
"""
sheet_dic = {}
for index in range(len(old_pallet)):
sheet_dic[old_pallet[index]] = sheets[index][1:]
new_sheets = []
for index in range(len(new_pallet)):
new_sheets.append(chr(index + 1) + sheet_dic.get(new_pallet[index], \
'\x00' * (16 * 64)))
return new_sheets
# File format management functions
def open_img(filename):
"""Open an image in any PIL-managed format, return a filedata"""
# Build the FileData
file_data = datacls.FileData()
new_index = file_data.new_data()
# Write metadata
file_data[new_index].name = 'Picture1'
file_data[new_index].dType = 'picture'
file_data[new_index].pallet = DEFAULT_PALLET
file_data[new_index].color_byte = 0
# Write data
img = Image.open(filename)
file_data.data[new_index].raw_data = data_to_raw(normalize(img), \
DEFAULT_PALLET)
return file_data
def save(filename, file_data, export=False):
"""Save a picture"""
folder = os.path.dirname(filename)
ext = os.path.splitext(filename)[1]
# For each data
if export:
index_list = file_data.export
else:
index_list = range(len(file_data.data))
for data in [file_data.data[index] for index in index_list]:
if data.dType == 'picture' or data.dType == 'screencapture' :
# make a filename from the name
if len(index_list) == 1 and os.path.basename(filename) != '':
# try to use filename as name
data_filename = filename
else:
data_filename = os.path.join(folder, data.name + ext)
# write data
img = Image.new('RGB', CASIO_SIZE)
img.putdata(raw_to_data(data.raw_data, data.color_byte,
data.pallet))
img.save(data_filename)
# Misc functions
def bin(number, total_length = 8):
"""Convert a number in binary, filled with 0 to reach total_length."""
out = ''
while number != 0:
number, out = number >> 1, `number & 1` + out
out = '0' * (total_length - len(out)) + out
return out
# This function is a contribution of Xion345 aka Fabien ANDRE.
# Xion345, thank you!
def img_to_basic(imagen, colors=COLORS):
"""Convert a *normalized* image into a Casio Basic program
This function only returns Horinzontal F-line. It may not be really
optimised for size"""
program_header = "\Cls\n\ViewWindow 0,127,1,0,63,1\n"
orange, green, blue, white = colors # colors dictionnary
# Splits the BIG list given by normalize into a list of list
# in order to have a table of 128 columns per 64 lines
pictureTable=[]
numberLine=0
basicPicture='' # A picture under the form of a basic program / Returned by
#the function
line=0
while line <= 63:
pictureTable.append(imagen[line*128:((line+1)*128)])
line += 1
line=0
while line <= 63:
col=0
currentColor=0 # This var contains the previously saved color
orig_x=0
orig_y=0
end_x=0
end_y=0 # In fact this varible is totally unuseful because the table is
#browsed line per line so
# end_y = orig_y. It is just used to make my function clearer
while col <= 127:
if pictureTable[line][col] != currentColor and \
pictureTable[line][col-1] == currentColor \
and currentColor in colors[:3] or col==127 and currentColor != \
white and pictureTable[line][col] == currentColor:
# If you get a pixel which color is different from currentColor
# and if before you have a colored pixel,
#that's because you encountered the end of the F-line
# The second condition after the or is an UGLY correction of a
# BUG ^W Feature
# If an F-line goes at the lats pixel of a pictureTable line,
# the line is not drawn because the first confition (end line
# see above ), waits for the pixel just after the end of the
# line. This blocks checks if were are at the last pixel of the
# line and if a F-line is being drawn (currentColor != white)
if col != 127:
end_x -= 1
if currentColor == orange:
basicPicture += "\\Orange "
if currentColor == green:
basicPicture += "\\Green "
# The origin of the reference mark is different
#on the casio graph and on the picture
# On casio origin is bottom left-hand corner
# On the picture and my table, it's top left-hand corner
# That's why it must do casio_line = 63-line
casio_orig_y = 63-orig_y
casio_end_y = 63-end_y
if end_x != orig_x:
basicPicture += "\\F-Line " \
+str(orig_x)+","+str(casio_orig_y)+"," \
+str(end_x)+","+str(casio_end_y)+"\n"
else:
basicPicture += "\\PlotOn " \
+str(orig_x)+","+str(casio_orig_y)+"\n"
currentColor=0 # This var contains the previously saved color
orig_x=0
orig_y=0
end_x=0
end_y=0
if pictureTable[line][col] != white and \
pictureTable[line][col] != currentColor:
# New F-line to add detected
currentColor=pictureTable[line][col]
end_x=col
orig_x=col
end_y=line
orig_y=line
if pictureTable[line][col] != white and \
pictureTable[line][col] == currentColor:
# Continues the F-line
end_x +=1
col += 1
line += 1
return program_header+basicPicture