diff --git a/examples/PikaCV/test1.py b/examples/PikaCV/test1.py index 4f97e314f..d80e7993a 100644 --- a/examples/PikaCV/test1.py +++ b/examples/PikaCV/test1.py @@ -5,4 +5,6 @@ img.read("test/assets/test.jpg") cv.Converter.toRGB565(img) print(str(Utils.b2a_hex(img.data()))) +cv.Converter.toBMP(img) +img.write("test/assets/test.bmp") diff --git a/package/PikaCV/PikaCV.pyi b/package/PikaCV/PikaCV.pyi index 83d7aadbf..dcf101703 100644 --- a/package/PikaCV/PikaCV.pyi +++ b/package/PikaCV/PikaCV.pyi @@ -22,6 +22,10 @@ class Image(TinyObj): """Read the image from the specified path, Need implement the `__platform_fopen()`, `__platform_fread()` and `__platform_fclose()`""" ... + def write(self, path: str): + """Write the image to the specified path, Need implement the `__platform_fopen()`, `__platform_fwrite()` and `__platform_fclose()`""" + ... + def loadJpeg(self, bytes: any): """Load the image from bytes""" @@ -81,3 +85,17 @@ class Converter(TinyObj): @staticmethod def toGray(image: Image): """Convert the image to Gray""" + + @staticmethod + def toBMP(image: Image): + """Convert the image to BMP""" + + @staticmethod + def toBGR888(image: Image): + """Convert the image to BGR888""" + + +class Transformer(TinyObj): + @staticmethod + def rotateDown(image: Image): + """Rotate the image """ diff --git a/package/PikaCV/PikaCV_Converter.c b/package/PikaCV/PikaCV_Converter.c index 3d9cafc8d..748fef795 100644 --- a/package/PikaCV/PikaCV_Converter.c +++ b/package/PikaCV/PikaCV_Converter.c @@ -1,4 +1,5 @@ #include "PikaCV_Converter.h" +#include "PikaCV_Transformer.h" #include "PikaCV_common.h" /* Session identifier for input/output functions (name, members and usage are as @@ -93,7 +94,7 @@ PIKA_RES Converter_JPEGtoRGB888(PikaObj* image) { return PIKA_RES_ERR_INVALID_PTR; } pika_assert(img->format == PikaCV_ImageFormat_Type_JPEG); - uint8_t* data = _Image_getData(image); + uint8_t* data = _image_getData(image); if (NULL == data) { __platform_printf("Converter_JPEGtoRGB888: data is NULL\n"); return PIKA_RES_ERR_INVALID_PTR; @@ -170,7 +171,7 @@ void PikaCV_Converter_toGray(PikaObj* self, PikaObj* image) { int size_new = img->height * img->width; Arg* arg_data_new = arg_setBytes(NULL, "", NULL, size_new); - uint8_t* data = _Image_getData(image); + uint8_t* data = _image_getData(image); uint8_t* data_new = arg_getBytes(arg_data_new); if (img->format == PikaCV_ImageFormat_Type_RGB888) { for (int i = 0; i < size_new; i++) { @@ -282,3 +283,132 @@ exit: img->size = size_new; arg_deinit(arg_data_new); } + +typedef struct /**** BMP file header structure ****/ +{ + unsigned int bfSize; /* Size of file */ + unsigned short bfReserved1; /* Reserved */ + unsigned short bfReserved2; /* ... */ + unsigned int bfOffBits; /* Offset to bitmap data */ +} BITMAPFILEHEADER; + +typedef struct /**** BMP file info structure ****/ +{ + unsigned int biSize; /* Size of info header */ + int biWidth; /* Width of image */ + int biHeight; /* Height of image */ + unsigned short biPlanes; /* Number of color planes */ + unsigned short biBitCount; /* Number of bits per pixel */ + unsigned int biCompression; /* Type of compression to use */ + unsigned int biSizeImage; /* Size of image data */ + int biXPelsPerMeter; /* X pixels per meter */ + int biYPelsPerMeter; /* Y pixels per meter */ + unsigned int biClrUsed; /* Number of colors used */ + unsigned int biClrImportant; /* Number of important colors */ +} BITMAPINFOHEADER; + +#define align(value, align) ((((value) + ((align)-1)) / (align)) * (align)) + +void PikaCV_Converter_toBMP(PikaObj* self, PikaObj* image) { + PikaCV_Image* img = obj_getStruct(image, "image"); + if (NULL == img) { + pika_assert(0); + return; + } + if (img->format == PikaCV_ImageFormat_Type_BMP) { + /* do nothing */ + return; + } + + /* convert to BGR */ + if (img->format != PikaCV_ImageFormat_Type_BGR888) { + PikaCV_Converter_toBGR888(self, image); + } + + PikaCV_Transformer_rotateDown(self, image); + + BITMAPFILEHEADER bfh; + BITMAPINFOHEADER bih; + int i = 0, row_align; + int width = img->width; + int height = img->height; + + // bmp的每行数据的长度要4字节对齐 + row_align = align(width * 3, 4); + + /* convert to BMP */ + int size_new = img->height * row_align + 54; + Arg* arg_data_new = arg_setBytes(NULL, "", NULL, size_new); + uint8_t* data = _image_getData(image); + uint8_t* data_new = arg_getBytes(arg_data_new); + + unsigned short bfType = 0x4d42; //'BM' + bfh.bfReserved1 = 0; + bfh.bfReserved2 = 0; + bfh.bfSize = 2 + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + + row_align * height; + bfh.bfOffBits = 2 + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); + + bih.biSize = sizeof(BITMAPINFOHEADER); + bih.biWidth = width; + bih.biHeight = height; + bih.biPlanes = 1; + bih.biBitCount = 24; + bih.biCompression = 0; + bih.biSizeImage = 0; + bih.biXPelsPerMeter = 0; + bih.biYPelsPerMeter = 0; + bih.biClrUsed = 0; + bih.biClrImportant = 0; + + __platform_memset(data_new, 0, size_new); + + __platform_memcpy(data_new, &bfType, sizeof(bfType)); + __platform_memcpy(data_new + sizeof(bfType), &bfh, sizeof(bfh)); + __platform_memcpy(data_new + sizeof(bfType) + sizeof(bfh), &bih, + sizeof(bih)); + + for (i = 0; i < height; i++) { + __platform_memcpy(data_new + sizeof(bfType) + sizeof(bfh) + + sizeof(bih) + row_align * i, + data + width * 3 * i, width * 3); + } + + obj_setBytes(image, "_data", data_new, size_new); + img->format = PikaCV_ImageFormat_Type_BMP; + img->size = size_new; + arg_deinit(arg_data_new); +} + +void PikaCV_Converter_toBGR888(PikaObj* self, PikaObj* image) { + PikaCV_Image* img = obj_getStruct(image, "image"); + if (NULL == img) { + pika_assert(0); + return; + } + if (img->format == PikaCV_ImageFormat_Type_BGR888) { + /* do nothing */ + return; + } + /* to RGB888 */ + if (img->format != PikaCV_ImageFormat_Type_RGB888) { + PikaCV_Converter_toRGB888(self, image); + } + /* to BGR888 */ + int size_new = img->size; + Arg* arg_data_new = arg_setBytes(NULL, "", NULL, size_new); + uint8_t* data = _image_getData(image); + uint8_t* data_new = arg_getBytes(arg_data_new); + + /* RBG888 to BGR888 */ + for (int i = 0; i < img->size; i += 3) { + data_new[i] = data[i + 2]; + data_new[i + 1] = data[i + 1]; + data_new[i + 2] = data[i]; + } + + obj_setBytes(image, "_data", data_new, size_new); + img->format = PikaCV_ImageFormat_Type_BGR888; + img->size = size_new; + arg_deinit(arg_data_new); +} diff --git a/package/PikaCV/PikaCV_Image.c b/package/PikaCV/PikaCV_Image.c index 9d933344c..d63ac58b6 100644 --- a/package/PikaCV/PikaCV_Image.c +++ b/package/PikaCV/PikaCV_Image.c @@ -15,10 +15,10 @@ void PikaCV_Image___init__(PikaObj* self) { .size = 0, }; obj_setStruct(self, "image", image); - PikaCV_Image_setData(self, NULL, 0); + _image_setData(self, NULL, 0); } -uint8_t* _Image_getData(PikaObj* self) { +uint8_t* _image_getData(PikaObj* self) { PikaCV_Image* image = obj_getStruct(self, "image"); if (NULL == image) { return NULL; @@ -26,7 +26,15 @@ uint8_t* _Image_getData(PikaObj* self) { return obj_getBytes(self, "_data"); } -PIKA_RES PikaCV_Image_setData(PikaObj* self, uint8_t* data, int size) { +int _image_getDataSize(PikaObj* self) { + PikaCV_Image* image = obj_getStruct(self, "image"); + if (NULL == image) { + return 0; + } + return obj_getBytesSize(self, "_data"); +} + +PIKA_RES _image_setData(PikaObj* self, uint8_t* data, int size) { PikaCV_Image* image = obj_getStruct(self, "image"); if (NULL == image) { return PIKA_RES_ERR_ARG_NO_FOUND; @@ -76,7 +84,7 @@ void PikaCV_Image_loadRGB565(PikaObj* self, image->height = height; image->width = width; image->size = height * width * 2; - PikaCV_Image_setData(self, bytes, image->size); + _image_setData(self, bytes, image->size); } void PikaCV_Image_loadRGB888(PikaObj* self, @@ -91,7 +99,7 @@ void PikaCV_Image_loadRGB888(PikaObj* self, image->height = height; image->width = width; image->size = height * width * 3; - PikaCV_Image_setData(self, bytes, image->size); + _image_setData(self, bytes, image->size); } void PikaCV_Image_loadGray(PikaObj* self, @@ -106,7 +114,7 @@ void PikaCV_Image_loadGray(PikaObj* self, image->height = height; image->width = width; image->size = height * width; - PikaCV_Image_setData(self, bytes, image->size); + _image_setData(self, bytes, image->size); } void PikaCV_Image_read(PikaObj* self, char* path) { @@ -144,7 +152,7 @@ void PikaCV_Image_setPixel(PikaObj* self, if (NULL == image) { return; } - uint8_t* data = _Image_getData(self); + uint8_t* data = _image_getData(self); if (image->format == PikaCV_ImageFormat_Type_RGB565) { data[(y * image->width + x) * 2 + channel] = value; } else if (image->format == PikaCV_ImageFormat_Type_RGB888) { @@ -163,7 +171,7 @@ int PikaCV_Image_getPixel(PikaObj* self, int channel, int x, int y) { if (NULL == image) { return 0; } - uint8_t* data = _Image_getData(self); + uint8_t* data = _image_getData(self); if (image->format == PikaCV_ImageFormat_Type_RGB565) { return data[(y * image->width + x) * 2 + channel]; } else if (image->format == PikaCV_ImageFormat_Type_RGB888) { @@ -193,3 +201,22 @@ int PikaCV_Image_width(PikaObj* self) { } return image->width; } + +void PikaCV_Image_write(PikaObj* self, char* path) { + uint8_t* data = _image_getData(self); + int size = _image_getDataSize(self); + if (NULL == data || size <= 0) { + obj_setErrorCode(self, PIKA_RES_ERR_OPERATION_FAILED); + __platform_printf("PikaCV_Image_write: data is NULL or size is 0\n"); + return; + } + FILE* fp = __platform_fopen(path, "wb+"); + if (NULL == fp) { + obj_setErrorCode(self, PIKA_RES_ERR_OPERATION_FAILED); + __platform_printf("PikaCV_Image_write: failed to open file: %s\n", + path); + return; + } + __platform_fwrite(data, 1, size, fp); + __platform_fclose(fp); +} diff --git a/package/PikaCV/PikaCV_Transformer.c b/package/PikaCV/PikaCV_Transformer.c new file mode 100644 index 000000000..ca6812ebf --- /dev/null +++ b/package/PikaCV/PikaCV_Transformer.c @@ -0,0 +1,37 @@ +#include "PikaCV_Transformer.h" +#include "PikaCV_Converter.h" +#include "PikaCV_common.h" + +void PikaCV_Transformer_rotateDown(PikaObj* self, PikaObj* image) { + PikaCV_Image* img = obj_getStruct(image, "image"); + if (NULL == img) { + pika_assert(0); + return; + } + if (img->format != PikaCV_ImageFormat_Type_BGR888 && + img->format != PikaCV_ImageFormat_Type_RGB888) { + obj_setErrorCode(self, PIKA_RES_ERR_OPERATION_FAILED); + __platform_printf("unsupported image format\n"); + return; + } + int width = img->width; + int height = img->height; + int size_new = width * height * 3; + Arg* arg_data_new = arg_setBytes(NULL, "", NULL, size_new); + uint8_t* data = _image_getData(image); + uint8_t* data_new = arg_getBytes(arg_data_new); + int i, j, k; + /* rotate */ + for (i = 0; i < height; i++) { + for (j = 0; j < width; j++) { + for (k = 0; k < 3; k++) { + data_new[(height - i - 1) * width * 3 + j * 3 + k] = + data[i * width * 3 + j * 3 + k]; + } + } + } + obj_setBytes(image, "_data", data_new, size_new); + img->format = PikaCV_ImageFormat_Type_BGR888; + img->size = size_new; + arg_deinit(arg_data_new); +} diff --git a/package/PikaCV/PikaCV_common.h b/package/PikaCV/PikaCV_common.h index faca37307..8b59fa6a5 100644 --- a/package/PikaCV/PikaCV_common.h +++ b/package/PikaCV/PikaCV_common.h @@ -1,11 +1,14 @@ #include "./3rd-party/tjpgd/src/tjpgd.h" +#define M_PI 3.14159265358979323846 typedef enum PikaCV_ImageFormat_Type { PikaCV_ImageFormat_Type_Unknown = 0, PikaCV_ImageFormat_Type_JPEG, PikaCV_ImageFormat_Type_RGB888, + PikaCV_ImageFormat_Type_BGR888, PikaCV_ImageFormat_Type_RGB565, PikaCV_ImageFormat_Type_GRAY, + PikaCV_ImageFormat_Type_BMP, } PikaCV_ImageFormat_Type; typedef struct PikaCV_Image { @@ -15,5 +18,6 @@ typedef struct PikaCV_Image { int size; } PikaCV_Image; -uint8_t* _Image_getData(PikaObj* self); -PIKA_RES PikaCV_Image_setData(PikaObj* self, uint8_t* data, int size); \ No newline at end of file +uint8_t* _image_getData(PikaObj* self); +PIKA_RES _image_setData(PikaObj* self, uint8_t* data, int size); +int _image_getDataSize(PikaObj* self); \ No newline at end of file diff --git a/port/linux/package/pikascript/PikaCV.pyi b/port/linux/package/pikascript/PikaCV.pyi index 83d7aadbf..dcf101703 100644 --- a/port/linux/package/pikascript/PikaCV.pyi +++ b/port/linux/package/pikascript/PikaCV.pyi @@ -22,6 +22,10 @@ class Image(TinyObj): """Read the image from the specified path, Need implement the `__platform_fopen()`, `__platform_fread()` and `__platform_fclose()`""" ... + def write(self, path: str): + """Write the image to the specified path, Need implement the `__platform_fopen()`, `__platform_fwrite()` and `__platform_fclose()`""" + ... + def loadJpeg(self, bytes: any): """Load the image from bytes""" @@ -81,3 +85,17 @@ class Converter(TinyObj): @staticmethod def toGray(image: Image): """Convert the image to Gray""" + + @staticmethod + def toBMP(image: Image): + """Convert the image to BMP""" + + @staticmethod + def toBGR888(image: Image): + """Convert the image to BGR888""" + + +class Transformer(TinyObj): + @staticmethod + def rotateDown(image: Image): + """Rotate the image """ diff --git a/port/linux/package/pikascript/pikascript-lib/PikaCV/PikaCV_Converter.c b/port/linux/package/pikascript/pikascript-lib/PikaCV/PikaCV_Converter.c index 3d9cafc8d..748fef795 100644 --- a/port/linux/package/pikascript/pikascript-lib/PikaCV/PikaCV_Converter.c +++ b/port/linux/package/pikascript/pikascript-lib/PikaCV/PikaCV_Converter.c @@ -1,4 +1,5 @@ #include "PikaCV_Converter.h" +#include "PikaCV_Transformer.h" #include "PikaCV_common.h" /* Session identifier for input/output functions (name, members and usage are as @@ -93,7 +94,7 @@ PIKA_RES Converter_JPEGtoRGB888(PikaObj* image) { return PIKA_RES_ERR_INVALID_PTR; } pika_assert(img->format == PikaCV_ImageFormat_Type_JPEG); - uint8_t* data = _Image_getData(image); + uint8_t* data = _image_getData(image); if (NULL == data) { __platform_printf("Converter_JPEGtoRGB888: data is NULL\n"); return PIKA_RES_ERR_INVALID_PTR; @@ -170,7 +171,7 @@ void PikaCV_Converter_toGray(PikaObj* self, PikaObj* image) { int size_new = img->height * img->width; Arg* arg_data_new = arg_setBytes(NULL, "", NULL, size_new); - uint8_t* data = _Image_getData(image); + uint8_t* data = _image_getData(image); uint8_t* data_new = arg_getBytes(arg_data_new); if (img->format == PikaCV_ImageFormat_Type_RGB888) { for (int i = 0; i < size_new; i++) { @@ -282,3 +283,132 @@ exit: img->size = size_new; arg_deinit(arg_data_new); } + +typedef struct /**** BMP file header structure ****/ +{ + unsigned int bfSize; /* Size of file */ + unsigned short bfReserved1; /* Reserved */ + unsigned short bfReserved2; /* ... */ + unsigned int bfOffBits; /* Offset to bitmap data */ +} BITMAPFILEHEADER; + +typedef struct /**** BMP file info structure ****/ +{ + unsigned int biSize; /* Size of info header */ + int biWidth; /* Width of image */ + int biHeight; /* Height of image */ + unsigned short biPlanes; /* Number of color planes */ + unsigned short biBitCount; /* Number of bits per pixel */ + unsigned int biCompression; /* Type of compression to use */ + unsigned int biSizeImage; /* Size of image data */ + int biXPelsPerMeter; /* X pixels per meter */ + int biYPelsPerMeter; /* Y pixels per meter */ + unsigned int biClrUsed; /* Number of colors used */ + unsigned int biClrImportant; /* Number of important colors */ +} BITMAPINFOHEADER; + +#define align(value, align) ((((value) + ((align)-1)) / (align)) * (align)) + +void PikaCV_Converter_toBMP(PikaObj* self, PikaObj* image) { + PikaCV_Image* img = obj_getStruct(image, "image"); + if (NULL == img) { + pika_assert(0); + return; + } + if (img->format == PikaCV_ImageFormat_Type_BMP) { + /* do nothing */ + return; + } + + /* convert to BGR */ + if (img->format != PikaCV_ImageFormat_Type_BGR888) { + PikaCV_Converter_toBGR888(self, image); + } + + PikaCV_Transformer_rotateDown(self, image); + + BITMAPFILEHEADER bfh; + BITMAPINFOHEADER bih; + int i = 0, row_align; + int width = img->width; + int height = img->height; + + // bmp的每行数据的长度要4字节对齐 + row_align = align(width * 3, 4); + + /* convert to BMP */ + int size_new = img->height * row_align + 54; + Arg* arg_data_new = arg_setBytes(NULL, "", NULL, size_new); + uint8_t* data = _image_getData(image); + uint8_t* data_new = arg_getBytes(arg_data_new); + + unsigned short bfType = 0x4d42; //'BM' + bfh.bfReserved1 = 0; + bfh.bfReserved2 = 0; + bfh.bfSize = 2 + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + + row_align * height; + bfh.bfOffBits = 2 + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); + + bih.biSize = sizeof(BITMAPINFOHEADER); + bih.biWidth = width; + bih.biHeight = height; + bih.biPlanes = 1; + bih.biBitCount = 24; + bih.biCompression = 0; + bih.biSizeImage = 0; + bih.biXPelsPerMeter = 0; + bih.biYPelsPerMeter = 0; + bih.biClrUsed = 0; + bih.biClrImportant = 0; + + __platform_memset(data_new, 0, size_new); + + __platform_memcpy(data_new, &bfType, sizeof(bfType)); + __platform_memcpy(data_new + sizeof(bfType), &bfh, sizeof(bfh)); + __platform_memcpy(data_new + sizeof(bfType) + sizeof(bfh), &bih, + sizeof(bih)); + + for (i = 0; i < height; i++) { + __platform_memcpy(data_new + sizeof(bfType) + sizeof(bfh) + + sizeof(bih) + row_align * i, + data + width * 3 * i, width * 3); + } + + obj_setBytes(image, "_data", data_new, size_new); + img->format = PikaCV_ImageFormat_Type_BMP; + img->size = size_new; + arg_deinit(arg_data_new); +} + +void PikaCV_Converter_toBGR888(PikaObj* self, PikaObj* image) { + PikaCV_Image* img = obj_getStruct(image, "image"); + if (NULL == img) { + pika_assert(0); + return; + } + if (img->format == PikaCV_ImageFormat_Type_BGR888) { + /* do nothing */ + return; + } + /* to RGB888 */ + if (img->format != PikaCV_ImageFormat_Type_RGB888) { + PikaCV_Converter_toRGB888(self, image); + } + /* to BGR888 */ + int size_new = img->size; + Arg* arg_data_new = arg_setBytes(NULL, "", NULL, size_new); + uint8_t* data = _image_getData(image); + uint8_t* data_new = arg_getBytes(arg_data_new); + + /* RBG888 to BGR888 */ + for (int i = 0; i < img->size; i += 3) { + data_new[i] = data[i + 2]; + data_new[i + 1] = data[i + 1]; + data_new[i + 2] = data[i]; + } + + obj_setBytes(image, "_data", data_new, size_new); + img->format = PikaCV_ImageFormat_Type_BGR888; + img->size = size_new; + arg_deinit(arg_data_new); +} diff --git a/port/linux/package/pikascript/pikascript-lib/PikaCV/PikaCV_Image.c b/port/linux/package/pikascript/pikascript-lib/PikaCV/PikaCV_Image.c index 9d933344c..d63ac58b6 100644 --- a/port/linux/package/pikascript/pikascript-lib/PikaCV/PikaCV_Image.c +++ b/port/linux/package/pikascript/pikascript-lib/PikaCV/PikaCV_Image.c @@ -15,10 +15,10 @@ void PikaCV_Image___init__(PikaObj* self) { .size = 0, }; obj_setStruct(self, "image", image); - PikaCV_Image_setData(self, NULL, 0); + _image_setData(self, NULL, 0); } -uint8_t* _Image_getData(PikaObj* self) { +uint8_t* _image_getData(PikaObj* self) { PikaCV_Image* image = obj_getStruct(self, "image"); if (NULL == image) { return NULL; @@ -26,7 +26,15 @@ uint8_t* _Image_getData(PikaObj* self) { return obj_getBytes(self, "_data"); } -PIKA_RES PikaCV_Image_setData(PikaObj* self, uint8_t* data, int size) { +int _image_getDataSize(PikaObj* self) { + PikaCV_Image* image = obj_getStruct(self, "image"); + if (NULL == image) { + return 0; + } + return obj_getBytesSize(self, "_data"); +} + +PIKA_RES _image_setData(PikaObj* self, uint8_t* data, int size) { PikaCV_Image* image = obj_getStruct(self, "image"); if (NULL == image) { return PIKA_RES_ERR_ARG_NO_FOUND; @@ -76,7 +84,7 @@ void PikaCV_Image_loadRGB565(PikaObj* self, image->height = height; image->width = width; image->size = height * width * 2; - PikaCV_Image_setData(self, bytes, image->size); + _image_setData(self, bytes, image->size); } void PikaCV_Image_loadRGB888(PikaObj* self, @@ -91,7 +99,7 @@ void PikaCV_Image_loadRGB888(PikaObj* self, image->height = height; image->width = width; image->size = height * width * 3; - PikaCV_Image_setData(self, bytes, image->size); + _image_setData(self, bytes, image->size); } void PikaCV_Image_loadGray(PikaObj* self, @@ -106,7 +114,7 @@ void PikaCV_Image_loadGray(PikaObj* self, image->height = height; image->width = width; image->size = height * width; - PikaCV_Image_setData(self, bytes, image->size); + _image_setData(self, bytes, image->size); } void PikaCV_Image_read(PikaObj* self, char* path) { @@ -144,7 +152,7 @@ void PikaCV_Image_setPixel(PikaObj* self, if (NULL == image) { return; } - uint8_t* data = _Image_getData(self); + uint8_t* data = _image_getData(self); if (image->format == PikaCV_ImageFormat_Type_RGB565) { data[(y * image->width + x) * 2 + channel] = value; } else if (image->format == PikaCV_ImageFormat_Type_RGB888) { @@ -163,7 +171,7 @@ int PikaCV_Image_getPixel(PikaObj* self, int channel, int x, int y) { if (NULL == image) { return 0; } - uint8_t* data = _Image_getData(self); + uint8_t* data = _image_getData(self); if (image->format == PikaCV_ImageFormat_Type_RGB565) { return data[(y * image->width + x) * 2 + channel]; } else if (image->format == PikaCV_ImageFormat_Type_RGB888) { @@ -193,3 +201,22 @@ int PikaCV_Image_width(PikaObj* self) { } return image->width; } + +void PikaCV_Image_write(PikaObj* self, char* path) { + uint8_t* data = _image_getData(self); + int size = _image_getDataSize(self); + if (NULL == data || size <= 0) { + obj_setErrorCode(self, PIKA_RES_ERR_OPERATION_FAILED); + __platform_printf("PikaCV_Image_write: data is NULL or size is 0\n"); + return; + } + FILE* fp = __platform_fopen(path, "wb+"); + if (NULL == fp) { + obj_setErrorCode(self, PIKA_RES_ERR_OPERATION_FAILED); + __platform_printf("PikaCV_Image_write: failed to open file: %s\n", + path); + return; + } + __platform_fwrite(data, 1, size, fp); + __platform_fclose(fp); +} diff --git a/port/linux/package/pikascript/pikascript-lib/PikaCV/PikaCV_Transformer.c b/port/linux/package/pikascript/pikascript-lib/PikaCV/PikaCV_Transformer.c new file mode 100644 index 000000000..ca6812ebf --- /dev/null +++ b/port/linux/package/pikascript/pikascript-lib/PikaCV/PikaCV_Transformer.c @@ -0,0 +1,37 @@ +#include "PikaCV_Transformer.h" +#include "PikaCV_Converter.h" +#include "PikaCV_common.h" + +void PikaCV_Transformer_rotateDown(PikaObj* self, PikaObj* image) { + PikaCV_Image* img = obj_getStruct(image, "image"); + if (NULL == img) { + pika_assert(0); + return; + } + if (img->format != PikaCV_ImageFormat_Type_BGR888 && + img->format != PikaCV_ImageFormat_Type_RGB888) { + obj_setErrorCode(self, PIKA_RES_ERR_OPERATION_FAILED); + __platform_printf("unsupported image format\n"); + return; + } + int width = img->width; + int height = img->height; + int size_new = width * height * 3; + Arg* arg_data_new = arg_setBytes(NULL, "", NULL, size_new); + uint8_t* data = _image_getData(image); + uint8_t* data_new = arg_getBytes(arg_data_new); + int i, j, k; + /* rotate */ + for (i = 0; i < height; i++) { + for (j = 0; j < width; j++) { + for (k = 0; k < 3; k++) { + data_new[(height - i - 1) * width * 3 + j * 3 + k] = + data[i * width * 3 + j * 3 + k]; + } + } + } + obj_setBytes(image, "_data", data_new, size_new); + img->format = PikaCV_ImageFormat_Type_BGR888; + img->size = size_new; + arg_deinit(arg_data_new); +} diff --git a/port/linux/package/pikascript/pikascript-lib/PikaCV/PikaCV_common.h b/port/linux/package/pikascript/pikascript-lib/PikaCV/PikaCV_common.h index faca37307..8b59fa6a5 100644 --- a/port/linux/package/pikascript/pikascript-lib/PikaCV/PikaCV_common.h +++ b/port/linux/package/pikascript/pikascript-lib/PikaCV/PikaCV_common.h @@ -1,11 +1,14 @@ #include "./3rd-party/tjpgd/src/tjpgd.h" +#define M_PI 3.14159265358979323846 typedef enum PikaCV_ImageFormat_Type { PikaCV_ImageFormat_Type_Unknown = 0, PikaCV_ImageFormat_Type_JPEG, PikaCV_ImageFormat_Type_RGB888, + PikaCV_ImageFormat_Type_BGR888, PikaCV_ImageFormat_Type_RGB565, PikaCV_ImageFormat_Type_GRAY, + PikaCV_ImageFormat_Type_BMP, } PikaCV_ImageFormat_Type; typedef struct PikaCV_Image { @@ -15,5 +18,6 @@ typedef struct PikaCV_Image { int size; } PikaCV_Image; -uint8_t* _Image_getData(PikaObj* self); -PIKA_RES PikaCV_Image_setData(PikaObj* self, uint8_t* data, int size); \ No newline at end of file +uint8_t* _image_getData(PikaObj* self); +PIKA_RES _image_setData(PikaObj* self, uint8_t* data, int size); +int _image_getDataSize(PikaObj* self); \ No newline at end of file diff --git a/src/PikaVersion.h b/src/PikaVersion.h index 6ea342256..b9dbc9c56 100644 --- a/src/PikaVersion.h +++ b/src/PikaVersion.h @@ -2,4 +2,4 @@ #define PIKA_VERSION_MINOR 9 #define PIKA_VERSION_MICRO 0 -#define PIKA_EDIT_TIME "2022/07/08 18:00:44" +#define PIKA_EDIT_TIME "2022/07/11 10:22:03"