Les membres ayant 30 points peuvent parler sur les canaux annonces, projets et hs du chat.

Forum Casio - Projets de programmation


Index du Forum » Projets de programmation » libPNG pour Casio prizm/G90+E
Slyvtt Hors ligne Community Manager Points: 891 Défis: 0 Message

libPNG pour Casio prizm/G90+E

Posté le 05/05/2022 15:58

Voici cette fois quelques news concernant la libPNG recompilée pour nos chères Casio CG10/20/50 (PRIZM et G90+E).

Cette librairie a pour but de permettre la lecture des fichiers PNG et de rendre les données du fichiers accessible sous une forme facilement exploitable (en gros un tableau de pixels (R,G,B,A) associé à une structure d'entête contenant diverses infos utiles telles que la largeur et la hauteur de l'image lue).

Cette librairie est utilisée par la SDL_image et repose sur la librairie Zlib (le format PNG est un format compressé sans perte), mais il peut s'avérer utile le l'utiliser en dehors de la SDL, par exemple pour un addin gint avec dimage().

Ceci est tout à fait possible et je vous prépare la version "standalone" que vous pourrez utiliser pour créer une image bopti_image_t (format utilisé par gint via les méthodes dimage et dsubimage).

Il faudra bien penser à disposer de cette lib ainsi que zlib pour pouvoir utiliser le code joint, ainsi que de mettre les options de linkage adhoc dans le Makefile ou CMakeLists.txt (Je ferai un tuto quand tout sera fignolé au petit oignons )

Code pour convertir un PNG au format bopti - Cliquer pour dérouler
Cliquer pour enrouler


#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;
}



et ce qui donne sur l'écran (le grand Mario est un dimage() obtenu depuis une image externe en PNG et la tête est obtenu via un dsubimage() ).


On peut donc bien utiliser les fonctions usuelles de gint avec la librairie.

Par contre attention, contrairement à l'habitude, les images ne sont pas allouée en statique, il faut donc bien penser à libérer la mémoire avec un free() et surtout attention à ne pas dépasser la taille maxie de RAM !!!

Le dépôt gitea est en cours de fabrication. Je passerai les infos asap.

Ciao

Sly

@RDP (j'en ai fini pour cette semaine )


Slyvtt Hors ligne Community Manager Points: 891 Défis: 0 Message

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 :

Cliquez pour découvrir
Cliquez pour recouvrir


#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

------------------------------------------------------------------
Le monde est dangereux à vivre ! Non pas tant à cause de ceux qui font le mal, mais à cause de ceux qui regardent et laissent faire.
-------------------------------------------------------------------
Albert Einstein
Mathématicien, Physicien, Scientifique (1879 - 1955)

LienAjouter une imageAjouter une vidéoAjouter un lien vers un profilAjouter du codeCiterAjouter un spoiler(texte affichable/masquable par un clic)Ajouter une barre de progressionItaliqueGrasSoulignéAfficher du texte barréCentréJustifiéPlus petitPlus grandPlus de smileys !
Cliquez pour épingler Cliquez pour détacher Cliquez pour fermer
Alignement de l'image: Redimensionnement de l'image (en pixel):
Afficher la liste des membres
:bow: :cool: :good: :love: ^^
:omg: :fusil: :aie: :argh: :mdr:
:boulet2: :thx: :champ: :whistle: :bounce:
valider
 :)  ;)  :D  :p
 :lol:  8)  :(  :@
 0_0  :oops:  :grr:  :E
 :O  :sry:  :mmm:  :waza:
 :'(  :here:  ^^  >:)

Σ π θ ± α β γ δ Δ σ λ
Veuillez donner la réponse en chiffre
Vous devez activer le Javascript dans votre navigateur pour pouvoir valider ce formulaire.

Si vous n'avez pas volontairement désactivé cette fonctionnalité de votre navigateur, il s'agit probablement d'un bug : contactez l'équipe de Planète Casio.

Planète Casio v42 © créé par Neuronix et Muelsaco 2004 - 2022 | Il y a 76 connectés | Nous contacter | Qui sommes-nous ? | Licences et remerciements

Planète Casio est un site communautaire non affilié à Casio. Toute reproduction de Planète Casio, même partielle, est interdite.
Les programmes et autres publications présentes sur Planète Casio restent la propriété de leurs auteurs et peuvent être soumis à des licences ou copyrights.
CASIO est une marque déposée par CASIO Computer Co., Ltd