assemble a splash preview if none was found (#277)
This commit is contained in:
9
include/conversion.h
Normal file
9
include/conversion.h
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
#ifndef CONVERISON_H
|
||||||
|
#define CONVERISON_H
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
size_t bin_to_abgr(char ** bufp, size_t size);
|
||||||
|
size_t png_to_abgr(char ** bufp, size_t size);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -31,6 +31,12 @@
|
|||||||
#include "music.h"
|
#include "music.h"
|
||||||
#include <jansson.h>
|
#include <jansson.h>
|
||||||
|
|
||||||
|
// These values assume a horizontal orientation
|
||||||
|
#define TOP_SCREEN_WIDTH 400
|
||||||
|
#define BOTTOM_SCREEN_WIDTH 320
|
||||||
|
#define SCREEN_HEIGHT 240
|
||||||
|
#define SCREEN_COLOR_DEPTH 4
|
||||||
|
|
||||||
enum ICON_IDS_OFFSET {
|
enum ICON_IDS_OFFSET {
|
||||||
ICONS_ABOVE = 0,
|
ICONS_ABOVE = 0,
|
||||||
ICONS_VISIBLE,
|
ICONS_VISIBLE,
|
||||||
@@ -118,7 +124,7 @@ void sort_by_filename(Entry_List_s * list);
|
|||||||
|
|
||||||
void delete_entry(Entry_s * entry, bool is_file);
|
void delete_entry(Entry_s * entry, bool is_file);
|
||||||
Result load_entries(const char * loading_path, Entry_List_s * list);
|
Result load_entries(const char * loading_path, Entry_List_s * list);
|
||||||
bool load_preview_from_buffer(void * buf, u32 size, C2D_Image * preview_image, int * preview_offset);
|
bool load_preview_from_buffer(char * row_pointers, u32 size, C2D_Image * preview_image, int * preview_offset);
|
||||||
bool load_preview(Entry_List_s list, C2D_Image * preview_image, int * preview_offset);
|
bool load_preview(Entry_List_s list, C2D_Image * preview_image, int * preview_offset);
|
||||||
void free_preview(C2D_Image preview_image);
|
void free_preview(C2D_Image preview_image);
|
||||||
Result load_audio(Entry_s, audio_s *);
|
Result load_audio(Entry_s, audio_s *);
|
||||||
|
|||||||
129
source/conversion.c
Normal file
129
source/conversion.c
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
#include "conversion.h"
|
||||||
|
#include "draw.h"
|
||||||
|
|
||||||
|
#include <png.h>
|
||||||
|
|
||||||
|
static void rotate_agbr_counterclockwise(char ** bufp, size_t size, size_t width)
|
||||||
|
{
|
||||||
|
uint32_t * buf = (uint32_t*)*bufp;
|
||||||
|
uint32_t * out = malloc(size);
|
||||||
|
|
||||||
|
size_t pixel_count = (size/4);
|
||||||
|
size_t height = pixel_count/width;
|
||||||
|
|
||||||
|
for (uint32_t h = 0; h < height; ++h)
|
||||||
|
{
|
||||||
|
for (uint32_t w = 0; w < width; ++w)
|
||||||
|
{
|
||||||
|
size_t buf_index = (w + (h * width));
|
||||||
|
size_t out_index = (height * (width-1)) - (height * w) + h;
|
||||||
|
|
||||||
|
out[out_index] = buf[buf_index];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free(*bufp);
|
||||||
|
*bufp = (char*)out;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t bin_to_abgr(char ** bufp, size_t size)
|
||||||
|
{
|
||||||
|
size_t out_size = (size / 3) * 4;
|
||||||
|
char* buf = malloc(out_size);
|
||||||
|
|
||||||
|
for (size_t i = 0, j = 0; i < size; i+=3, j+=4)
|
||||||
|
{
|
||||||
|
(buf+j)[0] = 0xFF; // A
|
||||||
|
(buf+j)[1] = (*bufp+i)[0]; // B
|
||||||
|
(buf+j)[2] = (*bufp+i)[1]; // G
|
||||||
|
(buf+j)[3] = (*bufp+i)[2]; // R
|
||||||
|
}
|
||||||
|
free(*bufp);
|
||||||
|
*bufp = buf;
|
||||||
|
|
||||||
|
// splash screens contain the raw framebuffer to put on the screen
|
||||||
|
// because the screens are mounted at a 90 degree angle we also need to rotate
|
||||||
|
// the output
|
||||||
|
rotate_agbr_counterclockwise(bufp, out_size, 240);
|
||||||
|
|
||||||
|
return out_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t png_to_abgr(char ** bufp, size_t size)
|
||||||
|
{
|
||||||
|
size_t out_size = 0;
|
||||||
|
if(size < 8 || png_sig_cmp((png_bytep)*bufp, 0, 8))
|
||||||
|
{
|
||||||
|
throw_error("Invalid preview.png", ERROR_LEVEL_WARNING);
|
||||||
|
return out_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t * buf = (uint32_t*)*bufp;
|
||||||
|
|
||||||
|
FILE * fp = fmemopen(buf, size, "rb");;
|
||||||
|
png_bytep * row_pointers = NULL;
|
||||||
|
|
||||||
|
png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
||||||
|
png_infop info = png_create_info_struct(png);
|
||||||
|
|
||||||
|
png_init_io(png, fp);
|
||||||
|
png_read_info(png, info);
|
||||||
|
|
||||||
|
u32 width = png_get_image_width(png, info);
|
||||||
|
u32 height = png_get_image_height(png, info);
|
||||||
|
|
||||||
|
png_byte color_type = png_get_color_type(png, info);
|
||||||
|
png_byte bit_depth = png_get_bit_depth(png, info);
|
||||||
|
|
||||||
|
// Read any color_type into 8bit depth, ABGR format.
|
||||||
|
// See http://www.libpng.org/pub/png/libpng-manual.txt
|
||||||
|
|
||||||
|
if(bit_depth == 16)
|
||||||
|
png_set_strip_16(png);
|
||||||
|
|
||||||
|
if(color_type == PNG_COLOR_TYPE_PALETTE)
|
||||||
|
png_set_palette_to_rgb(png);
|
||||||
|
|
||||||
|
// PNG_COLOR_TYPE_GRAY_ALPHA is always 8 or 16bit depth.
|
||||||
|
if(color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
|
||||||
|
png_set_expand_gray_1_2_4_to_8(png);
|
||||||
|
|
||||||
|
if(png_get_valid(png, info, PNG_INFO_tRNS))
|
||||||
|
png_set_tRNS_to_alpha(png);
|
||||||
|
|
||||||
|
// These color_type don't have an alpha channel then fill it with 0xff.
|
||||||
|
if(color_type == PNG_COLOR_TYPE_RGB ||
|
||||||
|
color_type == PNG_COLOR_TYPE_GRAY ||
|
||||||
|
color_type == PNG_COLOR_TYPE_PALETTE)
|
||||||
|
png_set_add_alpha(png, 0xFF, PNG_FILLER_BEFORE);
|
||||||
|
|
||||||
|
if(color_type == PNG_COLOR_TYPE_GRAY ||
|
||||||
|
color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
|
||||||
|
png_set_gray_to_rgb(png);
|
||||||
|
|
||||||
|
//output ABGR
|
||||||
|
png_set_bgr(png);
|
||||||
|
png_set_swap_alpha(png);
|
||||||
|
|
||||||
|
png_read_update_info(png, info);
|
||||||
|
|
||||||
|
row_pointers = malloc(sizeof(png_bytep) * height);
|
||||||
|
out_size = sizeof(u32) * (width * height);
|
||||||
|
u32 * out = malloc(out_size);
|
||||||
|
for(u32 y = 0; y < height; y++)
|
||||||
|
{
|
||||||
|
row_pointers[y] = (png_bytep)(out + (width * y));
|
||||||
|
}
|
||||||
|
|
||||||
|
png_read_image(png, row_pointers);
|
||||||
|
|
||||||
|
png_destroy_read_struct(&png, &info, NULL);
|
||||||
|
|
||||||
|
if (fp) fclose(fp);
|
||||||
|
if (row_pointers) free(row_pointers);
|
||||||
|
|
||||||
|
free(*bufp);
|
||||||
|
*bufp = (char*)out;
|
||||||
|
|
||||||
|
return out_size;
|
||||||
|
}
|
||||||
142
source/loading.c
142
source/loading.c
@@ -29,6 +29,7 @@
|
|||||||
#include "unicode.h"
|
#include "unicode.h"
|
||||||
#include "music.h"
|
#include "music.h"
|
||||||
#include "draw.h"
|
#include "draw.h"
|
||||||
|
#include "conversion.h"
|
||||||
|
|
||||||
#include <png.h>
|
#include <png.h>
|
||||||
|
|
||||||
@@ -449,77 +450,10 @@ void load_icons_thread(void * void_arg)
|
|||||||
while(arg->run_thread);
|
while(arg->run_thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool load_preview_from_buffer(void * buf, u32 size, C2D_Image * preview_image, int * preview_offset)
|
bool load_preview_from_buffer(char * row_pointers, u32 size, C2D_Image * preview_image, int * preview_offset)
|
||||||
{
|
{
|
||||||
if(size < 8 || png_sig_cmp(buf, 0, 8))
|
int height = SCREEN_HEIGHT * 2;
|
||||||
{
|
int width = (uint32_t)((size / 4) / height);
|
||||||
throw_error("Invalid preview.png", ERROR_LEVEL_WARNING);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
|
||||||
|
|
||||||
png_infop info = png_create_info_struct(png);
|
|
||||||
|
|
||||||
if(setjmp(png_jmpbuf(png)))
|
|
||||||
{
|
|
||||||
png_destroy_read_struct(&png, &info, NULL);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
FILE * fp = fmemopen(buf, size, "rb");
|
|
||||||
|
|
||||||
png_init_io(png, fp);
|
|
||||||
png_read_info(png, info);
|
|
||||||
|
|
||||||
int width = png_get_image_width(png, info);
|
|
||||||
int height = png_get_image_height(png, info);
|
|
||||||
|
|
||||||
png_byte color_type = png_get_color_type(png, info);
|
|
||||||
png_byte bit_depth = png_get_bit_depth(png, info);
|
|
||||||
|
|
||||||
// Read any color_type into 8bit depth, ABGR format.
|
|
||||||
// See http://www.libpng.org/pub/png/libpng-manual.txt
|
|
||||||
|
|
||||||
if(bit_depth == 16)
|
|
||||||
png_set_strip_16(png);
|
|
||||||
|
|
||||||
if(color_type == PNG_COLOR_TYPE_PALETTE)
|
|
||||||
png_set_palette_to_rgb(png);
|
|
||||||
|
|
||||||
// PNG_COLOR_TYPE_GRAY_ALPHA is always 8 or 16bit depth.
|
|
||||||
if(color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
|
|
||||||
png_set_expand_gray_1_2_4_to_8(png);
|
|
||||||
|
|
||||||
if(png_get_valid(png, info, PNG_INFO_tRNS))
|
|
||||||
png_set_tRNS_to_alpha(png);
|
|
||||||
|
|
||||||
// These color_type don't have an alpha channel then fill it with 0xff.
|
|
||||||
if(color_type == PNG_COLOR_TYPE_RGB ||
|
|
||||||
color_type == PNG_COLOR_TYPE_GRAY ||
|
|
||||||
color_type == PNG_COLOR_TYPE_PALETTE)
|
|
||||||
png_set_add_alpha(png, 0xFF, PNG_FILLER_BEFORE);
|
|
||||||
|
|
||||||
if(color_type == PNG_COLOR_TYPE_GRAY ||
|
|
||||||
color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
|
|
||||||
png_set_gray_to_rgb(png);
|
|
||||||
|
|
||||||
//output ABGR
|
|
||||||
png_set_bgr(png);
|
|
||||||
png_set_swap_alpha(png);
|
|
||||||
|
|
||||||
png_read_update_info(png, info);
|
|
||||||
|
|
||||||
png_bytep * row_pointers = malloc(sizeof(png_bytep) * height);
|
|
||||||
for(int y = 0; y < height; y++) {
|
|
||||||
row_pointers[y] = (png_byte*)malloc(png_get_rowbytes(png,info));
|
|
||||||
}
|
|
||||||
|
|
||||||
png_read_image(png, row_pointers);
|
|
||||||
|
|
||||||
fclose(fp);
|
|
||||||
png_destroy_read_struct(&png, &info, NULL);
|
|
||||||
|
|
||||||
|
|
||||||
free_preview(*preview_image);
|
free_preview(*preview_image);
|
||||||
|
|
||||||
@@ -540,20 +474,16 @@ bool load_preview_from_buffer(void * buf, u32 size, C2D_Image * preview_image, i
|
|||||||
memset(preview_image->tex->data, 0, preview_image->tex->size);
|
memset(preview_image->tex->data, 0, preview_image->tex->size);
|
||||||
|
|
||||||
for(int j = 0; j < height; j++) {
|
for(int j = 0; j < height; j++) {
|
||||||
png_bytep row = row_pointers[j];
|
png_bytep row = (png_bytep)(row_pointers + (width * 4 * j));
|
||||||
for(int i = 0; i < width; i++) {
|
for(int i = 0; i < width; i++) {
|
||||||
png_bytep px = &(row[i * 4]);
|
png_bytep px = &(row[i * 4]);
|
||||||
u32 dst = ((((j >> 3) * (512 >> 3) + (i >> 3)) << 6) + ((i & 1) | ((j & 1) << 1) | ((i & 2) << 1) | ((j & 2) << 2) | ((i & 4) << 2) | ((j & 4) << 3))) * 4;
|
u32 dst = ((((j >> 3) * (512 >> 3) + (i >> 3)) << 6) + ((i & 1) | ((j & 1) << 1) | ((i & 2) << 1) | ((j & 2) << 2) | ((i & 4) << 2) | ((j & 4) << 3))) * 4;
|
||||||
|
|
||||||
memcpy(preview_image->tex->data + dst, px, sizeof(u32));
|
memcpy(preview_image->tex->data + dst, px, sizeof(u32));
|
||||||
}
|
}
|
||||||
|
|
||||||
free(row_pointers[j]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
free(row_pointers);
|
*preview_offset = (width - TOP_SCREEN_WIDTH) / 2;
|
||||||
|
|
||||||
*preview_offset = (width-400)/2;
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -570,11 +500,65 @@ bool load_preview(Entry_List_s list, C2D_Image * preview_image, int * preview_of
|
|||||||
char *preview_buffer = NULL;
|
char *preview_buffer = NULL;
|
||||||
u64 size = load_data("/preview.png", entry, &preview_buffer);
|
u64 size = load_data("/preview.png", entry, &preview_buffer);
|
||||||
|
|
||||||
if(!size)
|
if(size)
|
||||||
|
{
|
||||||
|
if (!(size = png_to_abgr(&preview_buffer, size)))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
free(preview_buffer);
|
free(preview_buffer);
|
||||||
throw_error("No preview found.", ERROR_LEVEL_WARNING);
|
|
||||||
return false;
|
const int top_size = TOP_SCREEN_WIDTH * SCREEN_HEIGHT * SCREEN_COLOR_DEPTH;
|
||||||
|
const int out_size = top_size * 2;
|
||||||
|
|
||||||
|
char * rgba_buffer = malloc(out_size);
|
||||||
|
memset(rgba_buffer, 0, out_size);
|
||||||
|
bool found_splash = false;
|
||||||
|
|
||||||
|
// try to assembly a preview from the splash screens
|
||||||
|
size = load_data("/splash.bin", entry, &preview_buffer);
|
||||||
|
if (size)
|
||||||
|
{
|
||||||
|
found_splash = true;
|
||||||
|
bin_to_abgr(&preview_buffer, size);
|
||||||
|
|
||||||
|
memcpy(rgba_buffer, preview_buffer, top_size);
|
||||||
|
free(preview_buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
size = load_data("/splashbottom.bin", entry, &preview_buffer);
|
||||||
|
if (size)
|
||||||
|
{
|
||||||
|
found_splash = true;
|
||||||
|
bin_to_abgr(&preview_buffer, size);
|
||||||
|
|
||||||
|
const int buffer_width = TOP_SCREEN_WIDTH * SCREEN_COLOR_DEPTH;
|
||||||
|
const int bottom_buffer_width = BOTTOM_SCREEN_WIDTH * SCREEN_COLOR_DEPTH;
|
||||||
|
const int bottom_centered_offset = (TOP_SCREEN_WIDTH - BOTTOM_SCREEN_WIDTH) / 2;
|
||||||
|
|
||||||
|
// Store the bottom splash screen under the top splash and centered
|
||||||
|
for (int i = 0; i < SCREEN_HEIGHT; ++i)
|
||||||
|
memcpy(
|
||||||
|
rgba_buffer + top_size + (buffer_width * i) + (bottom_centered_offset * SCREEN_COLOR_DEPTH),
|
||||||
|
preview_buffer + (bottom_buffer_width * i),
|
||||||
|
bottom_buffer_width
|
||||||
|
);
|
||||||
|
|
||||||
|
free(preview_buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found_splash)
|
||||||
|
{
|
||||||
|
free(rgba_buffer);
|
||||||
|
throw_error("No preview found.", ERROR_LEVEL_WARNING);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
size = out_size;
|
||||||
|
preview_buffer = rgba_buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ret = load_preview_from_buffer(preview_buffer, size, preview_image, preview_offset);
|
bool ret = load_preview_from_buffer(preview_buffer, size, preview_image, preview_offset);
|
||||||
|
|||||||
@@ -32,6 +32,7 @@
|
|||||||
#include "unicode.h"
|
#include "unicode.h"
|
||||||
#include "music.h"
|
#include "music.h"
|
||||||
#include "urls.h"
|
#include "urls.h"
|
||||||
|
#include "conversion.h"
|
||||||
|
|
||||||
// forward declaration of special case used only here
|
// forward declaration of special case used only here
|
||||||
// TODO: replace this travesty with a proper handler
|
// TODO: replace this travesty with a proper handler
|
||||||
@@ -296,7 +297,18 @@ static bool load_remote_preview(Entry_s * entry, C2D_Image * preview_image, int
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ret = load_preview_from_buffer(preview_png, preview_size, preview_image, preview_offset);
|
char * preview_buf = malloc(preview_size);
|
||||||
|
u32 preview_buf_size = preview_size;
|
||||||
|
memcpy(preview_buf, preview_png, preview_size);
|
||||||
|
|
||||||
|
if (!(preview_buf_size = png_to_abgr(&preview_buf, preview_buf_size)))
|
||||||
|
{
|
||||||
|
free(preview_buf);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ret = load_preview_from_buffer(preview_buf, preview_buf_size, preview_image, preview_offset);
|
||||||
|
free(preview_buf);
|
||||||
|
|
||||||
if (ret && not_cached) // only save the preview if it loaded correctly - isn't corrupted
|
if (ret && not_cached) // only save the preview if it loaded correctly - isn't corrupted
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user