diff options
author | Ramzi BEN MEFTAH <rbmeftah@de.adit-jv.com> | 2020-05-11 05:12:05 +0200 |
---|---|---|
committer | Ramzi BEN MEFTAH <rbmeftah@de.adit-jv.com> | 2020-06-16 13:41:04 +0200 |
commit | ee7626d9ceb4bc15ec0d27820b701dad4dd3be02 (patch) | |
tree | a77eccaee62f578e25bb2e7ad176ae610ad1192a | |
parent | 8815ae5fcd11f3cfa53f8a7bda134e771143f3c3 (diff) | |
download | wayland-ivi-extension-ee7626d9ceb4bc15ec0d27820b701dad4dd3be02.tar.gz |
ilmControl: add support for saving screenshot as png file
To save as png file, the file name should have ".png" as extension.
Signed-off-by: Ramzi BEN MEFTAH <rbmeftah@de.adit-jv.com>
6 files changed, 364 insertions, 78 deletions
diff --git a/ivi-layermanagement-api/ilmControl/CMakeLists.txt b/ivi-layermanagement-api/ilmControl/CMakeLists.txt index 4265ef9..f6bc551 100644 --- a/ivi-layermanagement-api/ilmControl/CMakeLists.txt +++ b/ivi-layermanagement-api/ilmControl/CMakeLists.txt @@ -76,6 +76,7 @@ link_directories( add_library(${PROJECT_NAME} SHARED src/ilm_control_wayland_platform.c src/bitmap.c + src/writepng.c ivi-wm-client-protocol.h ivi-wm-protocol.c ivi-input-client-protocol.h @@ -90,6 +91,7 @@ set(LIBS ${LIBS} rt dl + png ${CMAKE_THREAD_LIBS_INIT} ${WAYLAND_CLIENT_LIBRARIES} ) diff --git a/ivi-layermanagement-api/ilmControl/src/bitmap.c b/ivi-layermanagement-api/ilmControl/src/bitmap.c index 2c7fdb5..79d2a5d 100644 --- a/ivi-layermanagement-api/ilmControl/src/bitmap.c +++ b/ivi-layermanagement-api/ilmControl/src/bitmap.c @@ -21,6 +21,11 @@ */ #include "bitmap.h" #include <stdio.h> +#include <stdlib.h> +#include <stdlib.h> +#include <stdbool.h> +#include <arpa/inet.h> +#include "ivi-wm-client-protocol.h" struct __attribute__ ((__packed__)) BITMAPFILEHEADER { char bfType[2]; @@ -49,22 +54,22 @@ create_file_header(struct BITMAPFILEHEADER *file_header, int32_t image_size) { file_header->bfType[0] = 'B'; file_header->bfType[1] = 'M'; - file_header->bfSize = sizeof(struct BITMAPFILEHEADER) - + sizeof(struct BITMAPINFOHEADER) - + image_size; - file_header->bfOffBits = sizeof(struct BITMAPFILEHEADER) - + sizeof(struct BITMAPINFOHEADER); + file_header->bfSize = htole32(sizeof(struct BITMAPFILEHEADER) + + sizeof(struct BITMAPINFOHEADER) + + image_size); + file_header->bfOffBits = htole32(sizeof(struct BITMAPFILEHEADER) + + sizeof(struct BITMAPINFOHEADER)); } static void create_info_header(struct BITMAPINFOHEADER *info_header, int32_t image_size, int32_t width, int32_t height, int16_t bpp) { - info_header->biSize = sizeof(struct BITMAPINFOHEADER); - info_header->biWidth = width; - info_header->biHeight = height; - info_header->biPlanes = 1; - info_header->biBitCount = bpp; - info_header->biSizeImage = image_size; + info_header->biSize = htole32(sizeof(struct BITMAPINFOHEADER)); + info_header->biWidth = htole32(width); + info_header->biHeight = htole32(height); + info_header->biPlanes = htole16(1); + info_header->biBitCount = htole16(bpp); + info_header->biSizeImage = htole32(image_size); } static int @@ -89,19 +94,87 @@ write_bitmap(const char *filename, int save_as_bitmap(const char *filename, const char *buffer, - int32_t image_size, int32_t width, int32_t height, - int16_t bpp) + uint32_t format) { + int32_t image_stride = 0; + int32_t image_size = 0; + char *image_buffer = NULL; + int32_t row = 0; + int32_t col = 0; + int32_t image_offset = 0; + int32_t offset = 0; + int32_t i = 0; + int32_t j = 0; + int bytes_per_pixel; + bool flip_order; + bool has_alpha; + if ((filename == NULL) || (buffer == NULL)) { return -1; } + switch (format) { + case WL_SHM_FORMAT_ARGB8888: + flip_order = true; + has_alpha = true; + break; + case WL_SHM_FORMAT_XRGB8888: + flip_order = true; + has_alpha = false; + break; + case WL_SHM_FORMAT_ABGR8888: + flip_order = false; + has_alpha = true; + break; + case WL_SHM_FORMAT_XBGR8888: + flip_order = false; + has_alpha = false; + break; + default: + fprintf(stderr, "unsupported pixelformat 0x%x\n", format); + return -1; + } + + bytes_per_pixel = has_alpha ? 4 : 3; + image_stride = (((width * bytes_per_pixel) + 3) & ~3); + image_size = image_stride * height; + + image_buffer = malloc(image_size); + if (image_buffer == NULL) { + fprintf(stderr, "failed to allocate %d bytes for image buffer: %m\n", + image_size); + return -1; + } + + // Store the image in image_buffer in the follwing order B, G, R, [A](B at the lowest address) + for (row = 0; row < height; ++row) { + for (col = 0; col < width; ++col) { + offset = (height - row - 1) * width + col; + uint32_t pixel = htonl(((uint32_t*)buffer)[offset]); + char * pixel_p = (char*) &pixel; + image_offset = row * image_stride + col * bytes_per_pixel; + for (i = 0; i < 3; ++i) { + j = flip_order ? 2 - i : i; + image_buffer[image_offset + i] = pixel_p[1 + j]; + } + if (has_alpha) { + image_buffer[image_offset + 3] = pixel_p[0]; + } + } + } + struct BITMAPFILEHEADER file_header = {}; struct BITMAPINFOHEADER info_header = {}; create_file_header(&file_header, image_size); - create_info_header(&info_header, image_size, width, height, bpp); - return write_bitmap(filename, &file_header, &info_header, buffer); + create_info_header(&info_header, image_size, width, height, bytes_per_pixel * 8); + if (write_bitmap(filename, &file_header, &info_header, image_buffer) != 0) { + free(image_buffer); + return -1; + } + + free(image_buffer); + return 0; } diff --git a/ivi-layermanagement-api/ilmControl/src/bitmap.h b/ivi-layermanagement-api/ilmControl/src/bitmap.h index 3cef52d..4b8520c 100644 --- a/ivi-layermanagement-api/ilmControl/src/bitmap.h +++ b/ivi-layermanagement-api/ilmControl/src/bitmap.h @@ -26,10 +26,9 @@ int save_as_bitmap(const char *filename, const char *buffer, - int32_t image_size, int32_t width, int32_t height, - int16_t bpp + uint32_t format ); #endif /* IVICONTROLLER_BITMAP_H_*/ diff --git a/ivi-layermanagement-api/ilmControl/src/ilm_control_wayland_platform.c b/ivi-layermanagement-api/ilmControl/src/ilm_control_wayland_platform.c index a912e50..be7c5a3 100644 --- a/ivi-layermanagement-api/ilmControl/src/ilm_control_wayland_platform.c +++ b/ivi-layermanagement-api/ilmControl/src/ilm_control_wayland_platform.c @@ -30,6 +30,7 @@ #include <sys/mman.h> #include <sys/eventfd.h> +#include "writepng.h" #include "bitmap.h" #include "ilm_common.h" #include "ilm_control_platform.h" @@ -2061,43 +2062,16 @@ static void screenshot_done(void *data, struct ivi_screenshot *ivi_screenshot, { struct screenshot_context *ctx_scrshot = data; char *buffer; - int32_t image_stride = 0; - int32_t image_size = 0; - char *image_buffer = NULL; - int32_t row = 0; - int32_t col = 0; - int32_t image_offset = 0; - int32_t offset = 0; - int32_t i = 0; - int32_t j = 0; size_t size = stride * height; - int bytes_per_pixel; - bool flip_order; - bool has_alpha; const char *filename = ctx_scrshot->filename; + char *filename_ext = NULL; ctx_scrshot->filename = NULL; ivi_screenshot_destroy(ivi_screenshot); - switch (format) { - case WL_SHM_FORMAT_ARGB8888: - flip_order = false; - has_alpha = true; - break; - case WL_SHM_FORMAT_XRGB8888: - flip_order = false; - has_alpha = false; - break; - case WL_SHM_FORMAT_ABGR8888: - flip_order = true; - has_alpha = true; - break; - case WL_SHM_FORMAT_XBGR8888: - flip_order = true; - has_alpha = false; - break; - default: - fprintf(stderr, "unsupported pixelformat 0x%x\n", format); + if (filename == NULL) { + ctx_scrshot->result = ILM_FAILED; + fprintf(stderr, "screenshot file name not provided: %m\n"); return; } @@ -2105,45 +2079,34 @@ static void screenshot_done(void *data, struct ivi_screenshot *ivi_screenshot, close(fd); if (buffer == MAP_FAILED) { + ctx_scrshot->result = ILM_FAILED; fprintf(stderr, "failed to mmap screenshot file: %m\n"); return; } - bytes_per_pixel = has_alpha ? 4 : 3; - image_stride = (((width * bytes_per_pixel) + 3) & ~3); - image_size = image_stride * height; - - image_buffer = malloc(image_size); - if (image_buffer == NULL) { - fprintf(stderr, "failed to allocate %d bytes for image buffer: %m\n", - image_size); - munmap(buffer, size); - return; - } + if ((filename_ext = strstr(filename, ".png")) && (strlen(filename_ext) == 4)) { + if (save_as_png(filename, (const char *)buffer, + width, height, format) == 0) { + ctx_scrshot->result = ILM_SUCCESS; + } else { + ctx_scrshot->result = ILM_FAILED; + fprintf(stderr, "failed to write screenshot as png file: %m\n"); + } + } else { + if (!((filename_ext = strstr(filename, ".bmp")) && (strlen(filename_ext) == 4))) { + fprintf(stderr, "trying to write screenshot as bmp file, although file extension does not match: %m\n"); + } - for (row = 0; row < height; ++row) { - for (col = 0; col < width; ++col) { - offset = (height - row - 1) * width + col; - image_offset = row * image_stride + col * bytes_per_pixel; - for (i = 0; i < 3; ++i) { - j = flip_order ? 2 - i : i; - image_buffer[image_offset + i] = buffer[offset * 4 + j]; - } - if (has_alpha) - image_buffer[image_offset + 3] = buffer[offset * 4 + 3]; + if (save_as_bitmap(filename, (const char *)buffer, + width, height, format) == 0) { + ctx_scrshot->result = ILM_SUCCESS; + } else { + ctx_scrshot->result = ILM_FAILED; + fprintf(stderr, "failed to write screenshot as bmp file: %m\n"); } } munmap(buffer, size); - - if (save_as_bitmap(filename, (const char *)image_buffer, - image_size, width, height, bytes_per_pixel * 8) == 0) { - ctx_scrshot->result = ILM_SUCCESS; - } else { - fprintf(stderr, "failed to write screenshot file: %m\n"); - } - - free(image_buffer); } static void screenshot_error(void *data, struct ivi_screenshot *ivi_screenshot, diff --git a/ivi-layermanagement-api/ilmControl/src/writepng.c b/ivi-layermanagement-api/ilmControl/src/writepng.c new file mode 100644 index 0000000..bf712b5 --- /dev/null +++ b/ivi-layermanagement-api/ilmControl/src/writepng.c @@ -0,0 +1,218 @@ +/*************************************************************************** + * + * Copyright (C) 2020 Advanced Driver Information Technology Joint Venture GmbH + * + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************/ +#include <stdio.h> +#include <stdlib.h> +#include <stdbool.h> +#include <arpa/inet.h> +#include "png.h" +#include "ivi-wm-client-protocol.h" +#include "writepng.h" + +typedef struct _image_info { + png_structp png_ptr; + png_infop info_ptr; + jmp_buf jmpbuf; + FILE *outfile; +} image_info; + + +static void +writepng_error_handler(png_structp png_ptr, + png_const_charp msg) +{ + fprintf(stderr, "writepng libpng error: %s\n", msg); +} + +static int +create_png_header(image_info *info, + int32_t width, + int32_t height, + uint32_t format) +{ + int color_type = 0; + int sample_depth = 8; + + info->info_ptr = png_create_info_struct(info->png_ptr); + if (!info->info_ptr) { + fprintf(stderr, "png_create_info_struct: failed, out of memory\n"); + png_destroy_write_struct(&info->png_ptr, NULL); + return -1; + } + + if (setjmp(info->jmpbuf)) { + fprintf(stderr, "setjmp: failed\n"); + png_destroy_write_struct(&info->png_ptr, &info->info_ptr); + return -1; + } + + png_init_io(info->png_ptr, info->outfile); + + png_set_compression_level(info->png_ptr, PNG_Z_DEFAULT_COMPRESSION); + + switch (format) { + case WL_SHM_FORMAT_ARGB8888: + color_type = PNG_COLOR_TYPE_RGB_ALPHA; + png_set_swap_alpha(info->png_ptr); + break; + case WL_SHM_FORMAT_XRGB8888: + color_type = PNG_COLOR_TYPE_RGB; + break; + case WL_SHM_FORMAT_ABGR8888: + color_type = PNG_COLOR_TYPE_RGB_ALPHA; + png_set_bgr(info->png_ptr); + png_set_swap_alpha(info->png_ptr); + break; + case WL_SHM_FORMAT_XBGR8888: + color_type = PNG_COLOR_TYPE_RGB; + png_set_bgr(info->png_ptr); + break; + default: + fprintf(stderr, "unsupported pixelformat 0x%x\n", format); + return -1; + } + + png_set_IHDR(info->png_ptr, info->info_ptr, width, height, + sample_depth, color_type, PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); + + png_write_info(info->png_ptr, info->info_ptr); + + return 0; +} + +static int +write_png_file(image_info *info, + const char *buffer, + int32_t width, + int32_t height, + uint32_t format, + int bytes_per_pixel) +{ + info->png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, + writepng_error_handler, NULL); + if (!info->png_ptr) { + fprintf(stderr, "png_create_write_struct: failed, out of memory\n"); + return -1; + } + + if (create_png_header(info, width, height, format) != 0) { + return -1; + } + + for(int j = 0; j < height ; ++j) { + png_const_bytep pointer = (png_const_bytep)buffer; + pointer += j * width * bytes_per_pixel; + + if (setjmp(info->jmpbuf)) { + fprintf(stderr, "setjmp: failed, j=%d\n", j); + png_destroy_write_struct(&info->png_ptr, &info->info_ptr); + info->png_ptr = NULL; + info->info_ptr = NULL; + return -1; + } + + png_write_row(info->png_ptr, pointer); + } + + if (setjmp(info->jmpbuf)) { + fprintf(stderr, "final setjmp failed\n"); + png_destroy_write_struct(&info->png_ptr, &info->info_ptr); + info->png_ptr = NULL; + info->info_ptr = NULL; + return -1; + } + + png_write_end(info->png_ptr, NULL); + + if (info->png_ptr && info->info_ptr) { + png_destroy_write_struct(&info->png_ptr, &info->info_ptr); + } + + return 0; +} + +int +save_as_png(const char *filename, + const char *buffer, + int32_t width, + int32_t height, + uint32_t format) +{ + int32_t image_stride = 0; + int32_t image_size = 0; + char *image_buffer = NULL; + int32_t row = 0; + int32_t col = 0; + int32_t image_offset = 0; + int32_t offset = 0; + int bytes_per_pixel = 0; + bool has_alpha = false; + image_info info; + + if ((filename == NULL) || (buffer == NULL)) { + return -1; + } + + info.outfile = fopen(filename, "wb"); + if (!info.outfile) { + fprintf(stderr, "could not open the file %s\n", filename); + return -1; + } + + switch (format) { + case WL_SHM_FORMAT_ARGB8888: + case WL_SHM_FORMAT_ABGR8888: + has_alpha = true; + break; + default: + has_alpha = false; + break; + } + + bytes_per_pixel = has_alpha ? 4 : 3; + image_stride = (((width * bytes_per_pixel) + 3) & ~3); + image_size = image_stride * height; + + image_buffer = malloc(image_size); + if (image_buffer == NULL) { + fprintf(stderr, "failed to allocate %d bytes for image buffer: %m\n", + image_size); + return -1; + } + + for (row = 0; row < height; ++row) { + for (col = 0; col < width; ++col) { + offset = row * width + col; + uint32_t pixel = htonl(((uint32_t*)buffer)[offset]); + char * pixel_p = (char*) &pixel; + image_offset = row * image_stride + col * bytes_per_pixel; + for (int i=0; i<bytes_per_pixel; ++i){ + image_buffer[image_offset + i] = pixel_p[i + (has_alpha ? 0 : 1)]; + } + } + } + + if (write_png_file(&info, image_buffer, width, height, format, bytes_per_pixel) != 0) { + free(image_buffer); + return -1; + } + + free(image_buffer); + return 0; +} diff --git a/ivi-layermanagement-api/ilmControl/src/writepng.h b/ivi-layermanagement-api/ilmControl/src/writepng.h new file mode 100644 index 0000000..0331a0a --- /dev/null +++ b/ivi-layermanagement-api/ilmControl/src/writepng.h @@ -0,0 +1,31 @@ +/*************************************************************************** + * + * Copyright (C) 2020 Advanced Driver Information Technology Joint Venture GmbH + * + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ****************************************************************************/ +#ifndef IVICONTROLLER_WRITEPNG_H_ +#define IVICONTROLLER_WRITEPNG_H_ + +#include <stdint.h> + +int +save_as_png(const char *filename, + const char *buffer, + int32_t width, + int32_t height, + uint32_t format); + +#endif /* IVICONTROLLER_WRITEPNG_H_ */ |