Compare commits
No commits in common. "e57d63f562f80785d00673c2cf93c00886d6b2dd" and "1d4e2242cd7ac37799d2c448f2aafa67c1326e50" have entirely different histories.
e57d63f562
...
1d4e2242cd
20
README.md
20
README.md
@ -2,11 +2,7 @@
|
|||||||
|
|
||||||
A pythonesque binding to FloatImg library available at https://git.tetalab.org/tTh/FloatImg
|
A pythonesque binding to FloatImg library available at https://git.tetalab.org/tTh/FloatImg
|
||||||
|
|
||||||
python-FloatImg requires a Python 3 implementation (tested with 3.6.9).
|
python-FloatImg requires a quite recent Python 3 implementation (tested with 3.6.9).
|
||||||
|
|
||||||
Most function are wrapped into a similar api, sometime with a more consistent naming and an object-oriented approach.
|
|
||||||
|
|
||||||
Color values are specified using triplets of float values, like (128.5, 34.234, 242.23).
|
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
@ -44,15 +40,13 @@ Or completely duplicate an existing image:
|
|||||||
new_img = img.clone()
|
new_img = img.clone()
|
||||||
|
|
||||||
# with copying data
|
# with copying data
|
||||||
new_img = img.clone(True)
|
new_img = img.clone(1)
|
||||||
```
|
```
|
||||||
|
|
||||||
### Image manipulation
|
### Image manipulation
|
||||||
|
|
||||||
#### Clear image
|
#### Clear image
|
||||||
|
|
||||||
Reset all pixels to zero.
|
|
||||||
|
|
||||||
```python
|
```python
|
||||||
img.clear()
|
img.clear()
|
||||||
```
|
```
|
||||||
@ -66,13 +60,13 @@ img.copy_data(another_img)
|
|||||||
#### Set pixel value
|
#### Set pixel value
|
||||||
|
|
||||||
```python
|
```python
|
||||||
img.put(x, y, (r, g, b))
|
img.put_rgb(x, y, (r, g, b))
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Get pixel value
|
#### Get pixel value
|
||||||
|
|
||||||
```python
|
```python
|
||||||
color = (r, g, b) = img.get(x, y)
|
r, g, b = img.get_rgb(x, y)
|
||||||
```
|
```
|
||||||
|
|
||||||
### File manipulation
|
### File manipulation
|
||||||
@ -80,13 +74,13 @@ color = (r, g, b) = img.get(x, y)
|
|||||||
#### Dump image to file
|
#### Dump image to file
|
||||||
|
|
||||||
```python
|
```python
|
||||||
img.dump("/tmp/image_dump")
|
img.dump_to_file("/tmp/image_dump")
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Restore image data from a dump file
|
#### Restore image data from a dump file
|
||||||
|
|
||||||
```python
|
```python
|
||||||
img.load("/tmp/image_dump")
|
img.load_from_dump("/tmp/image_dump")
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Create a new image from a dump file
|
#### Create a new image from a dump file
|
||||||
@ -96,8 +90,6 @@ img = floatimg.create_from_dump("/tmp/image_dump")
|
|||||||
```
|
```
|
||||||
#### Get dump metadata
|
#### Get dump metadata
|
||||||
|
|
||||||
TODO create a FileInfo named tuple.
|
|
||||||
|
|
||||||
```python
|
```python
|
||||||
witdh, height, img_type = floatimg.fileinfos("/tmp/image_dump")
|
witdh, height, img_type = floatimg.fileinfos("/tmp/image_dump")
|
||||||
```
|
```
|
||||||
|
@ -126,24 +126,22 @@ class FloatImg:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
# proxy attributes to the C_FloatImg structure
|
# proxy attributes to the C_FloatImg structure
|
||||||
# TODO: now more about them
|
|
||||||
magic = property(lambda self: self.c_img.magic)
|
magic = property(lambda self: self.c_img.magic)
|
||||||
|
width = property(lambda self: self.c_img.width)
|
||||||
|
height = property(lambda self: self.c_img.height)
|
||||||
|
type_id = property(lambda self: self.c_img.type)
|
||||||
fval = property(lambda self: self.c_img.fval)
|
fval = property(lambda self: self.c_img.fval)
|
||||||
count = property(lambda self: self.c_img.count)
|
count = property(lambda self: self.c_img.count)
|
||||||
|
|
||||||
# oh yeah, really really sluggish access to pixels img.R[0].contents
|
# oh yeah, really really sluggish access to pixels img.R[0].contents
|
||||||
# however, pixel data are not designed to be accessed this way
|
# however, pixel data are not designed to be accessed this way
|
||||||
# R = property(
|
R = property(
|
||||||
# lambda self: pointer(self.c_img.contents.R)[: self.width * self.height]
|
lambda self: pointer(self.c_img.contents.R)[: self.width * self.height]
|
||||||
# )
|
)
|
||||||
|
|
||||||
#######################################################################################################
|
#######################################################################################################
|
||||||
def __init__(self, c_img):
|
def __init__(self, c_img):
|
||||||
self.c_img = c_img
|
self.c_img = c_img
|
||||||
self.width = c_img.width
|
|
||||||
self.height = c_img.height
|
|
||||||
self.type_id = c_img.type
|
|
||||||
# convenient pointer for later calls to C library
|
|
||||||
self.c_img_p = ct.pointer(c_img)
|
self.c_img_p = ct.pointer(c_img)
|
||||||
|
|
||||||
#######################################################################################################
|
#######################################################################################################
|
||||||
@ -162,15 +160,11 @@ class FloatImg:
|
|||||||
#######################################################################################################
|
#######################################################################################################
|
||||||
def clear(self):
|
def clear(self):
|
||||||
"""clear data"""
|
"""clear data"""
|
||||||
assert c_fimg_clear(self.c_img_p) == 0
|
return c_fimg_clear(self.c_img_p)
|
||||||
|
|
||||||
#######################################################################################################
|
#######################################################################################################
|
||||||
def clone(self, copy_data=False):
|
def clone(self, flags=0):
|
||||||
"""return a clone of the current instance"""
|
"""return a clone of the current instance"""
|
||||||
if copy_data:
|
|
||||||
flags = 1
|
|
||||||
else:
|
|
||||||
flags = 0
|
|
||||||
new_pic = C_FloatImg()
|
new_pic = C_FloatImg()
|
||||||
assert c_fimg_clone(self.c_img_p, ct.pointer(new_pic), flags) == 0
|
assert c_fimg_clone(self.c_img_p, ct.pointer(new_pic), flags) == 0
|
||||||
return FloatImg(new_pic)
|
return FloatImg(new_pic)
|
||||||
@ -186,18 +180,18 @@ class FloatImg:
|
|||||||
return c_fimg_str_type(self.c_img.type).decode("utf-8")
|
return c_fimg_str_type(self.c_img.type).decode("utf-8")
|
||||||
|
|
||||||
#######################################################################################################
|
#######################################################################################################
|
||||||
def fill(self, color):
|
def rgb_constant(self, r, v, b):
|
||||||
assert c_fimg_rgb_constant(self.c_img_p, *color) == 0
|
assert c_fimg_rgb_constant(self.c_img_p, r, v, b) == 0
|
||||||
|
|
||||||
#######################################################################################################
|
#######################################################################################################
|
||||||
def get(self, x, y):
|
def get_rgb(self, x, y):
|
||||||
"""get r,g,b triplet from a pixel"""
|
"""get r,g,b triplet from a pixel"""
|
||||||
rgb = (ct.c_float * 3)()
|
rgb = (ct.c_float * 3)()
|
||||||
assert c_fimg_get_rgb(self.c_img_p, x, y, ct.pointer(rgb)) == 0
|
assert c_fimg_get_rgb(self.c_img_p, x, y, ct.pointer(rgb)) == 0
|
||||||
return rgb[:3]
|
return rgb[:3]
|
||||||
|
|
||||||
#######################################################################################################
|
#######################################################################################################
|
||||||
def put(self, x, y, rgb):
|
def put_rgb(self, x, y, rgb):
|
||||||
"""put r,g,b triplet to a pixel"""
|
"""put r,g,b triplet to a pixel"""
|
||||||
# TODO may be a better way to create the array rather than iterating
|
# TODO may be a better way to create the array rather than iterating
|
||||||
c_rgb = (ct.c_float * 3)()
|
c_rgb = (ct.c_float * 3)()
|
||||||
@ -206,7 +200,7 @@ class FloatImg:
|
|||||||
assert c_fimg_put_rgb(self.c_img_p, x, y, ct.pointer(c_rgb)) == 0
|
assert c_fimg_put_rgb(self.c_img_p, x, y, ct.pointer(c_rgb)) == 0
|
||||||
|
|
||||||
#######################################################################################################
|
#######################################################################################################
|
||||||
def dump(self, fname):
|
def dump_to_file(self, fname):
|
||||||
"""save data to a dump file"""
|
"""save data to a dump file"""
|
||||||
# TODO use system encoding instead of utf-8
|
# TODO use system encoding instead of utf-8
|
||||||
assert (
|
assert (
|
||||||
@ -217,7 +211,7 @@ class FloatImg:
|
|||||||
)
|
)
|
||||||
|
|
||||||
#######################################################################################################
|
#######################################################################################################
|
||||||
def load(self, fname):
|
def load_from_dump(self, fname):
|
||||||
"""load data from a dump. size and type have to be compatible"""
|
"""load data from a dump. size and type have to be compatible"""
|
||||||
assert (
|
assert (
|
||||||
c_fimg_load_from_dump(
|
c_fimg_load_from_dump(
|
||||||
@ -226,12 +220,6 @@ class FloatImg:
|
|||||||
== 0
|
== 0
|
||||||
)
|
)
|
||||||
|
|
||||||
# TODO
|
|
||||||
# fimg_plot_rgb
|
|
||||||
# fimg_add_rgb
|
|
||||||
|
|
||||||
# export(fname, flags) : depending file extension, save to the correct format
|
|
||||||
|
|
||||||
|
|
||||||
###########################################################################################################
|
###########################################################################################################
|
||||||
def fileinfos(fname):
|
def fileinfos(fname):
|
||||||
@ -264,7 +252,7 @@ def create_from_dump(fname):
|
|||||||
"""Create a new instance from a dump file"""
|
"""Create a new instance from a dump file"""
|
||||||
witdh, height, img_type = fileinfos(fname)
|
witdh, height, img_type = fileinfos(fname)
|
||||||
img = create(witdh, height, img_type)
|
img = create(witdh, height, img_type)
|
||||||
img.load(fname)
|
img.load_from_dump(fname)
|
||||||
return img
|
return img
|
||||||
|
|
||||||
|
|
||||||
|
@ -21,26 +21,26 @@ def test_clone():
|
|||||||
width = 5
|
width = 5
|
||||||
height = 5
|
height = 5
|
||||||
img = floatimg.create(width, height, floatimg.RGB)
|
img = floatimg.create(width, height, floatimg.RGB)
|
||||||
img.fill((127.0, 127.0, 127.0))
|
img.rgb_constant(127.0, 127.0, 127.0)
|
||||||
|
|
||||||
# clone without copying pixel values
|
# clone without copying pixel values
|
||||||
img2 = img.clone(False)
|
img2 = img.clone()
|
||||||
assert img.width == img2.width
|
assert img.width == img2.width
|
||||||
assert img.height == img2.height
|
assert img.height == img2.height
|
||||||
assert img.type_id == img2.type_id
|
assert img.type_id == img2.type_id
|
||||||
# TODO inspect RVB and do pixel per pixel comparison
|
# TODO inspect RVB and do pixel per pixel comparison
|
||||||
for y in range(height):
|
for y in range(height):
|
||||||
for x in range(width):
|
for x in range(width):
|
||||||
assert img.get(x, y) != img2.get(x, y)
|
assert img.get_rgb(x, y) != img2.get_rgb(x, y)
|
||||||
|
|
||||||
img2 = img.clone(True)
|
img2 = img.clone(1)
|
||||||
assert img.width == img2.width
|
assert img.width == img2.width
|
||||||
assert img.height == img2.height
|
assert img.height == img2.height
|
||||||
assert img.type_id == img2.type_id
|
assert img.type_id == img2.type_id
|
||||||
# TODO inspect RVB and do pixel per pixel comparison
|
# TODO inspect RVB and do pixel per pixel comparison
|
||||||
for y in range(height):
|
for y in range(height):
|
||||||
for x in range(width):
|
for x in range(width):
|
||||||
assert img.get(x, y) == img2.get(x, y)
|
assert img.get_rgb(x, y) == img2.get_rgb(x, y)
|
||||||
|
|
||||||
|
|
||||||
def test_rgb_constant():
|
def test_rgb_constant():
|
||||||
@ -48,11 +48,10 @@ def test_rgb_constant():
|
|||||||
height = 5
|
height = 5
|
||||||
color = [127.0, 127.0, 127.0]
|
color = [127.0, 127.0, 127.0]
|
||||||
img = floatimg.create_rgb(width, height)
|
img = floatimg.create_rgb(width, height)
|
||||||
img.fill(color)
|
img.rgb_constant(*color)
|
||||||
for y in range(height):
|
for y in range(height):
|
||||||
for x in range(width):
|
for x in range(width):
|
||||||
assert img.get(x, y) == color
|
assert img.get_rgb(x, y) == color
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def test_copy_data():
|
def test_copy_data():
|
||||||
@ -60,27 +59,27 @@ def test_copy_data():
|
|||||||
height = 5
|
height = 5
|
||||||
color = [127.0, 127.0, 127.0]
|
color = [127.0, 127.0, 127.0]
|
||||||
img = floatimg.create_rgb(width, height)
|
img = floatimg.create_rgb(width, height)
|
||||||
img.fill(color)
|
img.rgb_constant(*color)
|
||||||
|
|
||||||
img2 = floatimg.create_rgb(width, height)
|
img2 = floatimg.create_rgb(width, height)
|
||||||
img2.fill((64.0, 64.0, 64.0))
|
img2.rgb_constant(64.0, 64.0, 64.0)
|
||||||
|
|
||||||
img.copy_data(img2)
|
img.copy_data(img2)
|
||||||
|
|
||||||
for y in range(height):
|
for y in range(height):
|
||||||
for x in range(width):
|
for x in range(width):
|
||||||
assert img.get(x, y) == img2.get(x, y)
|
assert img.get_rgb(x, y) == img2.get_rgb(x, y)
|
||||||
|
|
||||||
|
|
||||||
def test_clear():
|
def test_clear():
|
||||||
width, height = 5, 5
|
width, height = 5, 5
|
||||||
color = [127.0, 127.0, 127.0]
|
color = [127.0, 127.0, 127.0]
|
||||||
img = floatimg.create_rgb(width, height)
|
img = floatimg.create_rgb(width, height)
|
||||||
img.fill(color)
|
img.rgb_constant(*color)
|
||||||
img.clear()
|
img.clear()
|
||||||
for y in range(height):
|
for y in range(height):
|
||||||
for x in range(width):
|
for x in range(width):
|
||||||
assert img.get(x, y) == [0.0, 0.0, 0.0]
|
assert img.get_rgb(x, y) == [0.0, 0.0, 0.0]
|
||||||
|
|
||||||
|
|
||||||
def test_str_type():
|
def test_str_type():
|
||||||
@ -101,6 +100,6 @@ def test__str__():
|
|||||||
def test_put_rgb():
|
def test_put_rgb():
|
||||||
width, height = 5, 5
|
width, height = 5, 5
|
||||||
img = floatimg.create_rgb(width, height)
|
img = floatimg.create_rgb(width, height)
|
||||||
assert img.get(0, 0) == [0.0, 0.0, 0.0]
|
assert img.get_rgb(0, 0) == [0.0, 0.0, 0.0]
|
||||||
img.put(0, 0, (127.0, 127.0, 127.0))
|
img.put_rgb(0, 0, [127.0, 127.0, 127.0])
|
||||||
assert img.get(0, 0) == [127.0, 127.0, 127.0]
|
assert img.get_rgb(0, 0) == [127.0, 127.0, 127.0]
|
||||||
|
@ -10,8 +10,8 @@ def create_dump():
|
|||||||
width, height = 5, 5
|
width, height = 5, 5
|
||||||
img = floatimg.create_rgb(width, height)
|
img = floatimg.create_rgb(width, height)
|
||||||
# fill it to have something to compare
|
# fill it to have something to compare
|
||||||
img.fill((64.0, 64.0, 64.0))
|
img.rgb_constant(64.0, 64.0, 64.0)
|
||||||
img.dump(TEST_PATH)
|
img.dump_to_file(TEST_PATH)
|
||||||
|
|
||||||
|
|
||||||
def test_dump_to_file():
|
def test_dump_to_file():
|
||||||
@ -34,11 +34,10 @@ def test_load():
|
|||||||
create_dump()
|
create_dump()
|
||||||
width, height = 5, 5
|
width, height = 5, 5
|
||||||
img = floatimg.create_rgb(width, height)
|
img = floatimg.create_rgb(width, height)
|
||||||
|
img.load_from_dump(TEST_PATH)
|
||||||
img.load(TEST_PATH)
|
|
||||||
for y in range(height):
|
for y in range(height):
|
||||||
for x in range(width):
|
for x in range(width):
|
||||||
assert img.get(x, y) == [64.0, 64.0, 64.0]
|
assert img.get_rgb(x, y) == [64.0, 64.0, 64.0]
|
||||||
os.remove(TEST_PATH)
|
os.remove(TEST_PATH)
|
||||||
|
|
||||||
|
|
||||||
@ -47,5 +46,5 @@ def test_create():
|
|||||||
img = floatimg.create_from_dump(TEST_PATH)
|
img = floatimg.create_from_dump(TEST_PATH)
|
||||||
for y in range(img.height):
|
for y in range(img.height):
|
||||||
for x in range(img.width):
|
for x in range(img.width):
|
||||||
assert img.get(x, y) == [64.0, 64.0, 64.0]
|
assert img.get_rgb(x, y) == [64.0, 64.0, 64.0]
|
||||||
os.remove(TEST_PATH)
|
os.remove(TEST_PATH)
|
||||||
|
Loading…
Reference in New Issue
Block a user