mirror of
https://github.com/openmv/openmv.git
synced 2025-11-04 14:49:50 +08:00
Merge pull request #82 from kwagyeman/master
Add BMP/PNM/JPEG image file loading and saving.
This commit is contained in:
commit
b8d7d662ad
@ -6,52 +6,180 @@
|
|||||||
* File System Helper Functions
|
* File System Helper Functions
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
#include <mp.h>
|
||||||
#include "ff_wrapper.h"
|
#include "ff_wrapper.h"
|
||||||
|
|
||||||
int read_byte(FIL *fp, uint8_t *value)
|
extern const char *ffs_strerror(FRESULT res);
|
||||||
|
|
||||||
|
NORETURN static void ff_fail(FIL *fp, FRESULT res)
|
||||||
{
|
{
|
||||||
UINT bytes; FRESULT res = f_read(fp, value, sizeof(*value), &bytes);
|
if (fp) f_close(fp);
|
||||||
return (bytes==sizeof(*value)) ? res : -1;
|
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, ffs_strerror(res)));
|
||||||
}
|
}
|
||||||
|
|
||||||
int read_word(FIL *fp, uint16_t *value)
|
NORETURN static void ff_read_fail(FIL *fp)
|
||||||
{
|
{
|
||||||
UINT bytes; FRESULT res = f_read(fp, value, sizeof(*value), &bytes);
|
if (fp) f_close(fp);
|
||||||
return (bytes==sizeof(*value)) ? res : -1;
|
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Failed to read requested bytes!"));
|
||||||
}
|
}
|
||||||
|
|
||||||
int read_long(FIL *fp, uint32_t *value)
|
NORETURN static void ff_write_fail(FIL *fp)
|
||||||
{
|
{
|
||||||
UINT bytes; FRESULT res = f_read(fp, value, sizeof(*value), &bytes);
|
if (fp) f_close(fp);
|
||||||
return (bytes==sizeof(*value)) ? res : -1;
|
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Failed to write requested bytes!"));
|
||||||
}
|
}
|
||||||
|
|
||||||
int read_data(FIL *fp, void *data, UINT size)
|
NORETURN static void ff_expect_fail(FIL *fp)
|
||||||
{
|
{
|
||||||
UINT bytes; FRESULT res = f_read(fp, data, size, &bytes);
|
if (fp) f_close(fp);
|
||||||
return (bytes==size) ? res : -1;
|
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Unexpected value read!"));
|
||||||
}
|
}
|
||||||
|
|
||||||
int write_byte(FIL *fp, uint8_t value)
|
NORETURN void ff_unsupported_format(FIL *fp)
|
||||||
{
|
{
|
||||||
UINT bytes; FRESULT res = f_write(fp, &value, sizeof(value), &bytes);
|
if (fp) f_close(fp);
|
||||||
return (bytes==sizeof(value)) ? res : -1;
|
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Unsupported format!"));
|
||||||
}
|
}
|
||||||
|
|
||||||
int write_word(FIL *fp, uint16_t value)
|
NORETURN void ff_file_corrupted(FIL *fp)
|
||||||
{
|
{
|
||||||
UINT bytes; FRESULT res = f_write(fp, &value, sizeof(value), &bytes);
|
if (fp) f_close(fp);
|
||||||
return (bytes==sizeof(value)) ? res : -1;
|
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "File corrupted!"));
|
||||||
}
|
}
|
||||||
|
|
||||||
int write_long(FIL *fp, uint32_t value)
|
NORETURN void ff_not_equal()
|
||||||
{
|
{
|
||||||
UINT bytes; FRESULT res = f_write(fp, &value, sizeof(value), &bytes);
|
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "Images not equal!"));
|
||||||
return (bytes==sizeof(value)) ? res : -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int write_data(FIL *fp, const void *data, UINT size)
|
NORETURN void ff_no_intersection()
|
||||||
{
|
{
|
||||||
UINT bytes; FRESULT res = f_write(fp, data, size, &bytes);
|
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "No intersection!"));
|
||||||
return (bytes==size) ? res : -1;
|
}
|
||||||
|
|
||||||
|
void file_read_open(FIL *fp, const char *path)
|
||||||
|
{
|
||||||
|
FRESULT res = f_open(fp, path, FA_READ|FA_OPEN_EXISTING);
|
||||||
|
if (res != FR_OK) ff_fail(fp, res);
|
||||||
|
}
|
||||||
|
|
||||||
|
void file_write_open(FIL *fp, const char *path)
|
||||||
|
{
|
||||||
|
FRESULT res = f_open(fp, path, FA_WRITE|FA_CREATE_ALWAYS);
|
||||||
|
if (res != FR_OK) ff_fail(fp, res);
|
||||||
|
}
|
||||||
|
|
||||||
|
void file_close(FIL *fp)
|
||||||
|
{
|
||||||
|
FRESULT res = f_close(fp);
|
||||||
|
if (res != FR_OK) ff_fail(fp, res);
|
||||||
|
}
|
||||||
|
|
||||||
|
void file_seek(FIL *fp, UINT offset)
|
||||||
|
{
|
||||||
|
FRESULT res = f_lseek(fp, offset);
|
||||||
|
if (res != FR_OK) ff_fail(fp, res);
|
||||||
|
}
|
||||||
|
|
||||||
|
void read_byte(FIL *fp, uint8_t *value)
|
||||||
|
{
|
||||||
|
UINT bytes;
|
||||||
|
FRESULT res = f_read(fp, value, sizeof(*value), &bytes);
|
||||||
|
if (res != FR_OK) ff_fail(fp, res);
|
||||||
|
if (bytes != sizeof(*value)) ff_read_fail(fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void read_byte_expect(FIL *fp, uint8_t value)
|
||||||
|
{
|
||||||
|
uint8_t compare;
|
||||||
|
read_byte(fp, &compare);
|
||||||
|
if (value != compare) ff_expect_fail(fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void read_byte_ignore(FIL *fp)
|
||||||
|
{
|
||||||
|
uint8_t trash;
|
||||||
|
read_byte(fp, &trash);
|
||||||
|
}
|
||||||
|
|
||||||
|
void read_word(FIL *fp, uint16_t *value)
|
||||||
|
{
|
||||||
|
UINT bytes;
|
||||||
|
FRESULT res = f_read(fp, value, sizeof(*value), &bytes);
|
||||||
|
if (res != FR_OK) ff_fail(fp, res);
|
||||||
|
if (bytes != sizeof(*value)) ff_read_fail(fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void read_word_expect(FIL *fp, uint16_t value)
|
||||||
|
{
|
||||||
|
uint16_t compare;
|
||||||
|
read_word(fp, &compare);
|
||||||
|
if (value != compare) ff_expect_fail(fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void read_word_ignore(FIL *fp)
|
||||||
|
{
|
||||||
|
uint16_t trash;
|
||||||
|
read_word(fp, &trash);
|
||||||
|
}
|
||||||
|
|
||||||
|
void read_long(FIL *fp, uint32_t *value)
|
||||||
|
{
|
||||||
|
UINT bytes;
|
||||||
|
FRESULT res = f_read(fp, value, sizeof(*value), &bytes);
|
||||||
|
if (res != FR_OK) ff_fail(fp, res);
|
||||||
|
if (bytes != sizeof(*value)) ff_read_fail(fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void read_long_expect(FIL *fp, uint32_t value)
|
||||||
|
{
|
||||||
|
uint32_t compare;
|
||||||
|
read_long(fp, &compare);
|
||||||
|
if (value != compare) ff_expect_fail(fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void read_long_ignore(FIL *fp)
|
||||||
|
{
|
||||||
|
uint32_t trash;
|
||||||
|
read_long(fp, &trash);
|
||||||
|
}
|
||||||
|
|
||||||
|
void read_data(FIL *fp, void *data, UINT size)
|
||||||
|
{
|
||||||
|
UINT bytes;
|
||||||
|
FRESULT res = f_read(fp, data, size, &bytes);
|
||||||
|
if (res != FR_OK) ff_fail(fp, res);
|
||||||
|
if (bytes != size) ff_read_fail(fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void write_byte(FIL *fp, uint8_t value)
|
||||||
|
{
|
||||||
|
UINT bytes;
|
||||||
|
FRESULT res = f_write(fp, &value, sizeof(value), &bytes);
|
||||||
|
if (res != FR_OK) ff_fail(fp, res);
|
||||||
|
if (bytes != sizeof(value)) ff_write_fail(fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void write_word(FIL *fp, uint16_t value)
|
||||||
|
{
|
||||||
|
UINT bytes;
|
||||||
|
FRESULT res = f_write(fp, &value, sizeof(value), &bytes);
|
||||||
|
if (res != FR_OK) ff_fail(fp, res);
|
||||||
|
if (bytes != sizeof(value)) ff_write_fail(fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void write_long(FIL *fp, uint32_t value)
|
||||||
|
{
|
||||||
|
UINT bytes;
|
||||||
|
FRESULT res = f_write(fp, &value, sizeof(value), &bytes);
|
||||||
|
if (res != FR_OK) ff_fail(fp, res);
|
||||||
|
if (bytes != sizeof(value)) ff_write_fail(fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void write_data(FIL *fp, const void *data, UINT size)
|
||||||
|
{
|
||||||
|
UINT bytes;
|
||||||
|
FRESULT res = f_write(fp, data, size, &bytes);
|
||||||
|
if (res != FR_OK) ff_fail(fp, res);
|
||||||
|
if (bytes != size) ff_write_fail(fp);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,72 +10,26 @@
|
|||||||
#define __FF_WRAPPER_H__
|
#define __FF_WRAPPER_H__
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <ff.h>
|
#include <ff.h>
|
||||||
|
void ff_unsupported_format(FIL *fp);
|
||||||
#define READ_BYTE(fp, value) \
|
void ff_file_corrupted(FIL *fp);
|
||||||
({ FRESULT _res = read_byte((fp), (value)); \
|
void ff_not_equal();
|
||||||
if (_res != FR_OK) { f_close((fp)); return _res; } })
|
void ff_no_intersection();
|
||||||
|
void file_read_open(FIL *fp, const char *path);
|
||||||
#define READ_BYTE_EXPECT(fp, value) \
|
void file_write_open(FIL *fp, const char *path);
|
||||||
({ uint8_t comp; FRESULT _res = read_byte((fp), &comp); \
|
void file_close(FIL *fp);
|
||||||
if (_res != FR_OK) { f_close((fp)); return _res; } \
|
void file_seek(FIL *fp, UINT offset);
|
||||||
if (comp != (value)) { f_close((fp)); return -1; } })
|
void read_byte(FIL *fp, uint8_t *value);
|
||||||
|
void read_byte_expect(FIL *fp, uint8_t value);
|
||||||
#define READ_BYTE_IGNORE(fp) \
|
void read_byte_ignore(FIL *fp);
|
||||||
({ uint8_t value; FRESULT _res = read_byte((fp), &value); \
|
void read_word(FIL *fp, uint16_t *value);
|
||||||
if (_res != FR_OK) { f_close((fp)); return _res; } })
|
void read_word_expect(FIL *fp, uint16_t value);
|
||||||
|
void read_word_ignore(FIL *fp);
|
||||||
#define READ_WORD(fp, value) \
|
void read_long(FIL *fp, uint32_t *value);
|
||||||
({ FRESULT _res = read_word((fp), (value)); \
|
void read_long_expect(FIL *fp, uint32_t value);
|
||||||
if (_res != FR_OK) { f_close((fp)); return _res; } })
|
void read_long_ignore(FIL *fp);
|
||||||
|
void read_data(FIL *fp, void *data, UINT size);
|
||||||
#define READ_WORD_EXPECT(fp, value) \
|
void write_byte(FIL *fp, uint8_t value);
|
||||||
({ uint16_t comp; FRESULT _res = read_word((fp), &comp); \
|
void write_word(FIL *fp, uint16_t value);
|
||||||
if (_res != FR_OK) { f_close((fp)); return _res; } \
|
void write_long(FIL *fp, uint32_t value);
|
||||||
if (comp != (value)) { f_close((fp)); return -1; } })
|
void write_data(FIL *fp, const void *data, UINT size);
|
||||||
|
|
||||||
#define READ_WORD_IGNORE(fp) \
|
|
||||||
({ uint16_t value; FRESULT _res = read_word((fp), &value); \
|
|
||||||
if (_res != FR_OK) { f_close((fp)); return _res; } })
|
|
||||||
|
|
||||||
#define READ_LONG(fp, value) \
|
|
||||||
({ FRESULT _res = read_long((fp), (value)); \
|
|
||||||
if (_res != FR_OK) { f_close((fp)); return _res; } })
|
|
||||||
|
|
||||||
#define READ_LONG_EXPECT(fp, value) \
|
|
||||||
({ uint32_t comp; FRESULT _res = read_long((fp), &comp); \
|
|
||||||
if (_res != FR_OK) { f_close((fp)); return _res; } \
|
|
||||||
if (comp != (value)) { f_close((fp)); return -1; } })
|
|
||||||
|
|
||||||
#define READ_LONG_IGNORE(fp) \
|
|
||||||
({ uint32_t value; FRESULT _res = read_long((fp), &value); \
|
|
||||||
if (_res != FR_OK) { f_close((fp)); return _res; } })
|
|
||||||
|
|
||||||
#define READ_DATA(fp, data, size) \
|
|
||||||
({ FRESULT _res = read_data((fp), (data), (size)); \
|
|
||||||
if (_res != FR_OK) { f_close((fp)); return _res; } })
|
|
||||||
|
|
||||||
#define WRITE_BYTE(fp, value) \
|
|
||||||
({ FRESULT _res = write_byte((fp), (value)); \
|
|
||||||
if (_res != FR_OK) { f_close((fp)); return _res; } })
|
|
||||||
|
|
||||||
#define WRITE_WORD(fp, value) \
|
|
||||||
({ FRESULT _res = write_word((fp), (value)); \
|
|
||||||
if (_res != FR_OK) { f_close((fp)); return _res; } })
|
|
||||||
|
|
||||||
#define WRITE_LONG(fp, value) \
|
|
||||||
({ FRESULT _res = write_long((fp), (value)); \
|
|
||||||
if (_res != FR_OK) { f_close((fp)); return _res; } })
|
|
||||||
|
|
||||||
#define WRITE_DATA(fp, data, size) \
|
|
||||||
({ FRESULT _res = write_data((fp), (data), (size)); \
|
|
||||||
if (_res != FR_OK) { f_close((fp)); return _res; } })
|
|
||||||
|
|
||||||
int read_byte(FIL *fp, uint8_t *value);
|
|
||||||
int read_word(FIL *fp, uint16_t *value);
|
|
||||||
int read_long(FIL *fp, uint32_t *value);
|
|
||||||
int read_data(FIL *fp, void *data, UINT size);
|
|
||||||
int write_byte(FIL *fp, uint8_t value);
|
|
||||||
int write_word(FIL *fp, uint16_t value);
|
|
||||||
int write_long(FIL *fp, uint32_t value);
|
|
||||||
int write_data(FIL *fp, const void *data, UINT size);
|
|
||||||
#endif /* __FF_WRAPPER_H__ */
|
#endif /* __FF_WRAPPER_H__ */
|
||||||
|
|||||||
@ -13,138 +13,94 @@
|
|||||||
#include "xalloc.h"
|
#include "xalloc.h"
|
||||||
#include "imlib.h"
|
#include "imlib.h"
|
||||||
|
|
||||||
// Store mode settings internally, no need for callers to store this info.
|
// This function inits the geometry values of an image (opens file).
|
||||||
static int32_t bmp_w;
|
bool bmp_read_geometry(FIL *fp, image_t *img, const char *path, bmp_read_settings_t *rs)
|
||||||
static int32_t bmp_h;
|
|
||||||
static uint16_t bmp_bpp;
|
|
||||||
static uint32_t bmp_fmt;
|
|
||||||
static uint32_t bmp_row_bytes;
|
|
||||||
|
|
||||||
// This function inits the geometry values of an image.
|
|
||||||
int bmp_read_geometry(FIL *fp, image_t *img, const char *path,
|
|
||||||
bool *w_flipped, bool *h_flipped)
|
|
||||||
{
|
{
|
||||||
FRESULT res = f_open(fp, path, FA_READ|FA_OPEN_EXISTING);
|
file_read_open(fp, path);
|
||||||
if (res != FR_OK) {
|
read_byte_expect(fp, 'B');
|
||||||
return res;
|
read_byte_expect(fp, 'M');
|
||||||
}
|
|
||||||
|
|
||||||
READ_BYTE_EXPECT(fp, 'B');
|
|
||||||
READ_BYTE_EXPECT(fp, 'M');
|
|
||||||
uint32_t file_size;
|
uint32_t file_size;
|
||||||
READ_LONG(fp, &file_size);
|
read_long(fp, &file_size);
|
||||||
READ_LONG_IGNORE(fp);
|
read_long_ignore(fp);
|
||||||
READ_LONG_IGNORE(fp);
|
read_long_ignore(fp);
|
||||||
|
|
||||||
uint32_t header_size;
|
uint32_t header_size;
|
||||||
READ_LONG(fp, &header_size);
|
read_long(fp, &header_size);
|
||||||
if (file_size <= header_size) {
|
if (file_size <= header_size) ff_file_corrupted(fp);
|
||||||
f_close(fp);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t data_size = file_size - header_size;
|
uint32_t data_size = file_size - header_size;
|
||||||
if (data_size % 4) { // must be some number of dwords
|
if (data_size % 4) ff_file_corrupted(fp);
|
||||||
f_close(fp);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
READ_LONG_EXPECT(fp, 40);
|
read_long_expect(fp, 40);
|
||||||
READ_LONG(fp, (uint32_t*) &bmp_w);
|
read_long(fp, (uint32_t*) &rs->bmp_w);
|
||||||
READ_LONG(fp, (uint32_t*) &bmp_h);
|
read_long(fp, (uint32_t*) &rs->bmp_h);
|
||||||
if ((bmp_w == 0) || (bmp_h == 0)) {
|
if ((rs->bmp_w == 0) || (rs->bmp_h == 0)) ff_file_corrupted(fp);
|
||||||
f_close(fp);
|
img->w = abs(rs->bmp_w);
|
||||||
return -1;
|
img->h = abs(rs->bmp_h);
|
||||||
}
|
|
||||||
img->w = abs(bmp_w);
|
|
||||||
img->h = abs(bmp_h);
|
|
||||||
|
|
||||||
READ_WORD_EXPECT(fp, 1);
|
read_word_expect(fp, 1);
|
||||||
READ_WORD(fp, &bmp_bpp);
|
read_word(fp, &rs->bmp_bpp);
|
||||||
if ((bmp_bpp != 8) && (bmp_bpp != 16) && (bmp_bpp != 24)) {
|
if ((rs->bmp_bpp != 8) && (rs->bmp_bpp != 16) && (rs->bmp_bpp != 24)) ff_unsupported_format(fp);
|
||||||
f_close(fp);
|
img->bpp = (rs->bmp_bpp == 8) ? 1 : 2;
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
img->bpp = (bmp_bpp == 8) ? 1 : 2;
|
|
||||||
|
|
||||||
READ_LONG(fp, &bmp_fmt);
|
read_long(fp, &rs->bmp_fmt);
|
||||||
if ((bmp_fmt != 0) && (bmp_fmt != 3)) {
|
if ((rs->bmp_fmt != 0) && (rs->bmp_fmt != 3)) ff_unsupported_format(fp);
|
||||||
f_close(fp);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
READ_LONG_EXPECT(fp, data_size);
|
read_long_expect(fp, data_size);
|
||||||
READ_LONG_IGNORE(fp);
|
read_long_ignore(fp);
|
||||||
READ_LONG_IGNORE(fp);
|
read_long_ignore(fp);
|
||||||
READ_LONG_IGNORE(fp);
|
read_long_ignore(fp);
|
||||||
READ_LONG_IGNORE(fp);
|
read_long_ignore(fp);
|
||||||
|
|
||||||
if (bmp_bpp == 8) {
|
if (rs->bmp_bpp == 8) {
|
||||||
if (bmp_fmt != 0) {
|
if (rs->bmp_fmt != 0) ff_unsupported_format(fp);
|
||||||
f_close(fp);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
// Color Table (1024 bytes)
|
// Color Table (1024 bytes)
|
||||||
for (int i = 0; i < 256; i++) {
|
for (int i = 0; i < 256; i++) {
|
||||||
READ_LONG_EXPECT(fp, ((i) << 16) | ((i) << 8) | i);
|
read_long_expect(fp, ((i) << 16) | ((i) << 8) | i);
|
||||||
}
|
|
||||||
} else if (bmp_bpp == 16) {
|
|
||||||
if (bmp_fmt != 3) {
|
|
||||||
f_close(fp);
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
} else if (rs->bmp_bpp == 16) {
|
||||||
|
if (rs->bmp_fmt != 3) ff_unsupported_format(fp);
|
||||||
// Bit Masks (12 bytes)
|
// Bit Masks (12 bytes)
|
||||||
READ_LONG_EXPECT(fp, 0x1F << 11);
|
read_long_expect(fp, 0x1F << 11);
|
||||||
READ_LONG_EXPECT(fp, 0x3F << 5);
|
read_long_expect(fp, 0x3F << 5);
|
||||||
READ_LONG_EXPECT(fp, 0x1F);
|
read_long_expect(fp, 0x1F);
|
||||||
} else if (bmp_bpp == 24) {
|
} else if (rs->bmp_bpp == 24) {
|
||||||
if (bmp_fmt == 3) {
|
if (rs->bmp_fmt == 3) {
|
||||||
// Bit Masks (12 bytes)
|
// Bit Masks (12 bytes)
|
||||||
READ_LONG_EXPECT(fp, 0xFF << 16);
|
read_long_expect(fp, 0xFF << 16);
|
||||||
READ_LONG_EXPECT(fp, 0xFF << 8);
|
read_long_expect(fp, 0xFF << 8);
|
||||||
READ_LONG_EXPECT(fp, 0xFF);
|
read_long_expect(fp, 0xFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bmp_row_bytes = (((img->w * bmp_bpp) + 31) / 32) * 4;
|
rs->bmp_row_bytes = (((img->w * rs->bmp_bpp) + 31) / 32) * 4;
|
||||||
if (data_size != (bmp_row_bytes * img->h)) {
|
if (data_size != (rs->bmp_row_bytes * img->h)) ff_file_corrupted(fp);
|
||||||
f_close(fp);
|
return (rs->bmp_h >= 0);
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (w_flipped) {
|
|
||||||
*w_flipped = (bmp_w < 0); // Raster scan perspective
|
|
||||||
}
|
|
||||||
if (h_flipped) {
|
|
||||||
*h_flipped = (bmp_h >= 0); // Raster scan perspective
|
|
||||||
}
|
|
||||||
|
|
||||||
return FR_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// This function reads the pixel values of an image.
|
// This function reads the pixel values of an image.
|
||||||
int bmp_read_pixels(FIL *fp, image_t *img, int line_start, int line_end)
|
void bmp_read_pixels(FIL *fp, image_t *img, int line_start, int line_end, bmp_read_settings_t *rs)
|
||||||
{
|
{
|
||||||
if (bmp_bpp == 8) {
|
if (rs->bmp_bpp == 8) {
|
||||||
if ((bmp_h < 0) && (bmp_w >= 0) && (img->w == bmp_row_bytes)) {
|
if ((rs->bmp_h < 0) && (rs->bmp_w >= 0) && (img->w == rs->bmp_row_bytes)) {
|
||||||
READ_DATA(fp, // Super Fast - Zoom, Zoom!
|
read_data(fp, // Super Fast - Zoom, Zoom!
|
||||||
img->pixels + (line_start * img->w),
|
img->pixels + (line_start * img->w),
|
||||||
(line_end - line_start + 1) * img->w);
|
(line_end - line_start + 1) * img->w);
|
||||||
} else {
|
} else {
|
||||||
for (int i = line_start; i < line_end; i++) {
|
for (int i = line_start; i < line_end; i++) {
|
||||||
for (int j = 0; j < bmp_row_bytes; j++) {
|
for (int j = 0; j < rs->bmp_row_bytes; j++) {
|
||||||
uint8_t pixel;
|
uint8_t pixel;
|
||||||
READ_BYTE(fp, &pixel);
|
read_byte(fp, &pixel);
|
||||||
if (j < img->w) {
|
if (j < img->w) {
|
||||||
if (bmp_h < 0) { // vertical flip (BMP file perspective)
|
if (rs->bmp_h < 0) { // vertical flip (BMP file perspective)
|
||||||
if (bmp_w < 0) { // horizontal flip (BMP file perspective)
|
if (rs->bmp_w < 0) { // horizontal flip (BMP file perspective)
|
||||||
IM_SET_GS_PIXEL(img, (img->w-j-1), i, pixel);
|
IM_SET_GS_PIXEL(img, (img->w-j-1), i, pixel);
|
||||||
} else {
|
} else {
|
||||||
IM_SET_GS_PIXEL(img, j, i, pixel);
|
IM_SET_GS_PIXEL(img, j, i, pixel);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (bmp_w < 0) {
|
if (rs->bmp_w < 0) {
|
||||||
IM_SET_GS_PIXEL(img, (img->w-j-1), (img->h-i-1), pixel);
|
IM_SET_GS_PIXEL(img, (img->w-j-1), (img->h-i-1), pixel);
|
||||||
} else {
|
} else {
|
||||||
IM_SET_GS_PIXEL(img, j, (img->h-i-1), pixel);
|
IM_SET_GS_PIXEL(img, j, (img->h-i-1), pixel);
|
||||||
@ -154,21 +110,21 @@ int bmp_read_pixels(FIL *fp, image_t *img, int line_start, int line_end)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (bmp_bpp == 16) {
|
} else if (rs->bmp_bpp == 16) {
|
||||||
for (int i = line_start; i < line_end; i++) {
|
for (int i = line_start; i < line_end; i++) {
|
||||||
for (int j = 0, jj = bmp_row_bytes / 2; j < jj; j++) {
|
for (int j = 0, jj = rs->bmp_row_bytes / 2; j < jj; j++) {
|
||||||
uint16_t pixel;
|
uint16_t pixel;
|
||||||
READ_WORD(fp, &pixel);
|
read_word(fp, &pixel);
|
||||||
IM_SWAP16(pixel);
|
IM_SWAP16(pixel);
|
||||||
if (j < img->w) {
|
if (j < img->w) {
|
||||||
if (bmp_h < 0) { // vertical flip (BMP file perspective)
|
if (rs->bmp_h < 0) { // vertical flip (BMP file perspective)
|
||||||
if (bmp_w < 0) { // horizontal flip (BMP file perspective)
|
if (rs->bmp_w < 0) { // horizontal flip (BMP file perspective)
|
||||||
IM_SET_RGB565_PIXEL(img, (img->w-j-1), i, pixel);
|
IM_SET_RGB565_PIXEL(img, (img->w-j-1), i, pixel);
|
||||||
} else {
|
} else {
|
||||||
IM_SET_RGB565_PIXEL(img, j, i, pixel);
|
IM_SET_RGB565_PIXEL(img, j, i, pixel);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (bmp_w < 0) {
|
if (rs->bmp_w < 0) {
|
||||||
IM_SET_RGB565_PIXEL(img, (img->w-j-1), (img->h-i-1), pixel);
|
IM_SET_RGB565_PIXEL(img, (img->w-j-1), (img->h-i-1), pixel);
|
||||||
} else {
|
} else {
|
||||||
IM_SET_RGB565_PIXEL(img, j, (img->h-i-1), pixel);
|
IM_SET_RGB565_PIXEL(img, j, (img->h-i-1), pixel);
|
||||||
@ -177,23 +133,23 @@ int bmp_read_pixels(FIL *fp, image_t *img, int line_start, int line_end)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (bmp_bpp == 24) {
|
} else if (rs->bmp_bpp == 24) {
|
||||||
for (int i = line_start; i < line_end; i++) {
|
for (int i = line_start; i < line_end; i++) {
|
||||||
for (int j = 0, jj = bmp_row_bytes / 3; j < jj; j++) {
|
for (int j = 0, jj = rs->bmp_row_bytes / 3; j < jj; j++) {
|
||||||
uint8_t r, g, b;
|
uint8_t r, g, b;
|
||||||
READ_BYTE(fp, &r);
|
read_byte(fp, &r);
|
||||||
READ_BYTE(fp, &g);
|
read_byte(fp, &g);
|
||||||
READ_BYTE(fp, &b);
|
read_byte(fp, &b);
|
||||||
uint16_t pixel = IM_RGB565(IM_R825(r), IM_G826(g), IM_B825(b));
|
uint16_t pixel = IM_RGB565(IM_R825(r), IM_G826(g), IM_B825(b));
|
||||||
if (j < img->w) {
|
if (j < img->w) {
|
||||||
if (bmp_h < 0) { // vertical flip
|
if (rs->bmp_h < 0) { // vertical flip
|
||||||
if (bmp_w < 0) { // horizontal flip
|
if (rs->bmp_w < 0) { // horizontal flip
|
||||||
IM_SET_RGB565_PIXEL(img, (img->w-j-1), i, pixel);
|
IM_SET_RGB565_PIXEL(img, (img->w-j-1), i, pixel);
|
||||||
} else {
|
} else {
|
||||||
IM_SET_RGB565_PIXEL(img, j, i, pixel);
|
IM_SET_RGB565_PIXEL(img, j, i, pixel);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (bmp_w < 0) {
|
if (rs->bmp_w < 0) {
|
||||||
IM_SET_RGB565_PIXEL(img, (img->w-j-1), (img->h-i-1), pixel);
|
IM_SET_RGB565_PIXEL(img, (img->w-j-1), (img->h-i-1), pixel);
|
||||||
} else {
|
} else {
|
||||||
IM_SET_RGB565_PIXEL(img, j, (img->h-i-1), pixel);
|
IM_SET_RGB565_PIXEL(img, j, (img->h-i-1), pixel);
|
||||||
@ -201,96 +157,66 @@ int bmp_read_pixels(FIL *fp, image_t *img, int line_start, int line_end)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (int j = 0, jj = bmp_row_bytes % 3; j < jj; j++) {
|
for (int j = 0, jj = rs->bmp_row_bytes % 3; j < jj; j++) {
|
||||||
READ_BYTE_IGNORE(fp);
|
read_byte_ignore(fp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return FR_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int bmp_read_int(image_t *img, const char *path)
|
void bmp_read(image_t *img, const char *path)
|
||||||
{
|
{
|
||||||
FIL fp;
|
FIL fp;
|
||||||
|
bmp_read_settings_t rs;
|
||||||
int res = bmp_read_geometry(&fp, img, path, NULL, NULL);
|
bmp_read_geometry(&fp, img, path, &rs);
|
||||||
if (res != FR_OK) {
|
if (!img->pixels) img->pixels = xalloc(img->w * img->h * img->bpp);
|
||||||
return res;
|
bmp_read_pixels(&fp, img, 0, img->h, &rs);
|
||||||
}
|
file_close(&fp);
|
||||||
|
|
||||||
if (!img->pixels) { // don't allocate if already allocated...
|
|
||||||
img->pixels = xalloc(img->w * img->h * img->bpp);
|
|
||||||
}
|
|
||||||
|
|
||||||
res = bmp_read_pixels(&fp, img, 0, img->h);
|
|
||||||
if (res != FR_OK) {
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
return f_close(&fp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int bmp_read(image_t *img, const char *path)
|
void bmp_write_subimg(image_t *img, const char *path, rectangle_t *r)
|
||||||
{
|
|
||||||
const uint8_t *backup = img->pixels;
|
|
||||||
const int res = bmp_read_int(img, path);
|
|
||||||
// free image if I didn't start with one...
|
|
||||||
if ((res != FR_OK) && (!backup) && (img->pixels)) {
|
|
||||||
xfree(img->pixels);
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
int bmp_write_subimg(image_t *img, const char *path, rectangle_t *r)
|
|
||||||
{
|
{
|
||||||
rectangle_t rect;
|
rectangle_t rect;
|
||||||
if (!rectangle_subimg(img, r, &rect)) {
|
if (!rectangle_subimg(img, r, &rect)) ff_no_intersection();
|
||||||
return -1; // no image intersection
|
|
||||||
}
|
|
||||||
|
|
||||||
FIL fp;
|
FIL fp;
|
||||||
FRESULT res = f_open(&fp, path, FA_WRITE|FA_CREATE_ALWAYS);
|
file_write_open(&fp, path);
|
||||||
if (res != FR_OK) {
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (IM_IS_GS(img)) {
|
if (IM_IS_GS(img)) {
|
||||||
const int row_bytes = (((rect.w * 8) + 31) / 32) * 4;
|
const int row_bytes = (((rect.w * 8) + 31) / 32) * 4;
|
||||||
const int data_size = (row_bytes * rect.h);
|
const int data_size = (row_bytes * rect.h);
|
||||||
const int waste = (row_bytes / sizeof(uint8_t)) - rect.w;
|
const int waste = (row_bytes / sizeof(uint8_t)) - rect.w;
|
||||||
// File Header (14 bytes)
|
// File Header (14 bytes)
|
||||||
WRITE_BYTE(&fp, 'B');
|
write_byte(&fp, 'B');
|
||||||
WRITE_BYTE(&fp, 'M');
|
write_byte(&fp, 'M');
|
||||||
WRITE_LONG(&fp, 14 + 40 + 1024 + data_size);
|
write_long(&fp, 14 + 40 + 1024 + data_size);
|
||||||
WRITE_WORD(&fp, 0);
|
write_word(&fp, 0);
|
||||||
WRITE_WORD(&fp, 0);
|
write_word(&fp, 0);
|
||||||
WRITE_LONG(&fp, 14 + 40 + 1024);
|
write_long(&fp, 14 + 40 + 1024);
|
||||||
// Info Header (40 bytes)
|
// Info Header (40 bytes)
|
||||||
WRITE_LONG(&fp, 40);
|
write_long(&fp, 40);
|
||||||
WRITE_LONG(&fp, rect.w);
|
write_long(&fp, rect.w);
|
||||||
WRITE_LONG(&fp, -rect.h); // store the image flipped (correctly)
|
write_long(&fp, -rect.h); // store the image flipped (correctly)
|
||||||
WRITE_WORD(&fp, 1);
|
write_word(&fp, 1);
|
||||||
WRITE_WORD(&fp, 8);
|
write_word(&fp, 8);
|
||||||
WRITE_LONG(&fp, 0);
|
write_long(&fp, 0);
|
||||||
WRITE_LONG(&fp, data_size);
|
write_long(&fp, data_size);
|
||||||
WRITE_LONG(&fp, 0);
|
write_long(&fp, 0);
|
||||||
WRITE_LONG(&fp, 0);
|
write_long(&fp, 0);
|
||||||
WRITE_LONG(&fp, 0);
|
write_long(&fp, 0);
|
||||||
WRITE_LONG(&fp, 0);
|
write_long(&fp, 0);
|
||||||
// Color Table (1024 bytes)
|
// Color Table (1024 bytes)
|
||||||
for (int i = 0; i < 256; i++) {
|
for (int i = 0; i < 256; i++) {
|
||||||
WRITE_LONG(&fp, ((i) << 16) | ((i) << 8) | i);
|
write_long(&fp, ((i) << 16) | ((i) << 8) | i);
|
||||||
}
|
}
|
||||||
if ((rect.x == 0) && (rect.w == img->w) && (img->w == row_bytes)) {
|
if ((rect.x == 0) && (rect.w == img->w) && (img->w == row_bytes)) {
|
||||||
WRITE_DATA(&fp, // Super Fast - Zoom, Zoom!
|
write_data(&fp, // Super Fast - Zoom, Zoom!
|
||||||
img->pixels + (rect.y * img->w),
|
img->pixels + (rect.y * img->w),
|
||||||
rect.w * rect.h);
|
rect.w * rect.h);
|
||||||
} else {
|
} else {
|
||||||
for (int i = 0; i < rect.h; i++) {
|
for (int i = 0; i < rect.h; i++) {
|
||||||
WRITE_DATA(&fp, img->pixels+((rect.y+i)*img->w)+rect.x, rect.w);
|
write_data(&fp, img->pixels+((rect.y+i)*img->w)+rect.x, rect.w);
|
||||||
for (int j = 0; j < waste; j++) {
|
for (int j = 0; j < waste; j++) {
|
||||||
WRITE_BYTE(&fp, 0);
|
write_byte(&fp, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -299,37 +225,37 @@ int bmp_write_subimg(image_t *img, const char *path, rectangle_t *r)
|
|||||||
const int data_size = (row_bytes * rect.h);
|
const int data_size = (row_bytes * rect.h);
|
||||||
const int waste = (row_bytes / sizeof(uint16_t)) - rect.w;
|
const int waste = (row_bytes / sizeof(uint16_t)) - rect.w;
|
||||||
// File Header (14 bytes)
|
// File Header (14 bytes)
|
||||||
WRITE_BYTE(&fp, 'B');
|
write_byte(&fp, 'B');
|
||||||
WRITE_BYTE(&fp, 'M');
|
write_byte(&fp, 'M');
|
||||||
WRITE_LONG(&fp, 14 + 40 + 12 + data_size);
|
write_long(&fp, 14 + 40 + 12 + data_size);
|
||||||
WRITE_WORD(&fp, 0);
|
write_word(&fp, 0);
|
||||||
WRITE_WORD(&fp, 0);
|
write_word(&fp, 0);
|
||||||
WRITE_LONG(&fp, 14 + 40 + 12);
|
write_long(&fp, 14 + 40 + 12);
|
||||||
// Info Header (40 bytes)
|
// Info Header (40 bytes)
|
||||||
WRITE_LONG(&fp, 40);
|
write_long(&fp, 40);
|
||||||
WRITE_LONG(&fp, rect.w);
|
write_long(&fp, rect.w);
|
||||||
WRITE_LONG(&fp, -rect.h); // store the image flipped (correctly)
|
write_long(&fp, -rect.h); // store the image flipped (correctly)
|
||||||
WRITE_WORD(&fp, 1);
|
write_word(&fp, 1);
|
||||||
WRITE_WORD(&fp, 16);
|
write_word(&fp, 16);
|
||||||
WRITE_LONG(&fp, 3);
|
write_long(&fp, 3);
|
||||||
WRITE_LONG(&fp, data_size);
|
write_long(&fp, data_size);
|
||||||
WRITE_LONG(&fp, 0);
|
write_long(&fp, 0);
|
||||||
WRITE_LONG(&fp, 0);
|
write_long(&fp, 0);
|
||||||
WRITE_LONG(&fp, 0);
|
write_long(&fp, 0);
|
||||||
WRITE_LONG(&fp, 0);
|
write_long(&fp, 0);
|
||||||
// Bit Masks (12 bytes)
|
// Bit Masks (12 bytes)
|
||||||
WRITE_LONG(&fp, 0x1F << 11);
|
write_long(&fp, 0x1F << 11);
|
||||||
WRITE_LONG(&fp, 0x3F << 5);
|
write_long(&fp, 0x3F << 5);
|
||||||
WRITE_LONG(&fp, 0x1F);
|
write_long(&fp, 0x1F);
|
||||||
for (int i = 0; i < rect.h; i++) {
|
for (int i = 0; i < rect.h; i++) {
|
||||||
for (int j = 0; j < rect.w; j++) {
|
for (int j = 0; j < rect.w; j++) {
|
||||||
WRITE_WORD(&fp, IM_SWAP16(IM_GET_RGB565_PIXEL(img, (rect.x + j), (rect.y + i))));
|
write_word(&fp, IM_SWAP16(IM_GET_RGB565_PIXEL(img, (rect.x + j), (rect.y + i))));
|
||||||
}
|
}
|
||||||
for (int j = 0; j < waste; j++) {
|
for (int j = 0; j < waste; j++) {
|
||||||
WRITE_WORD(&fp, 0);
|
write_word(&fp, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return f_close(&fp);
|
file_close(&fp);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -28,70 +28,78 @@ extern const uint16_t rainbow_table[256];
|
|||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#define IMLIB_READ_FUNCTION_LINE_BUFFER (32)
|
bool imlib_read_geometry(FIL *fp, image_t *image, const char *path, img_read_settings_t *rs)
|
||||||
|
|
||||||
static enum { PPM_IMAGE, BMP_IMAGE, JPEG_IMAGE } imlib_image_type;
|
|
||||||
|
|
||||||
int imlib_read_geometry(FIL *fp, image_t *image, const char *path,
|
|
||||||
bool *w_flipped, bool *h_flipped, bool disable_jpeg)
|
|
||||||
{
|
{
|
||||||
FRESULT res = f_open(fp, path, FA_READ|FA_OPEN_EXISTING);
|
file_read_open(fp, path);
|
||||||
if (res != FR_OK) {
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
char magic[2];
|
char magic[2];
|
||||||
READ_DATA(fp, &magic, 2);
|
read_data(fp, &magic, 2);
|
||||||
|
file_close(fp);
|
||||||
res = f_close(fp);
|
|
||||||
if (res != FR_OK) {
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((magic[0]=='P')
|
if ((magic[0]=='P')
|
||||||
&& ((magic[1]=='2') || (magic[1]=='3')
|
&& ((magic[1]=='2') || (magic[1]=='3')
|
||||||
|| (magic[1]=='5') || (magic[1]=='6'))) { // PPM
|
|| (magic[1]=='5') || (magic[1]=='6'))) { // PPM
|
||||||
imlib_image_type = PPM_IMAGE;
|
rs->format = FORMAT_PNM;
|
||||||
*w_flipped = false;
|
ppm_read_geometry(fp, image, path, &rs->ppm_rs);
|
||||||
*h_flipped = false;
|
|
||||||
return ppm_read_geometry(fp, image, path);
|
|
||||||
} else if ((magic[0]=='B') && (magic[1]=='M')) { // BMP
|
} else if ((magic[0]=='B') && (magic[1]=='M')) { // BMP
|
||||||
imlib_image_type = BMP_IMAGE;
|
rs->format = FORMAT_BMP;
|
||||||
return bmp_read_geometry(fp, image, path, w_flipped, h_flipped);
|
return bmp_read_geometry(fp, image, path, &rs->bmp_rs);
|
||||||
|
} else {
|
||||||
|
ff_unsupported_format(NULL);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void imlib_read_pixels(FIL *fp, image_t *img, int line_start, int line_end, img_read_settings_t *rs)
|
||||||
|
{
|
||||||
|
switch (rs->format) {
|
||||||
|
case FORMAT_BMP:
|
||||||
|
bmp_read_pixels(fp, img, line_start, line_end, &rs->bmp_rs);
|
||||||
|
break;
|
||||||
|
case FORMAT_PNM:
|
||||||
|
ppm_read_pixels(fp, img, line_start, line_end, &rs->ppm_rs);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void imlib_load_image(image_t *img, const char *path)
|
||||||
|
{
|
||||||
|
FIL fp;
|
||||||
|
file_read_open(&fp, path);
|
||||||
|
char magic[2];
|
||||||
|
read_data(&fp, &magic, 2);
|
||||||
|
file_close(&fp);
|
||||||
|
|
||||||
|
if ((magic[0]=='P')
|
||||||
|
&& ((magic[1]=='2') || (magic[1]=='3')
|
||||||
|
|| (magic[1]=='5') || (magic[1]=='6'))) { // PPM
|
||||||
|
ppm_read(img, path);
|
||||||
|
} else if ((magic[0]=='B') && (magic[1]=='M')) { // BMP
|
||||||
|
bmp_read(img, path);
|
||||||
} else if ((magic[0]==0xFF) && (magic[1]==0xD8)) { // JPEG
|
} else if ((magic[0]==0xFF) && (magic[1]==0xD8)) { // JPEG
|
||||||
if (disable_jpeg) {
|
jpeg_read(img, path);
|
||||||
nlr_jump(mp_obj_new_exception_msg(
|
} else {
|
||||||
&mp_type_OSError,
|
ff_unsupported_format(NULL);
|
||||||
"Operation not supported on JPEG"));
|
|
||||||
}
|
|
||||||
imlib_image_type = JPEG_IMAGE;
|
|
||||||
*w_flipped = false;
|
|
||||||
*h_flipped = false;
|
|
||||||
return jpeg_read_geometry(fp, image, path);
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int imlib_read_pixels(FIL *fp, image_t *img, int line_start, int line_end)
|
|
||||||
{
|
|
||||||
switch (imlib_image_type) {
|
|
||||||
case PPM_IMAGE: return ppm_read_pixels(fp, img, line_start, line_end);
|
|
||||||
case BMP_IMAGE: return bmp_read_pixels(fp, img, line_start, line_end);
|
|
||||||
default: return jpeg_read_pixels(fp, img);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* those just call ppm for now */
|
void imlib_save_image(image_t *img, const char *path, rectangle_t *roi, save_image_format_t format)
|
||||||
int imlib_load_image(image_t *image, const char *path)
|
|
||||||
{
|
{
|
||||||
// needs to be redone still
|
if (IM_IS_JPEG(img)) {
|
||||||
return ppm_read(image, path);
|
char *new_path = strcat(strcpy(fb_alloc(strlen(path)+5), path), ".jpg");
|
||||||
}
|
jpeg_write(img, new_path);
|
||||||
|
fb_free();
|
||||||
int imlib_save_image(image_t *image, const char *path, rectangle_t *roi)
|
} else if (format == FORMAT_BMP) {
|
||||||
{
|
char *new_path = strcat(strcpy(fb_alloc(strlen(path)+5), path), ".bmp");
|
||||||
return ppm_write_subimg(image, path, roi);
|
bmp_write_subimg(img, new_path, roi);
|
||||||
|
fb_free();
|
||||||
|
} else if (format == FORMAT_PNM) {
|
||||||
|
char *new_path = strcat(strcpy(fb_alloc(strlen(path)+5), path),
|
||||||
|
IM_IS_GS(img) ? ".pgm" : ".ppm");
|
||||||
|
ppm_write_subimg(img, new_path, roi);
|
||||||
|
fb_free();
|
||||||
|
} else {
|
||||||
|
ff_unsupported_format(NULL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|||||||
@ -281,25 +281,51 @@ typedef enum interp {
|
|||||||
INTERP_BICUBIC
|
INTERP_BICUBIC
|
||||||
} interp_t;
|
} interp_t;
|
||||||
|
|
||||||
|
typedef struct bmp_read_settings {
|
||||||
|
int32_t bmp_w;
|
||||||
|
int32_t bmp_h;
|
||||||
|
uint16_t bmp_bpp;
|
||||||
|
uint32_t bmp_fmt;
|
||||||
|
uint32_t bmp_row_bytes;
|
||||||
|
} bmp_read_settings_t;
|
||||||
|
|
||||||
|
typedef struct ppm_read_settings {
|
||||||
|
uint8_t read_int_c;
|
||||||
|
bool read_int_c_valid;
|
||||||
|
uint8_t ppm_fmt;
|
||||||
|
} ppm_read_settings_t;
|
||||||
|
|
||||||
|
typedef enum save_image_format {
|
||||||
|
FORMAT_BMP,
|
||||||
|
FORMAT_PNM
|
||||||
|
} save_image_format_t;
|
||||||
|
|
||||||
|
typedef struct img_read_settings {
|
||||||
|
union
|
||||||
|
{
|
||||||
|
bmp_read_settings_t bmp_rs;
|
||||||
|
ppm_read_settings_t ppm_rs;
|
||||||
|
};
|
||||||
|
save_image_format_t format;
|
||||||
|
} img_read_settings_t;
|
||||||
|
|
||||||
/* Image file functions */
|
/* Image file functions */
|
||||||
int ppm_read_geometry(FIL *fp, image_t *img, const char *path);
|
void ppm_read_geometry(FIL *fp, image_t *img, const char *path, ppm_read_settings_t *rs);
|
||||||
int ppm_read_pixels(FIL *fp, image_t *img, int line_start, int line_end);
|
void ppm_read_pixels(FIL *fp, image_t *img, int line_start, int line_end, ppm_read_settings_t *rs);
|
||||||
int ppm_read(image_t *img, const char *path);
|
void ppm_read(image_t *img, const char *path);
|
||||||
int ppm_write_subimg(image_t *img, const char *path, rectangle_t *r);
|
void ppm_write_subimg(image_t *img, const char *path, rectangle_t *r);
|
||||||
int bmp_read_geometry(FIL *fp, image_t *img, const char *path,
|
bool bmp_read_geometry(FIL *fp, image_t *img, const char *path, bmp_read_settings_t *rs);
|
||||||
bool *w_flipped, bool *h_flipped);
|
void bmp_read_pixels(FIL *fp, image_t *img, int line_start, int line_end, bmp_read_settings_t *rs);
|
||||||
int bmp_read_pixels(FIL *fp, image_t *img, int line_start, int line_end);
|
void bmp_read(image_t *img, const char *path);
|
||||||
int bmp_read(image_t *img, const char *path);
|
void bmp_write_subimg(image_t *img, const char *path, rectangle_t *r);
|
||||||
int bmp_write_subimg(image_t *img, const char *path, rectangle_t *r);
|
void jpeg_read_geometry(FIL *fp, image_t *img, const char *path);
|
||||||
int jpeg_read_geometry(FIL *fp, image_t *img, const char *path);
|
void jpeg_read_pixels(FIL *fp, image_t *img);
|
||||||
int jpeg_read_pixels(FIL *fp, image_t *img);
|
void jpeg_read(image_t *img, const char *path);
|
||||||
int jpeg_read(image_t *img, const char *path);
|
void jpeg_write(image_t *img, const char *path);
|
||||||
int jpeg_write(image_t *img, const char *path);
|
bool imlib_read_geometry(FIL *fp, image_t *img, const char *path, img_read_settings_t *rs);
|
||||||
int imlib_read_geometry(FIL *fp, image_t *img, const char *path,
|
void imlib_read_pixels(FIL *fp, image_t *img, int line_start, int line_end, img_read_settings_t *rs);
|
||||||
bool *w_flipped, bool *h_flipped, bool disable_jpeg);
|
void imlib_load_image(image_t *img, const char *path);
|
||||||
int imlib_read_pixels(FIL *fp, image_t *img, int line_start, int line_end);
|
void imlib_save_image(image_t *img, const char *path, rectangle_t *roi, save_image_format_t format);
|
||||||
int imlib_load_image(image_t *image, const char *path);
|
|
||||||
int imlib_save_image(image_t *image, const char *path, rectangle_t *roi);
|
|
||||||
|
|
||||||
/* Basic image functions */
|
/* Basic image functions */
|
||||||
int imlib_get_pixel(image_t *img, int x, int y);
|
int imlib_get_pixel(image_t *img, int x, int y);
|
||||||
|
|||||||
@ -7,14 +7,13 @@
|
|||||||
* Ported from public domain JPEG writer by Jon Olick - http://jonolick.com
|
* Ported from public domain JPEG writer by Jon Olick - http://jonolick.com
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
#include <stdio.h>
|
|
||||||
#include <arm_math.h>
|
#include <arm_math.h>
|
||||||
|
#include <stdio.h>
|
||||||
#include "ff.h"
|
#include <stm32f4xx_hal.h>
|
||||||
|
#include <ff.h>
|
||||||
#include "ff_wrapper.h"
|
#include "ff_wrapper.h"
|
||||||
#include "xalloc.h"
|
#include "xalloc.h"
|
||||||
#include "imlib.h"
|
#include "imlib.h"
|
||||||
#include "stm32f4xx_hal.h"
|
|
||||||
#define TIME_JPEG (0)
|
#define TIME_JPEG (0)
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -635,16 +634,12 @@ void jpeg_compress(image_t *src, image_t *dst, int quality)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// This function inits the geometry values of an image.
|
// This function inits the geometry values of an image.
|
||||||
int jpeg_read_geometry(FIL *fp, image_t *img, const char *path)
|
void jpeg_read_geometry(FIL *fp, image_t *img, const char *path)
|
||||||
{
|
{
|
||||||
FRESULT res = f_open(fp, path, FA_READ|FA_OPEN_EXISTING);
|
file_read_open(fp, path);
|
||||||
if (res != FR_OK) {
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
uint16_t header;
|
uint16_t header;
|
||||||
READ_WORD(fp, &header);
|
read_word(fp, &header);
|
||||||
IM_SWAP16(header);
|
IM_SWAP16(header);
|
||||||
if ((0xFFD0 <= header) && (header <= 0xFFD9)) {
|
if ((0xFFD0 <= header) && (header <= 0xFFD9)) {
|
||||||
continue;
|
continue;
|
||||||
@ -654,88 +649,53 @@ int jpeg_read_geometry(FIL *fp, image_t *img, const char *path)
|
|||||||
|| ((0xFFF0 <= header) && (header <= 0xFFFE)))
|
|| ((0xFFF0 <= header) && (header <= 0xFFFE)))
|
||||||
{
|
{
|
||||||
uint16_t size;
|
uint16_t size;
|
||||||
READ_WORD(fp, &size);
|
read_word(fp, &size);
|
||||||
IM_SWAP16(size);
|
IM_SWAP16(size);
|
||||||
if (((0xFFC0 <= header) && (header <= 0xFFC3))
|
if (((0xFFC0 <= header) && (header <= 0xFFC3))
|
||||||
|| ((0xFFC5 <= header) && (header <= 0xFFC7))
|
|| ((0xFFC5 <= header) && (header <= 0xFFC7))
|
||||||
|| ((0xFFC9 <= header) && (header <= 0xFFCB))
|
|| ((0xFFC9 <= header) && (header <= 0xFFCB))
|
||||||
|| ((0xFFCD <= header) && (header <= 0xFFCF)))
|
|| ((0xFFCD <= header) && (header <= 0xFFCF)))
|
||||||
{
|
{
|
||||||
READ_BYTE_IGNORE(fp);
|
read_byte_ignore(fp);
|
||||||
uint16_t width;
|
uint16_t width;
|
||||||
READ_WORD(fp, &width);
|
read_word(fp, &width);
|
||||||
IM_SWAP16(width);
|
IM_SWAP16(width);
|
||||||
uint16_t height;
|
uint16_t height;
|
||||||
READ_WORD(fp, &height);
|
read_word(fp, &height);
|
||||||
IM_SWAP16(height);
|
IM_SWAP16(height);
|
||||||
img->w = width;
|
img->w = width;
|
||||||
img->h = height;
|
img->h = height;
|
||||||
img->bpp = f_size(fp);
|
img->bpp = f_size(fp);
|
||||||
return FR_OK;
|
return;
|
||||||
}
|
} else {
|
||||||
FRESULT res = f_lseek(fp, f_tell(fp) + size - 2);
|
file_seek(fp, f_tell(fp) + size - 2);
|
||||||
if (res != FR_OK) {
|
|
||||||
f_close(fp);
|
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
f_close(fp);
|
ff_file_corrupted(fp);
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This function reads the pixel values of an image.
|
// This function reads the pixel values of an image.
|
||||||
int jpeg_read_pixels(FIL *fp, image_t *img)
|
void jpeg_read_pixels(FIL *fp, image_t *img)
|
||||||
{
|
{
|
||||||
FRESULT res = f_lseek(fp, 0);
|
file_seek(fp, 0);
|
||||||
if (res != FR_OK) {
|
read_data(fp, img->pixels, img->bpp);
|
||||||
f_close(fp);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
READ_DATA(fp, img->pixels, img->bpp);
|
|
||||||
return FR_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int jpeg_read_int(image_t *img, const char *path)
|
void jpeg_read(image_t *img, const char *path)
|
||||||
{
|
{
|
||||||
FIL fp;
|
FIL fp;
|
||||||
|
jpeg_read_geometry(&fp, img, path);
|
||||||
int res = jpeg_read_geometry(&fp, img, path);
|
if (!img->pixels) img->pixels = xalloc(img->w * img->h * img->bpp);
|
||||||
if (res != FR_OK) {
|
jpeg_read_pixels(&fp, img);
|
||||||
return res;
|
file_close(&fp);
|
||||||
}
|
|
||||||
|
|
||||||
if (!img->pixels) { // don't allocate if already allocated...
|
|
||||||
img->pixels = xalloc(img->bpp);
|
|
||||||
}
|
|
||||||
|
|
||||||
res = jpeg_read_pixels(&fp, img);
|
|
||||||
if (res != FR_OK) {
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
return f_close(&fp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int jpeg_read(image_t *img, const char *path)
|
void jpeg_write(image_t *img, const char *path)
|
||||||
{
|
|
||||||
const uint8_t *backup = img->pixels;
|
|
||||||
const int res = jpeg_read_int(img, path);
|
|
||||||
// free image if I didn't start with one...
|
|
||||||
if ((res != FR_OK) && (!backup) && (img->pixels)) {
|
|
||||||
xfree(img->pixels);
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
int jpeg_write(image_t *img, const char *path)
|
|
||||||
{
|
{
|
||||||
FIL fp;
|
FIL fp;
|
||||||
FRESULT res = f_open(&fp, path, FA_WRITE|FA_CREATE_ALWAYS);
|
file_write_open(&fp, path);
|
||||||
if (res != FR_OK) {
|
write_data(&fp, img->pixels, img->bpp);
|
||||||
return res;
|
file_close(&fp);
|
||||||
}
|
|
||||||
WRITE_DATA(&fp, img->pixels, img->bpp);
|
|
||||||
return f_close(&fp);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,197 +12,137 @@
|
|||||||
#include "xalloc.h"
|
#include "xalloc.h"
|
||||||
#include "imlib.h"
|
#include "imlib.h"
|
||||||
|
|
||||||
static uint8_t read_int_c;
|
static void read_int_reset(ppm_read_settings_t *rs)
|
||||||
static bool read_int_c_valid;
|
{
|
||||||
static void read_int_reset() {
|
rs->read_int_c_valid = false;
|
||||||
read_int_c_valid = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int read_int(FIL *fp, uint32_t *i)
|
static void read_int(FIL *fp, uint32_t *i, ppm_read_settings_t *rs)
|
||||||
{
|
{
|
||||||
enum { EAT_WHITESPACE, EAT_COMMENT, EAT_NUMBER } mode = EAT_WHITESPACE;
|
enum { EAT_WHITESPACE, EAT_COMMENT, EAT_NUMBER } mode = EAT_WHITESPACE;
|
||||||
for(*i = 0;;) {
|
for(*i = 0;;) {
|
||||||
if (!read_int_c_valid) {
|
if (!rs->read_int_c_valid) {
|
||||||
if (f_eof(fp)) {
|
if (f_eof(fp)) return;
|
||||||
return FR_OK;
|
read_byte(fp, &rs->read_int_c);
|
||||||
}
|
rs->read_int_c_valid = true;
|
||||||
int res = read_byte(fp, &read_int_c);
|
|
||||||
if (res != FR_OK) {
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
read_int_c_valid = true;
|
|
||||||
}
|
}
|
||||||
if (mode == EAT_WHITESPACE) {
|
if (mode == EAT_WHITESPACE) {
|
||||||
if (read_int_c == '#') {
|
if (rs->read_int_c == '#') {
|
||||||
mode = EAT_COMMENT;
|
mode = EAT_COMMENT;
|
||||||
} else if (('0' <= read_int_c) && (read_int_c <= '9')) {
|
} else if (('0' <= rs->read_int_c) && (rs->read_int_c <= '9')) {
|
||||||
*i = read_int_c - '0';
|
*i = rs->read_int_c - '0';
|
||||||
mode = EAT_NUMBER;
|
mode = EAT_NUMBER;
|
||||||
}
|
}
|
||||||
} else if (mode == EAT_COMMENT) {
|
} else if (mode == EAT_COMMENT) {
|
||||||
if ((read_int_c == '\n') || (read_int_c == '\r')) {
|
if ((rs->read_int_c == '\n') || (rs->read_int_c == '\r')) {
|
||||||
mode = EAT_WHITESPACE;
|
mode = EAT_WHITESPACE;
|
||||||
}
|
}
|
||||||
} else if (mode == EAT_NUMBER) {
|
} else if (mode == EAT_NUMBER) {
|
||||||
if (('0' <= read_int_c) && (read_int_c <= '9')) {
|
if (('0' <= rs->read_int_c) && (rs->read_int_c <= '9')) {
|
||||||
*i = (*i * 10) + read_int_c - '0';
|
*i = (*i * 10) + rs->read_int_c - '0';
|
||||||
} else {
|
} else {
|
||||||
return FR_OK; // read_int_c_valid==true on exit
|
return; // read_int_c_valid==true on exit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
read_int_c_valid = false;
|
rs->read_int_c_valid = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#define READ_INT(fp, i) \
|
|
||||||
({ FRESULT _res = read_int((fp), (i)); \
|
|
||||||
if (_res != FR_OK) { f_close((fp)); return _res; } })
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Store mode settings internally, no need for callers to store this info.
|
|
||||||
static uint8_t ppm_fmt;
|
|
||||||
|
|
||||||
// This function inits the geometry values of an image.
|
// This function inits the geometry values of an image.
|
||||||
int ppm_read_geometry(FIL *fp, image_t *img, const char *path)
|
void ppm_read_geometry(FIL *fp, image_t *img, const char *path, ppm_read_settings_t *rs)
|
||||||
{
|
{
|
||||||
read_int_reset();
|
read_int_reset(rs);
|
||||||
FRESULT res = f_open(fp, path, FA_READ|FA_OPEN_EXISTING);
|
file_read_open(fp, path);
|
||||||
if (res != FR_OK) {
|
read_byte_expect(fp, 'P');
|
||||||
return res;
|
read_byte(fp, &rs->ppm_fmt);
|
||||||
}
|
if ((rs->ppm_fmt!='2') && (rs->ppm_fmt!='3') && (rs->ppm_fmt!='5') && (rs->ppm_fmt!='6')) ff_unsupported_format(fp);
|
||||||
|
img->bpp = ((rs->ppm_fmt == '2') || (rs->ppm_fmt == '5')) ? 1 : 2;
|
||||||
|
|
||||||
READ_BYTE_EXPECT(fp, 'P');
|
read_int(fp, (uint32_t *) &img->w, rs);
|
||||||
READ_BYTE(fp, &ppm_fmt);
|
read_int(fp, (uint32_t *) &img->h, rs);
|
||||||
if ((ppm_fmt!='2') && (ppm_fmt!='3') && (ppm_fmt!='5') && (ppm_fmt!='6')) {
|
if ((img->w == 0) || (img->h == 0)) ff_file_corrupted(fp);
|
||||||
f_close(fp);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
img->bpp = ((ppm_fmt == '2') || (ppm_fmt == '5')) ? 1 : 2;
|
|
||||||
|
|
||||||
READ_INT(fp, (uint32_t *) &img->w);
|
|
||||||
READ_INT(fp, (uint32_t *) &img->h);
|
|
||||||
if ((img->w == 0) || (img->h == 0)) {
|
|
||||||
f_close(fp);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t max;
|
uint32_t max;
|
||||||
READ_INT(fp, &max);
|
read_int(fp, &max, rs);
|
||||||
if (max != 255) {
|
if (max != 255) ff_unsupported_format(fp);
|
||||||
f_close(fp);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return FR_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// This function reads the pixel values of an image.
|
// This function reads the pixel values of an image.
|
||||||
int ppm_read_pixels(FIL *fp, image_t *img, int line_start, int line_end)
|
void ppm_read_pixels(FIL *fp, image_t *img, int line_start, int line_end, ppm_read_settings_t *rs)
|
||||||
{
|
{
|
||||||
if (ppm_fmt == '2') {
|
if (rs->ppm_fmt == '2') {
|
||||||
for (int i = line_start; i < line_end; i++) {
|
for (int i = line_start; i < line_end; i++) {
|
||||||
for (int j = 0; j < img->w; j++) {
|
for (int j = 0; j < img->w; j++) {
|
||||||
uint32_t pixel;
|
uint32_t pixel;
|
||||||
READ_INT(fp, &pixel);
|
read_int(fp, &pixel, rs);
|
||||||
IM_SET_GS_PIXEL(img, j, i, pixel);
|
IM_SET_GS_PIXEL(img, j, i, pixel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (ppm_fmt == '3') {
|
} else if (rs->ppm_fmt == '3') {
|
||||||
for (int i = line_start; i < line_end; i++) {
|
for (int i = line_start; i < line_end; i++) {
|
||||||
for (int j = 0; j < img->w; j++) {
|
for (int j = 0; j < img->w; j++) {
|
||||||
uint32_t r, g, b;
|
uint32_t r, g, b;
|
||||||
READ_INT(fp, &r);
|
read_int(fp, &r, rs);
|
||||||
READ_INT(fp, &g);
|
read_int(fp, &g, rs);
|
||||||
READ_INT(fp, &b);
|
read_int(fp, &b, rs);
|
||||||
IM_SET_RGB565_PIXEL(img, j, i, IM_RGB565(IM_R825(r),
|
IM_SET_RGB565_PIXEL(img, j, i, IM_RGB565(IM_R825(r),
|
||||||
IM_G826(g),
|
IM_G826(g),
|
||||||
IM_B825(b)));
|
IM_B825(b)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (ppm_fmt == '5') {
|
} else if (rs->ppm_fmt == '5') {
|
||||||
READ_DATA(fp, // Super Fast - Zoom, Zoom!
|
read_data(fp, // Super Fast - Zoom, Zoom!
|
||||||
img->pixels + (line_start * img->w),
|
img->pixels + (line_start * img->w),
|
||||||
(line_end - line_start + 1) * img->w);
|
(line_end - line_start + 1) * img->w);
|
||||||
} else if (ppm_fmt == '6') {
|
} else if (rs->ppm_fmt == '6') {
|
||||||
for (int i = line_start; i < line_end; i++) {
|
for (int i = line_start; i < line_end; i++) {
|
||||||
for (int j = 0; j < img->w; j++) {
|
for (int j = 0; j < img->w; j++) {
|
||||||
uint8_t r, g, b;
|
uint8_t r, g, b;
|
||||||
READ_BYTE(fp, &r);
|
read_byte(fp, &r);
|
||||||
READ_BYTE(fp, &g);
|
read_byte(fp, &g);
|
||||||
READ_BYTE(fp, &b);
|
read_byte(fp, &b);
|
||||||
IM_SET_RGB565_PIXEL(img, j, i, IM_RGB565(IM_R825(r),
|
IM_SET_RGB565_PIXEL(img, j, i, IM_RGB565(IM_R825(r),
|
||||||
IM_G826(g),
|
IM_G826(g),
|
||||||
IM_B825(b)));
|
IM_B825(b)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return FR_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ppm_read_int(image_t *img, const char *path)
|
void ppm_read(image_t *img, const char *path)
|
||||||
{
|
{
|
||||||
FIL fp;
|
FIL fp;
|
||||||
|
ppm_read_settings_t rs;
|
||||||
int res = ppm_read_geometry(&fp, img, path);
|
ppm_read_geometry(&fp, img, path, &rs);
|
||||||
if (res != FR_OK) {
|
if (!img->pixels) img->pixels = xalloc(img->w * img->h * img->bpp);
|
||||||
return res;
|
ppm_read_pixels(&fp, img, 0, img->h, &rs);
|
||||||
}
|
file_close(&fp);
|
||||||
|
|
||||||
if (!img->pixels) { // don't allocate if already allocated...
|
|
||||||
img->pixels = xalloc(img->w * img->h * img->bpp);
|
|
||||||
}
|
|
||||||
|
|
||||||
res = ppm_read_pixels(&fp, img, 0, img->h);
|
|
||||||
if (res != FR_OK) {
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
return f_close(&fp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int ppm_read(image_t *img, const char *path)
|
void ppm_write_subimg(image_t *img, const char *path, rectangle_t *r)
|
||||||
{
|
|
||||||
const uint8_t *backup = img->pixels;
|
|
||||||
const int res = ppm_read_int(img, path);
|
|
||||||
// free image if I didn't start with one...
|
|
||||||
if ((res != FR_OK) && (!backup) && (img->pixels)) {
|
|
||||||
xfree(img->pixels);
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
int ppm_write_subimg(image_t *img, const char *path, rectangle_t *r)
|
|
||||||
{
|
{
|
||||||
rectangle_t rect;
|
rectangle_t rect;
|
||||||
if (!rectangle_subimg(img, r, &rect)) {
|
if (!rectangle_subimg(img, r, &rect)) ff_no_intersection();
|
||||||
return -1; // no image intersection
|
|
||||||
}
|
|
||||||
|
|
||||||
FIL fp;
|
FIL fp;
|
||||||
FRESULT res = f_open(&fp, path, FA_WRITE|FA_CREATE_ALWAYS);
|
file_write_open(&fp, path);
|
||||||
if (res != FR_OK) {
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (IM_IS_GS(img)) {
|
if (IM_IS_GS(img)) {
|
||||||
char buffer[20]; // exactly big enough for 5-digit w/h
|
char buffer[20]; // exactly big enough for 5-digit w/h
|
||||||
int len = snprintf(buffer, 20, "P5\n%d %d\n255\n", rect.w, rect.h);
|
int len = snprintf(buffer, 20, "P5\n%d %d\n255\n", rect.w, rect.h);
|
||||||
WRITE_DATA(&fp, buffer, len);
|
write_data(&fp, buffer, len);
|
||||||
if ((rect.x == 0) && (rect.w == img->w)) {
|
if ((rect.x == 0) && (rect.w == img->w)) {
|
||||||
WRITE_DATA(&fp, // Super Fast - Zoom, Zoom!
|
write_data(&fp, // Super Fast - Zoom, Zoom!
|
||||||
img->pixels + (rect.y * img->w),
|
img->pixels + (rect.y * img->w),
|
||||||
rect.w * rect.h);
|
rect.w * rect.h);
|
||||||
} else {
|
} else {
|
||||||
for (int i = 0; i < rect.h; i++) {
|
for (int i = 0; i < rect.h; i++) {
|
||||||
WRITE_DATA(&fp, img->pixels+((rect.y+i)*img->w)+rect.x, rect.w);
|
write_data(&fp, img->pixels+((rect.y+i)*img->w)+rect.x, rect.w);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
char buffer[20]; // exactly big enough for 5-digit w/h
|
char buffer[20]; // exactly big enough for 5-digit w/h
|
||||||
int len = snprintf(buffer, 20, "P6\n%d %d\n255\n", rect.w, rect.h);
|
int len = snprintf(buffer, 20, "P6\n%d %d\n255\n", rect.w, rect.h);
|
||||||
WRITE_DATA(&fp, buffer, len);
|
write_data(&fp, buffer, len);
|
||||||
for (int i = 0; i < rect.h; i++) {
|
for (int i = 0; i < rect.h; i++) {
|
||||||
for (int j = 0; j < rect.w; j++) {
|
for (int j = 0; j < rect.w; j++) {
|
||||||
int pixel = IM_GET_RGB565_PIXEL(img, (rect.x + j), (rect.y + i));
|
int pixel = IM_GET_RGB565_PIXEL(img, (rect.x + j), (rect.y + i));
|
||||||
@ -210,10 +150,10 @@ int ppm_write_subimg(image_t *img, const char *path, rectangle_t *r)
|
|||||||
buff[0] = IM_R528(IM_R565(pixel));
|
buff[0] = IM_R528(IM_R565(pixel));
|
||||||
buff[1] = IM_G628(IM_G565(pixel));
|
buff[1] = IM_G628(IM_G565(pixel));
|
||||||
buff[2] = IM_B528(IM_B565(pixel));
|
buff[2] = IM_B528(IM_B565(pixel));
|
||||||
WRITE_DATA(&fp, buff, 3);
|
write_data(&fp, buff, 3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return f_close(&fp);
|
file_close(&fp);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -156,6 +156,20 @@ static mp_obj_t py_image_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t va
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static mp_obj_t py_image_save(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
|
||||||
|
{
|
||||||
|
image_t *arg_img = py_image_cobj(args[0]);
|
||||||
|
const char *path = mp_obj_str_get_str(args[1]);
|
||||||
|
|
||||||
|
rectangle_t roi;
|
||||||
|
py_helper_lookup_rectangle(kw_args, arg_img, &roi);
|
||||||
|
|
||||||
|
imlib_save_image(arg_img, path, &roi,
|
||||||
|
py_helper_lookup_int(kw_args,
|
||||||
|
MP_OBJ_NEW_QSTR(MP_QSTR_format), FORMAT_BMP));
|
||||||
|
return mp_const_true;
|
||||||
|
}
|
||||||
|
|
||||||
static mp_obj_t py_image_width(mp_obj_t img_obj)
|
static mp_obj_t py_image_width(mp_obj_t img_obj)
|
||||||
{
|
{
|
||||||
image_t *arg_img = py_image_cobj(img_obj);
|
image_t *arg_img = py_image_cobj(img_obj);
|
||||||
@ -602,23 +616,6 @@ static mp_obj_t py_image_difference(mp_obj_t img_obj, mp_obj_t other_obj)
|
|||||||
return mp_const_none;
|
return mp_const_none;
|
||||||
}
|
}
|
||||||
|
|
||||||
static mp_obj_t py_image_save(uint n_args, const mp_obj_t *args, mp_map_t *kw_args)
|
|
||||||
{
|
|
||||||
int res;
|
|
||||||
rectangle_t roi;
|
|
||||||
image_t *image = py_image_cobj(args[0]);
|
|
||||||
const char *path = mp_obj_str_get_str(args[1]);
|
|
||||||
|
|
||||||
py_helper_lookup_rectangle(kw_args, image, &roi);
|
|
||||||
|
|
||||||
res = imlib_save_image(image, path, &roi);
|
|
||||||
if (res != FR_OK) {
|
|
||||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, ffs_strerror(res)));
|
|
||||||
}
|
|
||||||
|
|
||||||
return mp_const_true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static mp_obj_t py_image_scale(mp_obj_t image_obj, mp_obj_t size_obj)
|
static mp_obj_t py_image_scale(mp_obj_t image_obj, mp_obj_t size_obj)
|
||||||
{
|
{
|
||||||
int w,h;
|
int w,h;
|
||||||
@ -1149,6 +1146,9 @@ static mp_obj_t py_image_match_lbp(uint n_args, const mp_obj_t *args, mp_map_t *
|
|||||||
return mp_obj_new_int(imlib_lbp_desc_distance(d0, d1));
|
return mp_obj_new_int(imlib_lbp_desc_distance(d0, d1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Image file functions */
|
||||||
|
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_save_obj, 2, py_image_save);
|
||||||
|
/* Basic image functions */
|
||||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_width_obj, py_image_width);
|
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_width_obj, py_image_width);
|
||||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_height_obj, py_image_height);
|
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_height_obj, py_image_height);
|
||||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_format_obj, py_image_format);
|
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_format_obj, py_image_format);
|
||||||
@ -1179,7 +1179,6 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_orientation_degrees_obj, 1, py_image_
|
|||||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_negate_obj, py_image_negate);
|
STATIC MP_DEFINE_CONST_FUN_OBJ_1(py_image_negate_obj, py_image_negate);
|
||||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(py_image_difference_obj, py_image_difference);
|
STATIC MP_DEFINE_CONST_FUN_OBJ_2(py_image_difference_obj, py_image_difference);
|
||||||
|
|
||||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_save_obj, 2, py_image_save);
|
|
||||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(py_image_scale_obj, py_image_scale);
|
STATIC MP_DEFINE_CONST_FUN_OBJ_2(py_image_scale_obj, py_image_scale);
|
||||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(py_image_scaled_obj, py_image_scaled);
|
STATIC MP_DEFINE_CONST_FUN_OBJ_2(py_image_scaled_obj, py_image_scaled);
|
||||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(py_image_subimg_obj, py_image_subimg);
|
STATIC MP_DEFINE_CONST_FUN_OBJ_2(py_image_subimg_obj, py_image_subimg);
|
||||||
@ -1203,6 +1202,11 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(py_image_match_keypoints_obj, 4, 4, p
|
|||||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_match_lbp_obj, 2, py_image_match_lbp);
|
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_match_lbp_obj, 2, py_image_match_lbp);
|
||||||
|
|
||||||
static const mp_map_elem_t locals_dict_table[] = {
|
static const mp_map_elem_t locals_dict_table[] = {
|
||||||
|
{MP_OBJ_NEW_QSTR(MP_QSTR_FORMAT_BMP), MP_OBJ_NEW_SMALL_INT(FORMAT_BMP)},
|
||||||
|
{MP_OBJ_NEW_QSTR(MP_QSTR_FORMAT_PNM), MP_OBJ_NEW_SMALL_INT(FORMAT_PNM)},
|
||||||
|
/* Image file functions */
|
||||||
|
{MP_OBJ_NEW_QSTR(MP_QSTR_save), (mp_obj_t)&py_image_save_obj},
|
||||||
|
/* Basic image functions */
|
||||||
{MP_OBJ_NEW_QSTR(MP_QSTR_width), (mp_obj_t)&py_image_width_obj},
|
{MP_OBJ_NEW_QSTR(MP_QSTR_width), (mp_obj_t)&py_image_width_obj},
|
||||||
{MP_OBJ_NEW_QSTR(MP_QSTR_height), (mp_obj_t)&py_image_height_obj},
|
{MP_OBJ_NEW_QSTR(MP_QSTR_height), (mp_obj_t)&py_image_height_obj},
|
||||||
{MP_OBJ_NEW_QSTR(MP_QSTR_format), (mp_obj_t)&py_image_format_obj},
|
{MP_OBJ_NEW_QSTR(MP_QSTR_format), (mp_obj_t)&py_image_format_obj},
|
||||||
@ -1233,8 +1237,6 @@ static const mp_map_elem_t locals_dict_table[] = {
|
|||||||
{MP_OBJ_NEW_QSTR(MP_QSTR_negate), (mp_obj_t)&py_image_negate_obj},
|
{MP_OBJ_NEW_QSTR(MP_QSTR_negate), (mp_obj_t)&py_image_negate_obj},
|
||||||
{MP_OBJ_NEW_QSTR(MP_QSTR_difference), (mp_obj_t)&py_image_difference_obj},
|
{MP_OBJ_NEW_QSTR(MP_QSTR_difference), (mp_obj_t)&py_image_difference_obj},
|
||||||
|
|
||||||
/* basic image functions */
|
|
||||||
{MP_OBJ_NEW_QSTR(MP_QSTR_save), (mp_obj_t)&py_image_save_obj},
|
|
||||||
{MP_OBJ_NEW_QSTR(MP_QSTR_scale), (mp_obj_t)&py_image_scale_obj},
|
{MP_OBJ_NEW_QSTR(MP_QSTR_scale), (mp_obj_t)&py_image_scale_obj},
|
||||||
{MP_OBJ_NEW_QSTR(MP_QSTR_scaled), (mp_obj_t)&py_image_scaled_obj},
|
{MP_OBJ_NEW_QSTR(MP_QSTR_scaled), (mp_obj_t)&py_image_scaled_obj},
|
||||||
{MP_OBJ_NEW_QSTR(MP_QSTR_subimg), (mp_obj_t)&py_image_subimg_obj},
|
{MP_OBJ_NEW_QSTR(MP_QSTR_subimg), (mp_obj_t)&py_image_subimg_obj},
|
||||||
@ -1319,10 +1321,7 @@ mp_obj_t py_image_load_image(mp_obj_t path_obj)
|
|||||||
/* get image pointer */
|
/* get image pointer */
|
||||||
image = py_image_cobj(image_obj);
|
image = py_image_cobj(image_obj);
|
||||||
|
|
||||||
int res = imlib_load_image(image, path);
|
imlib_load_image(image, path);
|
||||||
if (res != FR_OK) {
|
|
||||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, ffs_strerror(res)));
|
|
||||||
}
|
|
||||||
|
|
||||||
return image_obj;
|
return image_obj;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -168,10 +168,7 @@ void usbdbg_data_out(void *buffer, int length)
|
|||||||
rectangle_t *roi = (rectangle_t*)buffer;
|
rectangle_t *roi = (rectangle_t*)buffer;
|
||||||
char *path = (char*)buffer+sizeof(rectangle_t);
|
char *path = (char*)buffer+sizeof(rectangle_t);
|
||||||
|
|
||||||
int res=imlib_save_image(&image, path, roi);
|
imlib_save_image(&image, path, roi, FORMAT_PNM);
|
||||||
if (res != FR_OK) {
|
|
||||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, ffs_strerror(res)));
|
|
||||||
}
|
|
||||||
// raise a flash IRQ to flush image
|
// raise a flash IRQ to flush image
|
||||||
//NVIC->STIR = FLASH_IRQn;
|
//NVIC->STIR = FLASH_IRQn;
|
||||||
break;
|
break;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user