mirror of
https://github.com/google/pebble.git
synced 2025-03-19 18:41:21 +00:00
133 lines
4 KiB
C
133 lines
4 KiB
C
|
/*
|
||
|
* Copyright 2024 Google LLC
|
||
|
*
|
||
|
* 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.
|
||
|
*/
|
||
|
|
||
|
#pragma once
|
||
|
|
||
|
#include "applib/graphics/gtypes.h"
|
||
|
|
||
|
#include <stdio.h>
|
||
|
#include <sys/wait.h>
|
||
|
#include <unistd.h>
|
||
|
|
||
|
#define PATH_STRING_LENGTH 512
|
||
|
|
||
|
extern GBitmapDataRowInfo prv_gbitmap_get_data_row_info(const GBitmap *bitmap, uint16_t y);
|
||
|
|
||
|
bool write_gbitmap_to_pbi(GBitmap *bmp, const char *filepath, const char *pbi2png_path) {
|
||
|
char pbi_path[PATH_STRING_LENGTH];
|
||
|
char png_path[PATH_STRING_LENGTH];
|
||
|
char *ext = NULL;
|
||
|
|
||
|
strncpy(pbi_path, filepath, sizeof(pbi_path));
|
||
|
ext = strrchr(pbi_path, '.');
|
||
|
strncpy(ext + 1, "pbi", 3);
|
||
|
|
||
|
strncpy(png_path, filepath, sizeof(png_path));
|
||
|
ext = strrchr(png_path, '.');
|
||
|
strncpy(ext + 1, "png", 3);
|
||
|
|
||
|
FILE *file = fopen(pbi_path, "w");
|
||
|
if (!file) {
|
||
|
printf("Unable to open file: %s\n", pbi_path);
|
||
|
return false;
|
||
|
}
|
||
|
// Just in case this output bitmap was created by hand.
|
||
|
bmp->info.version = GBITMAP_VERSION_CURRENT;
|
||
|
|
||
|
// PBL-24228 Support Circular PBIs
|
||
|
uint16_t info_flags = bmp->info_flags;
|
||
|
#ifdef PLATFORM_SPALDING
|
||
|
if(bmp->info.format == GBitmapFormat8BitCircular) {
|
||
|
// Have to force output format to 8Bit;
|
||
|
((BitmapInfo*)&info_flags)->format = GBitmapFormat8Bit;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
// use entire bounds to include entire image
|
||
|
GRect entire_bounds = GRect(0, 0,
|
||
|
bmp->bounds.origin.x + bmp->bounds.size.w,
|
||
|
bmp->bounds.origin.y + bmp->bounds.size.h);
|
||
|
|
||
|
fwrite(&bmp->row_size_bytes, sizeof(bmp->row_size_bytes), 1, file);
|
||
|
fwrite(&info_flags, 2, 1, file);
|
||
|
fwrite(&entire_bounds, sizeof(GRect), 1, file);
|
||
|
|
||
|
#ifdef PLATFORM_SPALDING
|
||
|
if(bmp->info.format == GBitmapFormat8BitCircular) {
|
||
|
for (int y = 0; y < entire_bounds.size.h; ++y) {
|
||
|
// 8-Bit circular buffer is centered in padded rows, so just grab row and write DISP_COLS
|
||
|
const GBitmapDataRowInfo dest_row_info = prv_gbitmap_get_data_row_info(bmp, y);
|
||
|
uint8_t *bmp_row = dest_row_info.data;
|
||
|
int x = 0;
|
||
|
const uint8_t blank = 0;
|
||
|
// PBL-24229 missing mask: data outside of circle is garbage from previous and next rows
|
||
|
// Pad with blanks before min_x
|
||
|
while (x < dest_row_info.min_x) {
|
||
|
fwrite(&blank, 1, 1, file);
|
||
|
x++;
|
||
|
}
|
||
|
if (x <= dest_row_info.max_x) {
|
||
|
int length = dest_row_info.max_x - x + 1;
|
||
|
fwrite(&bmp_row[dest_row_info.min_x], 1, length, file);
|
||
|
x += length;
|
||
|
}
|
||
|
// Pad with blanks after max_x
|
||
|
while (x < entire_bounds.size.w) {
|
||
|
fwrite(&blank, 1, 1, file);
|
||
|
x++;
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
#endif
|
||
|
size_t data_size = bmp->row_size_bytes * (entire_bounds.size.h);
|
||
|
fwrite(bmp->addr, 1, data_size, file);
|
||
|
#ifdef PLATFORM_SPALDING
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
uint8_t palette_size = gbitmap_get_palette_size(gbitmap_get_format(bmp));
|
||
|
if (palette_size > 0) {
|
||
|
fwrite(bmp->palette, 1, palette_size * sizeof(*bmp->palette), file);
|
||
|
}
|
||
|
fclose(file);
|
||
|
printf("PBI file written to: %s\n", pbi_path);
|
||
|
|
||
|
int pid = fork();
|
||
|
if (pid == 0) {
|
||
|
char *args[] = {
|
||
|
"python",
|
||
|
(char *)pbi2png_path,
|
||
|
(char *)pbi_path,
|
||
|
(char *)png_path,
|
||
|
NULL,
|
||
|
};
|
||
|
execvp("python", args);
|
||
|
|
||
|
perror("execv"); // Error internal to execve
|
||
|
exit(EXIT_FAILURE);
|
||
|
}
|
||
|
|
||
|
int status;
|
||
|
if (wait(&status) >= 0 && !WIFEXITED(status)) {
|
||
|
printf("FAILURE: pbi2png.py process exited with %d status. PNG file not written\n",
|
||
|
WEXITSTATUS(status));
|
||
|
} else {
|
||
|
printf("PNG file written to: %s\n", png_path);
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|