mirror of
https://github.com/openmv/openmv.git
synced 2025-11-04 14:49:50 +08:00
Merge pull request #1976 from openmv/ff_refactor
misc: Refactor file management code.
This commit is contained in:
commit
fb9379e1e1
@ -8,9 +8,9 @@
|
|||||||
*
|
*
|
||||||
* Framebuffer functions.
|
* Framebuffer functions.
|
||||||
*/
|
*/
|
||||||
#include <ff_wrapper.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include "fb_alloc.h"
|
#include "fb_alloc.h"
|
||||||
|
#include "file_utils.h"
|
||||||
|
|
||||||
#include "programmer/programmer.h"
|
#include "programmer/programmer.h"
|
||||||
#include "spi_flash/include/spi_flash_map.h"
|
#include "spi_flash/include/spi_flash_map.h"
|
||||||
@ -34,7 +34,7 @@ int burn_firmware(const char *path)
|
|||||||
int ret = M2M_ERR_FAIL;
|
int ret = M2M_ERR_FAIL;
|
||||||
uint8_t *buf = fb_alloc(FLASH_SECTOR_SZ, FB_ALLOC_NO_HINT);
|
uint8_t *buf = fb_alloc(FLASH_SECTOR_SZ, FB_ALLOC_NO_HINT);
|
||||||
|
|
||||||
if (f_open_helper(&fp, path, FA_READ|FA_OPEN_EXISTING) != FR_OK) {
|
if (file_ll_open(&fp, path, FA_READ|FA_OPEN_EXISTING) != FR_OK) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,7 +44,7 @@ int burn_firmware(const char *path)
|
|||||||
while (size) {
|
while (size) {
|
||||||
// Read a chuck (max FLASH_SECTOR_SZ bytes).
|
// Read a chuck (max FLASH_SECTOR_SZ bytes).
|
||||||
bytes = MIN(size, FLASH_SECTOR_SZ);
|
bytes = MIN(size, FLASH_SECTOR_SZ);
|
||||||
if (f_read(&fp, buf, bytes, &bytes_out) != FR_OK || bytes != bytes_out) {
|
if (file_ll_read(&fp, buf, bytes, &bytes_out) != FR_OK || bytes != bytes_out) {
|
||||||
printf("burn_firmware: file read error!\n");
|
printf("burn_firmware: file read error!\n");
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
@ -63,7 +63,7 @@ int burn_firmware(const char *path)
|
|||||||
|
|
||||||
error:
|
error:
|
||||||
fb_free();
|
fb_free();
|
||||||
f_close(&fp);
|
file_ll_close(&fp);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,7 +81,7 @@ int verify_firmware(const char *path)
|
|||||||
uint8_t *file_buf = fb_alloc(FLASH_SECTOR_SZ, FB_ALLOC_NO_HINT);
|
uint8_t *file_buf = fb_alloc(FLASH_SECTOR_SZ, FB_ALLOC_NO_HINT);
|
||||||
uint8_t *flash_buf = fb_alloc(FLASH_SECTOR_SZ, FB_ALLOC_NO_HINT);
|
uint8_t *flash_buf = fb_alloc(FLASH_SECTOR_SZ, FB_ALLOC_NO_HINT);
|
||||||
|
|
||||||
if (f_open_helper(&fp, path, FA_READ|FA_OPEN_EXISTING) != FR_OK) {
|
if (file_ll_open(&fp, path, FA_READ|FA_OPEN_EXISTING) != FR_OK) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,7 +92,7 @@ int verify_firmware(const char *path)
|
|||||||
// Firmware chuck size (max FLASH_SECTOR_SZ bytes).
|
// Firmware chuck size (max FLASH_SECTOR_SZ bytes).
|
||||||
bytes = MIN(size, FLASH_SECTOR_SZ);
|
bytes = MIN(size, FLASH_SECTOR_SZ);
|
||||||
|
|
||||||
if (f_read(&fp, file_buf, bytes, &bytes_out) != FR_OK || bytes_out != bytes) {
|
if (file_ll_read(&fp, file_buf, bytes, &bytes_out) != FR_OK || bytes_out != bytes) {
|
||||||
printf("verify_firmware: file read error!\n");
|
printf("verify_firmware: file read error!\n");
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
@ -118,7 +118,7 @@ int verify_firmware(const char *path)
|
|||||||
error:
|
error:
|
||||||
fb_free();
|
fb_free();
|
||||||
fb_free();
|
fb_free();
|
||||||
f_close(&fp);
|
file_ll_close(&fp);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -135,7 +135,7 @@ int dump_firmware(const char *path)
|
|||||||
int ret = M2M_ERR_FAIL;
|
int ret = M2M_ERR_FAIL;
|
||||||
uint8_t *flash_buf = fb_alloc(FLASH_SECTOR_SZ, FB_ALLOC_NO_HINT);
|
uint8_t *flash_buf = fb_alloc(FLASH_SECTOR_SZ, FB_ALLOC_NO_HINT);
|
||||||
|
|
||||||
if (f_open_helper(&fp, path, FA_WRITE | FA_CREATE_ALWAYS) != FR_OK) {
|
if (file_ll_open(&fp, path, FA_WRITE | FA_CREATE_ALWAYS) != FR_OK) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -151,7 +151,7 @@ int dump_firmware(const char *path)
|
|||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (f_write(&fp, flash_buf, bytes, &bytes_out) != FR_OK || bytes_out != bytes) {
|
if (file_ll_write(&fp, flash_buf, bytes, &bytes_out) != FR_OK || bytes_out != bytes) {
|
||||||
printf("dump_firmware: file write error!\n");
|
printf("dump_firmware: file write error!\n");
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
@ -164,6 +164,6 @@ int dump_firmware(const char *path)
|
|||||||
|
|
||||||
error:
|
error:
|
||||||
fb_free();
|
fb_free();
|
||||||
f_close(&fp);
|
file_ll_close(&fp);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,7 +17,7 @@ SRCS += $(addprefix alloc/, \
|
|||||||
|
|
||||||
SRCS += $(addprefix common/, \
|
SRCS += $(addprefix common/, \
|
||||||
array.c \
|
array.c \
|
||||||
ff_wrapper.c \
|
file_utils.c \
|
||||||
ini.c \
|
ini.c \
|
||||||
ringbuf.c \
|
ringbuf.c \
|
||||||
trace.c \
|
trace.c \
|
||||||
|
|||||||
@ -1,543 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of the OpenMV project.
|
|
||||||
* Copyright (c) 2013-2016 Kwabena W. Agyeman <kwagyeman@openmv.io>
|
|
||||||
* This work is licensed under the MIT license, see the file LICENSE for details.
|
|
||||||
*
|
|
||||||
* File System Helper Functions
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
#include "imlib_config.h"
|
|
||||||
#if defined(IMLIB_ENABLE_IMAGE_FILE_IO)
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
#include "py/runtime.h"
|
|
||||||
#include "extmod/vfs.h"
|
|
||||||
#include "extmod/vfs_fat.h"
|
|
||||||
|
|
||||||
#include "omv_common.h"
|
|
||||||
#include "fb_alloc.h"
|
|
||||||
#include "ff_wrapper.h"
|
|
||||||
#define FF_MIN(x, y) (((x) < (y))?(x):(y))
|
|
||||||
|
|
||||||
NORETURN static void ff_fail(FIL *fp, FRESULT res) {
|
|
||||||
if (fp) {
|
|
||||||
f_close(fp);
|
|
||||||
}
|
|
||||||
mp_raise_msg(&mp_type_OSError, (mp_rom_error_text_t) ffs_strerror(res));
|
|
||||||
}
|
|
||||||
|
|
||||||
NORETURN static void ff_read_fail(FIL *fp) {
|
|
||||||
if (fp) {
|
|
||||||
f_close(fp);
|
|
||||||
}
|
|
||||||
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Failed to read requested bytes!"));
|
|
||||||
}
|
|
||||||
|
|
||||||
NORETURN static void ff_write_fail(FIL *fp) {
|
|
||||||
if (fp) {
|
|
||||||
f_close(fp);
|
|
||||||
}
|
|
||||||
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Failed to write requested bytes!"));
|
|
||||||
}
|
|
||||||
|
|
||||||
NORETURN static void ff_expect_fail(FIL *fp) {
|
|
||||||
if (fp) {
|
|
||||||
f_close(fp);
|
|
||||||
}
|
|
||||||
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Unexpected value read!"));
|
|
||||||
}
|
|
||||||
|
|
||||||
NORETURN void ff_unsupported_format(FIL *fp) {
|
|
||||||
if (fp) {
|
|
||||||
f_close(fp);
|
|
||||||
}
|
|
||||||
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Unsupported format!"));
|
|
||||||
}
|
|
||||||
|
|
||||||
NORETURN void ff_file_corrupted(FIL *fp) {
|
|
||||||
if (fp) {
|
|
||||||
f_close(fp);
|
|
||||||
}
|
|
||||||
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("File corrupted!"));
|
|
||||||
}
|
|
||||||
|
|
||||||
NORETURN void ff_not_equal(FIL *fp) {
|
|
||||||
if (fp) {
|
|
||||||
f_close(fp);
|
|
||||||
}
|
|
||||||
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Images not equal!"));
|
|
||||||
}
|
|
||||||
|
|
||||||
NORETURN void ff_no_intersection(FIL *fp) {
|
|
||||||
if (fp) {
|
|
||||||
f_close(fp);
|
|
||||||
}
|
|
||||||
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("No intersection!"));
|
|
||||||
}
|
|
||||||
|
|
||||||
void file_read_open(FIL *fp, const char *path) {
|
|
||||||
FRESULT res = f_open_helper(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_helper(fp, path, FA_WRITE | FA_CREATE_ALWAYS);
|
|
||||||
if (res != FR_OK) {
|
|
||||||
ff_fail(fp, res);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void file_read_write_open_existing(FIL *fp, const char *path) {
|
|
||||||
FRESULT res = f_open_helper(fp, path, FA_READ | FA_WRITE | FA_OPEN_EXISTING);
|
|
||||||
if (res != FR_OK) {
|
|
||||||
ff_fail(fp, res);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void file_read_write_open_always(FIL *fp, const char *path) {
|
|
||||||
FRESULT res = f_open_helper(fp, path, FA_READ | FA_WRITE | FA_OPEN_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 file_truncate(FIL *fp) {
|
|
||||||
FRESULT res = f_truncate(fp);
|
|
||||||
if (res != FR_OK) {
|
|
||||||
ff_fail(fp, res);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void file_sync(FIL *fp) {
|
|
||||||
FRESULT res = f_sync(fp);
|
|
||||||
if (res != FR_OK) {
|
|
||||||
ff_fail(fp, res);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// These wrapper functions are used for backward compatibility with
|
|
||||||
// OpenMV code using vanilla FatFS. Note: Extracted from cc3200 ftp.c
|
|
||||||
|
|
||||||
STATIC FATFS *lookup_path(const TCHAR **path) {
|
|
||||||
mp_vfs_mount_t *fs = mp_vfs_lookup_path(*path, path);
|
|
||||||
if (fs == MP_VFS_NONE || fs == MP_VFS_ROOT) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
// here we assume that the mounted device is FATFS
|
|
||||||
return &((fs_user_mount_t *) MP_OBJ_TO_PTR(fs->obj))->fatfs;
|
|
||||||
}
|
|
||||||
|
|
||||||
FRESULT f_open_helper(FIL *fp, const TCHAR *path, BYTE mode) {
|
|
||||||
FATFS *fs = lookup_path(&path);
|
|
||||||
if (fs == NULL) {
|
|
||||||
return FR_NO_PATH;
|
|
||||||
}
|
|
||||||
return f_open(fs, fp, path, mode);
|
|
||||||
}
|
|
||||||
|
|
||||||
FRESULT f_opendir_helper(FF_DIR *dp, const TCHAR *path) {
|
|
||||||
FATFS *fs = lookup_path(&path);
|
|
||||||
if (fs == NULL) {
|
|
||||||
return FR_NO_PATH;
|
|
||||||
}
|
|
||||||
return f_opendir(fs, dp, path);
|
|
||||||
}
|
|
||||||
|
|
||||||
FRESULT f_stat_helper(const TCHAR *path, FILINFO *fno) {
|
|
||||||
FATFS *fs = lookup_path(&path);
|
|
||||||
if (fs == NULL) {
|
|
||||||
return FR_NO_PATH;
|
|
||||||
}
|
|
||||||
return f_stat(fs, path, fno);
|
|
||||||
}
|
|
||||||
|
|
||||||
FRESULT f_mkdir_helper(const TCHAR *path) {
|
|
||||||
FATFS *fs = lookup_path(&path);
|
|
||||||
if (fs == NULL) {
|
|
||||||
return FR_NO_PATH;
|
|
||||||
}
|
|
||||||
return f_mkdir(fs, path);
|
|
||||||
}
|
|
||||||
|
|
||||||
FRESULT f_unlink_helper(const TCHAR *path) {
|
|
||||||
FATFS *fs = lookup_path(&path);
|
|
||||||
if (fs == NULL) {
|
|
||||||
return FR_NO_PATH;
|
|
||||||
}
|
|
||||||
return f_unlink(fs, path);
|
|
||||||
}
|
|
||||||
|
|
||||||
FRESULT f_rename_helper(const TCHAR *path_old, const TCHAR *path_new) {
|
|
||||||
FATFS *fs_old = lookup_path(&path_old);
|
|
||||||
if (fs_old == NULL) {
|
|
||||||
return FR_NO_PATH;
|
|
||||||
}
|
|
||||||
FATFS *fs_new = lookup_path(&path_new);
|
|
||||||
if (fs_new == NULL) {
|
|
||||||
return FR_NO_PATH;
|
|
||||||
}
|
|
||||||
if (fs_old != fs_new) {
|
|
||||||
return FR_NO_PATH;
|
|
||||||
}
|
|
||||||
return f_rename(fs_new, path_old, path_new);
|
|
||||||
}
|
|
||||||
|
|
||||||
FRESULT f_touch_helper(const TCHAR *path) {
|
|
||||||
FIL fp;
|
|
||||||
FATFS *fs = lookup_path(&path);
|
|
||||||
if (fs == NULL) {
|
|
||||||
return FR_NO_PATH;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (f_stat(fs, path, NULL) != FR_OK) {
|
|
||||||
f_open(fs, &fp, path, FA_WRITE | FA_CREATE_ALWAYS);
|
|
||||||
f_close(&fp);
|
|
||||||
}
|
|
||||||
|
|
||||||
return FR_OK;
|
|
||||||
}
|
|
||||||
// When a sector boundary is encountered while writing a file and there are
|
|
||||||
// more than 512 bytes left to write FatFs will detect that it can bypass
|
|
||||||
// its internal write buffer and pass the data buffer passed to it directly
|
|
||||||
// to the disk write function. However, the disk write function needs the
|
|
||||||
// buffer to be aligned to a 4-byte boundary. FatFs doesn't know this and
|
|
||||||
// will pass an unaligned buffer if we don't fix the issue. To fix this problem
|
|
||||||
// we use a temporary buffer to fix the alignment and to speed everything up.
|
|
||||||
|
|
||||||
// We use this temporary buffer for both reads and writes. The buffer allows us
|
|
||||||
// to do multi-block reads and writes which significantly speed things up.
|
|
||||||
|
|
||||||
static uint32_t file_buffer_offset = 0;
|
|
||||||
static uint8_t *file_buffer_pointer = 0;
|
|
||||||
static uint32_t file_buffer_size = 0;
|
|
||||||
static uint32_t file_buffer_index = 0;
|
|
||||||
|
|
||||||
void file_buffer_init0() {
|
|
||||||
file_buffer_offset = 0;
|
|
||||||
file_buffer_pointer = 0;
|
|
||||||
file_buffer_size = 0;
|
|
||||||
file_buffer_index = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
OMV_ATTR_ALWAYS_INLINE static void file_fill(FIL *fp) {
|
|
||||||
if (file_buffer_index == file_buffer_size) {
|
|
||||||
file_buffer_pointer -= file_buffer_offset;
|
|
||||||
file_buffer_size += file_buffer_offset;
|
|
||||||
file_buffer_offset = 0;
|
|
||||||
file_buffer_index = 0;
|
|
||||||
uint32_t file_remaining = f_size(fp) - f_tell(fp);
|
|
||||||
uint32_t can_do = FF_MIN(file_buffer_size, file_remaining);
|
|
||||||
UINT bytes;
|
|
||||||
FRESULT res = f_read(fp, file_buffer_pointer, can_do, &bytes);
|
|
||||||
if (res != FR_OK) {
|
|
||||||
ff_fail(fp, res);
|
|
||||||
}
|
|
||||||
if (bytes != can_do) {
|
|
||||||
ff_read_fail(fp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
OMV_ATTR_ALWAYS_INLINE static void file_flush(FIL *fp) {
|
|
||||||
if (file_buffer_index == file_buffer_size) {
|
|
||||||
UINT bytes;
|
|
||||||
FRESULT res = f_write(fp, file_buffer_pointer, file_buffer_index, &bytes);
|
|
||||||
if (res != FR_OK) {
|
|
||||||
ff_fail(fp, res);
|
|
||||||
}
|
|
||||||
if (bytes != file_buffer_index) {
|
|
||||||
ff_write_fail(fp);
|
|
||||||
}
|
|
||||||
file_buffer_pointer -= file_buffer_offset;
|
|
||||||
file_buffer_size += file_buffer_offset;
|
|
||||||
file_buffer_offset = 0;
|
|
||||||
file_buffer_index = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t file_tell_w_buf(FIL *fp) {
|
|
||||||
if (fp->flag & FA_READ) {
|
|
||||||
return f_tell(fp) - file_buffer_size + file_buffer_index;
|
|
||||||
} else {
|
|
||||||
return f_tell(fp) + file_buffer_index;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t file_size_w_buf(FIL *fp) {
|
|
||||||
if (fp->flag & FA_READ) {
|
|
||||||
return f_size(fp);
|
|
||||||
} else {
|
|
||||||
return f_size(fp) + file_buffer_index;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void file_buffer_on(FIL *fp) {
|
|
||||||
file_buffer_offset = f_tell(fp) % 4;
|
|
||||||
file_buffer_pointer = fb_alloc_all(&file_buffer_size, FB_ALLOC_PREFER_SIZE) + file_buffer_offset;
|
|
||||||
if (!file_buffer_size) {
|
|
||||||
mp_raise_msg(&mp_type_MemoryError, MP_ERROR_TEXT("No memory!"));
|
|
||||||
}
|
|
||||||
file_buffer_size -= file_buffer_offset;
|
|
||||||
file_buffer_index = 0;
|
|
||||||
if (fp->flag & FA_READ) {
|
|
||||||
uint32_t file_remaining = f_size(fp) - f_tell(fp);
|
|
||||||
uint32_t can_do = FF_MIN(file_buffer_size, file_remaining);
|
|
||||||
UINT bytes;
|
|
||||||
FRESULT res = f_read(fp, file_buffer_pointer, can_do, &bytes);
|
|
||||||
if (res != FR_OK) {
|
|
||||||
ff_fail(fp, res);
|
|
||||||
}
|
|
||||||
if (bytes != can_do) {
|
|
||||||
ff_read_fail(fp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void file_buffer_off(FIL *fp) {
|
|
||||||
if ((fp->flag & FA_WRITE) && file_buffer_index) {
|
|
||||||
UINT bytes;
|
|
||||||
FRESULT res = f_write(fp, file_buffer_pointer, file_buffer_index, &bytes);
|
|
||||||
if (res != FR_OK) {
|
|
||||||
ff_fail(fp, res);
|
|
||||||
}
|
|
||||||
if (bytes != file_buffer_index) {
|
|
||||||
ff_write_fail(fp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
file_buffer_pointer = 0;
|
|
||||||
fb_free();
|
|
||||||
}
|
|
||||||
|
|
||||||
void read_byte(FIL *fp, uint8_t *value) {
|
|
||||||
if (file_buffer_pointer) {
|
|
||||||
// We get a massive speed boost by buffering up as much data as possible
|
|
||||||
// via massive reads. So much so that the time wasted by
|
|
||||||
// all these operations does not cost us.
|
|
||||||
for (size_t i = 0; i < sizeof(*value); i++) {
|
|
||||||
file_fill(fp);
|
|
||||||
((uint8_t *) value)[i] = file_buffer_pointer[file_buffer_index++];
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
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) {
|
|
||||||
if (file_buffer_pointer) {
|
|
||||||
// We get a massive speed boost by buffering up as much data as possible
|
|
||||||
// via massive reads. So much so that the time wasted by
|
|
||||||
// all these operations does not cost us.
|
|
||||||
for (size_t i = 0; i < sizeof(*value); i++) {
|
|
||||||
file_fill(fp);
|
|
||||||
((uint8_t *) value)[i] = file_buffer_pointer[file_buffer_index++];
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
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) {
|
|
||||||
if (file_buffer_pointer) {
|
|
||||||
// We get a massive speed boost by buffering up as much data as possible
|
|
||||||
// via massive reads. So much so that the time wasted by
|
|
||||||
// all these operations does not cost us.
|
|
||||||
for (size_t i = 0; i < sizeof(*value); i++) {
|
|
||||||
file_fill(fp);
|
|
||||||
((uint8_t *) value)[i] = file_buffer_pointer[file_buffer_index++];
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
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) {
|
|
||||||
if (file_buffer_pointer) {
|
|
||||||
// We get a massive speed boost by buffering up as much data as possible
|
|
||||||
// via massive reads. So much so that the time wasted by
|
|
||||||
// all these operations does not cost us.
|
|
||||||
while (size) {
|
|
||||||
file_fill(fp);
|
|
||||||
uint32_t file_buffer_space_left = file_buffer_size - file_buffer_index;
|
|
||||||
uint32_t can_do = FF_MIN(size, file_buffer_space_left);
|
|
||||||
memcpy(data, file_buffer_pointer + file_buffer_index, can_do);
|
|
||||||
file_buffer_index += can_do;
|
|
||||||
data += can_do;
|
|
||||||
size -= can_do;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
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) {
|
|
||||||
if (file_buffer_pointer) {
|
|
||||||
// We get a massive speed boost by buffering up as much data as possible
|
|
||||||
// before a write to the SD card. So much so that the time wasted by
|
|
||||||
// all these operations does not cost us.
|
|
||||||
for (size_t i = 0; i < sizeof(value); i++) {
|
|
||||||
file_buffer_pointer[file_buffer_index++] = ((uint8_t *) &value)[i];
|
|
||||||
file_flush(fp);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
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) {
|
|
||||||
if (file_buffer_pointer) {
|
|
||||||
// We get a massive speed boost by buffering up as much data as possible
|
|
||||||
// before a write to the SD card. So much so that the time wasted by
|
|
||||||
// all these operations does not cost us.
|
|
||||||
for (size_t i = 0; i < sizeof(value); i++) {
|
|
||||||
file_buffer_pointer[file_buffer_index++] = ((uint8_t *) &value)[i];
|
|
||||||
file_flush(fp);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
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) {
|
|
||||||
if (file_buffer_pointer) {
|
|
||||||
// We get a massive speed boost by buffering up as much data as possible
|
|
||||||
// before a write to the SD card. So much so that the time wasted by
|
|
||||||
// all these operations does not cost us.
|
|
||||||
for (size_t i = 0; i < sizeof(value); i++) {
|
|
||||||
file_buffer_pointer[file_buffer_index++] = ((uint8_t *) &value)[i];
|
|
||||||
file_flush(fp);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
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) {
|
|
||||||
if (file_buffer_pointer) {
|
|
||||||
// We get a massive speed boost by buffering up as much data as possible
|
|
||||||
// before a write to the SD card. So much so that the time wasted by
|
|
||||||
// all these operations does not cost us.
|
|
||||||
while (size) {
|
|
||||||
uint32_t file_buffer_space_left = file_buffer_size - file_buffer_index;
|
|
||||||
uint32_t can_do = FF_MIN(size, file_buffer_space_left);
|
|
||||||
memcpy(file_buffer_pointer + file_buffer_index, data, can_do);
|
|
||||||
file_buffer_index += can_do;
|
|
||||||
data += can_do;
|
|
||||||
size -= can_do;
|
|
||||||
file_flush(fp);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif //IMLIB_ENABLE_IMAGE_FILE_IO
|
|
||||||
@ -1,57 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of the OpenMV project.
|
|
||||||
* Copyright (c) 2013-2016 Kwabena W. Agyeman <kwagyeman@openmv.io>
|
|
||||||
* This work is licensed under the MIT license, see the file LICENSE for details.
|
|
||||||
*
|
|
||||||
* File System Helper Functions
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
#ifndef __FF_WRAPPER_H__
|
|
||||||
#define __FF_WRAPPER_H__
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <ff.h>
|
|
||||||
extern const char *ffs_strerror(FRESULT res);
|
|
||||||
|
|
||||||
//OOFATFS wrappers
|
|
||||||
FRESULT f_open_helper(FIL *fp, const TCHAR *path, BYTE mode);
|
|
||||||
FRESULT f_opendir_helper(FF_DIR *dp, const TCHAR *path);
|
|
||||||
FRESULT f_stat_helper(const TCHAR *path, FILINFO *fno);
|
|
||||||
FRESULT f_mkdir_helper(const TCHAR *path);
|
|
||||||
FRESULT f_unlink_helper(const TCHAR *path);
|
|
||||||
FRESULT f_rename_helper(const TCHAR *path_old, const TCHAR *path_new);
|
|
||||||
FRESULT f_touch_helper(const TCHAR *path);
|
|
||||||
|
|
||||||
void ff_unsupported_format(FIL *fp);
|
|
||||||
void ff_file_corrupted(FIL *fp);
|
|
||||||
void ff_not_equal(FIL *fp);
|
|
||||||
void ff_no_intersection(FIL *fp);
|
|
||||||
void file_read_open(FIL *fp, const char *path);
|
|
||||||
void file_write_open(FIL *fp, const char *path);
|
|
||||||
void file_read_write_open_existing(FIL *fp, const char *path);
|
|
||||||
void file_read_write_open_always(FIL *fp, const char *path);
|
|
||||||
void file_close(FIL *fp);
|
|
||||||
void file_seek(FIL *fp, UINT offset);
|
|
||||||
void file_truncate(FIL *fp);
|
|
||||||
void file_sync(FIL *fp);
|
|
||||||
|
|
||||||
// File buffer functions.
|
|
||||||
void file_buffer_init0();
|
|
||||||
void file_buffer_on(FIL *fp); // does fb_alloc_all
|
|
||||||
uint32_t file_tell_w_buf(FIL *fp); // valid between on and off
|
|
||||||
uint32_t file_size_w_buf(FIL *fp); // valid between on and off
|
|
||||||
void file_buffer_off(FIL *fp); // does fb_free
|
|
||||||
void read_byte(FIL *fp, uint8_t *value);
|
|
||||||
void read_byte_expect(FIL *fp, uint8_t value);
|
|
||||||
void read_byte_ignore(FIL *fp);
|
|
||||||
void read_word(FIL *fp, uint16_t *value);
|
|
||||||
void read_word_expect(FIL *fp, uint16_t value);
|
|
||||||
void read_word_ignore(FIL *fp);
|
|
||||||
void read_long(FIL *fp, uint32_t *value);
|
|
||||||
void read_long_expect(FIL *fp, uint32_t value);
|
|
||||||
void read_long_ignore(FIL *fp);
|
|
||||||
void read_data(FIL *fp, void *data, UINT size);
|
|
||||||
void write_byte(FIL *fp, uint8_t value);
|
|
||||||
void write_word(FIL *fp, uint16_t value);
|
|
||||||
void write_long(FIL *fp, uint32_t value);
|
|
||||||
void write_data(FIL *fp, const void *data, UINT size);
|
|
||||||
#endif /* __FF_WRAPPER_H__ */
|
|
||||||
416
src/omv/common/file_utils.c
Normal file
416
src/omv/common/file_utils.c
Normal file
@ -0,0 +1,416 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the OpenMV project.
|
||||||
|
* Copyright (c) 2013-2023 Kwabena W. Agyeman <kwagyeman@openmv.io>
|
||||||
|
* This work is licensed under the MIT license, see the file LICENSE for details.
|
||||||
|
*
|
||||||
|
* Filesystem helper functions.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#include "imlib_config.h"
|
||||||
|
#if defined(IMLIB_ENABLE_IMAGE_FILE_IO)
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include "py/runtime.h"
|
||||||
|
#include "extmod/vfs.h"
|
||||||
|
#include "extmod/vfs_fat.h"
|
||||||
|
|
||||||
|
#include "omv_common.h"
|
||||||
|
#include "fb_alloc.h"
|
||||||
|
#include "file_utils.h"
|
||||||
|
#define FF_MIN(x, y) (((x) < (y))?(x):(y))
|
||||||
|
|
||||||
|
NORETURN static void ff_read_fail(FIL *fp) {
|
||||||
|
if (fp) {
|
||||||
|
f_close(fp);
|
||||||
|
}
|
||||||
|
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Failed to read requested bytes!"));
|
||||||
|
}
|
||||||
|
|
||||||
|
NORETURN static void ff_write_fail(FIL *fp) {
|
||||||
|
if (fp) {
|
||||||
|
f_close(fp);
|
||||||
|
}
|
||||||
|
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Failed to write requested bytes!"));
|
||||||
|
}
|
||||||
|
|
||||||
|
NORETURN static void ff_expect_fail(FIL *fp) {
|
||||||
|
if (fp) {
|
||||||
|
f_close(fp);
|
||||||
|
}
|
||||||
|
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Unexpected value read!"));
|
||||||
|
}
|
||||||
|
|
||||||
|
NORETURN void file_raise_format(FIL *fp) {
|
||||||
|
if (fp) {
|
||||||
|
f_close(fp);
|
||||||
|
}
|
||||||
|
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Unsupported format!"));
|
||||||
|
}
|
||||||
|
|
||||||
|
NORETURN void file_raise_corrupted(FIL *fp) {
|
||||||
|
if (fp) {
|
||||||
|
f_close(fp);
|
||||||
|
}
|
||||||
|
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("File corrupted!"));
|
||||||
|
}
|
||||||
|
|
||||||
|
NORETURN void file_raise_error(FIL *fp, FRESULT res) {
|
||||||
|
if (fp) {
|
||||||
|
f_close(fp);
|
||||||
|
}
|
||||||
|
mp_raise_msg(&mp_type_OSError, (mp_rom_error_text_t) ffs_strerror(res));
|
||||||
|
}
|
||||||
|
|
||||||
|
static FATFS *lookup_path(const TCHAR **path) {
|
||||||
|
mp_vfs_mount_t *fs = mp_vfs_lookup_path(*path, path);
|
||||||
|
if (fs == MP_VFS_NONE || fs == MP_VFS_ROOT) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
// here we assume that the mounted device is FATFS
|
||||||
|
return &((fs_user_mount_t *) MP_OBJ_TO_PTR(fs->obj))->fatfs;
|
||||||
|
}
|
||||||
|
|
||||||
|
FRESULT file_ll_open(FIL *fp, const TCHAR *path, BYTE mode) {
|
||||||
|
FATFS *fs = lookup_path(&path);
|
||||||
|
if (fs == NULL) {
|
||||||
|
return FR_NO_PATH;
|
||||||
|
}
|
||||||
|
return f_open(fs, fp, path, mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
FRESULT file_ll_close(FIL *fp) {
|
||||||
|
return f_close(fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
FRESULT file_ll_read(FIL *fp, void *buff, UINT btr, UINT *br) {
|
||||||
|
return f_read(fp, buff, btr, br);
|
||||||
|
}
|
||||||
|
|
||||||
|
FRESULT file_ll_write(FIL *fp, const void *buff, UINT btw, UINT *bw) {
|
||||||
|
return f_write(fp, buff, btw, bw);
|
||||||
|
}
|
||||||
|
|
||||||
|
FRESULT file_ll_opendir(FF_DIR *dp, const TCHAR *path) {
|
||||||
|
FATFS *fs = lookup_path(&path);
|
||||||
|
if (fs == NULL) {
|
||||||
|
return FR_NO_PATH;
|
||||||
|
}
|
||||||
|
return f_opendir(fs, dp, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
FRESULT file_ll_stat(const TCHAR *path, FILINFO *fno) {
|
||||||
|
FATFS *fs = lookup_path(&path);
|
||||||
|
if (fs == NULL) {
|
||||||
|
return FR_NO_PATH;
|
||||||
|
}
|
||||||
|
return f_stat(fs, path, fno);
|
||||||
|
}
|
||||||
|
|
||||||
|
FRESULT file_ll_mkdir(const TCHAR *path) {
|
||||||
|
FATFS *fs = lookup_path(&path);
|
||||||
|
if (fs == NULL) {
|
||||||
|
return FR_NO_PATH;
|
||||||
|
}
|
||||||
|
return f_mkdir(fs, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
FRESULT file_ll_unlink(const TCHAR *path) {
|
||||||
|
FATFS *fs = lookup_path(&path);
|
||||||
|
if (fs == NULL) {
|
||||||
|
return FR_NO_PATH;
|
||||||
|
}
|
||||||
|
return f_unlink(fs, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
FRESULT file_ll_rename(const TCHAR *path_old, const TCHAR *path_new) {
|
||||||
|
FATFS *fs_old = lookup_path(&path_old);
|
||||||
|
if (fs_old == NULL) {
|
||||||
|
return FR_NO_PATH;
|
||||||
|
}
|
||||||
|
FATFS *fs_new = lookup_path(&path_new);
|
||||||
|
if (fs_new == NULL) {
|
||||||
|
return FR_NO_PATH;
|
||||||
|
}
|
||||||
|
if (fs_old != fs_new) {
|
||||||
|
return FR_NO_PATH;
|
||||||
|
}
|
||||||
|
return f_rename(fs_new, path_old, path_new);
|
||||||
|
}
|
||||||
|
|
||||||
|
FRESULT file_ll_touch(const TCHAR *path) {
|
||||||
|
FIL fp;
|
||||||
|
FATFS *fs = lookup_path(&path);
|
||||||
|
if (fs == NULL) {
|
||||||
|
return FR_NO_PATH;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (f_stat(fs, path, NULL) != FR_OK) {
|
||||||
|
f_open(fs, &fp, path, FA_WRITE | FA_CREATE_ALWAYS);
|
||||||
|
f_close(&fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
return FR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// When a sector boundary is encountered while writing a file and there are
|
||||||
|
// more than 512 bytes left to write FatFs will detect that it can bypass
|
||||||
|
// its internal write buffer and pass the data buffer passed to it directly
|
||||||
|
// to the disk write function. However, the disk write function needs the
|
||||||
|
// buffer to be aligned to a 4-byte boundary. FatFs doesn't know this and
|
||||||
|
// will pass an unaligned buffer if we don't fix the issue. To fix this problem
|
||||||
|
// we use a temporary buffer to fix the alignment and to speed everything up.
|
||||||
|
// We use this temporary buffer for both reads and writes. The buffer allows us
|
||||||
|
// to do multi-block reads and writes which significantly speed things up.
|
||||||
|
|
||||||
|
static uint32_t file_buffer_offset = 0;
|
||||||
|
static uint8_t *file_buffer_pointer = 0;
|
||||||
|
static uint32_t file_buffer_size = 0;
|
||||||
|
static uint32_t file_buffer_index = 0;
|
||||||
|
|
||||||
|
void file_buffer_init0() {
|
||||||
|
file_buffer_offset = 0;
|
||||||
|
file_buffer_pointer = 0;
|
||||||
|
file_buffer_size = 0;
|
||||||
|
file_buffer_index = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
OMV_ATTR_ALWAYS_INLINE static void file_fill(FIL *fp) {
|
||||||
|
if (file_buffer_index == file_buffer_size) {
|
||||||
|
file_buffer_pointer -= file_buffer_offset;
|
||||||
|
file_buffer_size += file_buffer_offset;
|
||||||
|
file_buffer_offset = 0;
|
||||||
|
file_buffer_index = 0;
|
||||||
|
uint32_t file_remaining = f_size(fp) - f_tell(fp);
|
||||||
|
uint32_t can_do = FF_MIN(file_buffer_size, file_remaining);
|
||||||
|
UINT bytes;
|
||||||
|
FRESULT res = f_read(fp, file_buffer_pointer, can_do, &bytes);
|
||||||
|
if (res != FR_OK) {
|
||||||
|
file_raise_error(fp, res);
|
||||||
|
}
|
||||||
|
if (bytes != can_do) {
|
||||||
|
ff_read_fail(fp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
OMV_ATTR_ALWAYS_INLINE static void file_flush(FIL *fp) {
|
||||||
|
if (file_buffer_index == file_buffer_size) {
|
||||||
|
UINT bytes;
|
||||||
|
FRESULT res = f_write(fp, file_buffer_pointer, file_buffer_index, &bytes);
|
||||||
|
if (res != FR_OK) {
|
||||||
|
file_raise_error(fp, res);
|
||||||
|
}
|
||||||
|
if (bytes != file_buffer_index) {
|
||||||
|
ff_write_fail(fp);
|
||||||
|
}
|
||||||
|
file_buffer_pointer -= file_buffer_offset;
|
||||||
|
file_buffer_size += file_buffer_offset;
|
||||||
|
file_buffer_offset = 0;
|
||||||
|
file_buffer_index = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void file_buffer_on(FIL *fp) {
|
||||||
|
file_buffer_offset = f_tell(fp) % 4;
|
||||||
|
file_buffer_pointer = fb_alloc_all(&file_buffer_size, FB_ALLOC_PREFER_SIZE) + file_buffer_offset;
|
||||||
|
if (!file_buffer_size) {
|
||||||
|
mp_raise_msg(&mp_type_MemoryError, MP_ERROR_TEXT("No memory!"));
|
||||||
|
}
|
||||||
|
file_buffer_size -= file_buffer_offset;
|
||||||
|
file_buffer_index = 0;
|
||||||
|
if (fp->flag & FA_READ) {
|
||||||
|
uint32_t file_remaining = f_size(fp) - f_tell(fp);
|
||||||
|
uint32_t can_do = FF_MIN(file_buffer_size, file_remaining);
|
||||||
|
UINT bytes;
|
||||||
|
FRESULT res = f_read(fp, file_buffer_pointer, can_do, &bytes);
|
||||||
|
if (res != FR_OK) {
|
||||||
|
file_raise_error(fp, res);
|
||||||
|
}
|
||||||
|
if (bytes != can_do) {
|
||||||
|
ff_read_fail(fp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void file_buffer_off(FIL *fp) {
|
||||||
|
if ((fp->flag & FA_WRITE) && file_buffer_index) {
|
||||||
|
UINT bytes;
|
||||||
|
FRESULT res = f_write(fp, file_buffer_pointer, file_buffer_index, &bytes);
|
||||||
|
if (res != FR_OK) {
|
||||||
|
file_raise_error(fp, res);
|
||||||
|
}
|
||||||
|
if (bytes != file_buffer_index) {
|
||||||
|
ff_write_fail(fp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_buffer_pointer = 0;
|
||||||
|
fb_free();
|
||||||
|
}
|
||||||
|
|
||||||
|
void file_open(FIL *fp, const char *path, bool buffered, uint32_t flags) {
|
||||||
|
FRESULT res = file_ll_open(fp, path, flags);
|
||||||
|
if (res != FR_OK) {
|
||||||
|
file_raise_error(fp, res);
|
||||||
|
}
|
||||||
|
if (buffered) {
|
||||||
|
file_buffer_on(fp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void file_close(FIL *fp) {
|
||||||
|
if (file_buffer_pointer) {
|
||||||
|
file_buffer_off(fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
FRESULT res = f_close(fp);
|
||||||
|
if (res != FR_OK) {
|
||||||
|
file_raise_error(fp, res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void file_seek(FIL *fp, UINT offset) {
|
||||||
|
FRESULT res = f_lseek(fp, offset);
|
||||||
|
if (res != FR_OK) {
|
||||||
|
file_raise_error(fp, res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void file_truncate(FIL *fp) {
|
||||||
|
FRESULT res = f_truncate(fp);
|
||||||
|
if (res != FR_OK) {
|
||||||
|
file_raise_error(fp, res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void file_sync(FIL *fp) {
|
||||||
|
FRESULT res = f_sync(fp);
|
||||||
|
if (res != FR_OK) {
|
||||||
|
file_raise_error(fp, res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t file_tell(FIL *fp) {
|
||||||
|
if (file_buffer_pointer) {
|
||||||
|
if (fp->flag & FA_READ) {
|
||||||
|
return f_tell(fp) - file_buffer_size + file_buffer_index;
|
||||||
|
} else {
|
||||||
|
return f_tell(fp) + file_buffer_index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return f_tell(fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t file_size(FIL *fp) {
|
||||||
|
if (file_buffer_pointer) {
|
||||||
|
if (fp->flag & FA_READ) {
|
||||||
|
return f_size(fp);
|
||||||
|
} else {
|
||||||
|
return f_size(fp) + file_buffer_index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return f_size(fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void file_read(FIL *fp, void *data, size_t size) {
|
||||||
|
if (data == NULL) {
|
||||||
|
uint8_t byte;
|
||||||
|
if (file_buffer_pointer) {
|
||||||
|
for (size_t i = 0; i < size; i++) {
|
||||||
|
file_fill(fp);
|
||||||
|
byte = file_buffer_pointer[file_buffer_index++];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (size_t i = 0; i < size; i++) {
|
||||||
|
UINT bytes;
|
||||||
|
FRESULT res = f_read(fp, &byte, 1, &bytes);
|
||||||
|
if (res != FR_OK) {
|
||||||
|
file_raise_error(fp, res);
|
||||||
|
}
|
||||||
|
if (bytes != 1) {
|
||||||
|
ff_read_fail(fp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file_buffer_pointer) {
|
||||||
|
if (size <= 4) {
|
||||||
|
for (size_t i = 0; i < size; i++) {
|
||||||
|
file_fill(fp);
|
||||||
|
((uint8_t *) data)[i] = file_buffer_pointer[file_buffer_index++];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
while (size) {
|
||||||
|
file_fill(fp);
|
||||||
|
uint32_t file_buffer_space_left = file_buffer_size - file_buffer_index;
|
||||||
|
uint32_t can_do = FF_MIN(size, file_buffer_space_left);
|
||||||
|
memcpy(data, file_buffer_pointer + file_buffer_index, can_do);
|
||||||
|
file_buffer_index += can_do;
|
||||||
|
data += can_do;
|
||||||
|
size -= can_do;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
UINT bytes;
|
||||||
|
FRESULT res = f_read(fp, data, size, &bytes);
|
||||||
|
if (res != FR_OK) {
|
||||||
|
file_raise_error(fp, res);
|
||||||
|
}
|
||||||
|
if (bytes != size) {
|
||||||
|
ff_read_fail(fp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void file_write(FIL *fp, const void *data, size_t size) {
|
||||||
|
if (file_buffer_pointer) {
|
||||||
|
// We get a massive speed boost by buffering up as much data as possible
|
||||||
|
// before a write to the SD card. So much so that the time wasted by
|
||||||
|
// all these operations does not cost us.
|
||||||
|
while (size) {
|
||||||
|
uint32_t file_buffer_space_left = file_buffer_size - file_buffer_index;
|
||||||
|
uint32_t can_do = FF_MIN(size, file_buffer_space_left);
|
||||||
|
memcpy(file_buffer_pointer + file_buffer_index, data, can_do);
|
||||||
|
file_buffer_index += can_do;
|
||||||
|
data += can_do;
|
||||||
|
size -= can_do;
|
||||||
|
file_flush(fp);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
UINT bytes;
|
||||||
|
FRESULT res = f_write(fp, data, size, &bytes);
|
||||||
|
if (res != FR_OK) {
|
||||||
|
file_raise_error(fp, res);
|
||||||
|
}
|
||||||
|
if (bytes != size) {
|
||||||
|
ff_write_fail(fp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void file_write_byte(FIL *fp, uint8_t value) {
|
||||||
|
file_write(fp, &value, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void file_write_short(FIL *fp, uint16_t value) {
|
||||||
|
file_write(fp, &value, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void file_write_long(FIL *fp, uint32_t value) {
|
||||||
|
file_write(fp, &value, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
void file_read_check(FIL *fp, const void *data, size_t size) {
|
||||||
|
uint8_t buf[16];
|
||||||
|
while (size) {
|
||||||
|
size_t len = OMV_MIN(sizeof(buf), size);
|
||||||
|
file_read(fp, buf, len);
|
||||||
|
if (memcmp(data, buf, len)) {
|
||||||
|
ff_expect_fail(fp);
|
||||||
|
}
|
||||||
|
size -= len;
|
||||||
|
data = ((uint8_t *) data) + len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif //IMLIB_ENABLE_IMAGE_FILE_IO
|
||||||
52
src/omv/common/file_utils.h
Normal file
52
src/omv/common/file_utils.h
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the OpenMV project.
|
||||||
|
* Copyright (c) 2013-2023 Kwabena W. Agyeman <kwagyeman@openmv.io>
|
||||||
|
* This work is licensed under the MIT license, see the file LICENSE for details.
|
||||||
|
*
|
||||||
|
* Filesystem helper functions.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#ifndef __FILE_UTILS_H__
|
||||||
|
#define __FILE_UTILS_H__
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <ff.h>
|
||||||
|
extern const char *ffs_strerror(FRESULT res);
|
||||||
|
|
||||||
|
void file_raise_format(FIL *fp);
|
||||||
|
void file_raise_corrupted(FIL *fp);
|
||||||
|
void file_raise_error(FIL *fp, FRESULT res);
|
||||||
|
|
||||||
|
// These low-level functions/wrappers don't use file buffering,
|
||||||
|
// and they don't raise any exceptions, so they're safe to call
|
||||||
|
// from anywhere.
|
||||||
|
FRESULT file_ll_open(FIL *fp, const TCHAR *path, BYTE mode);
|
||||||
|
FRESULT file_ll_close(FIL *fp);
|
||||||
|
FRESULT file_ll_read(FIL *fp, void *buff, UINT btr, UINT *br);
|
||||||
|
FRESULT file_ll_write(FIL *fp, const void *buff, UINT btw, UINT *bw);
|
||||||
|
FRESULT file_ll_opendir(FF_DIR *dp, const TCHAR *path);
|
||||||
|
FRESULT file_ll_stat(const TCHAR *path, FILINFO *fno);
|
||||||
|
FRESULT file_ll_mkdir(const TCHAR *path);
|
||||||
|
FRESULT file_ll_unlink(const TCHAR *path);
|
||||||
|
FRESULT file_ll_rename(const TCHAR *path_old, const TCHAR *path_new);
|
||||||
|
FRESULT file_ll_touch(const TCHAR *path);
|
||||||
|
|
||||||
|
// File buffer functions.
|
||||||
|
void file_buffer_init0();
|
||||||
|
void file_buffer_on(FIL *fp); // Calls fb_alloc_all()
|
||||||
|
void file_buffer_off(FIL *fp); // Calls fb_free()
|
||||||
|
|
||||||
|
void file_open(FIL *fp, const char *path, bool buffered, uint32_t flags);
|
||||||
|
void file_close(FIL *fp);
|
||||||
|
void file_seek(FIL *fp, UINT offset);
|
||||||
|
void file_truncate(FIL *fp);
|
||||||
|
void file_sync(FIL *fp);
|
||||||
|
uint32_t file_tell(FIL *fp);
|
||||||
|
uint32_t file_size(FIL *fp);
|
||||||
|
void file_read(FIL *fp, void *data, size_t size);
|
||||||
|
void file_write(FIL *fp, const void *data, size_t size);
|
||||||
|
void file_write_byte(FIL *fp, uint8_t value);
|
||||||
|
void file_write_short(FIL *fp, uint16_t value);
|
||||||
|
void file_write_long(FIL *fp, uint32_t value);
|
||||||
|
void file_read_check(FIL *fp, const void *data, size_t size);
|
||||||
|
#endif /* __FILE_UTILS_H__ */
|
||||||
@ -12,6 +12,7 @@
|
|||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "ini.h"
|
#include "ini.h"
|
||||||
|
#include "file_utils.h"
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------
|
/*-------------------------------------------------------------------------
|
||||||
_isppace.c - part of ctype.h
|
_isppace.c - part of ctype.h
|
||||||
@ -190,7 +191,7 @@ int ini_fgetc(FIL *fp) {
|
|||||||
char c;
|
char c;
|
||||||
UINT b;
|
UINT b;
|
||||||
|
|
||||||
if (f_read(fp, &c, 1, &b) != FR_OK || b != 1) {
|
if (file_ll_read(fp, &c, 1, &b) != FR_OK || b != 1) {
|
||||||
return (EOF);
|
return (EOF);
|
||||||
}
|
}
|
||||||
return (c);
|
return (c);
|
||||||
|
|||||||
@ -21,7 +21,7 @@ bool ini_is_true(const char *value);
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "ff_wrapper.h"
|
#include "file_utils.h"
|
||||||
|
|
||||||
/* Nonzero if ini_handler callback should accept lineno parameter. */
|
/* Nonzero if ini_handler callback should accept lineno parameter. */
|
||||||
#ifndef INI_HANDLER_LINENO
|
#ifndef INI_HANDLER_LINENO
|
||||||
|
|||||||
@ -24,7 +24,6 @@
|
|||||||
#include "sensor.h"
|
#include "sensor.h"
|
||||||
#endif
|
#endif
|
||||||
#include "framebuffer.h"
|
#include "framebuffer.h"
|
||||||
#include "ff.h"
|
|
||||||
#include "usbdbg.h"
|
#include "usbdbg.h"
|
||||||
#include "omv_boardconfig.h"
|
#include "omv_boardconfig.h"
|
||||||
#include "py_image.h"
|
#include "py_image.h"
|
||||||
|
|||||||
@ -16,157 +16,148 @@
|
|||||||
#include "py/runtime.h"
|
#include "py/runtime.h"
|
||||||
|
|
||||||
#include "xalloc.h"
|
#include "xalloc.h"
|
||||||
#include "ff_wrapper.h"
|
#include "file_utils.h"
|
||||||
|
|
||||||
// This function inits the geometry values of an image (opens file).
|
// This function inits the geometry values of an image (opens file).
|
||||||
bool bmp_read_geometry(FIL *fp, image_t *img, const char *path, bmp_read_settings_t *rs) {
|
bool bmp_read_geometry(FIL *fp, image_t *img, const char *path, bmp_read_settings_t *rs) {
|
||||||
read_byte_expect(fp, 'B');
|
file_read_check(fp, "BM", 2);
|
||||||
read_byte_expect(fp, 'M');
|
|
||||||
|
|
||||||
uint32_t file_size;
|
uint32_t file_size;
|
||||||
read_long(fp, &file_size);
|
file_read(fp, &file_size, 4);
|
||||||
read_word_ignore(fp);
|
file_read(fp, NULL, 4);
|
||||||
read_word_ignore(fp);
|
|
||||||
|
|
||||||
uint32_t header_size;
|
uint32_t header_size;
|
||||||
read_long(fp, &header_size);
|
file_read(fp, &header_size, 4);
|
||||||
if (file_size <= header_size) {
|
if (file_size <= header_size) {
|
||||||
ff_file_corrupted(fp);
|
file_raise_corrupted(fp);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t data_size = file_size - header_size;
|
uint32_t data_size = file_size - header_size;
|
||||||
if (data_size % 4) {
|
if (data_size % 4) {
|
||||||
ff_file_corrupted(fp);
|
file_raise_corrupted(fp);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t header_type;
|
uint32_t header_type;
|
||||||
read_long(fp, &header_type);
|
file_read(fp, &header_type, 4);
|
||||||
if ((header_type != 40) // BITMAPINFOHEADER
|
if ((header_type != 40) // BITMAPINFOHEADER
|
||||||
&& (header_type != 52) // BITMAPV2INFOHEADER
|
&& (header_type != 52) // BITMAPV2INFOHEADER
|
||||||
&& (header_type != 56) // BITMAPV3INFOHEADER
|
&& (header_type != 56) // BITMAPV3INFOHEADER
|
||||||
&& (header_type != 108) // BITMAPV4HEADER
|
&& (header_type != 108) // BITMAPV4HEADER
|
||||||
&& (header_type != 124)) {
|
&& (header_type != 124)) {
|
||||||
ff_unsupported_format(fp); // BITMAPV5HEADER
|
file_raise_format(fp); // BITMAPV5HEADER
|
||||||
}
|
}
|
||||||
read_long(fp, (uint32_t *) &rs->bmp_w);
|
file_read(fp, &rs->bmp_w, 4);
|
||||||
read_long(fp, (uint32_t *) &rs->bmp_h);
|
file_read(fp, &rs->bmp_h, 4);
|
||||||
if ((rs->bmp_w == 0) || (rs->bmp_h == 0)) {
|
if ((rs->bmp_w == 0) || (rs->bmp_h == 0)) {
|
||||||
ff_file_corrupted(fp);
|
file_raise_corrupted(fp);
|
||||||
}
|
}
|
||||||
img->w = abs(rs->bmp_w);
|
img->w = abs(rs->bmp_w);
|
||||||
img->h = abs(rs->bmp_h);
|
img->h = abs(rs->bmp_h);
|
||||||
|
|
||||||
read_word_expect(fp, 1);
|
file_read_check(fp, &(uint32_t) {1}, 2);
|
||||||
read_word(fp, &rs->bmp_bpp);
|
file_read(fp, &rs->bmp_bpp, 2);
|
||||||
if ((rs->bmp_bpp != 8) && (rs->bmp_bpp != 16) && (rs->bmp_bpp != 24)) {
|
if ((rs->bmp_bpp != 8) && (rs->bmp_bpp != 16) && (rs->bmp_bpp != 24)) {
|
||||||
ff_unsupported_format(fp);
|
file_raise_format(fp);
|
||||||
}
|
}
|
||||||
img->pixfmt = (rs->bmp_bpp == 8) ? PIXFORMAT_GRAYSCALE : PIXFORMAT_RGB565;
|
img->pixfmt = (rs->bmp_bpp == 8) ? PIXFORMAT_GRAYSCALE : PIXFORMAT_RGB565;
|
||||||
|
|
||||||
read_long(fp, &rs->bmp_fmt);
|
file_read(fp, &rs->bmp_fmt, 4);
|
||||||
if ((rs->bmp_fmt != 0) && (rs->bmp_fmt != 3)) {
|
if ((rs->bmp_fmt != 0) && (rs->bmp_fmt != 3)) {
|
||||||
ff_unsupported_format(fp);
|
file_raise_format(fp);
|
||||||
}
|
}
|
||||||
|
|
||||||
read_long_expect(fp, data_size);
|
file_read_check(fp, &data_size, 4);
|
||||||
read_long_ignore(fp);
|
file_read(fp, NULL, 16);
|
||||||
read_long_ignore(fp);
|
|
||||||
read_long_ignore(fp);
|
|
||||||
read_long_ignore(fp);
|
|
||||||
|
|
||||||
if (rs->bmp_bpp == 8) {
|
if (rs->bmp_bpp == 8) {
|
||||||
if (rs->bmp_fmt != 0) {
|
if (rs->bmp_fmt != 0) {
|
||||||
ff_unsupported_format(fp);
|
file_raise_format(fp);
|
||||||
}
|
}
|
||||||
if (header_type >= 52) {
|
if (header_type >= 52) {
|
||||||
// Skip past the remaining BITMAPV2INFOHEADER bytes.
|
// Skip past the remaining BITMAPV2INFOHEADER bytes.
|
||||||
for (int i = 0; i < 3; i++) {
|
for (int i = 0; i < 3; i++) {
|
||||||
read_long_ignore(fp);
|
file_read(fp, NULL, 4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (header_type >= 56) {
|
if (header_type >= 56) {
|
||||||
// Skip past the remaining BITMAPV3INFOHEADER bytes.
|
// Skip past the remaining BITMAPV3INFOHEADER bytes.
|
||||||
for (int i = 0; i < 1; i++) {
|
for (int i = 0; i < 1; i++) {
|
||||||
read_long_ignore(fp);
|
file_read(fp, NULL, 4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (header_type >= 108) {
|
if (header_type >= 108) {
|
||||||
// Skip past the remaining BITMAPV4HEADER bytes.
|
// Skip past the remaining BITMAPV4HEADER bytes.
|
||||||
for (int i = 0; i < 13; i++) {
|
for (int i = 0; i < 13; i++) {
|
||||||
read_long_ignore(fp);
|
file_read(fp, NULL, 4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (header_type >= 124) {
|
if (header_type >= 124) {
|
||||||
// Skip past the remaining BITMAPV5HEADER bytes.
|
// Skip past the remaining BITMAPV5HEADER bytes.
|
||||||
for (int i = 0; i < 4; i++) {
|
for (int i = 0; i < 4; i++) {
|
||||||
read_long_ignore(fp);
|
file_read(fp, NULL, 4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 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);
|
file_read_check(fp, &(uint32_t) {((i) << 16) | ((i) << 8) | i}, 4);
|
||||||
}
|
}
|
||||||
} else if (rs->bmp_bpp == 16) {
|
} else if (rs->bmp_bpp == 16) {
|
||||||
if (rs->bmp_fmt != 3) {
|
if (rs->bmp_fmt != 3) {
|
||||||
ff_unsupported_format(fp);
|
file_raise_format(fp);
|
||||||
}
|
}
|
||||||
// Bit Masks (12 bytes)
|
// Bit Masks (12 bytes)
|
||||||
read_long_expect(fp, 0x1F << 11);
|
file_read_check(fp, (uint32_t [3]) {0x1F << 11, 0x3F << 5, 0x1F}, 12);
|
||||||
read_long_expect(fp, 0x3F << 5);
|
|
||||||
read_long_expect(fp, 0x1F);
|
|
||||||
if (header_type >= 56) {
|
if (header_type >= 56) {
|
||||||
// Skip past the remaining BITMAPV3INFOHEADER bytes.
|
// Skip past the remaining BITMAPV3INFOHEADER bytes.
|
||||||
for (int i = 0; i < 1; i++) {
|
for (int i = 0; i < 1; i++) {
|
||||||
read_long_ignore(fp);
|
file_read(fp, NULL, 4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (header_type >= 108) {
|
if (header_type >= 108) {
|
||||||
// Skip past the remaining BITMAPV4HEADER bytes.
|
// Skip past the remaining BITMAPV4HEADER bytes.
|
||||||
for (int i = 0; i < 13; i++) {
|
for (int i = 0; i < 13; i++) {
|
||||||
read_long_ignore(fp);
|
file_read(fp, NULL, 4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (header_type >= 124) {
|
if (header_type >= 124) {
|
||||||
// Skip past the remaining BITMAPV5HEADER bytes.
|
// Skip past the remaining BITMAPV5HEADER bytes.
|
||||||
for (int i = 0; i < 4; i++) {
|
for (int i = 0; i < 4; i++) {
|
||||||
read_long_ignore(fp);
|
file_read(fp, NULL, 4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (rs->bmp_bpp == 24) {
|
} else if (rs->bmp_bpp == 24) {
|
||||||
if (rs->bmp_fmt == 3) {
|
if (rs->bmp_fmt == 3) {
|
||||||
// Bit Masks (12 bytes)
|
// Bit Masks (12 bytes)
|
||||||
read_long_expect(fp, 0xFF << 16);
|
file_read_check(fp, (uint32_t [3]) {0xFF << 16, 0xFF << 8, 0xFF}, 12);
|
||||||
read_long_expect(fp, 0xFF << 8);
|
|
||||||
read_long_expect(fp, 0xFF);
|
|
||||||
} else if (header_type >= 52) {
|
} else if (header_type >= 52) {
|
||||||
// Skip past the remaining BITMAPV2INFOHEADER bytes.
|
// Skip past the remaining BITMAPV2INFOHEADER bytes.
|
||||||
for (int i = 0; i < 3; i++) {
|
for (int i = 0; i < 3; i++) {
|
||||||
read_long_ignore(fp);
|
file_read(fp, NULL, 4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (header_type >= 56) {
|
if (header_type >= 56) {
|
||||||
// Skip past the remaining BITMAPV3INFOHEADER bytes.
|
// Skip past the remaining BITMAPV3INFOHEADER bytes.
|
||||||
for (int i = 0; i < 1; i++) {
|
for (int i = 0; i < 1; i++) {
|
||||||
read_long_ignore(fp);
|
file_read(fp, NULL, 4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (header_type >= 108) {
|
if (header_type >= 108) {
|
||||||
// Skip past the remaining BITMAPV4HEADER bytes.
|
// Skip past the remaining BITMAPV4HEADER bytes.
|
||||||
for (int i = 0; i < 13; i++) {
|
for (int i = 0; i < 13; i++) {
|
||||||
read_long_ignore(fp);
|
file_read(fp, NULL, 4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (header_type >= 124) {
|
if (header_type >= 124) {
|
||||||
// Skip past the remaining BITMAPV5HEADER bytes.
|
// Skip past the remaining BITMAPV5HEADER bytes.
|
||||||
for (int i = 0; i < 4; i++) {
|
for (int i = 0; i < 4; i++) {
|
||||||
read_long_ignore(fp);
|
file_read(fp, NULL, 4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rs->bmp_row_bytes = (((img->w * rs->bmp_bpp) + 31) / 32) * 4;
|
rs->bmp_row_bytes = (((img->w * rs->bmp_bpp) + 31) / 32) * 4;
|
||||||
if (data_size != (rs->bmp_row_bytes * img->h)) {
|
if (data_size != (rs->bmp_row_bytes * img->h)) {
|
||||||
ff_file_corrupted(fp);
|
file_raise_corrupted(fp);
|
||||||
}
|
}
|
||||||
return (rs->bmp_h >= 0);
|
return (rs->bmp_h >= 0);
|
||||||
}
|
}
|
||||||
@ -175,12 +166,12 @@ bool bmp_read_geometry(FIL *fp, image_t *img, const char *path, bmp_read_setting
|
|||||||
void bmp_read_pixels(FIL *fp, image_t *img, int n_lines, bmp_read_settings_t *rs) {
|
void bmp_read_pixels(FIL *fp, image_t *img, int n_lines, bmp_read_settings_t *rs) {
|
||||||
if (rs->bmp_bpp == 8) {
|
if (rs->bmp_bpp == 8) {
|
||||||
if ((rs->bmp_h < 0) && (rs->bmp_w >= 0) && (img->w == rs->bmp_row_bytes)) {
|
if ((rs->bmp_h < 0) && (rs->bmp_w >= 0) && (img->w == rs->bmp_row_bytes)) {
|
||||||
read_data(fp, img->pixels, n_lines * img->w);
|
file_read(fp, img->pixels, n_lines * img->w);
|
||||||
} else {
|
} else {
|
||||||
for (int i = 0; i < n_lines; i++) {
|
for (int i = 0; i < n_lines; i++) {
|
||||||
for (int j = 0; j < rs->bmp_row_bytes; j++) {
|
for (int j = 0; j < rs->bmp_row_bytes; j++) {
|
||||||
uint8_t pixel;
|
uint8_t pixel;
|
||||||
read_byte(fp, &pixel);
|
file_read(fp, &pixel, 1);
|
||||||
if (j < img->w) {
|
if (j < img->w) {
|
||||||
if (rs->bmp_h < 0) {
|
if (rs->bmp_h < 0) {
|
||||||
// vertical flip (BMP file perspective)
|
// vertical flip (BMP file perspective)
|
||||||
@ -205,7 +196,7 @@ void bmp_read_pixels(FIL *fp, image_t *img, int n_lines, bmp_read_settings_t *rs
|
|||||||
for (int i = 0; i < n_lines; i++) {
|
for (int i = 0; i < n_lines; i++) {
|
||||||
for (int j = 0, jj = rs->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);
|
file_read(fp, &pixel, 2);
|
||||||
if (j < img->w) {
|
if (j < img->w) {
|
||||||
if (rs->bmp_h < 0) {
|
if (rs->bmp_h < 0) {
|
||||||
// vertical flip (BMP file perspective)
|
// vertical flip (BMP file perspective)
|
||||||
@ -229,9 +220,9 @@ void bmp_read_pixels(FIL *fp, image_t *img, int n_lines, bmp_read_settings_t *rs
|
|||||||
for (int i = 0; i < n_lines; i++) {
|
for (int i = 0; i < n_lines; i++) {
|
||||||
for (int j = 0, jj = rs->bmp_row_bytes / 3; j < jj; j++) {
|
for (int j = 0, jj = rs->bmp_row_bytes / 3; j < jj; j++) {
|
||||||
uint8_t b, g, r;
|
uint8_t b, g, r;
|
||||||
read_byte(fp, &b);
|
file_read(fp, &b, 1);
|
||||||
read_byte(fp, &g);
|
file_read(fp, &g, 1);
|
||||||
read_byte(fp, &r);
|
file_read(fp, &r, 1);
|
||||||
uint16_t pixel = COLOR_R8_G8_B8_TO_RGB565(r, g, b);
|
uint16_t pixel = COLOR_R8_G8_B8_TO_RGB565(r, g, b);
|
||||||
if (j < img->w) {
|
if (j < img->w) {
|
||||||
if (rs->bmp_h < 0) {
|
if (rs->bmp_h < 0) {
|
||||||
@ -252,7 +243,7 @@ void bmp_read_pixels(FIL *fp, image_t *img, int n_lines, bmp_read_settings_t *rs
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (int j = 0, jj = rs->bmp_row_bytes % 3; j < jj; j++) {
|
for (int j = 0, jj = rs->bmp_row_bytes % 3; j < jj; j++) {
|
||||||
read_byte_ignore(fp);
|
file_read(fp, NULL, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -261,17 +252,33 @@ void bmp_read_pixels(FIL *fp, image_t *img, int n_lines, bmp_read_settings_t *rs
|
|||||||
void bmp_read(image_t *img, const char *path) {
|
void bmp_read(image_t *img, const char *path) {
|
||||||
FIL fp;
|
FIL fp;
|
||||||
bmp_read_settings_t rs;
|
bmp_read_settings_t rs;
|
||||||
file_read_open(&fp, path);
|
file_open(&fp, path, true, FA_READ | FA_OPEN_EXISTING);
|
||||||
file_buffer_on(&fp);
|
|
||||||
bmp_read_geometry(&fp, img, path, &rs);
|
bmp_read_geometry(&fp, img, path, &rs);
|
||||||
if (!img->pixels) {
|
if (!img->pixels) {
|
||||||
img->pixels = xalloc(img->w * img->h * img->bpp);
|
img->pixels = xalloc(img->w * img->h * img->bpp);
|
||||||
}
|
}
|
||||||
bmp_read_pixels(&fp, img, img->h, &rs);
|
bmp_read_pixels(&fp, img, img->h, &rs);
|
||||||
file_buffer_off(&fp);
|
|
||||||
file_close(&fp);
|
file_close(&fp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void bmp_write_header(FIL *fp, uint32_t header_size, uint32_t data_size,
|
||||||
|
uint32_t bpp, uint32_t ncomp, rectangle_t *r) {
|
||||||
|
// File Header (14 bytes)
|
||||||
|
file_write(fp, "BM", 2);
|
||||||
|
file_write_long(fp, 14 + 40 + header_size + data_size);
|
||||||
|
file_write_long(fp, 0);
|
||||||
|
file_write_long(fp, 14 + 40 + header_size);
|
||||||
|
// Info Header (40 bytes)
|
||||||
|
file_write_long(fp, 40);
|
||||||
|
file_write_long(fp, r->w);
|
||||||
|
file_write_long(fp, -r->h); // store the image flipped (correctly)
|
||||||
|
file_write_short(fp, 1);
|
||||||
|
file_write_short(fp, bpp);
|
||||||
|
file_write_long(fp, ncomp);
|
||||||
|
file_write_long(fp, data_size);
|
||||||
|
file_write(fp, (uint8_t [16]) {0}, 16);
|
||||||
|
}
|
||||||
|
|
||||||
void bmp_write_subimg(image_t *img, const char *path, rectangle_t *r) {
|
void 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)) {
|
||||||
@ -279,44 +286,25 @@ void bmp_write_subimg(image_t *img, const char *path, rectangle_t *r) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
FIL fp;
|
FIL fp;
|
||||||
file_write_open(&fp, path);
|
file_open(&fp, path, true, FA_WRITE | FA_CREATE_ALWAYS);
|
||||||
file_buffer_on(&fp);
|
|
||||||
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)
|
// Write BMP file header
|
||||||
write_byte(&fp, 'B');
|
bmp_write_header(&fp, 1024, data_size, 8, 0, &rect);
|
||||||
write_byte(&fp, 'M');
|
// Write color Table (1024 bytes)
|
||||||
write_long(&fp, 14 + 40 + 1024 + data_size);
|
|
||||||
write_word(&fp, 0);
|
|
||||||
write_word(&fp, 0);
|
|
||||||
write_long(&fp, 14 + 40 + 1024);
|
|
||||||
// Info Header (40 bytes)
|
|
||||||
write_long(&fp, 40);
|
|
||||||
write_long(&fp, rect.w);
|
|
||||||
write_long(&fp, -rect.h); // store the image flipped (correctly)
|
|
||||||
write_word(&fp, 1);
|
|
||||||
write_word(&fp, 8);
|
|
||||||
write_long(&fp, 0);
|
|
||||||
write_long(&fp, data_size);
|
|
||||||
write_long(&fp, 0);
|
|
||||||
write_long(&fp, 0);
|
|
||||||
write_long(&fp, 0);
|
|
||||||
write_long(&fp, 0);
|
|
||||||
// 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);
|
file_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!
|
file_write(&fp, img->pixels + (rect.y * img->w), rect.w * rect.h);
|
||||||
img->pixels + (rect.y * img->w),
|
|
||||||
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);
|
file_write(&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);
|
file_write_byte(&fp, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -324,40 +312,21 @@ void bmp_write_subimg(image_t *img, const char *path, rectangle_t *r) {
|
|||||||
const int row_bytes = (((rect.w * 16) + 31) / 32) * 4;
|
const int row_bytes = (((rect.w * 16) + 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(uint16_t)) - rect.w;
|
const int waste = (row_bytes / sizeof(uint16_t)) - rect.w;
|
||||||
// File Header (14 bytes)
|
// Write BMP file header
|
||||||
write_byte(&fp, 'B');
|
bmp_write_header(&fp, 12, data_size, 16, 3, &rect);
|
||||||
write_byte(&fp, 'M');
|
// Write Bit Masks (12 bytes)
|
||||||
write_long(&fp, 14 + 40 + 12 + data_size);
|
file_write_long(&fp, 0x1F << 11);
|
||||||
write_word(&fp, 0);
|
file_write_long(&fp, 0x3F << 5);
|
||||||
write_word(&fp, 0);
|
file_write_long(&fp, 0x1F);
|
||||||
write_long(&fp, 14 + 40 + 12);
|
|
||||||
// Info Header (40 bytes)
|
|
||||||
write_long(&fp, 40);
|
|
||||||
write_long(&fp, rect.w);
|
|
||||||
write_long(&fp, -rect.h); // store the image flipped (correctly)
|
|
||||||
write_word(&fp, 1);
|
|
||||||
write_word(&fp, 16);
|
|
||||||
write_long(&fp, 3);
|
|
||||||
write_long(&fp, data_size);
|
|
||||||
write_long(&fp, 0);
|
|
||||||
write_long(&fp, 0);
|
|
||||||
write_long(&fp, 0);
|
|
||||||
write_long(&fp, 0);
|
|
||||||
// Bit Masks (12 bytes)
|
|
||||||
write_long(&fp, 0x1F << 11);
|
|
||||||
write_long(&fp, 0x3F << 5);
|
|
||||||
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_GET_RGB565_PIXEL(img, (rect.x + j), (rect.y + i)));
|
file_write_short(&fp, 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);
|
file_write_short(&fp, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
file_buffer_off(&fp);
|
|
||||||
|
|
||||||
file_close(&fp);
|
file_close(&fp);
|
||||||
}
|
}
|
||||||
#endif //IMLIB_ENABLE_IMAGE_FILE_IO
|
#endif //IMLIB_ENABLE_IMAGE_FILE_IO
|
||||||
|
|||||||
@ -10,7 +10,7 @@
|
|||||||
#include "py/obj.h"
|
#include "py/obj.h"
|
||||||
#include <arm_math.h>
|
#include <arm_math.h>
|
||||||
#include "fb_alloc.h"
|
#include "fb_alloc.h"
|
||||||
#include "ff_wrapper.h"
|
#include "file_utils.h"
|
||||||
#include "omv_common.h"
|
#include "omv_common.h"
|
||||||
#include "fft.h"
|
#include "fft.h"
|
||||||
// http://processors.wiki.ti.com/index.php/Efficient_FFT_Computation_of_Real_Input
|
// http://processors.wiki.ti.com/index.php/Efficient_FFT_Computation_of_Real_Input
|
||||||
|
|||||||
@ -12,35 +12,34 @@
|
|||||||
#if defined(IMLIB_ENABLE_IMAGE_FILE_IO)
|
#if defined(IMLIB_ENABLE_IMAGE_FILE_IO)
|
||||||
|
|
||||||
#include "fb_alloc.h"
|
#include "fb_alloc.h"
|
||||||
#include "ff_wrapper.h"
|
#include "file_utils.h"
|
||||||
#define BLOCK_SIZE (126) // (2^7) - 2 // (DO NOT CHANGE!)
|
#define BLOCK_SIZE (126) // (2^7) - 2 // (DO NOT CHANGE!)
|
||||||
|
|
||||||
void gif_open(FIL *fp, int width, int height, bool color, bool loop) {
|
void gif_open(FIL *fp, int width, int height, bool color, bool loop) {
|
||||||
file_buffer_on(fp);
|
file_buffer_on(fp);
|
||||||
|
|
||||||
write_data(fp, "GIF89a", 6);
|
file_write(fp, "GIF89a", 6);
|
||||||
write_word(fp, width);
|
file_write(fp, (uint16_t []) {width, height}, 4);
|
||||||
write_word(fp, height);
|
file_write(fp, (uint8_t []) {0xF6, 0x00, 0x00}, 3);
|
||||||
write_data(fp, (uint8_t []) {0xF6, 0x00, 0x00}, 3);
|
|
||||||
|
|
||||||
if (color) {
|
if (color) {
|
||||||
for (int i = 0; i < 128; i++) {
|
for (int i = 0; i < 128; i++) {
|
||||||
int red = ((((i & 0x60) >> 5) * 255) + 1.5) / 3;
|
int red = ((((i & 0x60) >> 5) * 255) + 1.5) / 3;
|
||||||
int green = ((((i & 0x1C) >> 2) * 255) + 3.5) / 7;
|
int green = ((((i & 0x1C) >> 2) * 255) + 3.5) / 7;
|
||||||
int blue = (((i & 0x3) * 255) + 1.5) / 3;
|
int blue = (((i & 0x3) * 255) + 1.5) / 3;
|
||||||
write_data(fp, (uint8_t []) {red, green, blue}, 3);
|
file_write(fp, (uint8_t []) {red, green, blue}, 3);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (int i = 0; i < 128; i++) {
|
for (int i = 0; i < 128; i++) {
|
||||||
int gray = ((i * 255) + 63.5) / 127;
|
int gray = ((i * 255) + 63.5) / 127;
|
||||||
write_data(fp, (uint8_t []) {gray, gray, gray}, 3);
|
file_write(fp, (uint8_t []) {gray, gray, gray}, 3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (loop) {
|
if (loop) {
|
||||||
write_data(fp, (uint8_t []) {'!', 0xFF, 0x0B}, 3);
|
file_write(fp, (uint8_t []) {'!', 0xFF, 0x0B}, 3);
|
||||||
write_data(fp, "NETSCAPE2.0", 11);
|
file_write(fp, "NETSCAPE2.0", 11);
|
||||||
write_data(fp, (uint8_t []) {0x03, 0x01, 0x00, 0x00, 0x00}, 5);
|
file_write(fp, (uint8_t []) {0x03, 0x01, 0x00, 0x00, 0x00}, 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
file_buffer_off(fp);
|
file_buffer_off(fp);
|
||||||
@ -50,16 +49,15 @@ void gif_add_frame(FIL *fp, image_t *img, uint16_t delay) {
|
|||||||
file_buffer_on(fp);
|
file_buffer_on(fp);
|
||||||
|
|
||||||
if (delay) {
|
if (delay) {
|
||||||
write_data(fp, (uint8_t []) {'!', 0xF9, 0x04, 0x04}, 4);
|
file_write(fp, (uint8_t []) {'!', 0xF9, 0x04, 0x04}, 4);
|
||||||
write_word(fp, delay);
|
file_write_short(fp, delay);
|
||||||
write_word(fp, 0); // end
|
file_write_short(fp, 0); // end
|
||||||
}
|
}
|
||||||
|
|
||||||
write_byte(fp, 0x2C);
|
file_write_byte(fp, 0x2C);
|
||||||
write_long(fp, 0);
|
file_write_long(fp, 0);
|
||||||
write_word(fp, img->w);
|
file_write(fp, (uint16_t []) {img->w, img->h}, 4);
|
||||||
write_word(fp, img->h);
|
file_write(fp, (uint8_t []) {0x00, 0x07}, 2); // 7-bits
|
||||||
write_data(fp, (uint8_t []) {0x00, 0x07}, 2); // 7-bits
|
|
||||||
|
|
||||||
int bytes = img->h * img->w;
|
int bytes = img->h * img->w;
|
||||||
int blocks = (bytes + BLOCK_SIZE - 1) / BLOCK_SIZE;
|
int blocks = (bytes + BLOCK_SIZE - 1) / BLOCK_SIZE;
|
||||||
@ -67,30 +65,30 @@ void gif_add_frame(FIL *fp, image_t *img, uint16_t delay) {
|
|||||||
if (IM_IS_GS(img)) {
|
if (IM_IS_GS(img)) {
|
||||||
for (int y = 0; y < blocks; y++) {
|
for (int y = 0; y < blocks; y++) {
|
||||||
int block_size = IM_MIN(BLOCK_SIZE, bytes - (y * BLOCK_SIZE));
|
int block_size = IM_MIN(BLOCK_SIZE, bytes - (y * BLOCK_SIZE));
|
||||||
write_byte(fp, 1 + block_size);
|
file_write_byte(fp, 1 + block_size);
|
||||||
write_byte(fp, 0x80); // clear code
|
file_write_byte(fp, 0x80); // clear code
|
||||||
for (int x = 0; x < block_size; x++) {
|
for (int x = 0; x < block_size; x++) {
|
||||||
write_byte(fp, img->pixels[(y * BLOCK_SIZE) + x] >> 1);
|
file_write_byte(fp, img->pixels[(y * BLOCK_SIZE) + x] >> 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (IM_IS_RGB565(img)) {
|
} else if (IM_IS_RGB565(img)) {
|
||||||
for (int y = 0; y < blocks; y++) {
|
for (int y = 0; y < blocks; y++) {
|
||||||
int block_size = IM_MIN(BLOCK_SIZE, bytes - (y * BLOCK_SIZE));
|
int block_size = IM_MIN(BLOCK_SIZE, bytes - (y * BLOCK_SIZE));
|
||||||
write_byte(fp, 1 + block_size);
|
file_write_byte(fp, 1 + block_size);
|
||||||
write_byte(fp, 0x80); // clear code
|
file_write_byte(fp, 0x80); // clear code
|
||||||
for (int x = 0; x < block_size; x++) {
|
for (int x = 0; x < block_size; x++) {
|
||||||
int pixel = ((uint16_t *) img->pixels)[(y * BLOCK_SIZE) + x];
|
uint16_t pixel = ((uint16_t *) img->pixels)[(y * BLOCK_SIZE) + x];
|
||||||
int red = COLOR_RGB565_TO_R5(pixel) >> 3;
|
uint16_t r = COLOR_RGB565_TO_R5(pixel) >> 3;
|
||||||
int green = COLOR_RGB565_TO_G6(pixel) >> 3;
|
uint16_t g = COLOR_RGB565_TO_G6(pixel) >> 3;
|
||||||
int blue = COLOR_RGB565_TO_B5(pixel) >> 3;
|
uint16_t b = COLOR_RGB565_TO_B5(pixel) >> 3;
|
||||||
write_byte(fp, (red << 5) | (green << 2) | blue);
|
file_write_byte(fp, (r << 5) | (g << 2) | b);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (img->is_bayer || img->is_yuv) {
|
} else if (img->is_bayer || img->is_yuv) {
|
||||||
for (int y = 0; y < blocks; y++) {
|
for (int y = 0; y < blocks; y++) {
|
||||||
int block_size = IM_MIN(BLOCK_SIZE, bytes - (y * BLOCK_SIZE));
|
int block_size = IM_MIN(BLOCK_SIZE, bytes - (y * BLOCK_SIZE));
|
||||||
write_byte(fp, 1 + block_size);
|
file_write_byte(fp, 1 + block_size);
|
||||||
write_byte(fp, 0x80); // clear code
|
file_write_byte(fp, 0x80); // clear code
|
||||||
uint16_t pixels[block_size];
|
uint16_t pixels[block_size];
|
||||||
if (img->is_bayer) {
|
if (img->is_bayer) {
|
||||||
imlib_debayer_line(0, block_size, y, pixels, PIXFORMAT_RGB565, img);
|
imlib_debayer_line(0, block_size, y, pixels, PIXFORMAT_RGB565, img);
|
||||||
@ -98,22 +96,22 @@ void gif_add_frame(FIL *fp, image_t *img, uint16_t delay) {
|
|||||||
imlib_deyuv_line(0, block_size, y, pixels, PIXFORMAT_RGB565, img);
|
imlib_deyuv_line(0, block_size, y, pixels, PIXFORMAT_RGB565, img);
|
||||||
}
|
}
|
||||||
for (int x = 0; x < block_size; x++) {
|
for (int x = 0; x < block_size; x++) {
|
||||||
int r = COLOR_RGB565_TO_R8(pixels[x]);
|
uint16_t pixel = pixels[2];
|
||||||
int g = COLOR_RGB565_TO_G8(pixels[x]);
|
uint16_t r = COLOR_RGB565_TO_R5(pixel) >> 3;
|
||||||
int b = COLOR_RGB565_TO_B8(pixels[x]);
|
uint16_t g = COLOR_RGB565_TO_G6(pixel) >> 3;
|
||||||
r >>= 3; g >>= 3; b >>= 3;
|
uint16_t b = COLOR_RGB565_TO_B5(pixel) >> 3;
|
||||||
write_byte(fp, (r << 5) | (g << 2) | b);
|
file_write_byte(fp, (r << 5) | (g << 2) | b);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
write_data(fp, (uint8_t []) {0x01, 0x81, 0x00}, 3); // end code
|
file_write(fp, (uint8_t []) {0x01, 0x81, 0x00}, 3); // end code
|
||||||
|
|
||||||
file_buffer_off(fp);
|
file_buffer_off(fp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void gif_close(FIL *fp) {
|
void gif_close(FIL *fp) {
|
||||||
write_byte(fp, ';');
|
file_write_byte(fp, ';');
|
||||||
file_close(fp);
|
file_close(fp);
|
||||||
}
|
}
|
||||||
#endif //IMLIB_ENABLE_IMAGE_FILE_IO
|
#endif //IMLIB_ENABLE_IMAGE_FILE_IO
|
||||||
|
|||||||
@ -13,12 +13,11 @@
|
|||||||
#include "py/obj.h"
|
#include "py/obj.h"
|
||||||
#include "py/nlr.h"
|
#include "py/nlr.h"
|
||||||
|
|
||||||
#include "ff.h"
|
|
||||||
#include "ff_wrapper.h"
|
|
||||||
#include "xalloc.h"
|
#include "xalloc.h"
|
||||||
#include "imlib.h"
|
#include "imlib.h"
|
||||||
// built-in cascades
|
// built-in cascades
|
||||||
#include "cascade.h"
|
#include "cascade.h"
|
||||||
|
#include "file_utils.h"
|
||||||
|
|
||||||
static int eval_weak_classifier(cascade_t *cascade, point_t pt, int t_idx, int w_idx, int r_idx) {
|
static int eval_weak_classifier(cascade_t *cascade, point_t pt, int t_idx, int w_idx, int r_idx) {
|
||||||
int32_t sumw = 0;
|
int32_t sumw = 0;
|
||||||
@ -169,14 +168,13 @@ int imlib_load_cascade_from_file(cascade_t *cascade, const char *path) {
|
|||||||
FIL fp;
|
FIL fp;
|
||||||
FRESULT res = FR_OK;
|
FRESULT res = FR_OK;
|
||||||
|
|
||||||
file_read_open(&fp, path);
|
file_open(&fp, path, true, FA_READ | FA_OPEN_EXISTING);
|
||||||
file_buffer_on(&fp);
|
|
||||||
|
|
||||||
/* read detection window size */
|
// Read detection window size
|
||||||
read_data(&fp, &cascade->window, sizeof(cascade->window));
|
file_read(&fp, &cascade->window, sizeof(cascade->window));
|
||||||
|
|
||||||
/* read num stages */
|
// Read num stages
|
||||||
read_data(&fp, &cascade->n_stages, sizeof(cascade->n_stages));
|
file_read(&fp, &cascade->n_stages, sizeof(cascade->n_stages));
|
||||||
|
|
||||||
cascade->stages_array = xalloc(sizeof(*cascade->stages_array) * cascade->n_stages);
|
cascade->stages_array = xalloc(sizeof(*cascade->stages_array) * cascade->n_stages);
|
||||||
cascade->stages_thresh_array = xalloc(sizeof(*cascade->stages_thresh_array) * cascade->n_stages);
|
cascade->stages_thresh_array = xalloc(sizeof(*cascade->stages_thresh_array) * cascade->n_stages);
|
||||||
@ -187,7 +185,7 @@ int imlib_load_cascade_from_file(cascade_t *cascade, const char *path) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* read num features in each stages */
|
/* read num features in each stages */
|
||||||
read_data(&fp, cascade->stages_array, sizeof(uint8_t) * cascade->n_stages);
|
file_read(&fp, cascade->stages_array, sizeof(uint8_t) * cascade->n_stages);
|
||||||
|
|
||||||
/* sum num of features in each stages*/
|
/* sum num of features in each stages*/
|
||||||
for (i = 0, cascade->n_features = 0; i < cascade->n_stages; i++) {
|
for (i = 0, cascade->n_features = 0; i < cascade->n_stages; i++) {
|
||||||
@ -209,19 +207,19 @@ int imlib_load_cascade_from_file(cascade_t *cascade, const char *path) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* read stages thresholds */
|
/* read stages thresholds */
|
||||||
read_data(&fp, cascade->stages_thresh_array, sizeof(int16_t) * cascade->n_stages);
|
file_read(&fp, cascade->stages_thresh_array, sizeof(int16_t) * cascade->n_stages);
|
||||||
|
|
||||||
/* read features thresholds */
|
/* read features thresholds */
|
||||||
read_data(&fp, cascade->tree_thresh_array, sizeof(*cascade->tree_thresh_array) * cascade->n_features);
|
file_read(&fp, cascade->tree_thresh_array, sizeof(*cascade->tree_thresh_array) * cascade->n_features);
|
||||||
|
|
||||||
/* read alpha 1 */
|
/* read alpha 1 */
|
||||||
read_data(&fp, cascade->alpha1_array, sizeof(*cascade->alpha1_array) * cascade->n_features);
|
file_read(&fp, cascade->alpha1_array, sizeof(*cascade->alpha1_array) * cascade->n_features);
|
||||||
|
|
||||||
/* read alpha 2 */
|
/* read alpha 2 */
|
||||||
read_data(&fp, cascade->alpha2_array, sizeof(*cascade->alpha2_array) * cascade->n_features);
|
file_read(&fp, cascade->alpha2_array, sizeof(*cascade->alpha2_array) * cascade->n_features);
|
||||||
|
|
||||||
/* read num rectangles per feature*/
|
/* read num rectangles per feature*/
|
||||||
read_data(&fp, cascade->num_rectangles_array, sizeof(*cascade->num_rectangles_array) * cascade->n_features);
|
file_read(&fp, cascade->num_rectangles_array, sizeof(*cascade->num_rectangles_array) * cascade->n_features);
|
||||||
|
|
||||||
/* sum num of recatngles per feature*/
|
/* sum num of recatngles per feature*/
|
||||||
for (i = 0, cascade->n_rectangles = 0; i < cascade->n_features; i++) {
|
for (i = 0, cascade->n_rectangles = 0; i < cascade->n_features; i++) {
|
||||||
@ -238,13 +236,12 @@ int imlib_load_cascade_from_file(cascade_t *cascade, const char *path) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* read rectangles weights */
|
/* read rectangles weights */
|
||||||
read_data(&fp, cascade->weights_array, sizeof(*cascade->weights_array) * cascade->n_rectangles);
|
file_read(&fp, cascade->weights_array, sizeof(*cascade->weights_array) * cascade->n_rectangles);
|
||||||
|
|
||||||
/* read rectangles num rectangles * 4 points */
|
/* read rectangles num rectangles * 4 points */
|
||||||
read_data(&fp, cascade->rectangles_array, sizeof(*cascade->rectangles_array) * cascade->n_rectangles * 4);
|
file_read(&fp, cascade->rectangles_array, sizeof(*cascade->rectangles_array) * cascade->n_rectangles * 4);
|
||||||
|
|
||||||
error:
|
error:
|
||||||
file_buffer_off(&fp);
|
|
||||||
file_close(&fp);
|
file_close(&fp);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,7 +14,7 @@
|
|||||||
|
|
||||||
#include "font.h"
|
#include "font.h"
|
||||||
#include "array.h"
|
#include "array.h"
|
||||||
#include "ff_wrapper.h"
|
#include "file_utils.h"
|
||||||
#include "imlib.h"
|
#include "imlib.h"
|
||||||
#include "omv_common.h"
|
#include "omv_common.h"
|
||||||
#include "omv_boardconfig.h"
|
#include "omv_boardconfig.h"
|
||||||
@ -562,9 +562,9 @@ static save_image_format_t imblib_parse_extension(image_t *img, const char *path
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool imlib_read_geometry(FIL *fp, image_t *img, const char *path, img_read_settings_t *rs) {
|
bool imlib_read_geometry(FIL *fp, image_t *img, const char *path, img_read_settings_t *rs) {
|
||||||
file_read_open(fp, path);
|
|
||||||
char magic[4];
|
char magic[4];
|
||||||
read_data(fp, &magic, 4);
|
file_open(fp, path, false, FA_READ | FA_OPEN_EXISTING);
|
||||||
|
file_read(fp, &magic, 4);
|
||||||
file_close(fp);
|
file_close(fp);
|
||||||
|
|
||||||
bool vflipped = false;
|
bool vflipped = false;
|
||||||
@ -573,31 +573,27 @@ bool imlib_read_geometry(FIL *fp, image_t *img, const char *path, img_read_setti
|
|||||||
|| (magic[1] == '5') || (magic[1] == '6'))) {
|
|| (magic[1] == '5') || (magic[1] == '6'))) {
|
||||||
// PPM
|
// PPM
|
||||||
rs->format = FORMAT_PNM;
|
rs->format = FORMAT_PNM;
|
||||||
file_read_open(fp, path);
|
file_open(fp, path, true, FA_READ | FA_OPEN_EXISTING);
|
||||||
file_buffer_on(fp); // REMEMBER TO TURN THIS OFF LATER!
|
|
||||||
ppm_read_geometry(fp, img, path, &rs->ppm_rs);
|
ppm_read_geometry(fp, img, path, &rs->ppm_rs);
|
||||||
} else if ((magic[0] == 'B') && (magic[1] == 'M')) {
|
} else if ((magic[0] == 'B') && (magic[1] == 'M')) {
|
||||||
// BMP
|
// BMP
|
||||||
rs->format = FORMAT_BMP;
|
rs->format = FORMAT_BMP;
|
||||||
file_read_open(fp, path);
|
file_open(fp, path, true, FA_READ | FA_OPEN_EXISTING);
|
||||||
file_buffer_on(fp); // REMEMBER TO TURN THIS OFF LATER!
|
|
||||||
vflipped = bmp_read_geometry(fp, img, path, &rs->bmp_rs);
|
vflipped = bmp_read_geometry(fp, img, path, &rs->bmp_rs);
|
||||||
} else if ((magic[0] == 0xFF) && (magic[1] == 0xD8)) {
|
} else if ((magic[0] == 0xFF) && (magic[1] == 0xD8)) {
|
||||||
// JPG
|
// JPG
|
||||||
rs->format = FORMAT_JPG;
|
rs->format = FORMAT_JPG;
|
||||||
file_read_open(fp, path);
|
file_open(fp, path, false, FA_READ | FA_OPEN_EXISTING);
|
||||||
// Do not use file_buffer_on() here.
|
|
||||||
jpeg_read_geometry(fp, img, path, &rs->jpg_rs);
|
jpeg_read_geometry(fp, img, path, &rs->jpg_rs);
|
||||||
file_buffer_on(fp); // REMEMBER TO TURN THIS OFF LATER!
|
file_buffer_on(fp);
|
||||||
} else if ((magic[0] == 0x89) && (magic[1] == 0x50) && (magic[2] == 0x4E) && (magic[3] == 0x47)) {
|
} else if ((magic[0] == 0x89) && (magic[1] == 0x50) && (magic[2] == 0x4E) && (magic[3] == 0x47)) {
|
||||||
// PNG
|
// PNG
|
||||||
rs->format = FORMAT_PNG;
|
rs->format = FORMAT_PNG;
|
||||||
file_read_open(fp, path);
|
file_open(fp, path, false, FA_READ | FA_OPEN_EXISTING);
|
||||||
// Do not use file_buffer_on() here.
|
|
||||||
png_read_geometry(fp, img, path, &rs->png_rs);
|
png_read_geometry(fp, img, path, &rs->png_rs);
|
||||||
file_buffer_on(fp); // REMEMBER TO TURN THIS OFF LATER!
|
file_buffer_on(fp);
|
||||||
} else {
|
} else {
|
||||||
ff_unsupported_format(NULL);
|
file_raise_format(NULL);
|
||||||
}
|
}
|
||||||
imblib_parse_extension(img, path); // Enforce extension!
|
imblib_parse_extension(img, path); // Enforce extension!
|
||||||
return vflipped;
|
return vflipped;
|
||||||
@ -631,7 +627,7 @@ void imlib_image_operation(image_t *img, const char *path, image_t *other, int s
|
|||||||
img_read_settings_t rs;
|
img_read_settings_t rs;
|
||||||
bool vflipped = imlib_read_geometry(&fp, &temp, path, &rs);
|
bool vflipped = imlib_read_geometry(&fp, &temp, path, &rs);
|
||||||
if (!IM_EQUAL(img, &temp)) {
|
if (!IM_EQUAL(img, &temp)) {
|
||||||
f_close(&fp);
|
file_close(&fp);
|
||||||
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Images not equal!"));
|
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Images not equal!"));
|
||||||
}
|
}
|
||||||
// When processing vertically flipped images the read function will fill
|
// When processing vertically flipped images the read function will fill
|
||||||
@ -657,7 +653,6 @@ void imlib_image_operation(image_t *img, const char *path, image_t *other, int s
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
file_buffer_off(&fp);
|
|
||||||
file_close(&fp);
|
file_close(&fp);
|
||||||
fb_free();
|
fb_free();
|
||||||
#else
|
#else
|
||||||
@ -744,9 +739,9 @@ void imlib_image_operation(image_t *img, const char *path, image_t *other, int s
|
|||||||
#if defined(IMLIB_ENABLE_IMAGE_FILE_IO)
|
#if defined(IMLIB_ENABLE_IMAGE_FILE_IO)
|
||||||
void imlib_load_image(image_t *img, const char *path) {
|
void imlib_load_image(image_t *img, const char *path) {
|
||||||
FIL fp;
|
FIL fp;
|
||||||
file_read_open(&fp, path);
|
|
||||||
char magic[4];
|
char magic[4];
|
||||||
read_data(&fp, &magic, 4);
|
file_open(&fp, path, false, FA_READ | FA_OPEN_EXISTING);
|
||||||
|
file_read(&fp, &magic, 4);
|
||||||
file_close(&fp);
|
file_close(&fp);
|
||||||
|
|
||||||
if ((magic[0] == 'P')
|
if ((magic[0] == 'P')
|
||||||
@ -764,7 +759,7 @@ void imlib_load_image(image_t *img, const char *path) {
|
|||||||
// PNG
|
// PNG
|
||||||
png_read(img, path);
|
png_read(img, path);
|
||||||
} else {
|
} else {
|
||||||
ff_unsupported_format(NULL);
|
file_raise_format(NULL);
|
||||||
}
|
}
|
||||||
imblib_parse_extension(img, path); // Enforce extension!
|
imblib_parse_extension(img, path); // Enforce extension!
|
||||||
}
|
}
|
||||||
@ -779,8 +774,8 @@ void imlib_save_image(image_t *img, const char *path, rectangle_t *roi, int qual
|
|||||||
break;
|
break;
|
||||||
case FORMAT_RAW: {
|
case FORMAT_RAW: {
|
||||||
FIL fp;
|
FIL fp;
|
||||||
file_write_open(&fp, path);
|
file_open(&fp, path, false, FA_WRITE | FA_CREATE_ALWAYS);
|
||||||
write_data(&fp, img->pixels, img->w * img->h);
|
file_write(&fp, img->pixels, img->w * img->h);
|
||||||
file_close(&fp);
|
file_close(&fp);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -803,8 +798,8 @@ void imlib_save_image(image_t *img, const char *path, rectangle_t *roi, int qual
|
|||||||
} else if (IM_IS_BAYER(img)) {
|
} else if (IM_IS_BAYER(img)) {
|
||||||
FIL fp;
|
FIL fp;
|
||||||
char *new_path = strcat(strcpy(fb_alloc(strlen(path) + 5, FB_ALLOC_NO_HINT), path), ".raw");
|
char *new_path = strcat(strcpy(fb_alloc(strlen(path) + 5, FB_ALLOC_NO_HINT), path), ".raw");
|
||||||
file_write_open(&fp, new_path);
|
file_open(&fp, new_path, false, FA_WRITE | FA_CREATE_ALWAYS);
|
||||||
write_data(&fp, img->pixels, img->w * img->h);
|
file_write(&fp, img->pixels, img->w * img->h);
|
||||||
file_close(&fp);
|
file_close(&fp);
|
||||||
fb_free();
|
fb_free();
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -19,8 +19,8 @@
|
|||||||
#include <float.h>
|
#include <float.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <arm_math.h>
|
#include <arm_math.h>
|
||||||
#include <ff.h>
|
|
||||||
#include "fb_alloc.h"
|
#include "fb_alloc.h"
|
||||||
|
#include "file_utils.h"
|
||||||
#include "umm_malloc.h"
|
#include "umm_malloc.h"
|
||||||
#include "xalloc.h"
|
#include "xalloc.h"
|
||||||
#include "array.h"
|
#include "array.h"
|
||||||
|
|||||||
@ -12,7 +12,7 @@
|
|||||||
*/
|
*/
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#include "ff_wrapper.h"
|
#include "file_utils.h"
|
||||||
#include "imlib.h"
|
#include "imlib.h"
|
||||||
#include "omv_boardconfig.h"
|
#include "omv_boardconfig.h"
|
||||||
|
|
||||||
@ -2202,7 +2202,7 @@ int jpeg_clean_trailing_bytes(int size, uint8_t *data) {
|
|||||||
void jpeg_read_geometry(FIL *fp, image_t *img, const char *path, jpg_read_settings_t *rs) {
|
void jpeg_read_geometry(FIL *fp, image_t *img, const char *path, jpg_read_settings_t *rs) {
|
||||||
for (;;) {
|
for (;;) {
|
||||||
uint16_t header;
|
uint16_t header;
|
||||||
read_word(fp, &header);
|
file_read(fp, &header, 2);
|
||||||
header = __REV16(header);
|
header = __REV16(header);
|
||||||
if ((0xFFD0 <= header) && (header <= 0xFFD9)) {
|
if ((0xFFD0 <= header) && (header <= 0xFFD9)) {
|
||||||
continue;
|
continue;
|
||||||
@ -2211,19 +2211,19 @@ void jpeg_read_geometry(FIL *fp, image_t *img, const char *path, jpg_read_settin
|
|||||||
|| ((0xFFE0 <= header) && (header <= 0xFFEF))
|
|| ((0xFFE0 <= header) && (header <= 0xFFEF))
|
||||||
|| ((0xFFF0 <= header) && (header <= 0xFFFE))) {
|
|| ((0xFFF0 <= header) && (header <= 0xFFFE))) {
|
||||||
uint16_t size;
|
uint16_t size;
|
||||||
read_word(fp, &size);
|
file_read(fp, &size, 2);
|
||||||
size = __REV16(size);
|
size = __REV16(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);
|
file_read(fp, NULL, 1);
|
||||||
uint16_t height;
|
uint16_t height;
|
||||||
read_word(fp, &height);
|
file_read(fp, &height, 2);
|
||||||
height = __REV16(height);
|
height = __REV16(height);
|
||||||
|
|
||||||
uint16_t width;
|
uint16_t width;
|
||||||
read_word(fp, &width);
|
file_read(fp, &width, 2);
|
||||||
width = __REV16(width);
|
width = __REV16(width);
|
||||||
|
|
||||||
rs->jpg_w = width;
|
rs->jpg_w = width;
|
||||||
@ -2239,7 +2239,7 @@ void jpeg_read_geometry(FIL *fp, image_t *img, const char *path, jpg_read_settin
|
|||||||
file_seek(fp, f_tell(fp) + size - 2);
|
file_seek(fp, f_tell(fp) + size - 2);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ff_file_corrupted(fp);
|
file_raise_corrupted(fp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2247,16 +2247,15 @@ void jpeg_read_geometry(FIL *fp, image_t *img, const char *path, jpg_read_settin
|
|||||||
// This function reads the pixel values of an image.
|
// This function reads the pixel values of an image.
|
||||||
void jpeg_read_pixels(FIL *fp, image_t *img) {
|
void jpeg_read_pixels(FIL *fp, image_t *img) {
|
||||||
file_seek(fp, 0);
|
file_seek(fp, 0);
|
||||||
read_data(fp, img->pixels, img->size);
|
file_read(fp, img->pixels, img->size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void jpeg_read(image_t *img, const char *path) {
|
void jpeg_read(image_t *img, const char *path) {
|
||||||
FIL fp;
|
FIL fp;
|
||||||
jpg_read_settings_t rs;
|
jpg_read_settings_t rs;
|
||||||
|
|
||||||
file_read_open(&fp, path);
|
// Do not use file buffering here.
|
||||||
|
file_open(&fp, path, false, FA_READ | FA_OPEN_EXISTING);
|
||||||
// Do not use file_buffer_on() here.
|
|
||||||
jpeg_read_geometry(&fp, img, path, &rs);
|
jpeg_read_geometry(&fp, img, path, &rs);
|
||||||
|
|
||||||
if (!img->pixels) {
|
if (!img->pixels) {
|
||||||
@ -2269,16 +2268,16 @@ void jpeg_read(image_t *img, const char *path) {
|
|||||||
|
|
||||||
void jpeg_write(image_t *img, const char *path, int quality) {
|
void jpeg_write(image_t *img, const char *path, int quality) {
|
||||||
FIL fp;
|
FIL fp;
|
||||||
file_write_open(&fp, path);
|
file_open(&fp, path, false, FA_WRITE | FA_CREATE_ALWAYS);
|
||||||
if (IM_IS_JPEG(img)) {
|
if (IM_IS_JPEG(img)) {
|
||||||
write_data(&fp, img->pixels, img->size);
|
file_write(&fp, img->pixels, img->size);
|
||||||
} else {
|
} else {
|
||||||
image_t out = { .w = img->w, .h = img->h, .pixfmt = PIXFORMAT_JPEG, .size = 0, .pixels = NULL }; // alloc in jpeg compress
|
image_t out = { .w = img->w, .h = img->h, .pixfmt = PIXFORMAT_JPEG, .size = 0, .pixels = NULL }; // alloc in jpeg compress
|
||||||
// When jpeg_compress needs more memory than in currently allocated it
|
// When jpeg_compress needs more memory than in currently allocated it
|
||||||
// will try to realloc. MP will detect that the pointer is outside of
|
// will try to realloc. MP will detect that the pointer is outside of
|
||||||
// the heap and return NULL which will cause an out of memory error.
|
// the heap and return NULL which will cause an out of memory error.
|
||||||
jpeg_compress(img, &out, quality, false);
|
jpeg_compress(img, &out, quality, false);
|
||||||
write_data(&fp, out.pixels, out.size);
|
file_write(&fp, out.pixels, out.size);
|
||||||
fb_free(); // frees alloc in jpeg_compress()
|
fb_free(); // frees alloc in jpeg_compress()
|
||||||
}
|
}
|
||||||
file_close(&fp);
|
file_close(&fp);
|
||||||
|
|||||||
@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
#include "imlib.h"
|
#include "imlib.h"
|
||||||
#include "xalloc.h"
|
#include "xalloc.h"
|
||||||
#include "ff.h"
|
#include "file_utils.h"
|
||||||
#ifdef IMLIB_ENABLE_FIND_LBP
|
#ifdef IMLIB_ENABLE_FIND_LBP
|
||||||
|
|
||||||
#define LBP_HIST_SIZE (59) //58 uniform hist + 1
|
#define LBP_HIST_SIZE (59) //58 uniform hist + 1
|
||||||
@ -93,7 +93,7 @@ int imlib_lbp_desc_distance(uint8_t *d0, uint8_t *d1) {
|
|||||||
int imlib_lbp_desc_save(FIL *fp, uint8_t *desc) {
|
int imlib_lbp_desc_save(FIL *fp, uint8_t *desc) {
|
||||||
UINT bytes;
|
UINT bytes;
|
||||||
// Write descriptor
|
// Write descriptor
|
||||||
return f_write(fp, desc, LBP_DESC_SIZE, &bytes);
|
return file_ll_write(fp, desc, LBP_DESC_SIZE, &bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
int imlib_lbp_desc_load(FIL *fp, uint8_t **desc) {
|
int imlib_lbp_desc_load(FIL *fp, uint8_t **desc) {
|
||||||
@ -104,7 +104,7 @@ int imlib_lbp_desc_load(FIL *fp, uint8_t **desc) {
|
|||||||
uint8_t *hist = xalloc(LBP_DESC_SIZE);
|
uint8_t *hist = xalloc(LBP_DESC_SIZE);
|
||||||
|
|
||||||
// Read descriptor
|
// Read descriptor
|
||||||
res = f_read(fp, hist, LBP_DESC_SIZE, &bytes);
|
res = file_ll_read(fp, hist, LBP_DESC_SIZE, &bytes);
|
||||||
if (res != FR_OK || bytes != LBP_DESC_SIZE) {
|
if (res != FR_OK || bytes != LBP_DESC_SIZE) {
|
||||||
*desc = NULL;
|
*desc = NULL;
|
||||||
xfree(hist);
|
xfree(hist);
|
||||||
|
|||||||
@ -11,7 +11,7 @@
|
|||||||
#include "imlib.h"
|
#include "imlib.h"
|
||||||
#if defined(IMLIB_ENABLE_IMAGE_FILE_IO)
|
#if defined(IMLIB_ENABLE_IMAGE_FILE_IO)
|
||||||
|
|
||||||
#include "ff_wrapper.h"
|
#include "file_utils.h"
|
||||||
|
|
||||||
#define SIZE_OFFSET (1 * 4)
|
#define SIZE_OFFSET (1 * 4)
|
||||||
#define MICROS_OFFSET (8 * 4)
|
#define MICROS_OFFSET (8 * 4)
|
||||||
@ -23,72 +23,72 @@
|
|||||||
#define MOVI_OFFSET (54 * 4)
|
#define MOVI_OFFSET (54 * 4)
|
||||||
|
|
||||||
void mjpeg_open(FIL *fp, int width, int height) {
|
void mjpeg_open(FIL *fp, int width, int height) {
|
||||||
write_data(fp, "RIFF", 4); // FOURCC fcc; - 0
|
file_write(fp, "RIFF", 4); // FOURCC fcc; - 0
|
||||||
write_long(fp, 0); // DWORD cb; size - updated on close - 1
|
file_write_long(fp, 0); // DWORD cb; size - updated on close - 1
|
||||||
write_data(fp, "AVI ", 4); // FOURCC fcc; - 2
|
file_write(fp, "AVI ", 4); // FOURCC fcc; - 2
|
||||||
|
|
||||||
write_data(fp, "LIST", 4); // FOURCC fcc; - 3
|
file_write(fp, "LIST", 4); // FOURCC fcc; - 3
|
||||||
write_long(fp, 192); // DWORD cb; - 4
|
file_write_long(fp, 192); // DWORD cb; - 4
|
||||||
write_data(fp, "hdrl", 4); // FOURCC fcc; - 5
|
file_write(fp, "hdrl", 4); // FOURCC fcc; - 5
|
||||||
|
|
||||||
write_data(fp, "avih", 4); // FOURCC fcc; - 6
|
file_write(fp, "avih", 4); // FOURCC fcc; - 6
|
||||||
write_long(fp, 56); // DWORD cb; - 7
|
file_write_long(fp, 56); // DWORD cb; - 7
|
||||||
write_long(fp, 0); // DWORD dwMicroSecPerFrame; micros - updated on close - 8
|
file_write_long(fp, 0); // DWORD dwMicroSecPerFrame; micros - updated on close - 8
|
||||||
write_long(fp, 0); // DWORD dwMaxBytesPerSec; updated on close - 9
|
file_write_long(fp, 0); // DWORD dwMaxBytesPerSec; updated on close - 9
|
||||||
write_long(fp, 4); // DWORD dwPaddingGranularity; - 10
|
file_write_long(fp, 4); // DWORD dwPaddingGranularity; - 10
|
||||||
write_long(fp, 0); // DWORD dwFlags; - 11
|
file_write_long(fp, 0); // DWORD dwFlags; - 11
|
||||||
write_long(fp, 0); // DWORD dwTotalFrames; frames - updated on close - 12
|
file_write_long(fp, 0); // DWORD dwTotalFrames; frames - updated on close - 12
|
||||||
write_long(fp, 0); // DWORD dwInitialFrames; - 13
|
file_write_long(fp, 0); // DWORD dwInitialFrames; - 13
|
||||||
write_long(fp, 1); // DWORD dwStreams; - 14
|
file_write_long(fp, 1); // DWORD dwStreams; - 14
|
||||||
write_long(fp, 0); // DWORD dwSuggestedBufferSize; - 15
|
file_write_long(fp, 0); // DWORD dwSuggestedBufferSize; - 15
|
||||||
write_long(fp, width); // DWORD dwWidth; - 16
|
file_write_long(fp, width); // DWORD dwWidth; - 16
|
||||||
write_long(fp, height); // DWORD dwHeight; - 17
|
file_write_long(fp, height); // DWORD dwHeight; - 17
|
||||||
write_long(fp, 1000); // DWORD dwScale; - 18
|
file_write_long(fp, 1000); // DWORD dwScale; - 18
|
||||||
write_long(fp, 0); // DWORD dwRate; rate - updated on close - 19
|
file_write_long(fp, 0); // DWORD dwRate; rate - updated on close - 19
|
||||||
write_long(fp, 0); // DWORD dwStart; - 20
|
file_write_long(fp, 0); // DWORD dwStart; - 20
|
||||||
write_long(fp, 0); // DWORD dwLength; length - updated on close - 21
|
file_write_long(fp, 0); // DWORD dwLength; length - updated on close - 21
|
||||||
|
|
||||||
write_data(fp, "LIST", 4); // FOURCC fcc; - 22
|
file_write(fp, "LIST", 4); // FOURCC fcc; - 22
|
||||||
write_long(fp, 116); // DWORD cb; - 23
|
file_write_long(fp, 116); // DWORD cb; - 23
|
||||||
write_data(fp, "strl", 4); // FOURCC fcc; - 24
|
file_write(fp, "strl", 4); // FOURCC fcc; - 24
|
||||||
|
|
||||||
write_data(fp, "strh", 4); // FOURCC fcc; - 25
|
file_write(fp, "strh", 4); // FOURCC fcc; - 25
|
||||||
write_long(fp, 56); // DWORD cb; - 26
|
file_write_long(fp, 56); // DWORD cb; - 26
|
||||||
write_data(fp, "vids", 4); // FOURCC fccType; - 27
|
file_write(fp, "vids", 4); // FOURCC fccType; - 27
|
||||||
write_data(fp, "MJPG", 4); // FOURCC fccHandler; - 28
|
file_write(fp, "MJPG", 4); // FOURCC fccHandler; - 28
|
||||||
write_long(fp, 0); // DWORD dwFlags; - 29
|
file_write_long(fp, 0); // DWORD dwFlags; - 29
|
||||||
write_word(fp, 0); // WORD wPriority; - 30
|
file_write_short(fp, 0); // WORD wPriority; - 30
|
||||||
write_word(fp, 0); // WORD wLanguage; - 30.5
|
file_write_short(fp, 0); // WORD wLanguage; - 30.5
|
||||||
write_long(fp, 0); // DWORD dwInitialFrames; - 31
|
file_write_long(fp, 0); // DWORD dwInitialFrames; - 31
|
||||||
write_long(fp, 1000); // DWORD dwScale; - 32
|
file_write_long(fp, 1000); // DWORD dwScale; - 32
|
||||||
write_long(fp, 0); // DWORD dwRate; rate - updated on close - 33
|
file_write_long(fp, 0); // DWORD dwRate; rate - updated on close - 33
|
||||||
write_long(fp, 0); // DWORD dwStart; - 34
|
file_write_long(fp, 0); // DWORD dwStart; - 34
|
||||||
write_long(fp, 0); // DWORD dwLength; length - updated on close - 35
|
file_write_long(fp, 0); // DWORD dwLength; length - updated on close - 35
|
||||||
write_long(fp, 0); // DWORD dwSuggestedBufferSize; - 36
|
file_write_long(fp, 0); // DWORD dwSuggestedBufferSize; - 36
|
||||||
write_long(fp, 10000); // DWORD dwQuality; - 37
|
file_write_long(fp, 10000); // DWORD dwQuality; - 37
|
||||||
write_long(fp, 0); // DWORD dwSampleSize; - 38
|
file_write_long(fp, 0); // DWORD dwSampleSize; - 38
|
||||||
write_word(fp, 0); // short int left; - 39
|
file_write_short(fp, 0); // short int left; - 39
|
||||||
write_word(fp, 0); // short int top; - 39.5
|
file_write_short(fp, 0); // short int top; - 39.5
|
||||||
write_word(fp, 0); // short int right; - 40
|
file_write_short(fp, 0); // short int right; - 40
|
||||||
write_word(fp, 0); // short int bottom; - 40.5
|
file_write_short(fp, 0); // short int bottom; - 40.5
|
||||||
|
|
||||||
write_data(fp, "strf", 4); // FOURCC fcc; - 41
|
file_write(fp, "strf", 4); // FOURCC fcc; - 41
|
||||||
write_long(fp, 40); // DWORD cb; - 42
|
file_write_long(fp, 40); // DWORD cb; - 42
|
||||||
write_long(fp, 40); // DWORD biSize; - 43
|
file_write_long(fp, 40); // DWORD biSize; - 43
|
||||||
write_long(fp, width); // LONG biWidth; - 44
|
file_write_long(fp, width); // DWORD biWidth; - 44
|
||||||
write_long(fp, height); // LONG biHeight; - 45
|
file_write_long(fp, height); // DWORD biHeight; - 45
|
||||||
write_word(fp, 1); // WORD biPlanes; - 46
|
file_write_short(fp, 1); // WORD biPlanes; - 46
|
||||||
write_word(fp, 24); // WORD biBitCount; - 46.5
|
file_write_short(fp, 24); // WORD biBitCount; - 46.5
|
||||||
write_data(fp, "MJPG", 4); // DWORD biCompression; - 47
|
file_write(fp, "MJPG", 4); // DWORD biCompression; - 47
|
||||||
write_long(fp, 0); // DWORD biSizeImage; - 48
|
file_write_long(fp, 0); // DWORD biSizeImage; - 48
|
||||||
write_long(fp, 0); // LONG biXPelsPerMeter; - 49
|
file_write_long(fp, 0); // DWORD biXPelsPerMeter; - 49
|
||||||
write_long(fp, 0); // LONG biYPelsPerMeter; - 50
|
file_write_long(fp, 0); // DWORD biYPelsPerMeter; - 50
|
||||||
write_long(fp, 0); // DWORD biClrUsed; - 51
|
file_write_long(fp, 0); // DWORD biClrUsed; - 51
|
||||||
write_long(fp, 0); // DWORD biClrImportant; - 52
|
file_write_long(fp, 0); // DWORD biClrImportant; - 52
|
||||||
|
|
||||||
write_data(fp, "LIST", 4); // FOURCC fcc; - 53
|
file_write(fp, "LIST", 4); // FOURCC fcc; - 53
|
||||||
write_long(fp, 0); // DWORD cb; movi - updated on close - 54
|
file_write_long(fp, 0); // DWORD cb; movi - updated on close - 54
|
||||||
write_data(fp, "movi", 4); // FOURCC fcc; - 55
|
file_write(fp, "movi", 4); // FOURCC fcc; - 55
|
||||||
}
|
}
|
||||||
|
|
||||||
void mjpeg_write(FIL *fp, int width, int height, uint32_t *frames, uint32_t *bytes,
|
void mjpeg_write(FIL *fp, int width, int height, uint32_t *frames, uint32_t *bytes,
|
||||||
@ -185,9 +185,9 @@ void mjpeg_write(FIL *fp, int width, int height, uint32_t *frames, uint32_t *byt
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint32_t size_padded = (((dst_img.size + 3) / 4) * 4);
|
uint32_t size_padded = (((dst_img.size + 3) / 4) * 4);
|
||||||
write_data(fp, "00dc", 4); // FOURCC fcc;
|
file_write(fp, "00dc", 4); // FOURCC fcc;
|
||||||
write_long(fp, size_padded); // DWORD cb;
|
file_write_long(fp, size_padded); // DWORD cb;
|
||||||
write_data(fp, dst_img.data, size_padded); // reading past okay
|
file_write(fp, dst_img.data, size_padded); // reading past okay
|
||||||
|
|
||||||
*frames += 1;
|
*frames += 1;
|
||||||
*bytes += size_padded;
|
*bytes += size_padded;
|
||||||
@ -199,67 +199,39 @@ void mjpeg_sync(FIL *fp, uint32_t *frames, uint32_t *bytes, float fps) {
|
|||||||
uint32_t position = f_tell(fp);
|
uint32_t position = f_tell(fp);
|
||||||
// Needed
|
// Needed
|
||||||
file_seek(fp, SIZE_OFFSET);
|
file_seek(fp, SIZE_OFFSET);
|
||||||
write_long(fp, 216 + (*frames * 8) + *bytes);
|
file_write_long(fp, 216 + (*frames * 8) + *bytes);
|
||||||
// Needed
|
// Needed
|
||||||
file_seek(fp, MICROS_OFFSET);
|
file_seek(fp, MICROS_OFFSET);
|
||||||
write_long(fp, (!fast_roundf(fps)) ? 0 :
|
file_write_long(fp, (!fast_roundf(fps)) ? 0 :
|
||||||
fast_roundf(1000000 / fps));
|
fast_roundf(1000000 / fps));
|
||||||
write_long(fp, (!(*frames)) ? 0 :
|
file_write_long(fp, (!(*frames)) ? 0 :
|
||||||
fast_roundf((((*frames * 8) + *bytes) * fps) / *frames));
|
fast_roundf((((*frames * 8) + *bytes) * fps) / *frames));
|
||||||
// Needed
|
// Needed
|
||||||
file_seek(fp, FRAMES_OFFSET);
|
file_seek(fp, FRAMES_OFFSET);
|
||||||
write_long(fp, *frames);
|
file_write_long(fp, *frames);
|
||||||
// Probably not needed but writing it just in case.
|
// Probably not needed but writing it just in case.
|
||||||
file_seek(fp, RATE_0_OFFSET);
|
file_seek(fp, RATE_0_OFFSET);
|
||||||
write_long(fp, fast_roundf(fps * 1000));
|
file_write_long(fp, fast_roundf(fps * 1000));
|
||||||
// Probably not needed but writing it just in case.
|
// Probably not needed but writing it just in case.
|
||||||
file_seek(fp, LENGTH_0_OFFSET);
|
file_seek(fp, LENGTH_0_OFFSET);
|
||||||
write_long(fp, (!fast_roundf(fps)) ? 0 :
|
file_write_long(fp, (!fast_roundf(fps)) ? 0 :
|
||||||
fast_roundf((*frames * 1000) / fps));
|
fast_roundf((*frames * 1000) / fps));
|
||||||
// Probably not needed but writing it just in case.
|
// Probably not needed but writing it just in case.
|
||||||
file_seek(fp, RATE_1_OFFSET);
|
file_seek(fp, RATE_1_OFFSET);
|
||||||
write_long(fp, fast_roundf(fps * 1000));
|
file_write_long(fp, fast_roundf(fps * 1000));
|
||||||
// Probably not needed but writing it just in case.
|
// Probably not needed but writing it just in case.
|
||||||
file_seek(fp, LENGTH_1_OFFSET);
|
file_seek(fp, LENGTH_1_OFFSET);
|
||||||
write_long(fp, (!fast_roundf(fps)) ? 0 :
|
file_write_long(fp, (!fast_roundf(fps)) ? 0 :
|
||||||
fast_roundf((*frames * 1000) / fps));
|
fast_roundf((*frames * 1000) / fps));
|
||||||
// Needed
|
// Needed
|
||||||
file_seek(fp, MOVI_OFFSET);
|
file_seek(fp, MOVI_OFFSET);
|
||||||
write_long(fp, 4 + (*frames * 8) + *bytes);
|
file_write_long(fp, 4 + (*frames * 8) + *bytes);
|
||||||
file_sync(fp);
|
file_sync(fp);
|
||||||
file_seek(fp, position);
|
file_seek(fp, position);
|
||||||
}
|
}
|
||||||
|
|
||||||
void mjpeg_close(FIL *fp, uint32_t *frames, uint32_t *bytes, float fps) {
|
void mjpeg_close(FIL *fp, uint32_t *frames, uint32_t *bytes, float fps) {
|
||||||
// Needed
|
mjpeg_sync(fp, frames, bytes, fps);
|
||||||
file_seek(fp, SIZE_OFFSET);
|
|
||||||
write_long(fp, 216 + (*frames * 8) + *bytes);
|
|
||||||
// Needed
|
|
||||||
file_seek(fp, MICROS_OFFSET);
|
|
||||||
write_long(fp, (!fast_roundf(fps)) ? 0 :
|
|
||||||
fast_roundf(1000000 / fps));
|
|
||||||
write_long(fp, (!(*frames)) ? 0 :
|
|
||||||
fast_roundf((((*frames * 8) + *bytes) * fps) / *frames));
|
|
||||||
// Needed
|
|
||||||
file_seek(fp, FRAMES_OFFSET);
|
|
||||||
write_long(fp, *frames);
|
|
||||||
// Probably not needed but writing it just in case.
|
|
||||||
file_seek(fp, RATE_0_OFFSET);
|
|
||||||
write_long(fp, fast_roundf(fps * 1000));
|
|
||||||
// Probably not needed but writing it just in case.
|
|
||||||
file_seek(fp, LENGTH_0_OFFSET);
|
|
||||||
write_long(fp, (!fast_roundf(fps)) ? 0 :
|
|
||||||
fast_roundf((*frames * 1000) / fps));
|
|
||||||
// Probably not needed but writing it just in case.
|
|
||||||
file_seek(fp, RATE_1_OFFSET);
|
|
||||||
write_long(fp, fast_roundf(fps * 1000));
|
|
||||||
// Probably not needed but writing it just in case.
|
|
||||||
file_seek(fp, LENGTH_1_OFFSET);
|
|
||||||
write_long(fp, (!fast_roundf(fps)) ? 0 :
|
|
||||||
fast_roundf((*frames * 1000) / fps));
|
|
||||||
// Needed
|
|
||||||
file_seek(fp, MOVI_OFFSET);
|
|
||||||
write_long(fp, 4 + (*frames * 8) + *bytes);
|
|
||||||
file_close(fp);
|
file_close(fp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -42,10 +42,10 @@
|
|||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include "fmath.h"
|
#include "fmath.h"
|
||||||
#include "arm_math.h"
|
#include "arm_math.h"
|
||||||
#include "ff.h"
|
|
||||||
#include "imlib.h"
|
#include "imlib.h"
|
||||||
#include "xalloc.h"
|
#include "xalloc.h"
|
||||||
#include "fb_alloc.h"
|
#include "fb_alloc.h"
|
||||||
|
#include "file_utils.h"
|
||||||
#ifdef IMLIB_ENABLE_FIND_KEYPOINTS
|
#ifdef IMLIB_ENABLE_FIND_KEYPOINTS
|
||||||
|
|
||||||
#define PATCH_SIZE (31) // 31x31 pixels
|
#define PATCH_SIZE (31) // 31x31 pixels
|
||||||
@ -719,7 +719,7 @@ int orb_save_descriptor(FIL *fp, array_t *kpts) {
|
|||||||
int kpts_size = array_length(kpts);
|
int kpts_size = array_length(kpts);
|
||||||
|
|
||||||
// Write the number of keypoints
|
// Write the number of keypoints
|
||||||
res = f_write(fp, &kpts_size, sizeof(kpts_size), &bytes);
|
res = file_ll_write(fp, &kpts_size, sizeof(kpts_size), &bytes);
|
||||||
if (res != FR_OK || bytes != sizeof(kpts_size)) {
|
if (res != FR_OK || bytes != sizeof(kpts_size)) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
@ -729,37 +729,37 @@ int orb_save_descriptor(FIL *fp, array_t *kpts) {
|
|||||||
kp_t *kp = array_at(kpts, i);
|
kp_t *kp = array_at(kpts, i);
|
||||||
|
|
||||||
// Write X
|
// Write X
|
||||||
res = f_write(fp, &kp->x, sizeof(kp->x), &bytes);
|
res = file_ll_write(fp, &kp->x, sizeof(kp->x), &bytes);
|
||||||
if (res != FR_OK || bytes != sizeof(kp->x)) {
|
if (res != FR_OK || bytes != sizeof(kp->x)) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write Y
|
// Write Y
|
||||||
res = f_write(fp, &kp->y, sizeof(kp->y), &bytes);
|
res = file_ll_write(fp, &kp->y, sizeof(kp->y), &bytes);
|
||||||
if (res != FR_OK || bytes != sizeof(kp->y)) {
|
if (res != FR_OK || bytes != sizeof(kp->y)) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write Score
|
// Write Score
|
||||||
res = f_write(fp, &kp->score, sizeof(kp->score), &bytes);
|
res = file_ll_write(fp, &kp->score, sizeof(kp->score), &bytes);
|
||||||
if (res != FR_OK || bytes != sizeof(kp->score)) {
|
if (res != FR_OK || bytes != sizeof(kp->score)) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write Octave
|
// Write Octave
|
||||||
res = f_write(fp, &kp->octave, sizeof(kp->octave), &bytes);
|
res = file_ll_write(fp, &kp->octave, sizeof(kp->octave), &bytes);
|
||||||
if (res != FR_OK || bytes != sizeof(kp->octave)) {
|
if (res != FR_OK || bytes != sizeof(kp->octave)) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write Angle
|
// Write Angle
|
||||||
res = f_write(fp, &kp->angle, sizeof(kp->angle), &bytes);
|
res = file_ll_write(fp, &kp->angle, sizeof(kp->angle), &bytes);
|
||||||
if (res != FR_OK || bytes != sizeof(kp->angle)) {
|
if (res != FR_OK || bytes != sizeof(kp->angle)) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write descriptor
|
// Write descriptor
|
||||||
res = f_write(fp, kp->desc, KDESC_SIZE, &bytes);
|
res = file_ll_write(fp, kp->desc, KDESC_SIZE, &bytes);
|
||||||
if (res != FR_OK || bytes != KDESC_SIZE) {
|
if (res != FR_OK || bytes != KDESC_SIZE) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
@ -776,7 +776,7 @@ int orb_load_descriptor(FIL *fp, array_t *kpts) {
|
|||||||
int kpts_size = 0;
|
int kpts_size = 0;
|
||||||
|
|
||||||
// Read number of keypoints
|
// Read number of keypoints
|
||||||
res = f_read(fp, &kpts_size, sizeof(kpts_size), &bytes);
|
res = file_ll_read(fp, &kpts_size, sizeof(kpts_size), &bytes);
|
||||||
if (res != FR_OK || bytes != sizeof(kpts_size)) {
|
if (res != FR_OK || bytes != sizeof(kpts_size)) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
@ -787,37 +787,37 @@ int orb_load_descriptor(FIL *fp, array_t *kpts) {
|
|||||||
kp->matched = 0;
|
kp->matched = 0;
|
||||||
|
|
||||||
// Read X
|
// Read X
|
||||||
res = f_read(fp, &kp->x, sizeof(kp->x), &bytes);
|
res = file_ll_read(fp, &kp->x, sizeof(kp->x), &bytes);
|
||||||
if (res != FR_OK || bytes != sizeof(kp->x)) {
|
if (res != FR_OK || bytes != sizeof(kp->x)) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read Y
|
// Read Y
|
||||||
res = f_read(fp, &kp->y, sizeof(kp->y), &bytes);
|
res = file_ll_read(fp, &kp->y, sizeof(kp->y), &bytes);
|
||||||
if (res != FR_OK || bytes != sizeof(kp->y)) {
|
if (res != FR_OK || bytes != sizeof(kp->y)) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read Score
|
// Read Score
|
||||||
res = f_read(fp, &kp->score, sizeof(kp->score), &bytes);
|
res = file_ll_read(fp, &kp->score, sizeof(kp->score), &bytes);
|
||||||
if (res != FR_OK || bytes != sizeof(kp->score)) {
|
if (res != FR_OK || bytes != sizeof(kp->score)) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read Octave
|
// Read Octave
|
||||||
res = f_read(fp, &kp->octave, sizeof(kp->octave), &bytes);
|
res = file_ll_read(fp, &kp->octave, sizeof(kp->octave), &bytes);
|
||||||
if (res != FR_OK || bytes != sizeof(kp->octave)) {
|
if (res != FR_OK || bytes != sizeof(kp->octave)) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read Angle
|
// Read Angle
|
||||||
res = f_read(fp, &kp->angle, sizeof(kp->angle), &bytes);
|
res = file_ll_read(fp, &kp->angle, sizeof(kp->angle), &bytes);
|
||||||
if (res != FR_OK || bytes != sizeof(kp->angle)) {
|
if (res != FR_OK || bytes != sizeof(kp->angle)) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read descriptor
|
// Read descriptor
|
||||||
res = f_read(fp, kp->desc, KDESC_SIZE, &bytes);
|
res = file_ll_read(fp, kp->desc, KDESC_SIZE, &bytes);
|
||||||
if (res != FR_OK || bytes != KDESC_SIZE) {
|
if (res != FR_OK || bytes != KDESC_SIZE) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,7 +12,7 @@
|
|||||||
#include "imlib.h"
|
#include "imlib.h"
|
||||||
#include "py/mphal.h"
|
#include "py/mphal.h"
|
||||||
#include "py/runtime.h"
|
#include "py/runtime.h"
|
||||||
#include "ff_wrapper.h"
|
#include "file_utils.h"
|
||||||
#if defined(IMLIB_ENABLE_PNG_ENCODER) || defined(IMLIB_ENABLE_PNG_DECODER)
|
#if defined(IMLIB_ENABLE_PNG_ENCODER) || defined(IMLIB_ENABLE_PNG_DECODER)
|
||||||
#include "lodepng.h"
|
#include "lodepng.h"
|
||||||
#include "umm_malloc.h"
|
#include "umm_malloc.h"
|
||||||
@ -265,12 +265,12 @@ void png_decompress(image_t *dst, image_t *src) {
|
|||||||
void png_read_geometry(FIL *fp, image_t *img, const char *path, png_read_settings_t *rs) {
|
void png_read_geometry(FIL *fp, image_t *img, const char *path, png_read_settings_t *rs) {
|
||||||
uint32_t header;
|
uint32_t header;
|
||||||
file_seek(fp, 12); // start of IHDR
|
file_seek(fp, 12); // start of IHDR
|
||||||
read_long(fp, &header);
|
file_read(fp, &header, 4);
|
||||||
if (header == 0x52444849) {
|
if (header == 0x52444849) {
|
||||||
// IHDR
|
// IHDR
|
||||||
uint32_t width, height;
|
uint32_t width, height;
|
||||||
read_long(fp, &width);
|
file_read(fp, &width, 4);
|
||||||
read_long(fp, &height);
|
file_read(fp, &height, 4);
|
||||||
width = __builtin_bswap32(width);
|
width = __builtin_bswap32(width);
|
||||||
height = __builtin_bswap32(height);
|
height = __builtin_bswap32(height);
|
||||||
|
|
||||||
@ -283,23 +283,23 @@ void png_read_geometry(FIL *fp, image_t *img, const char *path, png_read_setting
|
|||||||
img->size = rs->png_size;
|
img->size = rs->png_size;
|
||||||
img->pixfmt = PIXFORMAT_PNG;
|
img->pixfmt = PIXFORMAT_PNG;
|
||||||
} else {
|
} else {
|
||||||
ff_file_corrupted(fp);
|
file_raise_corrupted(fp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This function reads the pixel values of an image.
|
// This function reads the pixel values of an image.
|
||||||
void png_read_pixels(FIL *fp, image_t *img) {
|
void png_read_pixels(FIL *fp, image_t *img) {
|
||||||
file_seek(fp, 0);
|
file_seek(fp, 0);
|
||||||
read_data(fp, img->pixels, img->size);
|
file_read(fp, img->pixels, img->size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void png_read(image_t *img, const char *path) {
|
void png_read(image_t *img, const char *path) {
|
||||||
FIL fp;
|
FIL fp;
|
||||||
png_read_settings_t rs;
|
png_read_settings_t rs;
|
||||||
|
|
||||||
file_read_open(&fp, path);
|
// Do not use file buferring here.
|
||||||
|
file_open(&fp, path, false, FA_READ | FA_OPEN_EXISTING);
|
||||||
|
|
||||||
// Do not use file_buffer_on() here.
|
|
||||||
png_read_geometry(&fp, img, path, &rs);
|
png_read_geometry(&fp, img, path, &rs);
|
||||||
|
|
||||||
if (!img->pixels) {
|
if (!img->pixels) {
|
||||||
@ -312,13 +312,13 @@ void png_read(image_t *img, const char *path) {
|
|||||||
|
|
||||||
void png_write(image_t *img, const char *path) {
|
void png_write(image_t *img, const char *path) {
|
||||||
FIL fp;
|
FIL fp;
|
||||||
file_write_open(&fp, path);
|
file_open(&fp, path, false, FA_WRITE | FA_CREATE_ALWAYS);
|
||||||
if (img->pixfmt == PIXFORMAT_PNG) {
|
if (img->pixfmt == PIXFORMAT_PNG) {
|
||||||
write_data(&fp, img->pixels, img->size);
|
file_write(&fp, img->pixels, img->size);
|
||||||
} else {
|
} else {
|
||||||
image_t out = { .w = img->w, .h = img->h, .pixfmt = PIXFORMAT_PNG, .size = 0, .pixels = NULL }; // alloc in png compress
|
image_t out = { .w = img->w, .h = img->h, .pixfmt = PIXFORMAT_PNG, .size = 0, .pixels = NULL }; // alloc in png compress
|
||||||
png_compress(img, &out);
|
png_compress(img, &out);
|
||||||
write_data(&fp, out.pixels, out.size);
|
file_write(&fp, out.pixels, out.size);
|
||||||
fb_free(); // frees alloc in png_compress()
|
fb_free(); // frees alloc in png_compress()
|
||||||
}
|
}
|
||||||
file_close(&fp);
|
file_close(&fp);
|
||||||
|
|||||||
@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
#include "xalloc.h"
|
#include "xalloc.h"
|
||||||
#include "imlib.h"
|
#include "imlib.h"
|
||||||
#include "ff_wrapper.h"
|
#include "file_utils.h"
|
||||||
|
|
||||||
static void read_int_reset(ppm_read_settings_t *rs) {
|
static void read_int_reset(ppm_read_settings_t *rs) {
|
||||||
rs->read_int_c_valid = false;
|
rs->read_int_c_valid = false;
|
||||||
@ -31,10 +31,10 @@ static void read_int(FIL *fp, uint32_t *i, ppm_read_settings_t *rs) {
|
|||||||
mode = EAT_WHITESPACE;
|
mode = EAT_WHITESPACE;
|
||||||
for (*i = 0;;) {
|
for (*i = 0;;) {
|
||||||
if (!rs->read_int_c_valid) {
|
if (!rs->read_int_c_valid) {
|
||||||
if (file_tell_w_buf(fp) == file_size_w_buf(fp)) {
|
if (file_tell(fp) == file_size(fp)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
read_byte(fp, &rs->read_int_c);
|
file_read(fp, &rs->read_int_c, 1);
|
||||||
rs->read_int_c_valid = true;
|
rs->read_int_c_valid = true;
|
||||||
}
|
}
|
||||||
if (mode == EAT_WHITESPACE) {
|
if (mode == EAT_WHITESPACE) {
|
||||||
@ -62,11 +62,11 @@ static void read_int(FIL *fp, uint32_t *i, ppm_read_settings_t *rs) {
|
|||||||
// This function inits the geometry values of an image.
|
// This function inits the geometry values of an image.
|
||||||
void ppm_read_geometry(FIL *fp, image_t *img, const char *path, ppm_read_settings_t *rs) {
|
void ppm_read_geometry(FIL *fp, image_t *img, const char *path, ppm_read_settings_t *rs) {
|
||||||
read_int_reset(rs);
|
read_int_reset(rs);
|
||||||
read_byte_expect(fp, 'P');
|
file_read_check(fp, "P", 1);
|
||||||
read_byte(fp, &rs->ppm_fmt);
|
file_read(fp, &rs->ppm_fmt, 1);
|
||||||
|
|
||||||
if ((rs->ppm_fmt != '2') && (rs->ppm_fmt != '3') && (rs->ppm_fmt != '5') && (rs->ppm_fmt != '6')) {
|
if ((rs->ppm_fmt != '2') && (rs->ppm_fmt != '3') && (rs->ppm_fmt != '5') && (rs->ppm_fmt != '6')) {
|
||||||
ff_unsupported_format(fp);
|
file_raise_format(fp);
|
||||||
}
|
}
|
||||||
|
|
||||||
img->pixfmt = ((rs->ppm_fmt == '2') || (rs->ppm_fmt == '5')) ? PIXFORMAT_GRAYSCALE : PIXFORMAT_RGB565;
|
img->pixfmt = ((rs->ppm_fmt == '2') || (rs->ppm_fmt == '5')) ? PIXFORMAT_GRAYSCALE : PIXFORMAT_RGB565;
|
||||||
@ -75,13 +75,13 @@ void ppm_read_geometry(FIL *fp, image_t *img, const char *path, ppm_read_setting
|
|||||||
read_int(fp, (uint32_t *) &img->h, rs);
|
read_int(fp, (uint32_t *) &img->h, rs);
|
||||||
|
|
||||||
if ((img->w == 0) || (img->h == 0)) {
|
if ((img->w == 0) || (img->h == 0)) {
|
||||||
ff_file_corrupted(fp);
|
file_raise_corrupted(fp);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t max;
|
uint32_t max;
|
||||||
read_int(fp, &max, rs);
|
read_int(fp, &max, rs);
|
||||||
if (max != 255) {
|
if (max != 255) {
|
||||||
ff_unsupported_format(fp);
|
file_raise_format(fp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,14 +106,14 @@ void ppm_read_pixels(FIL *fp, image_t *img, int n_lines, ppm_read_settings_t *rs
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (rs->ppm_fmt == '5') {
|
} else if (rs->ppm_fmt == '5') {
|
||||||
read_data(fp, img->pixels, n_lines * img->w);
|
file_read(fp, img->pixels, n_lines * img->w);
|
||||||
} else if (rs->ppm_fmt == '6') {
|
} else if (rs->ppm_fmt == '6') {
|
||||||
for (int i = 0; i < n_lines; i++) {
|
for (int i = 0; i < n_lines; 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);
|
file_read(fp, &r, 1);
|
||||||
read_byte(fp, &g);
|
file_read(fp, &g, 1);
|
||||||
read_byte(fp, &b);
|
file_read(fp, &b, 1);
|
||||||
IM_SET_RGB565_PIXEL(img, j, i, COLOR_R8_G8_B8_TO_RGB565(r, g, b));
|
IM_SET_RGB565_PIXEL(img, j, i, COLOR_R8_G8_B8_TO_RGB565(r, g, b));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -124,16 +124,13 @@ void ppm_read(image_t *img, const char *path) {
|
|||||||
FIL fp;
|
FIL fp;
|
||||||
ppm_read_settings_t rs;
|
ppm_read_settings_t rs;
|
||||||
|
|
||||||
file_read_open(&fp, path);
|
file_open(&fp, path, true, FA_READ | FA_OPEN_EXISTING);
|
||||||
file_buffer_on(&fp);
|
|
||||||
ppm_read_geometry(&fp, img, path, &rs);
|
ppm_read_geometry(&fp, img, path, &rs);
|
||||||
|
|
||||||
if (!img->pixels) {
|
if (!img->pixels) {
|
||||||
img->pixels = xalloc(img->w * img->h * img->bpp);
|
img->pixels = xalloc(img->w * img->h * img->bpp);
|
||||||
}
|
}
|
||||||
ppm_read_pixels(&fp, img, img->h, &rs);
|
ppm_read_pixels(&fp, img, img->h, &rs);
|
||||||
|
|
||||||
file_buffer_off(&fp);
|
|
||||||
file_close(&fp);
|
file_close(&fp);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -144,25 +141,23 @@ void ppm_write_subimg(image_t *img, const char *path, rectangle_t *r) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
FIL fp;
|
FIL fp;
|
||||||
file_write_open(&fp, path);
|
file_open(&fp, path, true, FA_WRITE | FA_CREATE_ALWAYS);
|
||||||
file_buffer_on(&fp);
|
|
||||||
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);
|
file_write(&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!
|
file_write(&fp, img->pixels + (rect.y * img->w), rect.w * rect.h);
|
||||||
img->pixels + (rect.y * img->w),
|
|
||||||
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);
|
file_write(&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);
|
file_write(&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));
|
||||||
@ -170,12 +165,10 @@ void ppm_write_subimg(image_t *img, const char *path, rectangle_t *r) {
|
|||||||
buff[0] = COLOR_RGB565_TO_R8(pixel);
|
buff[0] = COLOR_RGB565_TO_R8(pixel);
|
||||||
buff[1] = COLOR_RGB565_TO_G8(pixel);
|
buff[1] = COLOR_RGB565_TO_G8(pixel);
|
||||||
buff[2] = COLOR_RGB565_TO_B8(pixel);
|
buff[2] = COLOR_RGB565_TO_B8(pixel);
|
||||||
write_data(&fp, buff, 3);
|
file_write(&fp, buff, 3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
file_buffer_off(&fp);
|
|
||||||
|
|
||||||
file_close(&fp);
|
file_close(&fp);
|
||||||
}
|
}
|
||||||
#endif //IMLIB_ENABLE_IMAGE_FILE_IO
|
#endif //IMLIB_ENABLE_IMAGE_FILE_IO
|
||||||
|
|||||||
@ -11,7 +11,7 @@
|
|||||||
#include "py/mphal.h"
|
#include "py/mphal.h"
|
||||||
#include "py/runtime.h"
|
#include "py/runtime.h"
|
||||||
|
|
||||||
#include "ff_wrapper.h"
|
#include "file_utils.h"
|
||||||
#include "framebuffer.h"
|
#include "framebuffer.h"
|
||||||
#include "imlib.h"
|
#include "imlib.h"
|
||||||
#include "py_assert.h"
|
#include "py_assert.h"
|
||||||
@ -40,7 +40,7 @@ static mp_obj_t py_gif_open(uint n_args, const mp_obj_t *args, mp_map_t *kw_args
|
|||||||
gif->base.type = &py_gif_type;
|
gif->base.type = &py_gif_type;
|
||||||
|
|
||||||
#if defined(IMLIB_ENABLE_IMAGE_FILE_IO)
|
#if defined(IMLIB_ENABLE_IMAGE_FILE_IO)
|
||||||
file_write_open(&gif->fp, mp_obj_str_get_str(args[0]));
|
file_open(&gif->fp, mp_obj_str_get_str(args[0]), false, FA_WRITE | FA_CREATE_ALWAYS);
|
||||||
gif_open(&gif->fp, gif->width, gif->height, gif->color, gif->loop);
|
gif_open(&gif->fp, gif->width, gif->height, gif->color, gif->loop);
|
||||||
#else
|
#else
|
||||||
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Image I/O is not supported"));
|
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Image I/O is not supported"));
|
||||||
@ -66,7 +66,7 @@ static mp_obj_t py_gif_format(mp_obj_t gif_obj) {
|
|||||||
static mp_obj_t py_gif_size(mp_obj_t gif_obj) {
|
static mp_obj_t py_gif_size(mp_obj_t gif_obj) {
|
||||||
#if defined(IMLIB_ENABLE_IMAGE_FILE_IO)
|
#if defined(IMLIB_ENABLE_IMAGE_FILE_IO)
|
||||||
py_gif_obj_t *arg_gif = gif_obj;
|
py_gif_obj_t *arg_gif = gif_obj;
|
||||||
return mp_obj_new_int(file_size_w_buf(&arg_gif->fp));
|
return mp_obj_new_int(file_size(&arg_gif->fp));
|
||||||
#else
|
#else
|
||||||
return mp_obj_new_int(0);
|
return mp_obj_new_int(0);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -23,7 +23,7 @@
|
|||||||
|
|
||||||
#include "imlib.h"
|
#include "imlib.h"
|
||||||
#include "array.h"
|
#include "array.h"
|
||||||
#include "ff_wrapper.h"
|
#include "file_utils.h"
|
||||||
#include "xalloc.h"
|
#include "xalloc.h"
|
||||||
#include "fb_alloc.h"
|
#include "fb_alloc.h"
|
||||||
#include "framebuffer.h"
|
#include "framebuffer.h"
|
||||||
@ -6892,7 +6892,6 @@ mp_obj_t py_image_load_image(uint n_args, const mp_obj_t *pos_args, mp_map_t *kw
|
|||||||
|
|
||||||
fb_alloc_mark();
|
fb_alloc_mark();
|
||||||
imlib_read_geometry(&fp, &image, path, &rs);
|
imlib_read_geometry(&fp, &image, path, &rs);
|
||||||
file_buffer_off(&fp);
|
|
||||||
file_close(&fp);
|
file_close(&fp);
|
||||||
|
|
||||||
if (args[ARG_copy_to_fb].u_bool) {
|
if (args[ARG_copy_to_fb].u_bool) {
|
||||||
@ -6980,59 +6979,54 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_load_cascade_obj, 1, py_image_load_ca
|
|||||||
#if defined(IMLIB_ENABLE_IMAGE_FILE_IO)
|
#if defined(IMLIB_ENABLE_IMAGE_FILE_IO)
|
||||||
mp_obj_t py_image_load_descriptor(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) {
|
mp_obj_t py_image_load_descriptor(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) {
|
||||||
FIL fp;
|
FIL fp;
|
||||||
UINT bytes;
|
FRESULT res = FR_OK;
|
||||||
FRESULT res;
|
|
||||||
|
|
||||||
uint32_t desc_type;
|
uint32_t desc_type;
|
||||||
mp_obj_t desc = mp_const_none;
|
mp_obj_t desc = mp_const_none;
|
||||||
const char *path = mp_obj_str_get_str(args[0]);
|
const char *path = mp_obj_str_get_str(args[0]);
|
||||||
|
|
||||||
if ((res = f_open_helper(&fp, path, FA_READ | FA_OPEN_EXISTING)) == FR_OK) {
|
file_open(&fp, path, false, FA_READ | FA_OPEN_EXISTING);
|
||||||
// Read descriptor type
|
|
||||||
res = f_read(&fp, &desc_type, sizeof(desc_type), &bytes);
|
|
||||||
if (res != FR_OK || bytes != sizeof(desc_type)) {
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load descriptor
|
// Read descriptor type
|
||||||
switch (desc_type) {
|
file_read(&fp, &desc_type, sizeof(desc_type));
|
||||||
#if defined(IMLIB_ENABLE_FIND_LBP)
|
|
||||||
case DESC_LBP: {
|
|
||||||
py_lbp_obj_t *lbp = m_new_obj(py_lbp_obj_t);
|
|
||||||
lbp->base.type = &py_lbp_type;
|
|
||||||
|
|
||||||
res = imlib_lbp_desc_load(&fp, &lbp->hist);
|
// Load descriptor
|
||||||
if (res == FR_OK) {
|
switch (desc_type) {
|
||||||
desc = lbp;
|
#if defined(IMLIB_ENABLE_FIND_LBP)
|
||||||
}
|
case DESC_LBP: {
|
||||||
break;
|
py_lbp_obj_t *lbp = m_new_obj(py_lbp_obj_t);
|
||||||
|
lbp->base.type = &py_lbp_type;
|
||||||
|
|
||||||
|
res = imlib_lbp_desc_load(&fp, &lbp->hist);
|
||||||
|
if (res == FR_OK) {
|
||||||
|
desc = lbp;
|
||||||
}
|
}
|
||||||
#endif //IMLIB_ENABLE_FIND_LBP
|
break;
|
||||||
#if defined(IMLIB_ENABLE_FIND_KEYPOINTS)
|
|
||||||
case DESC_ORB: {
|
|
||||||
array_t *kpts = NULL;
|
|
||||||
array_alloc(&kpts, xfree);
|
|
||||||
|
|
||||||
res = orb_load_descriptor(&fp, kpts);
|
|
||||||
if (res == FR_OK) {
|
|
||||||
// Return keypoints MP object
|
|
||||||
py_kp_obj_t *kp_obj = m_new_obj(py_kp_obj_t);
|
|
||||||
kp_obj->base.type = &py_kp_type;
|
|
||||||
kp_obj->kpts = kpts;
|
|
||||||
kp_obj->threshold = 10;
|
|
||||||
kp_obj->normalized = false;
|
|
||||||
desc = kp_obj;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
#endif //IMLIB_ENABLE_FIND_KEYPOINTS
|
|
||||||
}
|
}
|
||||||
|
#endif //IMLIB_ENABLE_FIND_LBP
|
||||||
|
#if defined(IMLIB_ENABLE_FIND_KEYPOINTS)
|
||||||
|
case DESC_ORB: {
|
||||||
|
array_t *kpts = NULL;
|
||||||
|
array_alloc(&kpts, xfree);
|
||||||
|
|
||||||
f_close(&fp);
|
res = orb_load_descriptor(&fp, kpts);
|
||||||
|
if (res == FR_OK) {
|
||||||
|
// Return keypoints MP object
|
||||||
|
py_kp_obj_t *kp_obj = m_new_obj(py_kp_obj_t);
|
||||||
|
kp_obj->base.type = &py_kp_type;
|
||||||
|
kp_obj->kpts = kpts;
|
||||||
|
kp_obj->threshold = 10;
|
||||||
|
kp_obj->normalized = false;
|
||||||
|
desc = kp_obj;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif //IMLIB_ENABLE_FIND_KEYPOINTS
|
||||||
}
|
}
|
||||||
|
|
||||||
error:
|
file_close(&fp);
|
||||||
// File open or write error
|
|
||||||
|
// File read error
|
||||||
if (res != FR_OK) {
|
if (res != FR_OK) {
|
||||||
mp_raise_msg(&mp_type_OSError, (mp_rom_error_text_t) ffs_strerror(res));
|
mp_raise_msg(&mp_type_OSError, (mp_rom_error_text_t) ffs_strerror(res));
|
||||||
}
|
}
|
||||||
@ -7047,58 +7041,54 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_load_descriptor_obj, 1, py_image_load
|
|||||||
|
|
||||||
mp_obj_t py_image_save_descriptor(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) {
|
mp_obj_t py_image_save_descriptor(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) {
|
||||||
FIL fp;
|
FIL fp;
|
||||||
UINT bytes;
|
FRESULT res = FR_OK;
|
||||||
FRESULT res;
|
|
||||||
|
|
||||||
uint32_t desc_type;
|
uint32_t desc_type;
|
||||||
const char *path = mp_obj_str_get_str(args[1]);
|
const char *path = mp_obj_str_get_str(args[1]);
|
||||||
|
|
||||||
if ((res = f_open_helper(&fp, path, FA_WRITE | FA_CREATE_ALWAYS)) == FR_OK) {
|
file_open(&fp, path, false, FA_WRITE | FA_CREATE_ALWAYS);
|
||||||
// Find descriptor type
|
|
||||||
const mp_obj_type_t *desc_obj_type = mp_obj_get_type(args[0]);
|
|
||||||
if (0) {
|
|
||||||
#if defined(IMLIB_ENABLE_FIND_LBP)
|
|
||||||
} else if (desc_obj_type == &py_lbp_type) {
|
|
||||||
desc_type = DESC_LBP;
|
|
||||||
#endif //IMLIB_ENABLE_FIND_LBP
|
|
||||||
#if defined(IMLIB_ENABLE_FIND_KEYPOINTS)
|
|
||||||
} else if (desc_obj_type == &py_kp_type) {
|
|
||||||
desc_type = DESC_ORB;
|
|
||||||
#endif //IMLIB_ENABLE_FIND_KEYPOINTS
|
|
||||||
} else {
|
|
||||||
(void) desc_obj_type;
|
|
||||||
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Descriptor type is not supported"));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write descriptor type
|
// Find descriptor type
|
||||||
res = f_write(&fp, &desc_type, sizeof(desc_type), &bytes);
|
const mp_obj_type_t *desc_obj_type = mp_obj_get_type(args[0]);
|
||||||
if (res != FR_OK || bytes != sizeof(desc_type)) {
|
if (0) {
|
||||||
goto error;
|
#if defined(IMLIB_ENABLE_FIND_LBP)
|
||||||
}
|
} else if (desc_obj_type == &py_lbp_type) {
|
||||||
|
desc_type = DESC_LBP;
|
||||||
// Write descriptor
|
#endif //IMLIB_ENABLE_FIND_LBP
|
||||||
switch (desc_type) {
|
#if defined(IMLIB_ENABLE_FIND_KEYPOINTS)
|
||||||
#if defined(IMLIB_ENABLE_FIND_LBP)
|
} else if (desc_obj_type == &py_kp_type) {
|
||||||
case DESC_LBP: {
|
desc_type = DESC_ORB;
|
||||||
py_lbp_obj_t *lbp = ((py_lbp_obj_t *) args[0]);
|
#endif //IMLIB_ENABLE_FIND_KEYPOINTS
|
||||||
res = imlib_lbp_desc_save(&fp, lbp->hist);
|
} else {
|
||||||
break;
|
(void) desc_obj_type;
|
||||||
}
|
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Descriptor type is not supported"));
|
||||||
#endif //IMLIB_ENABLE_FIND_LBP
|
|
||||||
#if defined(IMLIB_ENABLE_FIND_KEYPOINTS)
|
|
||||||
case DESC_ORB: {
|
|
||||||
py_kp_obj_t *kpts = ((py_kp_obj_t *) args[0]);
|
|
||||||
res = orb_save_descriptor(&fp, kpts->kpts);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
#endif //IMLIB_ENABLE_FIND_KEYPOINTS
|
|
||||||
}
|
|
||||||
// ignore unsupported descriptors when saving
|
|
||||||
f_close(&fp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
error:
|
// Write descriptor type
|
||||||
// File open or read error
|
file_write(&fp, &desc_type, sizeof(desc_type));
|
||||||
|
|
||||||
|
// Write descriptor
|
||||||
|
switch (desc_type) {
|
||||||
|
#if defined(IMLIB_ENABLE_FIND_LBP)
|
||||||
|
case DESC_LBP: {
|
||||||
|
py_lbp_obj_t *lbp = ((py_lbp_obj_t *) args[0]);
|
||||||
|
res = imlib_lbp_desc_save(&fp, lbp->hist);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif //IMLIB_ENABLE_FIND_LBP
|
||||||
|
#if defined(IMLIB_ENABLE_FIND_KEYPOINTS)
|
||||||
|
case DESC_ORB: {
|
||||||
|
py_kp_obj_t *kpts = ((py_kp_obj_t *) args[0]);
|
||||||
|
res = orb_save_descriptor(&fp, kpts->kpts);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif //IMLIB_ENABLE_FIND_KEYPOINTS
|
||||||
|
}
|
||||||
|
|
||||||
|
// ignore unsupported descriptors when saving
|
||||||
|
file_close(&fp);
|
||||||
|
|
||||||
|
// File write error
|
||||||
if (res != FR_OK) {
|
if (res != FR_OK) {
|
||||||
mp_raise_msg(&mp_type_OSError, (mp_rom_error_text_t) ffs_strerror(res));
|
mp_raise_msg(&mp_type_OSError, (mp_rom_error_text_t) ffs_strerror(res));
|
||||||
}
|
}
|
||||||
@ -7194,18 +7184,12 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_match_descriptor_obj, 2, py_image_mat
|
|||||||
#if defined(IMLIB_ENABLE_FIND_KEYPOINTS) && defined(IMLIB_ENABLE_IMAGE_FILE_IO)
|
#if defined(IMLIB_ENABLE_FIND_KEYPOINTS) && defined(IMLIB_ENABLE_IMAGE_FILE_IO)
|
||||||
int py_image_descriptor_from_roi(image_t *img, const char *path, rectangle_t *roi) {
|
int py_image_descriptor_from_roi(image_t *img, const char *path, rectangle_t *roi) {
|
||||||
FIL fp;
|
FIL fp;
|
||||||
FRESULT res = FR_OK;
|
|
||||||
|
|
||||||
printf("Save Descriptor: ROI(%d %d %d %d)\n", roi->x, roi->y, roi->w, roi->h);
|
|
||||||
array_t *kpts = orb_find_keypoints(img, false, 20, 1.5f, 100, CORNER_AGAST, roi);
|
array_t *kpts = orb_find_keypoints(img, false, 20, 1.5f, 100, CORNER_AGAST, roi);
|
||||||
printf("Save Descriptor: KPTS(%d)\n", array_length(kpts));
|
|
||||||
|
|
||||||
if (array_length(kpts)) {
|
if (array_length(kpts)) {
|
||||||
if ((res = f_open_helper(&fp, path, FA_WRITE | FA_CREATE_ALWAYS)) == FR_OK) {
|
file_open(&fp, path, false, FA_WRITE | FA_CREATE_ALWAYS);
|
||||||
res = orb_save_descriptor(&fp, kpts);
|
FRESULT res = orb_save_descriptor(&fp, kpts);
|
||||||
f_close(&fp);
|
file_close(&fp);
|
||||||
}
|
// File write error
|
||||||
// File open/write error
|
|
||||||
if (res != FR_OK) {
|
if (res != FR_OK) {
|
||||||
mp_raise_msg(&mp_type_OSError, (mp_rom_error_text_t) ffs_strerror(res));
|
mp_raise_msg(&mp_type_OSError, (mp_rom_error_text_t) ffs_strerror(res));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -22,7 +22,7 @@
|
|||||||
#include "py_imageio.h"
|
#include "py_imageio.h"
|
||||||
|
|
||||||
#if defined(IMLIB_ENABLE_IMAGE_FILE_IO)
|
#if defined(IMLIB_ENABLE_IMAGE_FILE_IO)
|
||||||
#include "ff_wrapper.h"
|
#include "file_utils.h"
|
||||||
#endif
|
#endif
|
||||||
#include "framebuffer.h"
|
#include "framebuffer.h"
|
||||||
#include "omv_boardconfig.h"
|
#include "omv_boardconfig.h"
|
||||||
@ -182,37 +182,37 @@ STATIC mp_obj_t py_imageio_write(mp_obj_t self, mp_obj_t img_obj) {
|
|||||||
} else if (stream->type == IMAGE_IO_FILE_STREAM) {
|
} else if (stream->type == IMAGE_IO_FILE_STREAM) {
|
||||||
FIL *fp = &stream->fp;
|
FIL *fp = &stream->fp;
|
||||||
|
|
||||||
write_long(fp, elapsed_ms);
|
file_write_long(fp, elapsed_ms);
|
||||||
write_long(fp, image->w);
|
file_write_long(fp, image->w);
|
||||||
write_long(fp, image->h);
|
file_write_long(fp, image->h);
|
||||||
|
|
||||||
char padding[ALIGN_SIZE] = {};
|
char padding[ALIGN_SIZE] = {};
|
||||||
|
|
||||||
if (stream->version < NEW_PIXFORMAT_VER) {
|
if (stream->version < NEW_PIXFORMAT_VER) {
|
||||||
if (image->pixfmt == PIXFORMAT_BINARY) {
|
if (image->pixfmt == PIXFORMAT_BINARY) {
|
||||||
write_long(fp, OLD_BINARY_BPP);
|
file_write_long(fp, OLD_BINARY_BPP);
|
||||||
} else if (image->pixfmt == PIXFORMAT_GRAYSCALE) {
|
} else if (image->pixfmt == PIXFORMAT_GRAYSCALE) {
|
||||||
write_long(fp, OLD_GRAYSCALE_BPP);
|
file_write_long(fp, OLD_GRAYSCALE_BPP);
|
||||||
} else if (image->pixfmt == PIXFORMAT_RGB565) {
|
} else if (image->pixfmt == PIXFORMAT_RGB565) {
|
||||||
write_long(fp, OLD_RGB565_BPP);
|
file_write_long(fp, OLD_RGB565_BPP);
|
||||||
} else if (image->pixfmt == PIXFORMAT_BAYER) {
|
} else if (image->pixfmt == PIXFORMAT_BAYER) {
|
||||||
write_long(fp, OLD_BAYER_BPP);
|
file_write_long(fp, OLD_BAYER_BPP);
|
||||||
} else if (image->pixfmt == PIXFORMAT_JPEG) {
|
} else if (image->pixfmt == PIXFORMAT_JPEG) {
|
||||||
write_long(fp, image->size);
|
file_write_long(fp, image->size);
|
||||||
} else {
|
} else {
|
||||||
mp_raise_msg(&mp_type_ValueError, MP_ERROR_TEXT("Invalid image stream bpp"));
|
mp_raise_msg(&mp_type_ValueError, MP_ERROR_TEXT("Invalid image stream bpp"));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
write_long(fp, image->pixfmt);
|
file_write_long(fp, image->pixfmt);
|
||||||
write_long(fp, image->size);
|
file_write_long(fp, image->size);
|
||||||
write_data(fp, padding, AFTER_SIZE_PADDING);
|
file_write(fp, padding, AFTER_SIZE_PADDING);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t size = image_size(image);
|
uint32_t size = image_size(image);
|
||||||
write_data(fp, image->data, size);
|
file_write(fp, image->data, size);
|
||||||
|
|
||||||
if (size % ALIGN_SIZE) {
|
if (size % ALIGN_SIZE) {
|
||||||
write_data(fp, padding, ALIGN_SIZE - (size % ALIGN_SIZE));
|
file_write(fp, padding, ALIGN_SIZE - (size % ALIGN_SIZE));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Seeking to the middle of a file and writing data corrupts the remainder of the file. So,
|
// Seeking to the middle of a file and writing data corrupts the remainder of the file. So,
|
||||||
@ -251,7 +251,7 @@ STATIC void int_py_imageio_pause(py_imageio_obj_t *stream, bool pause) {
|
|||||||
if (0) {
|
if (0) {
|
||||||
#if defined(IMLIB_ENABLE_IMAGE_FILE_IO)
|
#if defined(IMLIB_ENABLE_IMAGE_FILE_IO)
|
||||||
} else if (stream->type == IMAGE_IO_FILE_STREAM) {
|
} else if (stream->type == IMAGE_IO_FILE_STREAM) {
|
||||||
read_long(&stream->fp, &elapsed_ms);
|
file_read(&stream->fp, &elapsed_ms, 4);
|
||||||
#endif
|
#endif
|
||||||
} else if (stream->type == IMAGE_IO_MEMORY_STREAM) {
|
} else if (stream->type == IMAGE_IO_MEMORY_STREAM) {
|
||||||
elapsed_ms = *((uint32_t *) (stream->buffer + (stream->offset * stream->size)));
|
elapsed_ms = *((uint32_t *) (stream->buffer + (stream->offset * stream->size)));
|
||||||
@ -274,11 +274,11 @@ STATIC void int_py_imageio_read_chunk(py_imageio_obj_t *stream, image_t *image,
|
|||||||
|
|
||||||
int_py_imageio_pause(stream, pause);
|
int_py_imageio_pause(stream, pause);
|
||||||
|
|
||||||
read_long(fp, (uint32_t *) &image->w);
|
file_read(fp, &image->w, 4);
|
||||||
read_long(fp, (uint32_t *) &image->h);
|
file_read(fp, &image->h, 4);
|
||||||
|
|
||||||
uint32_t bpp;
|
uint32_t bpp;
|
||||||
read_long(fp, (uint32_t *) &bpp);
|
file_read(fp, &bpp, 4);
|
||||||
|
|
||||||
if (stream->version < NEW_PIXFORMAT_VER) {
|
if (stream->version < NEW_PIXFORMAT_VER) {
|
||||||
if (bpp < 0) {
|
if (bpp < 0) {
|
||||||
@ -300,10 +300,10 @@ STATIC void int_py_imageio_read_chunk(py_imageio_obj_t *stream, image_t *image,
|
|||||||
}
|
}
|
||||||
|
|
||||||
image->pixfmt = bpp;
|
image->pixfmt = bpp;
|
||||||
read_long(fp, (uint32_t *) &image->size);
|
file_read(fp, &image->size, 4);
|
||||||
|
|
||||||
char ignore[AFTER_SIZE_PADDING];
|
char ignore[AFTER_SIZE_PADDING];
|
||||||
read_data(fp, ignore, AFTER_SIZE_PADDING);
|
file_read(fp, ignore, AFTER_SIZE_PADDING);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -377,7 +377,7 @@ STATIC mp_obj_t py_imageio_read(uint n_args, const mp_obj_t *args, mp_map_t *kw_
|
|||||||
#if defined(IMLIB_ENABLE_IMAGE_FILE_IO)
|
#if defined(IMLIB_ENABLE_IMAGE_FILE_IO)
|
||||||
} else if (stream->type == IMAGE_IO_FILE_STREAM) {
|
} else if (stream->type == IMAGE_IO_FILE_STREAM) {
|
||||||
FIL *fp = &stream->fp;
|
FIL *fp = &stream->fp;
|
||||||
read_data(fp, image.data, size);
|
file_read(fp, image.data, size);
|
||||||
|
|
||||||
// Check if original byte reversed data.
|
// Check if original byte reversed data.
|
||||||
if ((image.pixfmt == PIXFORMAT_RGB565) && (stream->version == ORIGINAL_VER)) {
|
if ((image.pixfmt == PIXFORMAT_RGB565) && (stream->version == ORIGINAL_VER)) {
|
||||||
@ -395,7 +395,7 @@ STATIC mp_obj_t py_imageio_read(uint n_args, const mp_obj_t *args, mp_map_t *kw_
|
|||||||
|
|
||||||
if (size % ALIGN_SIZE) {
|
if (size % ALIGN_SIZE) {
|
||||||
char ignore[ALIGN_SIZE];
|
char ignore[ALIGN_SIZE];
|
||||||
read_data(fp, ignore, ALIGN_SIZE - (size % ALIGN_SIZE));
|
file_read(fp, ignore, ALIGN_SIZE - (size % ALIGN_SIZE));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stream->offset >= stream->count) {
|
if (stream->offset >= stream->count) {
|
||||||
@ -507,20 +507,20 @@ STATIC mp_obj_t py_imageio_make_new(const mp_obj_type_t *type, size_t n_args, si
|
|||||||
char mode = mp_obj_str_get_str(args[1])[0];
|
char mode = mp_obj_str_get_str(args[1])[0];
|
||||||
|
|
||||||
if ((mode == 'W') || (mode == 'w')) {
|
if ((mode == 'W') || (mode == 'w')) {
|
||||||
file_read_write_open_always(fp, mp_obj_str_get_str(args[0]));
|
file_open(fp, mp_obj_str_get_str(args[0]), false, FA_READ | FA_WRITE | FA_OPEN_ALWAYS);
|
||||||
const char string[] = "OMV IMG STR V2.0";
|
const char string[] = "OMV IMG STR V2.0";
|
||||||
stream->version = NEW_PIXFORMAT_VER;
|
stream->version = NEW_PIXFORMAT_VER;
|
||||||
|
|
||||||
// Overwrite if file is too small.
|
// Overwrite if file is too small.
|
||||||
if (f_size(fp) < MAGIC_SIZE) {
|
if (f_size(fp) < MAGIC_SIZE) {
|
||||||
write_data(fp, string, sizeof(string) - 1); // exclude null terminator
|
file_write(fp, string, sizeof(string) - 1); // exclude null terminator
|
||||||
} else {
|
} else {
|
||||||
uint8_t version_hi, period, version_lo;
|
uint8_t version_hi, period, version_lo;
|
||||||
char temp[sizeof(string) - 3] = {};
|
char temp[sizeof(string) - 3] = {};
|
||||||
read_data(fp, temp, sizeof(temp) - 1);
|
file_read(fp, temp, sizeof(temp) - 1);
|
||||||
read_byte(fp, &version_hi);
|
file_read(fp, &version_hi, 1);
|
||||||
read_byte(fp, &period);
|
file_read(fp, &period, 1);
|
||||||
read_byte(fp, &version_lo);
|
file_read(fp, &version_lo, 1);
|
||||||
int version = ((version_hi - '0') * 10) + (version_lo - '0');
|
int version = ((version_hi - '0') * 10) + (version_lo - '0');
|
||||||
|
|
||||||
// Overwrite if file magic does not match.
|
// Overwrite if file magic does not match.
|
||||||
@ -530,7 +530,7 @@ STATIC mp_obj_t py_imageio_make_new(const mp_obj_type_t *type, size_t n_args, si
|
|||||||
|| (version != RGB565_FIXED_VER)
|
|| (version != RGB565_FIXED_VER)
|
||||||
|| (version != NEW_PIXFORMAT_VER)) {
|
|| (version != NEW_PIXFORMAT_VER)) {
|
||||||
file_seek(fp, 0);
|
file_seek(fp, 0);
|
||||||
write_data(fp, string, sizeof(string) - 1); // exclude null terminator
|
file_write(fp, string, sizeof(string) - 1); // exclude null terminator
|
||||||
} else {
|
} else {
|
||||||
file_close(fp);
|
file_close(fp);
|
||||||
mode = 'R';
|
mode = 'R';
|
||||||
@ -540,14 +540,12 @@ STATIC mp_obj_t py_imageio_make_new(const mp_obj_type_t *type, size_t n_args, si
|
|||||||
|
|
||||||
if ((mode == 'R') || (mode == 'r')) {
|
if ((mode == 'R') || (mode == 'r')) {
|
||||||
uint8_t version_hi, version_lo;
|
uint8_t version_hi, version_lo;
|
||||||
file_read_write_open_existing(fp, mp_obj_str_get_str(args[0]));
|
file_open(fp, mp_obj_str_get_str(args[0]), false, FA_READ | FA_WRITE | FA_OPEN_EXISTING);
|
||||||
read_long_expect(fp, *((uint32_t *) "OMV ")); // OpenMV
|
file_read_check(fp, "OMV IMG STR ", 12); // Magic
|
||||||
read_long_expect(fp, *((uint32_t *) "IMG ")); // Image
|
file_read_check(fp, "V", 1);
|
||||||
read_long_expect(fp, *((uint32_t *) "STR ")); // Stream
|
file_read(fp, &version_hi, 1);
|
||||||
read_byte_expect(fp, 'V');
|
file_read_check(fp, ".", 1);
|
||||||
read_byte(fp, &version_hi);
|
file_read(fp, &version_lo, 1);
|
||||||
read_byte_expect(fp, '.');
|
|
||||||
read_byte(fp, &version_lo);
|
|
||||||
|
|
||||||
stream->version = ((version_hi - '0') * 10) + (version_lo - '0');
|
stream->version = ((version_hi - '0') * 10) + (version_lo - '0');
|
||||||
|
|
||||||
|
|||||||
@ -20,7 +20,7 @@
|
|||||||
#include "py_helper.h"
|
#include "py_helper.h"
|
||||||
#include "py_image.h"
|
#include "py_image.h"
|
||||||
|
|
||||||
#include "ff_wrapper.h"
|
#include "file_utils.h"
|
||||||
#include "framebuffer.h"
|
#include "framebuffer.h"
|
||||||
#include "omv_boardconfig.h"
|
#include "omv_boardconfig.h"
|
||||||
|
|
||||||
@ -144,7 +144,7 @@ STATIC mp_obj_t py_mjpeg_open(uint n_args, const mp_obj_t *args, mp_map_t *kw_ar
|
|||||||
mjpeg->height = py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_height), MAIN_FB()->h);
|
mjpeg->height = py_helper_keyword_int(n_args, args, 2, kw_args, MP_OBJ_NEW_QSTR(MP_QSTR_height), MAIN_FB()->h);
|
||||||
mjpeg->frames = 0;
|
mjpeg->frames = 0;
|
||||||
mjpeg->bytes = 0;
|
mjpeg->bytes = 0;
|
||||||
file_write_open(&mjpeg->fp, mp_obj_str_get_str(args[0]));
|
file_open(&mjpeg->fp, mp_obj_str_get_str(args[0]), false, FA_WRITE | FA_CREATE_ALWAYS);
|
||||||
mjpeg_open(&mjpeg->fp, mjpeg->width, mjpeg->height);
|
mjpeg_open(&mjpeg->fp, mjpeg->width, mjpeg->height);
|
||||||
return mjpeg;
|
return mjpeg;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -23,7 +23,7 @@
|
|||||||
|
|
||||||
#ifdef IMLIB_ENABLE_TF
|
#ifdef IMLIB_ENABLE_TF
|
||||||
#include "py_image.h"
|
#include "py_image.h"
|
||||||
#include "ff_wrapper.h"
|
#include "file_utils.h"
|
||||||
#include "py_tf.h"
|
#include "py_tf.h"
|
||||||
#include "libtf_builtin_models.h"
|
#include "libtf_builtin_models.h"
|
||||||
#define GRAYSCALE_RANGE ((COLOR_GRAYSCALE_MAX) -(COLOR_GRAYSCALE_MIN))
|
#define GRAYSCALE_RANGE ((COLOR_GRAYSCALE_MAX) -(COLOR_GRAYSCALE_MIN))
|
||||||
@ -178,12 +178,12 @@ STATIC mp_obj_t int_py_tf_load(mp_obj_t path_obj, bool alloc_mode, bool helper_m
|
|||||||
if (tf_model->model_data == NULL) {
|
if (tf_model->model_data == NULL) {
|
||||||
#if defined(IMLIB_ENABLE_IMAGE_FILE_IO)
|
#if defined(IMLIB_ENABLE_IMAGE_FILE_IO)
|
||||||
FIL fp;
|
FIL fp;
|
||||||
file_read_open(&fp, path);
|
file_open(&fp, path, false, FA_READ | FA_OPEN_EXISTING);
|
||||||
tf_model->model_data_len = f_size(&fp);
|
tf_model->model_data_len = f_size(&fp);
|
||||||
tf_model->model_data = alloc_mode
|
tf_model->model_data = alloc_mode
|
||||||
? fb_alloc(tf_model->model_data_len, FB_ALLOC_PREFER_SIZE)
|
? fb_alloc(tf_model->model_data_len, FB_ALLOC_PREFER_SIZE)
|
||||||
: xalloc(tf_model->model_data_len);
|
: xalloc(tf_model->model_data_len);
|
||||||
read_data(&fp, tf_model->model_data, tf_model->model_data_len);
|
file_read(&fp, tf_model->model_data, tf_model->model_data_len);
|
||||||
file_close(&fp);
|
file_close(&fp);
|
||||||
#else
|
#else
|
||||||
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Image I/O is not supported"));
|
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Image I/O is not supported"));
|
||||||
|
|||||||
@ -59,7 +59,7 @@
|
|||||||
#include "tinyusb_debug.h"
|
#include "tinyusb_debug.h"
|
||||||
#include "fb_alloc.h"
|
#include "fb_alloc.h"
|
||||||
#include "dma_alloc.h"
|
#include "dma_alloc.h"
|
||||||
#include "ff_wrapper.h"
|
#include "file_utils.h"
|
||||||
#include "mimxrt_hal.h"
|
#include "mimxrt_hal.h"
|
||||||
|
|
||||||
extern uint8_t _sstack, _estack, _heap_start, _heap_end;
|
extern uint8_t _sstack, _estack, _heap_start, _heap_end;
|
||||||
|
|||||||
@ -127,7 +127,7 @@ FIRM_OBJ += $(addprefix $(BUILD)/$(OMV_DIR)/alloc/, \
|
|||||||
|
|
||||||
FIRM_OBJ += $(addprefix $(BUILD)/$(OMV_DIR)/common/, \
|
FIRM_OBJ += $(addprefix $(BUILD)/$(OMV_DIR)/common/, \
|
||||||
array.o \
|
array.o \
|
||||||
ff_wrapper.o \
|
file_utils.o \
|
||||||
ini.o \
|
ini.o \
|
||||||
ringbuf.o \
|
ringbuf.o \
|
||||||
trace.o \
|
trace.o \
|
||||||
|
|||||||
@ -100,7 +100,7 @@ FIRM_OBJ += $(addprefix $(BUILD)/$(OMV_DIR)/alloc/, \
|
|||||||
|
|
||||||
FIRM_OBJ += $(addprefix $(BUILD)/$(OMV_DIR)/common/, \
|
FIRM_OBJ += $(addprefix $(BUILD)/$(OMV_DIR)/common/, \
|
||||||
array.o \
|
array.o \
|
||||||
ff_wrapper.o \
|
file_utils.o \
|
||||||
ini.o \
|
ini.o \
|
||||||
ringbuf.o \
|
ringbuf.o \
|
||||||
trace.o \
|
trace.o \
|
||||||
|
|||||||
@ -93,7 +93,7 @@ target_sources(${MICROPY_TARGET} PRIVATE
|
|||||||
${TOP_DIR}/${OMV_DIR}/alloc/unaligned_memcpy.c
|
${TOP_DIR}/${OMV_DIR}/alloc/unaligned_memcpy.c
|
||||||
|
|
||||||
${TOP_DIR}/${OMV_DIR}/common/array.c
|
${TOP_DIR}/${OMV_DIR}/common/array.c
|
||||||
${TOP_DIR}/${OMV_DIR}/common/ff_wrapper.c
|
${TOP_DIR}/${OMV_DIR}/common/file_utils.c
|
||||||
${TOP_DIR}/${OMV_DIR}/common/ini.c
|
${TOP_DIR}/${OMV_DIR}/common/ini.c
|
||||||
${TOP_DIR}/${OMV_DIR}/common/ringbuf.c
|
${TOP_DIR}/${OMV_DIR}/common/ringbuf.c
|
||||||
${TOP_DIR}/${OMV_DIR}/common/trace.c
|
${TOP_DIR}/${OMV_DIR}/common/trace.c
|
||||||
|
|||||||
@ -11,10 +11,10 @@
|
|||||||
#if (OMV_ENABLE_HASH == 1)
|
#if (OMV_ENABLE_HASH == 1)
|
||||||
#include STM32_HAL_H
|
#include STM32_HAL_H
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <ff_wrapper.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include "fb_alloc.h"
|
|
||||||
#include "hash.h"
|
#include "hash.h"
|
||||||
|
#include "fb_alloc.h"
|
||||||
|
#include "file_utils.h"
|
||||||
|
|
||||||
#define BLOCK_SIZE (512)
|
#define BLOCK_SIZE (512)
|
||||||
static HASH_HandleTypeDef hhash;
|
static HASH_HandleTypeDef hhash;
|
||||||
@ -56,7 +56,7 @@ int hash_from_file(const char *path, uint8_t *digest) {
|
|||||||
int ret = -1;
|
int ret = -1;
|
||||||
uint8_t *buf = fb_alloc(BLOCK_SIZE, FB_ALLOC_NO_HINT);
|
uint8_t *buf = fb_alloc(BLOCK_SIZE, FB_ALLOC_NO_HINT);
|
||||||
|
|
||||||
if (f_open_helper(&fp, path, FA_READ | FA_OPEN_EXISTING) != FR_OK) {
|
if (file_ll_open(&fp, path, FA_READ | FA_OPEN_EXISTING) != FR_OK) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,7 +66,7 @@ int hash_from_file(const char *path, uint8_t *digest) {
|
|||||||
while (size) {
|
while (size) {
|
||||||
// Read a block.
|
// Read a block.
|
||||||
bytes = MIN(size, BLOCK_SIZE);
|
bytes = MIN(size, BLOCK_SIZE);
|
||||||
if (f_read(&fp, buf, bytes, &bytes_out) != FR_OK || bytes != bytes_out) {
|
if (file_ll_read(&fp, buf, bytes, &bytes_out) != FR_OK || bytes != bytes_out) {
|
||||||
printf("hash_from_file: file read error!\n");
|
printf("hash_from_file: file read error!\n");
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
@ -92,7 +92,7 @@ int hash_from_file(const char *path, uint8_t *digest) {
|
|||||||
|
|
||||||
error:
|
error:
|
||||||
fb_free();
|
fb_free();
|
||||||
f_close(&fp);
|
file_ll_close(&fp);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
#endif //OMV_ENABLE_HASH == 1
|
#endif //OMV_ENABLE_HASH == 1
|
||||||
|
|||||||
@ -33,7 +33,6 @@
|
|||||||
#include "rtc.h"
|
#include "rtc.h"
|
||||||
#include "storage.h"
|
#include "storage.h"
|
||||||
#include "sdcard.h"
|
#include "sdcard.h"
|
||||||
#include "ff.h"
|
|
||||||
#include "extmod/modnetwork.h"
|
#include "extmod/modnetwork.h"
|
||||||
#include "modmachine.h"
|
#include "modmachine.h"
|
||||||
|
|
||||||
@ -59,7 +58,7 @@
|
|||||||
#include "sdram.h"
|
#include "sdram.h"
|
||||||
#include "fb_alloc.h"
|
#include "fb_alloc.h"
|
||||||
#include "dma_alloc.h"
|
#include "dma_alloc.h"
|
||||||
#include "ff_wrapper.h"
|
#include "file_utils.h"
|
||||||
|
|
||||||
#include "usbd_core.h"
|
#include "usbd_core.h"
|
||||||
#include "usbd_desc.h"
|
#include "usbd_desc.h"
|
||||||
@ -124,9 +123,9 @@ void NORETURN __fatal_error(const char *msg) {
|
|||||||
FA_WRITE | FA_CREATE_ALWAYS) == FR_OK) {
|
FA_WRITE | FA_CREATE_ALWAYS) == FR_OK) {
|
||||||
UINT bytes;
|
UINT bytes;
|
||||||
const char *hdr = "FATAL ERROR:\n";
|
const char *hdr = "FATAL ERROR:\n";
|
||||||
f_write(&fp, hdr, strlen(hdr), &bytes);
|
file_ll_write(&fp, hdr, strlen(hdr), &bytes);
|
||||||
f_write(&fp, msg, strlen(msg), &bytes);
|
file_ll_write(&fp, msg, strlen(msg), &bytes);
|
||||||
f_close(&fp);
|
file_ll_close(&fp);
|
||||||
storage_flush();
|
storage_flush();
|
||||||
// Initialize the USB device if it's not already initialize to allow
|
// Initialize the USB device if it's not already initialize to allow
|
||||||
// the host to mount the filesystem and access the error log.
|
// the host to mount the filesystem and access the error log.
|
||||||
@ -234,7 +233,7 @@ FRESULT exec_boot_script(const char *path, bool selftest, bool interruptible, bo
|
|||||||
// Try to run the frozen module first.
|
// Try to run the frozen module first.
|
||||||
if (pyexec_frozen_module(path, true) == false) {
|
if (pyexec_frozen_module(path, true) == false) {
|
||||||
// No frozen module, try the filesystem.
|
// No frozen module, try the filesystem.
|
||||||
f_res = f_stat(&vfs_fat->fatfs, path, NULL);
|
f_res = file_ll_stat(path, NULL);
|
||||||
if (f_res == FR_OK) {
|
if (f_res == FR_OK) {
|
||||||
// Parse, compile and execute the script.
|
// Parse, compile and execute the script.
|
||||||
pyexec_file(path, true);
|
pyexec_file(path, true);
|
||||||
@ -270,7 +269,7 @@ FRESULT exec_boot_script(const char *path, bool selftest, bool interruptible, bo
|
|||||||
|
|
||||||
if (selftest && f_res == FR_OK) {
|
if (selftest && f_res == FR_OK) {
|
||||||
// Remove self tests script and flush cache
|
// Remove self tests script and flush cache
|
||||||
f_unlink(&vfs_fat->fatfs, path);
|
file_ll_unlink(path);
|
||||||
storage_flush();
|
storage_flush();
|
||||||
|
|
||||||
#ifdef OMV_SELF_TEST_SWD_ADDR
|
#ifdef OMV_SELF_TEST_SWD_ADDR
|
||||||
@ -507,7 +506,7 @@ else {
|
|||||||
MP_STATE_PORT(vfs_cur) = vfs;
|
MP_STATE_PORT(vfs_cur) = vfs;
|
||||||
|
|
||||||
// Mark FS as OpenMV disk.
|
// Mark FS as OpenMV disk.
|
||||||
f_touch_helper("/.openmv_disk");
|
file_ll_touch("/.openmv_disk");
|
||||||
|
|
||||||
// Parse OpenMV configuration file.
|
// Parse OpenMV configuration file.
|
||||||
openmv_config_t openmv_config;
|
openmv_config_t openmv_config;
|
||||||
|
|||||||
@ -24,7 +24,7 @@
|
|||||||
#include "genhdr/pins.h"
|
#include "genhdr/pins.h"
|
||||||
#include "omv_common.h"
|
#include "omv_common.h"
|
||||||
#include "py_helper.h"
|
#include "py_helper.h"
|
||||||
#include "ff_wrapper.h"
|
#include "file_utils.h"
|
||||||
|
|
||||||
#include "winc.h"
|
#include "winc.h"
|
||||||
#include "socket/include/socket.h"
|
#include "socket/include/socket.h"
|
||||||
@ -325,7 +325,7 @@ static mp_obj_t py_winc_fw_update(mp_obj_t self_in, mp_obj_t path_in) {
|
|||||||
FILINFO fno;
|
FILINFO fno;
|
||||||
const char *path = mp_obj_str_get_str(path_in);
|
const char *path = mp_obj_str_get_str(path_in);
|
||||||
|
|
||||||
if ((res = f_stat_helper(path, &fno)) != FR_OK) {
|
if ((res = file_ll_stat(path, &fno)) != FR_OK) {
|
||||||
mp_raise_msg(&mp_type_OSError, (mp_rom_error_text_t) ffs_strerror(res));
|
mp_raise_msg(&mp_type_OSError, (mp_rom_error_text_t) ffs_strerror(res));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -144,7 +144,7 @@ FIRM_OBJ += $(addprefix $(BUILD)/$(OMV_DIR)/alloc/, \
|
|||||||
|
|
||||||
FIRM_OBJ += $(addprefix $(BUILD)/$(OMV_DIR)/common/, \
|
FIRM_OBJ += $(addprefix $(BUILD)/$(OMV_DIR)/common/, \
|
||||||
array.o \
|
array.o \
|
||||||
ff_wrapper.o \
|
file_utils.o \
|
||||||
ini.o \
|
ini.o \
|
||||||
ringbuf.o \
|
ringbuf.o \
|
||||||
trace.o \
|
trace.o \
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user