#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
Citer : Posté le 29/03/2025 17:43 | # |
Fichier joint
Je vous mets ici (libPNG_App) un petit addin de démonstration pour faire les opérations de base avec la libPNG :
- lire une image dans un fichier externe PNG, le stocker dans un image_t et l'afficher avec dimage ou dsubimage
- faire un screenshot de la vram et stocker ceci dans une image sur la flash de la calculatrice (attention seulement pour la fxCG50), si besoin, je pourrai faire aussi pour la fx9860g si il y a de la demande.
Ca donne ça en capture :
Citer : Posté le 29/03/2025 17:53 | #
Cool pour PythonExtra
Citer : Posté le 29/03/2025 17:55 | #
J'ai pas chronométré, mais dans les 10 secondes je dirai à vue de nez
Par contre la libPNG est assez lourde, donc l'addin fait 217ko
Citer : Posté le 29/03/2025 17:56 | #
Ouch donc en fait c'est aussi long que ce que j'estimais avec le BMP et plus lourd que ce que je pensais en termes de place. @_@
Pour PythonExtra qui fait 330 ko actuellement, un ajout d'environ 150 ko c'est dur à avaler quand même :x
Citer : Posté le 29/03/2025 18:00 | #
oui ça pique un peu (mais en fait la linPNG embarque elle meme la libZlib), donc a un moment y'a plus de miracle possible.
Par contre le screencap fait 18Ko en PNG (donc en contre partie on gagne sur chaque image générée).
Je confirme le chrono : 9.1 secondes sans OC.
Citer : Posté le 29/03/2025 18:04 | #
9 secondes pour 18 ko c'est waaat. On est d'accord que c'est l'écriture dans le fichier qui prend tout ce temps, pas la génération du PNG ? Il fait peut-être les deux en même temps tu vas me dire.
Il est peut-être temps pour toi de backup ta calto et réinitialiser tout le système de fichiers, c'est délirant ces délais o_o
Citer : Posté le 29/03/2025 18:07 | #
Ah oui non, c'est l'ensemble des opérations (lecture de la vram avec décomposition de chaque pixel en RGB565-->RGB888 + ecriture du PNG).
C'est pas juste l'écriture sur la flash.
Oui sinon effectivement ça ferait beaucoup