diff --git a/src/omv/img/imlib.c b/src/omv/img/imlib.c index 4398fbf8b..723848301 100644 --- a/src/omv/img/imlib.c +++ b/src/omv/img/imlib.c @@ -28,36 +28,101 @@ extern const uint16_t rainbow_table[256]; //////////////////////////////////////////////////////////////////////////////// -bool imlib_read_geometry(FIL *fp, image_t *image, const char *path, img_read_settings_t *rs) +static save_image_format_t imblib_parse_extension(image_t *img, const char *path) +{ + size_t l = strlen(path); + const char *p = path + l; + if (l >= 5) { + if (((p[-1] == 'g') || (p[-1] == 'G')) + && ((p[-2] == 'e') || (p[-2] == 'E')) + && ((p[-3] == 'p') || (p[-3] == 'P')) + && ((p[-4] == 'j') || (p[-4] == 'J')) + && ((p[-5] == '.') || (p[-5] == '.'))) { + if (!IM_IS_JPEG(img)) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, + "Image is not JPEG!")); + } + return FORMAT_JPG; + } + } + if (l >= 4) { + if (((p[-1] == 'g') || (p[-1] == 'G')) + && ((p[-2] == 'p') || (p[-2] == 'P')) + && ((p[-3] == 'j') || (p[-3] == 'J')) + && ((p[-4] == '.') || (p[-4] == '.'))) { + if (!IM_IS_JPEG(img)) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, + "Image is not JPG!")); + } + return FORMAT_JPG; + } else if (((p[-1] == 'p') || (p[-1] == 'P')) + && ((p[-2] == 'm') || (p[-2] == 'M')) + && ((p[-3] == 'b') || (p[-3] == 'B')) + && ((p[-4] == '.') || (p[-4] == '.'))) { + if (IM_IS_JPEG(img)) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, + "Image is not BMP!")); + } + return FORMAT_BMP; + } else if (((p[-1] == 'm') || (p[-1] == 'M')) + && ((p[-2] == 'p') || (p[-2] == 'P')) + && ((p[-3] == 'p') || (p[-3] == 'P')) + && ((p[-4] == '.') || (p[-4] == '.'))) { + if (!IM_IS_RGB565(img)) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, + "Image is not PPM!")); + } + return FORMAT_PNM; + } else if (((p[-1] == 'm') || (p[-1] == 'M')) + && ((p[-2] == 'g') || (p[-2] == 'G')) + && ((p[-3] == 'p') || (p[-3] == 'P')) + && ((p[-4] == '.') || (p[-4] == '.'))) { + if (!IM_IS_GS(img)) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, + "Image is not PGM!")); + } + return FORMAT_PNM; + } + } + return FORMAT_DONT_CARE; +} + +bool imlib_read_geometry(FIL *fp, image_t *img, const char *path, img_read_settings_t *rs) { file_read_open(fp, path); char magic[2]; read_data(fp, &magic, 2); file_close(fp); + bool vflipped = false; if ((magic[0]=='P') && ((magic[1]=='2') || (magic[1]=='3') || (magic[1]=='5') || (magic[1]=='6'))) { // PPM rs->format = FORMAT_PNM; - ppm_read_geometry(fp, image, path, &rs->ppm_rs); + ppm_read_geometry(fp, img, path, &rs->ppm_rs); } else if ((magic[0]=='B') && (magic[1]=='M')) { // BMP rs->format = FORMAT_BMP; - return bmp_read_geometry(fp, image, path, &rs->bmp_rs); + vflipped = bmp_read_geometry(fp, img, path, &rs->bmp_rs); } else { ff_unsupported_format(NULL); } - return false; + imblib_parse_extension(img, path); // Enforce extension! + return vflipped; } void imlib_read_pixels(FIL *fp, image_t *img, int line_start, int line_end, img_read_settings_t *rs) { switch (rs->format) { + case FORMAT_DONT_CARE: // won't happen + break; case FORMAT_BMP: bmp_read_pixels(fp, img, line_start, line_end, &rs->bmp_rs); break; case FORMAT_PNM: ppm_read_pixels(fp, img, line_start, line_end, &rs->ppm_rs); break; + case FORMAT_JPG: // won't happen + break; } } @@ -80,25 +145,32 @@ void imlib_load_image(image_t *img, const char *path) } else { ff_unsupported_format(NULL); } + imblib_parse_extension(img, path); // Enforce extension! } -void imlib_save_image(image_t *img, const char *path, rectangle_t *roi, save_image_format_t format) +void imlib_save_image(image_t *img, const char *path, rectangle_t *roi) { - if (IM_IS_JPEG(img)) { - char *new_path = strcat(strcpy(fb_alloc(strlen(path)+5), path), ".jpg"); - jpeg_write(img, new_path); - fb_free(); - } else if (format == FORMAT_BMP) { - char *new_path = strcat(strcpy(fb_alloc(strlen(path)+5), path), ".bmp"); - bmp_write_subimg(img, new_path, roi); - fb_free(); - } else if (format == FORMAT_PNM) { - char *new_path = strcat(strcpy(fb_alloc(strlen(path)+5), path), - IM_IS_GS(img) ? ".pgm" : ".ppm"); - ppm_write_subimg(img, new_path, roi); - fb_free(); - } else { - ff_unsupported_format(NULL); + switch (imblib_parse_extension(img, path)) { + case FORMAT_DONT_CARE: + if (IM_IS_JPEG(img)) { + char *new_path = strcat(strcpy(fb_alloc(strlen(path)+5), path), ".jpg"); + jpeg_write(img, new_path); + fb_free(); + } else { + char *new_path = strcat(strcpy(fb_alloc(strlen(path)+5), path), ".bmp"); + bmp_write_subimg(img, new_path, roi); + fb_free(); + } + break; + case FORMAT_BMP: + bmp_write_subimg(img, path, roi); + break; + case FORMAT_PNM: + ppm_write_subimg(img, path, roi); + break; + case FORMAT_JPG: + jpeg_write(img, path); + break; } } diff --git a/src/omv/img/imlib.h b/src/omv/img/imlib.h index fa6366df5..e44f7b2bb 100644 --- a/src/omv/img/imlib.h +++ b/src/omv/img/imlib.h @@ -296,8 +296,10 @@ typedef struct ppm_read_settings { } ppm_read_settings_t; typedef enum save_image_format { + FORMAT_DONT_CARE, FORMAT_BMP, - FORMAT_PNM + FORMAT_PNM, + FORMAT_JPG } save_image_format_t; typedef struct img_read_settings { @@ -322,10 +324,8 @@ void jpeg_read_geometry(FIL *fp, image_t *img, const char *path); void jpeg_read_pixels(FIL *fp, image_t *img); void jpeg_read(image_t *img, const char *path); void jpeg_write(image_t *img, const char *path); -bool imlib_read_geometry(FIL *fp, image_t *img, const char *path, img_read_settings_t *rs); -void imlib_read_pixels(FIL *fp, image_t *img, int line_start, int line_end, img_read_settings_t *rs); void imlib_load_image(image_t *img, const char *path); -void imlib_save_image(image_t *img, const char *path, rectangle_t *roi, save_image_format_t format); +void imlib_save_image(image_t *img, const char *path, rectangle_t *roi); /* Basic image functions */ int imlib_get_pixel(image_t *img, int x, int y); diff --git a/src/omv/mdefs.h b/src/omv/mdefs.h index a090ea13d..6153e6871 100644 --- a/src/omv/mdefs.h +++ b/src/omv/mdefs.h @@ -17,3 +17,7 @@ #ifndef DISABLE_OPT #define DISABLE_OPT __attribute__((optimize("O0"))) #endif + +#ifndef PRINT_LINE +#define PRINT_LINE printf("%s:%d\n", __FILE__, __LINE__) +#endif diff --git a/src/omv/py/py_image.c b/src/omv/py/py_image.c index ccd64ffd7..768b1a814 100644 --- a/src/omv/py/py_image.c +++ b/src/omv/py/py_image.c @@ -164,9 +164,7 @@ static mp_obj_t py_image_save(uint n_args, const mp_obj_t *args, mp_map_t *kw_ar rectangle_t roi; py_helper_lookup_rectangle(kw_args, arg_img, &roi); - imlib_save_image(arg_img, path, &roi, - py_helper_lookup_int(kw_args, - MP_OBJ_NEW_QSTR(MP_QSTR_format), FORMAT_BMP)); + imlib_save_image(arg_img, path, &roi); return mp_const_true; } @@ -1202,8 +1200,6 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(py_image_match_keypoints_obj, 4, 4, p STATIC MP_DEFINE_CONST_FUN_OBJ_KW(py_image_match_lbp_obj, 2, py_image_match_lbp); static const mp_map_elem_t locals_dict_table[] = { - {MP_OBJ_NEW_QSTR(MP_QSTR_FORMAT_BMP), MP_OBJ_NEW_SMALL_INT(FORMAT_BMP)}, - {MP_OBJ_NEW_QSTR(MP_QSTR_FORMAT_PNM), MP_OBJ_NEW_SMALL_INT(FORMAT_PNM)}, /* Image file functions */ {MP_OBJ_NEW_QSTR(MP_QSTR_save), (mp_obj_t)&py_image_save_obj}, /* Basic image functions */ diff --git a/src/omv/usbdbg.c b/src/omv/usbdbg.c index e4936440c..0cf7e5485 100644 --- a/src/omv/usbdbg.c +++ b/src/omv/usbdbg.c @@ -168,7 +168,7 @@ void usbdbg_data_out(void *buffer, int length) rectangle_t *roi = (rectangle_t*)buffer; char *path = (char*)buffer+sizeof(rectangle_t); - imlib_save_image(&image, path, roi, FORMAT_PNM); + imlib_save_image(&image, path, roi); // raise a flash IRQ to flush image //NVIC->STIR = FLASH_IRQn; break; diff --git a/usr/tests/test_save.py b/usr/tests/test_save.py new file mode 100644 index 000000000..691ee9d97 --- /dev/null +++ b/usr/tests/test_save.py @@ -0,0 +1,111 @@ +import pyb, sensor, image, os, time +sensor.reset() +sensor.set_framesize(sensor.QVGA) +if not "test" in os.listdir(): os.mkdir("test") +while(True): + sensor.set_pixformat(sensor.GRAYSCALE) + for i in range(2): + img = sensor.snapshot() + num = pyb.rng() + print("Saving %d" % num) + img.save("test/image-%d" % num) + # + img = sensor.snapshot() + num = pyb.rng() + print("Saving %d" % num) + img.save("test/image-%d.bmp" % num) + # + img = sensor.snapshot() + num = pyb.rng() + print("Saving %d" % num) + img.save("test/image-%d.pgm" % num) + # + img = sensor.snapshot() + num = pyb.rng() + print("Saving %d" % num) + img.save("/test/image-%d" % num) + # + img = sensor.snapshot() + num = pyb.rng() + print("Saving %d" % num) + img.save("/test/image-%d.bmp" % num) + # + img = sensor.snapshot() + num = pyb.rng() + print("Saving %d" % num) + img.save("/test/image-%d.pgm" % num) + # + sensor.set_pixformat(sensor.RGB565) + for i in range(2): + img = sensor.snapshot() + num = pyb.rng() + print("Saving %d" % num) + img.save("test/image-%d" % num) + # + img = sensor.snapshot() + num = pyb.rng() + print("Saving %d" % num) + img.save("test/image-%d.bmp" % num) + # + img = sensor.snapshot() + num = pyb.rng() + print("Saving %d" % num) + img.save("test/image-%d.ppm" % num) + # + img = sensor.snapshot() + num = pyb.rng() + print("Saving %d" % num) + img.save("/test/image-%d" % num) + # + img = sensor.snapshot() + num = pyb.rng() + print("Saving %d" % num) + img.save("/test/image-%d.bmp" % num) + # + img = sensor.snapshot() + num = pyb.rng() + print("Saving %d" % num) + img.save("/test/image-%d.ppm" % num) + # + sensor.set_pixformat(sensor.JPEG) + for i in range(2): + img = sensor.snapshot() + num = pyb.rng() + print("Saving %d" % num) + img.save("test/image-%d" % num) + # + img = sensor.snapshot() + num = pyb.rng() + print("Saving %d" % num) + img.save("test/image-%d.jpg" % num) + # + img = sensor.snapshot() + num = pyb.rng() + print("Saving %d" % num) + img.save("test/image-%d.jpeg" % num) + # + img = sensor.snapshot() + num = pyb.rng() + print("Saving %d" % num) + img.save("/test/image-%d" % num) + # + img = sensor.snapshot() + num = pyb.rng() + print("Saving %d" % num) + img.save("/test/image-%d.jpg" % num) + # + img = sensor.snapshot() + num = pyb.rng() + print("Saving %d" % num) + img.save("/test/image-%d.jpeg" % num) + # + print("Sleeping 5...") + time.sleep(1000) + print("Sleeping 4...") + time.sleep(1000) + print("Sleeping 3...") + time.sleep(1000) + print("Sleeping 2...") + time.sleep(1000) + print("Sleeping 1...") + time.sleep(1000)