#include <gint/gint.h>
#include <gint/display.h>
#include <gint/keyboard.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <zlib.h>
#define PNG_DEBUG 3
#include <png.h>
int currentline = 0;
void abort_(const char * s, ...)
{
#if(0)
va_list args;
va_start(args, s);
dprint(1, 1+currentline*10, C_BLACK, s, args );
currentline++;
va_end(args);
abort();
#endif
}
int x, y;
int width, height;
png_byte color_type;
png_byte bit_depth;
png_structp png_ptr;
png_infop info_ptr;
int number_of_passes;
png_bytep *row_pointers;
//Return 0 on success and -1 on error
int read_png_file(char* file_name)
{
char header[8]; // 8 is the maximum size that can be checked
FILE *fp = fopen(file_name, "rb");
if (!fp)
{
abort_("[read_png_file] File %s could not be opened for reading", file_name);
return -1;
}
fread(header, 1, 8, fp);
if (png_sig_cmp(header, 0, 8))
{
abort_("[read_png_file] File %s is not recognized as a PNG file", file_name);
return -1;
}
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (!png_ptr)
{
abort_("[read_png_file] png_create_read_struct failed");
return -1;
}
info_ptr = png_create_info_struct(png_ptr);
if (!info_ptr)
{
abort_("[read_png_file] png_create_info_struct failed");
return -1;
}
if (setjmp(png_jmpbuf(png_ptr)))
{
abort_("[read_png_file] Error during init_io");
return -1;
}
png_init_io(png_ptr, fp);
png_set_sig_bytes(png_ptr, 8);
png_read_info(png_ptr, info_ptr);
width = png_get_image_width(png_ptr, info_ptr);
height = png_get_image_height(png_ptr, info_ptr);
color_type = png_get_color_type(png_ptr, info_ptr);
bit_depth = png_get_bit_depth(png_ptr, info_ptr);
number_of_passes = png_set_interlace_handling(png_ptr);
png_read_update_info(png_ptr, info_ptr);
if (setjmp(png_jmpbuf(png_ptr)))
{
abort_("[read_png_file] Error during read_image");
return -1;
}
row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * height);
for (y=0; y<height; y++)
row_pointers[y] = (png_byte*) malloc(png_get_rowbytes(png_ptr,info_ptr));
png_read_image(png_ptr, row_pointers);
fclose(fp);
return 0;
}
void process_file(void)
{
if (png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_RGB)
abort_("[process_file] input file is PNG_COLOR_TYPE_RGB but must be PNG_COLOR_TYPE_RGBA "
"(lacks the alpha channel)");
if (png_get_color_type(png_ptr, info_ptr) != PNG_COLOR_TYPE_RGBA)
abort_("[process_file] color_type of input file must be PNG_COLOR_TYPE_RGBA (%d) (is %d)",
PNG_COLOR_TYPE_RGBA, png_get_color_type(png_ptr, info_ptr));
for (y=0; y<height; y++)
{
png_byte* row = row_pointers[y];
for (x=0; x<width; x++)
{
png_byte* ptr = &(row[x*4]);
dprint( 1, 200, C_WHITE, "Pixel at position [ %d - %d ] has RGBA values: %d - %d - %d - %d\n",
x, y, ptr[0], ptr[1], ptr[2], ptr[3]);
ptr[0] = 0;
ptr[1] = ptr[2];
}
}
}
size_t image_size_profile(int width, int height)
{
size_t size = sizeof(bopti_image_t);
size += width * height * 2;
return size;
}
void set_pixel(bopti_image_t *img, int x, int y, int color)
{
if((unsigned)x >= img->width || (unsigned)y >= img->height)
return;
uint8_t *bytes = (void *)img->data;
img->data[y * img->width + x] = color;
}
bopti_image_t *convert_png_to_bopti( char *filename )
{
if (gint_world_switch(GINT_CALL(read_png_file, filename ))==-1) // qq chose s'est mal passé durant la lecture
return NULL;
int Wmax = width;
if (width%2==1) Wmax++; // si largeur impaire, on rajoute un pixel transparent
size_t size = image_size_profile(Wmax, height);
bopti_image_t *image_temp = malloc( size );
if(!image_temp) return NULL;
image_temp->profile = 0; // par defaut on a pas la transparence (on updatera si besoin après)
image_temp->alpha = 0x0001;
image_temp->width = Wmax;
image_temp->height = height;
uint16_t color;
for(int v=0; v<height; v++)
{
png_byte* row = row_pointers[v];
for(int u=0; u<width; u++)
{
png_byte* ptr = &(row[u*4]);
if (ptr[3]>128)
{
color = C_RGB( ptr[0]>>3, ptr[1]>>3, ptr[2]>>3 );
if (color!=0x0001) set_pixel(image_temp, u, v, color);
else set_pixel(image_temp, u, v, 0x0000); // si par manque de chance on tombe sur la couleur transparente à la conversion, on met du noir
}
else
{
set_pixel(image_temp, u, v, 0x0001); // set transparency
image_temp->profile = 1; // on mets à jour le profil car il y a de la transparence
}
}
if (Wmax!=width) // si on doit ajouter un pixel supplémentaire sur la largeur
{
set_pixel(image_temp, Wmax, v, 0x0001);
}
}
for (y=0; y<height; y++)
free(row_pointers[y]);
free(row_pointers);
return image_temp;
}
bopti_image_t *image = NULL;
bopti_image_t *image2 = NULL;
int main(void)
{
// Jute ici pour désactiver le triple buffering par défaut
uint16_t *vram1, *vram2;
dgetvram(&vram1, &vram2);
dsetvram(vram1, vram1);
dclear(C_WHITE);
dtext(1, 1, C_BLACK, "Sample libcPNG to bopti test :");
dupdate();
image = convert_png_to_bopti( "mario.png" );
image2 = convert_png_to_bopti( "nofile.png" ); // fichier qui n'existe pas, controle de la stabilité
dimage( 0, 0, image );
dimage( 0, 0, image2 ); // ne doit pas planter
dsubimage( 200, 50, image, 21,15, 120, 88, DIMAGE_NONE );
dsubimage( 200, 50, image2, 21,15, 120, 88, DIMAGE_NONE ); // idem, sans plantage
dupdate();
getkey();
if (image!=NULL) free(image); // IMPORTANT : contrairement à l'habitude avec fxconv, il faut libérer la mémoire, on est ici en allocation dynamique
if (image2!=NULL) free(image2);
return 1;
}
Citer : Posté le 28/05/2022 12:51 | #
Hello,
suite au changement de gint <2.7.1 vers 2.8 avec l'introduction des nouvelles routines image et du nouveau format image_t en remplacement du "vieux" format bopti_image_t, je vous fais une MàJ de la routine d'import de libPNG vers ce nouveau format image_t.
Donc si vous êtes en gint <2.7.1, c'est l'ancienne routine qu'il faut utiliser (voir un post plus haut), si vous êtes en gint 2.8 (ou ultérieur, cela viendra), il vous faudra désormais utiliser le code suivant :
#include <gint/gint.h>
#include <gint/display.h>
#include <gint/keyboard.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <zlib.h>
#define PNG_DEBUG 3
#include <png.h>
int currentline = 0;
void abort_(const char * s, ...)
{
#if(0)
va_list args;
va_start(args, s);
dprint(1, 1+currentline*10, C_BLACK, s, args );
currentline++;
va_end(args);
abort();
#endif
}
int x, y;
int width, height;
png_byte color_type;
png_byte bit_depth;
png_structp png_ptr;
png_infop info_ptr;
int number_of_passes;
png_bytep *row_pointers;
//Return 0 on success and -1 on error
int read_png_file(char* file_name)
{
char header[8]; // 8 is the maximum size that can be checked
FILE *fp = fopen(file_name, "rb");
if (!fp)
{
abort_("[read_png_file] File %s could not be opened for reading", file_name);
return -1;
}
fread(header, 1, 8, fp);
if (png_sig_cmp(header, 0, 8))
{
abort_("[read_png_file] File %s is not recognized as a PNG file", file_name);
return -1;
}
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (!png_ptr)
{
abort_("[read_png_file] png_create_read_struct failed");
return -1;
}
info_ptr = png_create_info_struct(png_ptr);
if (!info_ptr)
{
abort_("[read_png_file] png_create_info_struct failed");
return -1;
}
if (setjmp(png_jmpbuf(png_ptr)))
{
abort_("[read_png_file] Error during init_io");
return -1;
}
png_init_io(png_ptr, fp);
png_set_sig_bytes(png_ptr, 8);
png_read_info(png_ptr, info_ptr);
width = png_get_image_width(png_ptr, info_ptr);
height = png_get_image_height(png_ptr, info_ptr);
color_type = png_get_color_type(png_ptr, info_ptr);
bit_depth = png_get_bit_depth(png_ptr, info_ptr);
number_of_passes = png_set_interlace_handling(png_ptr);
png_read_update_info(png_ptr, info_ptr);
if (setjmp(png_jmpbuf(png_ptr)))
{
abort_("[read_png_file] Error during read_image");
return -1;
}
row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * height);
for (y=0; y<height; y++)
row_pointers[y] = (png_byte*) malloc(png_get_rowbytes(png_ptr,info_ptr));
png_read_image(png_ptr, row_pointers);
fclose(fp);
return 0;
}
void process_file(void)
{
if (png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_RGB)
abort_("[process_file] input file is PNG_COLOR_TYPE_RGB but must be PNG_COLOR_TYPE_RGBA "
"(lacks the alpha channel)");
if (png_get_color_type(png_ptr, info_ptr) != PNG_COLOR_TYPE_RGBA)
abort_("[process_file] color_type of input file must be PNG_COLOR_TYPE_RGBA (%d) (is %d)",
PNG_COLOR_TYPE_RGBA, png_get_color_type(png_ptr, info_ptr));
for (y=0; y<height; y++)
{
png_byte* row = row_pointers[y];
for (x=0; x<width; x++)
{
png_byte* ptr = &(row[x*4]);
dprint( 1, 200, C_WHITE, "Pixel at position [ %d - %d ] has RGBA values: %d - %d - %d - %d\n",
x, y, ptr[0], ptr[1], ptr[2], ptr[3]);
ptr[0] = 0;
ptr[1] = ptr[2];
}
}
}
image_t *convert_png_to_image_t( char *filename )
{
if (gint_world_switch(GINT_CALL(read_png_file, filename ))==-1) // qq chose s'est mal passé durant la lecture
return NULL;
image_t *image_temp;
int Wmax = width;
if (Wmax%2==1)
{
Wmax++; // si largeur impaire, on rajoute un pixel transparent
image_temp = image_alloc( Wmax, height, IMAGE_RGB565A ); // le format devient avec couleur transparente
}
else
image_temp = image_alloc( Wmax, height, IMAGE_RGB565 ); // sinon le format est sans transparence
if(!image_temp) return NULL;
uint16_t color;
for(int v=0; v<height; v++)
{
png_byte* row = row_pointers[v];
for(int u=0; u<width; u++)
{
png_byte* ptr = &(row[u*4]);
if (ptr[3]>128)
{
color = C_RGB( ptr[0]>>3, ptr[1]>>3, ptr[2]>>3 );
if (color!=0x0001) image_set_pixel(image_temp, u, v, color);
else image_set_pixel(image_temp, u, v, 0x0000); // si par manque de chance on tombe sur la couleur transparente à la conversion, on met du noir
}
else
{
image_temp->format = IMAGE_RGB565A; // on mets à jour le profil car il y a de la transparence
image_set_pixel(image_temp, u, v, image_alpha(IMAGE_RGB565A)); // set transparency
}
}
if (Wmax!=width) // si on doit ajouter un pixel supplémentaire sur la largeur
{
image_set_pixel(image_temp, Wmax, v, image_alpha(IMAGE_RGB565A));
}
}
for (y=0; y<height; y++)
free(row_pointers[y]);
free(row_pointers);
return image_temp;
}
image_t *image = NULL;
image_t *image2 = NULL;
int main(void)
{
// Jute ici pour désactiver le triple buffering par défaut
uint16_t *vram1, *vram2;
dgetvram(&vram1, &vram2);
dsetvram(vram1, vram1);
dclear(C_WHITE);
dtext(1, 1, C_BLACK, "Simple libcPNG to image_t (gint 2.8) test :");
dupdate();
image = convert_png_to_image_t( "mario.png" );
image2 = convert_png_to_image_t( "nofile.png" ); // fichier qui n'existe pas, controle de la stabilité
dimage( 0, 0, image );
dimage( 0, 0, image2 ); // ne doit pas planter
dsubimage( 200, 50, image, 21,15, 120, 88, DIMAGE_NONE );
dsubimage( 200, 50, image2, 21,15, 120, 88, DIMAGE_NONE ); // idem, sans plantage
dupdate();
getkey();
if (image!=NULL) free(image);
return 1;
}
a priori l'inversion (ou mix entre les versions de gint/cette routine) n'est pas possible, vous aurez forcément une erreur à la compilation soit pour cause de membre .profil absent (remplacé par .format dans gint 2.8), soit pour cause d'absence de définition de image_t.
A plus
Sly