diff --git a/README.md b/README.md index 69b0ffd..e3fc194 100644 --- a/README.md +++ b/README.md @@ -12,16 +12,18 @@ Color values are specified using triplets of float values, like (128.5, 34.234, python-FloatImg requires a shared object file (.so) that is not yet officialy available from FloatImg. -The file `floatimg/settings.py` contains the path to the .so file. +The file `floatimg/settings.py` contains the path to the .so file and the encoding of path characters. ## Usage -The FloatImg class encapsulate core and file functionnalities of FloatImg library. Import if from the main module: - ```python import floatimg ``` +The FloatImg class encapsulate core and file functionnalities of FloatImg library. Instances are created with functions from the module. + +Colors are tuple of three elements `(r, g, b)`. + ### Image creation `FloatImg` has two class methods to create an image. @@ -47,60 +49,54 @@ new_img = img.clone() new_img = img.clone(True) ``` -### Image manipulation - -#### Clear image - -Reset all pixels to zero. - -```python -img.clear() -``` - -#### Copy pixels to another image - -```python -img.copy_data(another_img) -``` - -#### Set pixel value - -```python -img.put(x, y, (r, g, b)) -``` - -#### Get pixel value +### Basic pixel manipulation ```python +# Get pixel value color = (r, g, b) = img.get(x, y) + +# Set pixel value +img.put(x, y, (r, g, b)) + +# Reset all pixels to zero. +img.clear() + +# Copy pixels to another image of the same format +img.copy_data(another_img) ``` ### File manipulation -#### Dump image to file +#### Raw dump files ```python -img.dump("/tmp/image_dump") +# Dump image to file +img.dump(path) + +# Restore image data from a dump file +img.load(path) + +# Create a new image from a dump file +img = floatimg.create_from_dump(path) + +# Get dump metadata (TODO create a FileInfo named tuple) +witdh, height, img_type = floatimg.fileinfos(path) ``` -#### Restore image data from a dump file +#### External formats ```python -img.load("/tmp/image_dump") +# export supports the following extentions : .fimg, .png, .tiff, .pnm, .fits +# save as png +img.export("test.png") + +# create an image instance from png file +img = floatimg.create_from_png("test.png") + +# load pixel data from png file in an existing instance. size and type have to be compatible +img.load_png("test.png") ``` -#### Create a new image from a dump file - -```python -img = floatimg.create_from_dump("/tmp/image_dump") -``` -#### Get dump metadata - -TODO create a FileInfo named tuple. - -```python -witdh, height, img_type = floatimg.fileinfos("/tmp/image_dump") -``` ## Operators diff --git a/floatimg/__init__.py b/floatimg/__init__.py index 5cd4dad..b765067 100644 --- a/floatimg/__init__.py +++ b/floatimg/__init__.py @@ -8,6 +8,7 @@ from floatimg.image import ( create, create_rgb, create_from_dump, + create_from_png, fileinfos, ) diff --git a/floatimg/image.py b/floatimg/image.py index 932fe5a..2c01099 100644 --- a/floatimg/image.py +++ b/floatimg/image.py @@ -1,6 +1,6 @@ import ctypes as ct -from floatimg.settings import LIB +from floatimg.settings import LIB, PATH_ENCODING ############################################################################################################ # type constants @@ -163,6 +163,19 @@ c_fimg_maximum.argtypes = ( ) c_fimg_maximum.restype = ct.c_int +# Files i/o +c_fimg_export_picture = LIB.fimg_export_picture +c_fimg_export_picture.argtypes = (ct.POINTER(C_FloatImg), ct.c_char_p) +c_fimg_export_picture.restype = ct.c_int + +c_fimg_create_from_png = LIB.fimg_create_from_png +c_fimg_create_from_png.argtypes = (ct.c_char_p, ct.POINTER(C_FloatImg)) +c_fimg_create_from_png.restype = ct.c_int + +c_fimg_load_from_png = LIB.fimg_load_from_png +c_fimg_load_from_png.argtypes = (ct.c_char_p, ct.POINTER(C_FloatImg)) +c_fimg_load_from_png.restype = ct.c_int + ############################################################################################################ class FloatImg: @@ -175,7 +188,7 @@ class FloatImg: """ # proxy attributes to the C_FloatImg structure - # TODO: now more about them + # TODO: now more about them ;) magic = property(lambda self: self.c_img.magic) fval = property(lambda self: self.c_img.fval) count = property(lambda self: self.c_img.count) @@ -247,22 +260,32 @@ class FloatImg: assert c_fimg_add_rgb(self.c_img_p, x, y, *color) == 0 ####################################################################################################### - def dump(self, fname): + def dump(self, path): """save data to a dump file""" # TODO use system encoding instead of utf-8 assert ( c_fimg_dump_to_file( - self.c_img_p, ct.c_char_p(bytes(fname, encoding="utf8")), 0 + self.c_img_p, ct.c_char_p(bytes(path, encoding=PATH_ENCODING)), 0 ) == 0 ) ####################################################################################################### - def load(self, fname): + def load(self, path): """load data from a dump. size and type have to be compatible""" assert ( c_fimg_load_from_dump( - ct.c_char_p(bytes(fname, encoding="utf8")), self.c_img_p + ct.c_char_p(bytes(path, encoding=PATH_ENCODING)), self.c_img_p + ) + == 0 + ) + + ####################################################################################################### + def load_png(self, path): + """load data from a png file. size and type have to be compatible""" + assert ( + c_fimg_load_from_png( + ct.c_char_p(bytes(path, encoding=PATH_ENCODING)), self.c_img_p ) == 0 ) @@ -292,7 +315,7 @@ class FloatImg: def min(self, img): """return a new image with minimum pixel values per channel between current and parameter""" res = self.clone(False) - # C code invert comparison + # C code inverts comparison assert c_fimg_maximum(self.c_img_p, img.c_img_p, res.c_img_p) == 0 return res @@ -300,12 +323,19 @@ class FloatImg: def max(self, img): """return a new image with maximum pixel values per channel between current and parameter""" res = self.clone(False) - # C code invert comparison + # C code inverts comparison assert c_fimg_minimum(self.c_img_p, img.c_img_p, res.c_img_p) == 0 return res - # TODO - # export(fname, flags) : depending file extension, save to the correct format + ####################################################################################################### + def export(self, path): + """export image to path. allowed extension: .fimg, .png, .tiff, .pnm, .fits""" + assert ( + c_fimg_export_picture( + self.c_img_p, ct.c_char_p(bytes(path, encoding=PATH_ENCODING)), 0 + ) + == 0 + ) ########################################################################################################### @@ -313,7 +343,9 @@ def fileinfos(fname): """return witdh, height, img_type triplet read from a dump file""" datas = (ct.c_int * 3)() assert ( - c_fimg_fileinfos(ct.c_char_p(bytes(fname, encoding="utf8")), ct.pointer(datas)) + c_fimg_fileinfos( + ct.c_char_p(bytes(fname, encoding=PATH_ENCODING)), ct.pointer(datas) + ) == 0 ) return datas[:3] @@ -335,14 +367,25 @@ def create_rgb(witdh, height): ########################################################################################################### -def create_from_dump(fname): - """Create a new instance from a dump file""" - witdh, height, img_type = fileinfos(fname) +def create_from_dump(path): + """Create a FloatImg instance from a dump file""" + witdh, height, img_type = fileinfos(path) img = create(witdh, height, img_type) - img.load(fname) + img.load(path) return img +########################################################################################################### +def create_from_png(path): + """Create a FloatImg instance from a png file""" + img = C_FloatImg() + assert ( + c_fimg_create_from_png(ct.c_char_p(bytes(path, encoding=PATH_ENCODING)), img) + == 0 + ) + return FloatImg(img) + + ########################################################################################################### def type_is_valid(type_id): """return True if type_id is a valid one""" diff --git a/floatimg/settings.py b/floatimg/settings.py index 8bd20f5..782d282 100644 --- a/floatimg/settings.py +++ b/floatimg/settings.py @@ -1,5 +1,5 @@ import ctypes -# LIB = ctypes.cdll.LoadLibrary("../FloatImg/libfloatimg.so") +PATH_ENCODING = "utf8" LIB = ctypes.cdll.LoadLibrary("../FloatImg4PythonBinding/build/lib/libfloatimg.so") diff --git a/tests/files.py b/tests/files.py new file mode 100644 index 0000000..aa5c423 --- /dev/null +++ b/tests/files.py @@ -0,0 +1,28 @@ +import os + +import floatimg + +def create_img(): + width, height = 5, 5 + img = floatimg.create_rgb(width, height) + img.fill((255.0, 0.0, 0.0)) + return img + +def test_png(): + width, height = 5, 5 + path = "test.png" + img = create_img() + img.export(path) + assert os.path.getsize(path) == 74 + img2 = floatimg.create_from_png(path) + for y in range(height): + for x in range(width): + assert img.get(x, y) == img2.get(x, y) + + img3 = img2.clone(False) + img3.load_png(path) + for y in range(height): + for x in range(width): + assert img.get(x, y) == img3.get(x, y) + +