file import/export
This commit is contained in:
parent
95c1e6d9c6
commit
fbea9488f0
80
README.md
80
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.
|
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
|
## Usage
|
||||||
|
|
||||||
The FloatImg class encapsulate core and file functionnalities of FloatImg library. Import if from the main module:
|
|
||||||
|
|
||||||
```python
|
```python
|
||||||
import floatimg
|
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
|
### Image creation
|
||||||
|
|
||||||
`FloatImg` has two class methods to create an image.
|
`FloatImg` has two class methods to create an image.
|
||||||
@ -47,60 +49,54 @@ new_img = img.clone()
|
|||||||
new_img = img.clone(True)
|
new_img = img.clone(True)
|
||||||
```
|
```
|
||||||
|
|
||||||
### Image manipulation
|
### Basic pixel 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
|
|
||||||
|
|
||||||
```python
|
```python
|
||||||
|
# Get pixel value
|
||||||
color = (r, g, b) = img.get(x, y)
|
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
|
### File manipulation
|
||||||
|
|
||||||
#### Dump image to file
|
#### Raw dump files
|
||||||
|
|
||||||
```python
|
```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
|
```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
|
## Operators
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@ from floatimg.image import (
|
|||||||
create,
|
create,
|
||||||
create_rgb,
|
create_rgb,
|
||||||
create_from_dump,
|
create_from_dump,
|
||||||
|
create_from_png,
|
||||||
fileinfos,
|
fileinfos,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import ctypes as ct
|
import ctypes as ct
|
||||||
|
|
||||||
from floatimg.settings import LIB
|
from floatimg.settings import LIB, PATH_ENCODING
|
||||||
|
|
||||||
############################################################################################################
|
############################################################################################################
|
||||||
# type constants
|
# type constants
|
||||||
@ -163,6 +163,19 @@ c_fimg_maximum.argtypes = (
|
|||||||
)
|
)
|
||||||
c_fimg_maximum.restype = ct.c_int
|
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:
|
class FloatImg:
|
||||||
@ -175,7 +188,7 @@ class FloatImg:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
# proxy attributes to the C_FloatImg structure
|
# 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)
|
magic = property(lambda self: self.c_img.magic)
|
||||||
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)
|
||||||
@ -247,22 +260,32 @@ class FloatImg:
|
|||||||
assert c_fimg_add_rgb(self.c_img_p, x, y, *color) == 0
|
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"""
|
"""save data to a dump file"""
|
||||||
# TODO use system encoding instead of utf-8
|
# TODO use system encoding instead of utf-8
|
||||||
assert (
|
assert (
|
||||||
c_fimg_dump_to_file(
|
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
|
== 0
|
||||||
)
|
)
|
||||||
|
|
||||||
#######################################################################################################
|
#######################################################################################################
|
||||||
def load(self, fname):
|
def load(self, path):
|
||||||
"""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(
|
||||||
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
|
== 0
|
||||||
)
|
)
|
||||||
@ -292,7 +315,7 @@ class FloatImg:
|
|||||||
def min(self, img):
|
def min(self, img):
|
||||||
"""return a new image with minimum pixel values per channel between current and parameter"""
|
"""return a new image with minimum pixel values per channel between current and parameter"""
|
||||||
res = self.clone(False)
|
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
|
assert c_fimg_maximum(self.c_img_p, img.c_img_p, res.c_img_p) == 0
|
||||||
return res
|
return res
|
||||||
|
|
||||||
@ -300,12 +323,19 @@ class FloatImg:
|
|||||||
def max(self, img):
|
def max(self, img):
|
||||||
"""return a new image with maximum pixel values per channel between current and parameter"""
|
"""return a new image with maximum pixel values per channel between current and parameter"""
|
||||||
res = self.clone(False)
|
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
|
assert c_fimg_minimum(self.c_img_p, img.c_img_p, res.c_img_p) == 0
|
||||||
return res
|
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"""
|
"""return witdh, height, img_type triplet read from a dump file"""
|
||||||
datas = (ct.c_int * 3)()
|
datas = (ct.c_int * 3)()
|
||||||
assert (
|
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
|
== 0
|
||||||
)
|
)
|
||||||
return datas[:3]
|
return datas[:3]
|
||||||
@ -335,14 +367,25 @@ def create_rgb(witdh, height):
|
|||||||
|
|
||||||
|
|
||||||
###########################################################################################################
|
###########################################################################################################
|
||||||
def create_from_dump(fname):
|
def create_from_dump(path):
|
||||||
"""Create a new instance from a dump file"""
|
"""Create a FloatImg instance from a dump file"""
|
||||||
witdh, height, img_type = fileinfos(fname)
|
witdh, height, img_type = fileinfos(path)
|
||||||
img = create(witdh, height, img_type)
|
img = create(witdh, height, img_type)
|
||||||
img.load(fname)
|
img.load(path)
|
||||||
return img
|
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):
|
def type_is_valid(type_id):
|
||||||
"""return True if type_id is a valid one"""
|
"""return True if type_id is a valid one"""
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import ctypes
|
import ctypes
|
||||||
|
|
||||||
# LIB = ctypes.cdll.LoadLibrary("../FloatImg/libfloatimg.so")
|
PATH_ENCODING = "utf8"
|
||||||
|
|
||||||
LIB = ctypes.cdll.LoadLibrary("../FloatImg4PythonBinding/build/lib/libfloatimg.so")
|
LIB = ctypes.cdll.LoadLibrary("../FloatImg4PythonBinding/build/lib/libfloatimg.so")
|
||||||
|
28
tests/files.py
Normal file
28
tests/files.py
Normal file
@ -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)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user