Journal Pixel Art et C++14

Posté par  (site web personnel) . Licence CC By‑SA.
Étiquettes :
22
3
avr.
2018

Petit délire illustrant l'usage de constexpr et de la biliothèsque frozen.

Première étape : faire un dessin en pixel art, par exemple:

  constexpr unsigned char bytes[] = "   ###              ###   "
                                    "  ##### ########## #####  "
                                    " #######          ####### "
                                    " ####                #### "
                                    " ###                  ### "
                                    "  #                    #  "
                                    "  #                    #  "
                                    " #    ###        ###    # "
                                    " #   #####      #####   # "
                                    " #  #### #      # ####  # "
                                    " #  #### #      # ####  # "
                                    " #  #####        #####  # "
                                    " #   ###    ##    ###   # "
                                    "  #         ##         #  "
                                    "  ####  RRR    RRR  ####  "
                                    " ######RRRRR  RRRRR###### "
                                    " ######RRRRRRRRRRRR###### "
                                    " ######RRRRRRRRRRRR###### "
                                    " ######RRRRRRRRRRRR###### "
                                    " #######RRRRRRRRRR####### "
                                    "  #####  RRRRRRRR  ####   "
                                    "   ###    RRRRRR    ##    "
                                    "           RRRR           ";

On remarquera l'énorme code de couleur espace → blanc, # → noir et R → rouge.

Ensuite on encode cette colormap dans une petite table de hash (oui dans ce cas un tableau de char suffirait) :

#include <frozen/map.h>

constexpr frozen::map<char, std::array<char, 3>, 5> Tans{
    {'R', {(char)0xFF, (char)0x00, (char)0x00}},
    {'G', {(char)0x00, (char)0xFF, (char)0x00}},
    {'B', {(char)0x00, (char)0x00, (char)0xFF}},
    {'#', {(char)0x00, (char)0x00, (char)0x00}},
    {' ', {(char)0xFF, (char)0xFF, (char)0xFF}},
};

Et comme on est tout foufou, on demande au compilateur C++ de traduire cette image pixel art en image au format PPM, à compile time

constexpr unsigned itoa(unsigned char * start, unsigned i) {
  constexpr unsigned step = sizeof(unsigned) * 3;
    for(unsigned k = 0; k < step; ++k)
      *start++ = ' ';
    do {
      *--start = '0' + i % 10;
      i /= 10;
    } while(i);
    return step;
}

template <unsigned H, unsigned W> struct ppm {
  unsigned char bytes[9 /* fixed header*/ + sizeof(unsigned) * 3 * 2 /* to hold sizes */ + 3 * H * W];

  constexpr ppm(unsigned char const *data) : bytes{0} {
    unsigned j = 0;
    bytes[j++] = 'P';
    bytes[j++] = '6';
    bytes[j++] = ' ';

    j += itoa(bytes + j, H);

    bytes[j++] = ' ';

    j += itoa(bytes + j, W);

    bytes[j++] = ' ';
    bytes[j++] = '2';
    bytes[j++] = '5';
    bytes[j++] = '5';
    bytes[j++] = '\n';
    for (unsigned i = 0; i < H * W; ++i) {
      auto const code = Tans.find(data[i])->second;
      bytes[j + 3 * i + 0] = code[0];
      bytes[j + 3 * i + 1] = code[1];
      bytes[j + 3 * i + 2] = code[2];
    }
  }

  void save(char const path[]) const {
    std::ofstream out{path, std::ios::binary};
    out.write((char *)bytes, sizeof bytes);
  }
};

On vient donc de créer une image dans un format binaire, en embarquant les sources de cette binaire dans les sources. À quand un encodeur jpeg constexpr?

PS: sources complètes par ici

  • # XPM

    Posté par  . Évalué à 6.

    Ça me fait penser au format d'image XPM !

    • [^] # Re: XPM

      Posté par  (site web personnel) . Évalué à 2.

      Mais mais… tu as raison, très amusant ce petit format :-)

      • [^] # Re: XPM

        Posté par  . Évalué à 6.

        Il y a aussi pbm pour les image monochromes (bitmap) et pgm pour les niveaux de gris (grayscale)

        L'avantage de tout ces petits formats est qu'il sont triviaux à lire et a écrire dans quasiment tout les langages. Le paquet netpbm fournit de nombreux utilitaires de conversions tels que pnmtojpeg ou ppnmtopng. Combiné avec popen, cela permet de générer des images JPEG ou PNG à partir de données brutes en seulement quelques lignes de C ou C++

        #include <math.h>
        #include <stdio.h>
        
        #define M 100
        #define N 100
        
        #define MAXV 65535
        
        #define OUTPUT "out.png"
        
        int main(void)
        {
        
          double val[M][N] ;
          int i,j ;
          FILE *out ;
        
          // Tableau de données brutes dans l'intervalle [-1.0,1.0]
          for (i=0;i<M;i++)
            for (j=0;j<N;j++)
              {
                val[i][j] = sin(cos(i*0.1+j*0.3)*2)*sin(j*0.2-i*0.03) ;
              }
        
          //  out = stdout ;
          out = popen("pnmtopng > " OUTPUT ,"w");
        
          fprintf(out,"P2\n%d %d\n%d\n",N,M,MAXV) ;
          for (i=0;i<M;i++) {
            for (j=0;j<N;j++) {
              // convertion de  [-1.0:+1.0] vers  [0:MAXV]
              int v = MAXV*((val[i][j]+1.0)/2.0) ;
              fprintf(out , "%d ", v);
            }
            fprintf(out,"\n");
          }
        
          return 0;
        }
        
        • [^] # Re: XPM

          Posté par  . Évalué à 1.

          Toute ma jeunesse les PGM lorsque je faisais du TNI.

          Un bon souvenir.

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.