From 8a61c17d5c1d4047cfec1d3aee7fd5aa758e3bed Mon Sep 17 00:00:00 2001 From: "Valeriano A.R" Date: Tue, 1 Jul 2014 01:41:59 +0200 Subject: [PATCH] Replace BMP image file loading with PNG image file loading --- GameEnts.c | 69 +- GameLib/Draw.c | 241 +- GameLib/Draw.h | 7 + GameLib/Entity.h | 4 +- GameLib/Util.c | 14 + GameLib/Util.h | 10 +- GameLib/lodepng.c | 6285 +++++++++++++++++++++++++++++++++ GameLib/lodepng.h | 1710 +++++++++ data/block.bmp | Bin 16438 -> 0 bytes data/block.png | Bin 0 -> 4280 bytes data/bunny_left.bmp | Bin 4150 -> 0 bytes data/bunny_left.png | Bin 0 -> 1893 bytes data/bunny_right.bmp | Bin 4150 -> 0 bytes data/bunny_right.png | Bin 0 -> 1914 bytes data/carnivoreplant_left.bmp | Bin 8246 -> 0 bytes data/carnivoreplant_left.png | Bin 0 -> 2619 bytes data/carnivoreplant_right.bmp | Bin 8246 -> 0 bytes data/carnivoreplant_right.png | Bin 0 -> 2641 bytes data/earth/0.bmp | Bin 4150 -> 0 bytes data/earth/0.png | Bin 0 -> 2682 bytes data/earth/1.bmp | Bin 4150 -> 0 bytes data/earth/1.png | Bin 0 -> 2715 bytes data/earth/2.bmp | Bin 4150 -> 0 bytes data/earth/2.png | Bin 0 -> 2811 bytes data/earth/3.bmp | Bin 4150 -> 0 bytes data/earth/3.png | Bin 0 -> 2779 bytes data/earth/4.bmp | Bin 4150 -> 0 bytes data/earth/4.png | Bin 0 -> 2705 bytes data/earth/5.bmp | Bin 4150 -> 0 bytes data/earth/5.png | Bin 0 -> 2728 bytes data/earth/6.bmp | Bin 4150 -> 0 bytes data/earth/6.png | Bin 0 -> 2914 bytes data/earth/7.bmp | Bin 4150 -> 0 bytes data/earth/7.png | Bin 0 -> 2994 bytes data/earth/8.bmp | Bin 4150 -> 0 bytes data/earth/8.png | Bin 0 -> 2813 bytes data/earth/9.bmp | Bin 4150 -> 0 bytes data/earth/9.png | Bin 0 -> 2883 bytes data/earth/A.bmp | Bin 4150 -> 0 bytes data/earth/A.png | Bin 0 -> 2935 bytes data/earth/B.bmp | Bin 4150 -> 0 bytes data/earth/B.png | Bin 0 -> 2903 bytes data/earth/C.bmp | Bin 4150 -> 0 bytes data/earth/C.png | Bin 0 -> 2840 bytes data/earth/D.bmp | Bin 4150 -> 0 bytes data/earth/D.png | Bin 0 -> 2924 bytes data/earth/E.bmp | Bin 4150 -> 0 bytes data/earth/E.png | Bin 0 -> 2982 bytes data/earth/F.bmp | Bin 4150 -> 0 bytes data/earth/F.png | Bin 0 -> 2994 bytes data/flower_left.bmp | Bin 8246 -> 0 bytes data/flower_left.png | Bin 0 -> 1666 bytes data/flower_right.bmp | Bin 8246 -> 0 bytes data/flower_right.png | Bin 0 -> 1666 bytes data/heaven.bmp | Bin 65590 -> 0 bytes data/heaven.png | Bin 0 -> 12146 bytes data/magikball.bmp | Bin 1078 -> 0 bytes data/magikball.png | Bin 0 -> 597 bytes data/platform.bmp | Bin 4150 -> 0 bytes data/platform.png | Bin 0 -> 652 bytes data/player.bmp | Bin 4150 -> 0 bytes data/player.png | Bin 0 -> 1164 bytes data/rock.bmp | Bin 4150 -> 0 bytes data/rock.png | Bin 0 -> 2658 bytes data/soldier.bmp | Bin 6200 -> 0 bytes data/soldier.png | Bin 0 -> 3323 bytes data/spider_left.bmp | Bin 4150 -> 0 bytes data/spider_left.png | Bin 0 -> 1294 bytes data/spider_right.bmp | Bin 4150 -> 0 bytes data/spider_right.png | Bin 0 -> 1277 bytes data/spike_left.bmp | Bin 1078 -> 0 bytes data/spike_left.png | Bin 0 -> 364 bytes data/spike_right.bmp | Bin 1078 -> 0 bytes data/spike_right.png | Bin 0 -> 366 bytes data/spikedbush.bmp | Bin 4150 -> 0 bytes data/spikedbush.png | Bin 0 -> 1486 bytes data/wizard_left.bmp | Bin 8246 -> 0 bytes data/wizard_left.png | Bin 0 -> 3807 bytes data/wizard_right.bmp | Bin 8246 -> 0 bytes data/wizard_right.png | Bin 0 -> 3807 bytes main.c | 2 +- 81 files changed, 8168 insertions(+), 174 deletions(-) create mode 100644 GameLib/lodepng.c create mode 100644 GameLib/lodepng.h delete mode 100644 data/block.bmp create mode 100644 data/block.png delete mode 100644 data/bunny_left.bmp create mode 100644 data/bunny_left.png delete mode 100644 data/bunny_right.bmp create mode 100644 data/bunny_right.png delete mode 100644 data/carnivoreplant_left.bmp create mode 100644 data/carnivoreplant_left.png delete mode 100644 data/carnivoreplant_right.bmp create mode 100644 data/carnivoreplant_right.png delete mode 100644 data/earth/0.bmp create mode 100644 data/earth/0.png delete mode 100644 data/earth/1.bmp create mode 100644 data/earth/1.png delete mode 100644 data/earth/2.bmp create mode 100644 data/earth/2.png delete mode 100644 data/earth/3.bmp create mode 100644 data/earth/3.png delete mode 100644 data/earth/4.bmp create mode 100644 data/earth/4.png delete mode 100644 data/earth/5.bmp create mode 100644 data/earth/5.png delete mode 100644 data/earth/6.bmp create mode 100644 data/earth/6.png delete mode 100644 data/earth/7.bmp create mode 100644 data/earth/7.png delete mode 100644 data/earth/8.bmp create mode 100644 data/earth/8.png delete mode 100644 data/earth/9.bmp create mode 100644 data/earth/9.png delete mode 100644 data/earth/A.bmp create mode 100644 data/earth/A.png delete mode 100644 data/earth/B.bmp create mode 100644 data/earth/B.png delete mode 100644 data/earth/C.bmp create mode 100644 data/earth/C.png delete mode 100644 data/earth/D.bmp create mode 100644 data/earth/D.png delete mode 100644 data/earth/E.bmp create mode 100644 data/earth/E.png delete mode 100644 data/earth/F.bmp create mode 100644 data/earth/F.png delete mode 100644 data/flower_left.bmp create mode 100644 data/flower_left.png delete mode 100644 data/flower_right.bmp create mode 100644 data/flower_right.png delete mode 100644 data/heaven.bmp create mode 100644 data/heaven.png delete mode 100644 data/magikball.bmp create mode 100644 data/magikball.png delete mode 100644 data/platform.bmp create mode 100644 data/platform.png delete mode 100644 data/player.bmp create mode 100644 data/player.png delete mode 100644 data/rock.bmp create mode 100644 data/rock.png delete mode 100644 data/soldier.bmp create mode 100644 data/soldier.png delete mode 100644 data/spider_left.bmp create mode 100644 data/spider_left.png delete mode 100644 data/spider_right.bmp create mode 100644 data/spider_right.png delete mode 100644 data/spike_left.bmp create mode 100644 data/spike_left.png delete mode 100644 data/spike_right.bmp create mode 100644 data/spike_right.png delete mode 100644 data/spikedbush.bmp create mode 100644 data/spikedbush.png delete mode 100644 data/wizard_left.bmp create mode 100644 data/wizard_left.png delete mode 100644 data/wizard_right.bmp create mode 100644 data/wizard_right.png diff --git a/GameEnts.c b/GameEnts.c index 451e3d7..f9783bf 100644 --- a/GameEnts.c +++ b/GameEnts.c @@ -458,68 +458,69 @@ void GameEnts_Init(){ // Load and initialize media. // - img_player=Draw_LoadImage("data/player.bmp"); - img_platform=Draw_LoadImage("data/platform.bmp"); - img_block=Draw_LoadImage("data/block.bmp"); + img_player=Draw_LoadImage("data/player.png"); + img_platform=Draw_LoadImage("data/platform.png"); + img_block=Draw_LoadImage("data/block.png"); // Wizard - img_wizard[0]=Draw_LoadImage("data/wizard_left.bmp"); - img_wizard[1]=Draw_LoadImage("data/wizard_right.bmp"); + img_wizard[0]=Draw_LoadImage("data/wizard_left.png"); + //img_wizard[1]=Draw_LoadImage("data/wizard_right.png"); + img_wizard[1]=Draw_LoadImage("data/wizard_right.png"); // Magik Ball - img_magikball=Draw_LoadImage("data/magikball.bmp"); + img_magikball=Draw_LoadImage("data/magikball.png"); // Load the earth images - img_earth[ 0]=Draw_LoadImage("data/earth/0.bmp"); - img_earth[ 1]=Draw_LoadImage("data/earth/1.bmp"); - img_earth[ 2]=Draw_LoadImage("data/earth/2.bmp"); - img_earth[ 3]=Draw_LoadImage("data/earth/3.bmp"); - img_earth[ 4]=Draw_LoadImage("data/earth/4.bmp"); - img_earth[ 5]=Draw_LoadImage("data/earth/5.bmp"); - img_earth[ 6]=Draw_LoadImage("data/earth/6.bmp"); - img_earth[ 7]=Draw_LoadImage("data/earth/7.bmp"); - img_earth[ 8]=Draw_LoadImage("data/earth/8.bmp"); - img_earth[ 9]=Draw_LoadImage("data/earth/9.bmp"); - img_earth[10]=Draw_LoadImage("data/earth/A.bmp"); - img_earth[11]=Draw_LoadImage("data/earth/B.bmp"); - img_earth[12]=Draw_LoadImage("data/earth/C.bmp"); - img_earth[13]=Draw_LoadImage("data/earth/D.bmp"); - img_earth[14]=Draw_LoadImage("data/earth/E.bmp"); - img_earth[15]=Draw_LoadImage("data/earth/F.bmp"); + img_earth[ 0]=Draw_LoadImage("data/earth/0.png"); + img_earth[ 1]=Draw_LoadImage("data/earth/1.png"); + img_earth[ 2]=Draw_LoadImage("data/earth/2.png"); + img_earth[ 3]=Draw_LoadImage("data/earth/3.png"); + img_earth[ 4]=Draw_LoadImage("data/earth/4.png"); + img_earth[ 5]=Draw_LoadImage("data/earth/5.png"); + img_earth[ 6]=Draw_LoadImage("data/earth/6.png"); + img_earth[ 7]=Draw_LoadImage("data/earth/7.png"); + img_earth[ 8]=Draw_LoadImage("data/earth/8.png"); + img_earth[ 9]=Draw_LoadImage("data/earth/9.png"); + img_earth[10]=Draw_LoadImage("data/earth/A.png"); + img_earth[11]=Draw_LoadImage("data/earth/B.png"); + img_earth[12]=Draw_LoadImage("data/earth/C.png"); + img_earth[13]=Draw_LoadImage("data/earth/D.png"); + img_earth[14]=Draw_LoadImage("data/earth/E.png"); + img_earth[15]=Draw_LoadImage("data/earth/F.png"); // FIXME: Earth back // Stone Brick - img_stoneBrick=Draw_LoadImage("data/rock.bmp"); + img_stoneBrick=Draw_LoadImage("data/rock.png"); // FIXME: Stone Brick back // Spiked Bush - img_spikedBush=Draw_LoadImage("data/spikedbush.bmp"); + img_spikedBush=Draw_LoadImage("data/spikedbush.png"); // FIXME: Lava Pit // FIXME: Fireball // Flower - img_flower[0]=Draw_LoadImage("data/flower_left.bmp"); - img_flower[1]=Draw_LoadImage("data/flower_right.bmp"); + img_flower[0]=Draw_LoadImage("data/flower_left.png"); + img_flower[1]=Draw_LoadImage("data/flower_right.png"); // Spike - img_spike[0]=Draw_LoadImage("data/spike_left.bmp"); - img_spike[1]=Draw_LoadImage("data/spike_right.bmp"); + img_spike[0]=Draw_LoadImage("data/spike_left.png"); + img_spike[1]=Draw_LoadImage("data/spike_right.png"); // Carnivore Plant - img_carnivorePlant[0]=Draw_LoadImage("data/carnivoreplant_left.bmp"); - img_carnivorePlant[1]=Draw_LoadImage("data/carnivoreplant_right.bmp"); + img_carnivorePlant[0]=Draw_LoadImage("data/carnivoreplant_left.png"); + img_carnivorePlant[1]=Draw_LoadImage("data/carnivoreplant_right.png"); // Bunny - img_bunny[0]=Draw_LoadImage("data/bunny_left.bmp"); - img_bunny[1]=Draw_LoadImage("data/bunny_right.bmp"); + img_bunny[0]=Draw_LoadImage("data/bunny_left.png"); + img_bunny[1]=Draw_LoadImage("data/bunny_right.png"); // Spider - img_spider[0]=Draw_LoadImage("data/spider_left.bmp"); - img_spider[1]=Draw_LoadImage("data/spider_right.bmp"); + img_spider[0]=Draw_LoadImage("data/spider_left.png"); + img_spider[1]=Draw_LoadImage("data/spider_right.png"); // FIXME: Guard diff --git a/GameLib/Draw.c b/GameLib/Draw.c index 9a17ed1..3d421cf 100644 --- a/GameLib/Draw.c +++ b/GameLib/Draw.c @@ -20,6 +20,7 @@ #include #endif #endif +#include "lodepng.c" #include #include "Time.h" @@ -28,16 +29,33 @@ #include "Draw.h" +//////////////////////////////////////////////// +// DrawImage // +/////////////// +// Image container. +typedef struct TDrawImage TDrawImage, *DrawImage; +struct TDrawImage { + unsigned char *data; + int x,y; + int w,h; + GLuint tex; +}; + + // Globals SDL_Surface *_screen=NULL; int _width; int _height; long long proc_t_frame=33333; long long draw_t_frame=16667; +int _fps=60; QuadArray2D _quadArray=NULL; -GLuint _tex=-1; +DrawImage _currentImg=NULL; float _color[4]; + + + ///////////////////////////// // Draw_Init // @@ -84,6 +102,7 @@ int Draw_Init(int width,int height,char *title,int pfps,int fps){ SDL_WM_SetCaption(title, NULL); proc_t_frame=1000000/pfps; draw_t_frame=1000000/fps; + _fps=fps; _width=width; _height=height; @@ -228,118 +247,79 @@ void Draw_Clean( } - -//////////////////////////////////////////////// -// DrawImage // -/////////////// -// Image container. -typedef struct Tag_DrawImage { - SDL_Surface *surf; - GLuint tex; - int x,y; -} DrawImage; - - -///////////////////////////// -// Draw_LoadSurface -// -// Loads a surface. -SDL_Surface *Draw_LoadSurface(char *filename){ - SDL_Surface *surf; - - // Load the BMP as a surface - surf=SDL_LoadBMP(filename); - if(surf == NULL){ - printf("Draw_LoadImage: Failure Loading image: %s\n",filename); - printf("Draw_LoadImage: SDL Error: %s\n",SDL_GetError()); - return(NULL); - } - - if (surf->format->BytesPerPixel==4) { - // Swap RGB to BGR - Uint32 *ptr,*ptr_end; - ptr=(Uint32 *)surf->pixels; - ptr_end=ptr+(surf->w*surf->h); - while (ptrw ); + glPixelStorei( GL_UNPACK_ROW_LENGTH, w ); glPixelStorei( GL_UNPACK_ALIGNMENT, 1 ); - //glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, - // surf->w, surf->h, 0, - // GL_RGBA, GL_UNSIGNED_BYTE, surf->pixels); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, - surf->w, surf->h, 0, - GL_RGBA, GL_UNSIGNED_BYTE, surf->pixels); - //glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, - // imagen->ancho, imagen->alto, 0, - // GL_RGB, GL_UNSIGNED_BYTE, imagen->data); + w, h, 0, + GL_RGBA, GL_UNSIGNED_BYTE, pixels); return(tex); } +///////////////////////////// +// Draw_CreateImage +// +DrawImg Draw_CreateImage(int w,int h){ + DrawImage image; + + // Create the image container + image=malloc(sizeof(TDrawImage)); + image->data=malloc(w*h*4); + image->x=0; + image->y=0; + image->w=w; + image->h=h; + image->tex=-1; + + return((DrawImg)image); +} + + ///////////////////////////// // Draw_LoadImage // // Loads a image, giving a reference. DrawImg Draw_LoadImage(char *filename){ - DrawImage *image; - SDL_Surface *surf; + DrawImage image; - - // Loads the surface - surf=Draw_LoadSurface(filename); - if(surf == NULL){ - return(NULL); + // Try loading PNG images + if(EndsWith(filename,".png") || EndsWith(filename,".PNG")){ + image=malloc(sizeof(TDrawImage)); + unsigned error = lodepng_decode32_file( + &image->data, + (unsigned*)&image->w, + (unsigned*)&image->h, + filename); + if(error){ + printf("Draw_LoadImage: PNG decoder error %u: %s\n", error, lodepng_error_text(error)); + return(NULL); + } + image->x=-(int)(image->w/2); + image->y=-(int)(image->h/2); + image->tex=-1; + return (DrawImg)image; } - - // Create the image container - image=malloc(sizeof(DrawImage)); - image->surf=surf; - image->tex=Draw_UploadGLTexture(surf); - //image->x=0; - //image->y=0; - image->x=-(surf->w/2); - image->y=-(surf->h/2); - - - return((DrawImg)image); + printf("Draw_LoadImage: Image type not supported: %s\n",filename); + return(NULL); } @@ -348,11 +328,11 @@ DrawImg Draw_LoadImage(char *filename){ // // Gets the image size. void Draw_GetSize(DrawImg img,int *w,int *h){ - DrawImage *image=img; + DrawImage image=img; // Gets the image size - *w=image->surf->w; - *h=image->surf->h; + *w=image->w; + *h=image->h; } @@ -362,14 +342,14 @@ void Draw_GetSize(DrawImg img,int *w,int *h){ // // Sets and Gets the image offset. void Draw_SetOffset(DrawImg img,int x,int y){ - DrawImage *image=img; + DrawImage image=img; // Sets the image offset image->x=x; image->y=y; } void Draw_GetOffset(DrawImg img,int *x,int *y){ - DrawImage *image=img; + DrawImage image=img; // Gets the image offset *x=image->x; @@ -382,9 +362,15 @@ void Draw_GetOffset(DrawImg img,int *x,int *y){ // // Performs all the queued draw actions. void Draw_Flush(){ + if(_currentImg==NULL){ + return; + } + if(_currentImg->tex==-1){ + _currentImg->tex=Draw_UploadGLTexture(_currentImg->w, _currentImg->h, _currentImg->data); + } // Draw the quad array - glBindTexture(GL_TEXTURE_2D, _tex); + glBindTexture(GL_TEXTURE_2D, _currentImg->tex); glEnableClientState(GL_COLOR_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glEnableClientState(GL_VERTEX_ARRAY); @@ -402,7 +388,6 @@ void Draw_Flush(){ glDisableClientState(GL_TEXTURE_COORD_ARRAY); glDisableClientState(GL_VERTEX_ARRAY); - // Empty it QuadArray2D_Clean(_quadArray); } @@ -413,19 +398,19 @@ void Draw_Flush(){ // // Draws an image. void Draw_DrawImg(DrawImg img,int x,int y){ - DrawImage *image=img; + DrawImage image=img; float x1,x2,y1,y2; // Prepare x1=x+image->x; y1=_height-(y+image->y); - x2=(x+image->x)+image->surf->w; - y2=_height-((y+image->y)+image->surf->h); + x2=(x+image->x)+image->w; + y2=_height-((y+image->y)+image->h); // Draw a quad - if(_tex!=image->tex){ + if(_currentImg!=image){ Draw_Flush(); - _tex=image->tex; + _currentImg=image; } QuadArray2D_AddQuad(_quadArray, x1,y1,0.0f,0.0f, @@ -439,7 +424,7 @@ void Draw_DrawImg(DrawImg img,int x,int y){ // // Draws an image, resizing. void Draw_DrawImgResized(DrawImg img,int x,int y,float w,float h){ - DrawImage *image=img; + DrawImage image=img; int x1,x2,y1,y2; // Prepare @@ -449,9 +434,9 @@ void Draw_DrawImgResized(DrawImg img,int x,int y,float w,float h){ y2=_height-((y+image->y)+h); // Draw a quad - if(_tex!=image->tex){ + if(_currentImg!=image){ Draw_Flush(); - _tex=image->tex; + _currentImg=image; } QuadArray2D_AddQuad(_quadArray, x1,y1,0.0f,0.0f, @@ -466,7 +451,7 @@ void Draw_DrawImgResized(DrawImg img,int x,int y,float w,float h){ // // Draws an image part. void Draw_DrawImgPart(DrawImg img,int x,int y,int w,int i){ - DrawImage *image=img; + DrawImage image=img; int x1,x2,y1,y2; float us,u1,u2; @@ -474,15 +459,15 @@ void Draw_DrawImgPart(DrawImg img,int x,int y,int w,int i){ x1=x+image->x; y1=_height-(y+image->y); x2=(x+image->x)+w; - y2=_height-((y+image->y)+image->surf->h); - us=1.0f/image->surf->w; + y2=_height-((y+image->y)+image->h); + us=1.0f/image->w; u1=us*i*w; u2=u1+us*w; // Draw a quad - if(_tex!=image->tex){ + if(_currentImg!=image){ Draw_Flush(); - _tex=image->tex; + _currentImg=image; } QuadArray2D_AddQuad(_quadArray, x1,y1,u1,0.0f, @@ -516,51 +501,41 @@ typedef struct { ///////////////////////////// -// Draw_DefaultFont +// Draw_DefaultImage // -// Creates a surface with the default font. +// Creates a image with the default font. #include "FontData.h" -SDL_Surface *Draw_DefaultFontSurface( +DrawImage Draw_DefaultFontImage( unsigned char r, unsigned char g, unsigned char b, unsigned char a) { - SDL_Surface *surf; + DrawImage img; int x,y,c; Uint32 color,color2; - // Create the surface - surf = SDL_CreateRGBSurface(SDL_SWSURFACE, - 8*256, 8, 32,0,0,0,0); - surf->format->Amask=0xFF000000; - surf->format->Ashift=24; - SDL_SetAlpha(surf, SDL_SRCALPHA, 255); - - // HACK: Set the colors in BGR order - color =SDL_MapRGBA(surf->format,b,g,r,a); - color2=SDL_MapRGBA(surf->format,b,g,r,0); + // Create the image and colors + img=Draw_CreateImage(8*256,8); // Draw the font - //SDL_LockSurface(surf); for(c=0;c<256;c++){ for(y=0;y<8;y++){ for(x=0;x<8;x++){ + int offset=((c*8+x)+(8*256*y))*4; + img->data[offset+0]=r; + img->data[offset+1]=g; + img->data[offset+2]=b; if(((fontdata_8x8[c*8+y]>>(7-x)) & 0x01)==1){ - //Imagen_PutPixel(dest,c*8+x,y,color); - ((Uint32 *)surf->pixels)[(c*8+x)+(8*256*y)]= - color; + img->data[offset+3]=0xFF; }else{ - //Imagen_PutPixel(dest,c*8+x,y,color2); - ((Uint32 *)surf->pixels)[(c*8+x)+(8*256*y)]= - color2; + img->data[offset+3]=0x00; } } } } - //SDL_UnlockSurface(surf); - return(surf); + return(img); } @@ -578,10 +553,7 @@ DrawFnt Draw_DefaultFont( // Create the default font font=malloc(sizeof(DrawFont)); - font->img.surf=Draw_DefaultFontSurface(r,g,b,a); - font->img.tex=Draw_UploadGLTexture(font->img.surf); - font->img.x=0; - font->img.y=0; + font->img=Draw_DefaultFontImage(r,g,b,a); font->w=8; font->h=8; font->min=0; @@ -599,12 +571,9 @@ DrawFnt Draw_LoadFont(char *fichero,int min,int max){ // Create the font form the image font=malloc(sizeof(DrawFont)); - font->img.surf=Draw_LoadSurface(fichero); - font->img.tex=Draw_UploadGLTexture(font->img.surf); - font->img.x=0; - font->img.y=0; - font->w=font->img.surf->w/(max-min); - font->h=font->img.surf->h; + font->img=Draw_LoadImage(fichero); + font->w=font->img->w/(max-min); + font->h=font->img->h; font->min=min; font->max=max; @@ -624,7 +593,7 @@ void Draw_DrawText(DrawFnt f,char *text,int x,int y){ ptr=text; while(*ptr){ if((*ptr)max){ - Draw_DrawImgPart((DrawImg)&font->img,x,y,font->w,(*ptr)-font->min); + Draw_DrawImgPart(font->img,x,y,font->w,(*ptr)-font->min); } x+=font->w; ptr++; diff --git a/GameLib/Draw.h b/GameLib/Draw.h index cfbf2ae..c7704b0 100644 --- a/GameLib/Draw.h +++ b/GameLib/Draw.h @@ -34,6 +34,7 @@ void Draw_Clean( // Performs all the queued draw actions. void Draw_Flush(); + //////////////////////////////////////////////// // DrawImg // ///////////// @@ -41,6 +42,12 @@ void Draw_Flush(); typedef void *DrawImg; +///////////////////////////// +// Draw_CreateImage +// +DrawImg Draw_CreateImage(int w,int h); + + ///////////////////////////// // Draw_LoadImage // diff --git a/GameLib/Entity.h b/GameLib/Entity.h index 1b6e477..27e87ad 100644 --- a/GameLib/Entity.h +++ b/GameLib/Entity.h @@ -152,10 +152,10 @@ CollisionInfo CollisionInfo_New(int responseType,Entity ent1,Entity ent2,float t ///////////////////////////// -// CollisionInfo_Free +// CollisionInfo_Destroy // // -void CollisionInfo_Free(CollisionInfo *collInfoRef); +void CollisionInfo_Destroy(CollisionInfo *collInfoRef); ///////////////////////////// diff --git a/GameLib/Util.c b/GameLib/Util.c index 1329f9f..76df057 100644 --- a/GameLib/Util.c +++ b/GameLib/Util.c @@ -200,3 +200,17 @@ float fabsmod(float v,int d){ +///////////////////////////// +// EndsWith +// +int EndsWith(char *str, char *suffix){ + if (!str || !suffix) + return 0; + int lenStr = strlen(str); + int lenSuffix = strlen(suffix); + if (lenSuffix > lenStr) + return 0; + return strncmp(str+lenStr-lenSuffix, suffix, lenSuffix)==0; +} + + diff --git a/GameLib/Util.h b/GameLib/Util.h index 17246b4..bc85c12 100644 --- a/GameLib/Util.h +++ b/GameLib/Util.h @@ -37,6 +37,7 @@ float vec2_norm(vec2 v); // Intersection between a ray and a Unit Circle. int Intersec_RayUnitCircle(vec2 orig,vec2 vel,vec2 center,float *t); + ///////////////////////////// // Intersect_CircleCircle // @@ -46,6 +47,7 @@ int Colision_CircleCircle( vec2 cb,float rb, float *t,vec2 n); + ///////////////////////////// // Intersect_RayEdge // @@ -56,7 +58,6 @@ int Intersect_RayEdge( float *t); - ///////////////////////////// // absmod // @@ -64,4 +65,11 @@ int absmod(int v,int d); float fabsmod(float v,int d); + +///////////////////////////// +// EndsWith +// +int EndsWith(char *str, char *suffix); + + #endif diff --git a/GameLib/lodepng.c b/GameLib/lodepng.c new file mode 100644 index 0000000..bcc009f --- /dev/null +++ b/GameLib/lodepng.c @@ -0,0 +1,6285 @@ +/* +LodePNG version 20140624 + +Copyright (c) 2005-2014 Lode Vandevenne + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. +*/ + +/* +The manual and changelog are in the header file "lodepng.h" +Rename this file to lodepng.cpp to use it for C++, or to lodepng.c to use it for C. +*/ + +#include "lodepng.h" + +#include +#include + +#ifdef LODEPNG_COMPILE_CPP +#include +#endif /*LODEPNG_COMPILE_CPP*/ + +#define VERSION_STRING "20140624" + +#if (_MSC_VER >= 1310) /*Visual Studio: Kept warning-free but a few warning types are not desired here.*/ +#pragma warning( disable : 4244 ) /*implicit conversions: not warned by gcc -Wall -Wextra and requires too much casts*/ +#pragma warning( disable : 4996 ) /*VS does not like fopen, but fopen_s is not standard C so unusable here*/ +#endif /*_MSC_VER >= 1310*/ + +/* +This source file is built up in the following large parts. The code sections +with the "LODEPNG_COMPILE_" #defines divide this up further in an intermixed way. +-Tools for C and common code for PNG and Zlib +-C Code for Zlib (huffman, deflate, ...) +-C Code for PNG (file format chunks, adam7, PNG filters, color conversions, ...) +-The C++ wrapper around all of the above +*/ + +/*The malloc, realloc and free functions defined here with "lodepng_" in front +of the name, so that you can easily change them to others related to your +platform if needed. Everything else in the code calls these. Pass +-DLODEPNG_NO_COMPILE_ALLOCATORS to the compiler, or comment out +#define LODEPNG_COMPILE_ALLOCATORS in the header, to disable the ones here and +define them in your own project's source files without needing to change +lodepng source code. Don't forget to remove "static" if you copypaste them +from here.*/ + +#ifdef LODEPNG_COMPILE_ALLOCATORS +static void* lodepng_malloc(size_t size) +{ + return malloc(size); +} + +static void* lodepng_realloc(void* ptr, size_t new_size) +{ + return realloc(ptr, new_size); +} + +static void lodepng_free(void* ptr) +{ + free(ptr); +} +#else /*LODEPNG_COMPILE_ALLOCATORS*/ +void* lodepng_malloc(size_t size); +void* lodepng_realloc(void* ptr, size_t new_size); +void lodepng_free(void* ptr); +#endif /*LODEPNG_COMPILE_ALLOCATORS*/ + +/* ////////////////////////////////////////////////////////////////////////// */ +/* ////////////////////////////////////////////////////////////////////////// */ +/* // Tools for C, and common code for PNG and Zlib. // */ +/* ////////////////////////////////////////////////////////////////////////// */ +/* ////////////////////////////////////////////////////////////////////////// */ + +/* +Often in case of an error a value is assigned to a variable and then it breaks +out of a loop (to go to the cleanup phase of a function). This macro does that. +It makes the error handling code shorter and more readable. + +Example: if(!uivector_resizev(&frequencies_ll, 286, 0)) ERROR_BREAK(83); +*/ +#define CERROR_BREAK(errorvar, code)\ +{\ + errorvar = code;\ + break;\ +} + +/*version of CERROR_BREAK that assumes the common case where the error variable is named "error"*/ +#define ERROR_BREAK(code) CERROR_BREAK(error, code) + +/*Set error var to the error code, and return it.*/ +#define CERROR_RETURN_ERROR(errorvar, code)\ +{\ + errorvar = code;\ + return code;\ +} + +/*Try the code, if it returns error, also return the error.*/ +#define CERROR_TRY_RETURN(call)\ +{\ + unsigned error = call;\ + if(error) return error;\ +} + +/* +About uivector, ucvector and string: +-All of them wrap dynamic arrays or text strings in a similar way. +-LodePNG was originally written in C++. The vectors replace the std::vectors that were used in the C++ version. +-The string tools are made to avoid problems with compilers that declare things like strncat as deprecated. +-They're not used in the interface, only internally in this file as static functions. +-As with many other structs in this file, the init and cleanup functions serve as ctor and dtor. +*/ + +#ifdef LODEPNG_COMPILE_ZLIB +/*dynamic vector of unsigned ints*/ +typedef struct uivector +{ + unsigned* data; + size_t size; /*size in number of unsigned longs*/ + size_t allocsize; /*allocated size in bytes*/ +} uivector; + +static void uivector_cleanup(void* p) +{ + ((uivector*)p)->size = ((uivector*)p)->allocsize = 0; + lodepng_free(((uivector*)p)->data); + ((uivector*)p)->data = NULL; +} + +/*returns 1 if success, 0 if failure ==> nothing done*/ +static unsigned uivector_resize(uivector* p, size_t size) +{ + if(size * sizeof(unsigned) > p->allocsize) + { + size_t newsize = size * sizeof(unsigned) * 2; + void* data = lodepng_realloc(p->data, newsize); + if(data) + { + p->allocsize = newsize; + p->data = (unsigned*)data; + p->size = size; + } + else return 0; + } + else p->size = size; + return 1; +} + +/*resize and give all new elements the value*/ +static unsigned uivector_resizev(uivector* p, size_t size, unsigned value) +{ + size_t oldsize = p->size, i; + if(!uivector_resize(p, size)) return 0; + for(i = oldsize; i < size; i++) p->data[i] = value; + return 1; +} + +static void uivector_init(uivector* p) +{ + p->data = NULL; + p->size = p->allocsize = 0; +} + +#ifdef LODEPNG_COMPILE_ENCODER +/*returns 1 if success, 0 if failure ==> nothing done*/ +static unsigned uivector_push_back(uivector* p, unsigned c) +{ + if(!uivector_resize(p, p->size + 1)) return 0; + p->data[p->size - 1] = c; + return 1; +} + +/*copy q to p, returns 1 if success, 0 if failure ==> nothing done*/ +static unsigned uivector_copy(uivector* p, const uivector* q) +{ + size_t i; + if(!uivector_resize(p, q->size)) return 0; + for(i = 0; i < q->size; i++) p->data[i] = q->data[i]; + return 1; +} +#endif /*LODEPNG_COMPILE_ENCODER*/ +#endif /*LODEPNG_COMPILE_ZLIB*/ + +/* /////////////////////////////////////////////////////////////////////////// */ + +/*dynamic vector of unsigned chars*/ +typedef struct ucvector +{ + unsigned char* data; + size_t size; /*used size*/ + size_t allocsize; /*allocated size*/ +} ucvector; + +/*returns 1 if success, 0 if failure ==> nothing done*/ +static unsigned ucvector_resize(ucvector* p, size_t size) +{ + if(size * sizeof(unsigned char) > p->allocsize) + { + size_t newsize = size * sizeof(unsigned char) * 2; + void* data = lodepng_realloc(p->data, newsize); + if(data) + { + p->allocsize = newsize; + p->data = (unsigned char*)data; + p->size = size; + } + else return 0; /*error: not enough memory*/ + } + else p->size = size; + return 1; +} + +#ifdef LODEPNG_COMPILE_PNG + +static void ucvector_cleanup(void* p) +{ + ((ucvector*)p)->size = ((ucvector*)p)->allocsize = 0; + lodepng_free(((ucvector*)p)->data); + ((ucvector*)p)->data = NULL; +} + +static void ucvector_init(ucvector* p) +{ + p->data = NULL; + p->size = p->allocsize = 0; +} + +#ifdef LODEPNG_COMPILE_DECODER +/*resize and give all new elements the value*/ +static unsigned ucvector_resizev(ucvector* p, size_t size, unsigned char value) +{ + size_t oldsize = p->size, i; + if(!ucvector_resize(p, size)) return 0; + for(i = oldsize; i < size; i++) p->data[i] = value; + return 1; +} +#endif /*LODEPNG_COMPILE_DECODER*/ +#endif /*LODEPNG_COMPILE_PNG*/ + +#ifdef LODEPNG_COMPILE_ZLIB +/*you can both convert from vector to buffer&size and vica versa. If you use +init_buffer to take over a buffer and size, it is not needed to use cleanup*/ +static void ucvector_init_buffer(ucvector* p, unsigned char* buffer, size_t size) +{ + p->data = buffer; + p->allocsize = p->size = size; +} +#endif /*LODEPNG_COMPILE_ZLIB*/ + +#if (defined(LODEPNG_COMPILE_PNG) && defined(LODEPNG_COMPILE_ANCILLARY_CHUNKS)) || defined(LODEPNG_COMPILE_ENCODER) +/*returns 1 if success, 0 if failure ==> nothing done*/ +static unsigned ucvector_push_back(ucvector* p, unsigned char c) +{ + if(!ucvector_resize(p, p->size + 1)) return 0; + p->data[p->size - 1] = c; + return 1; +} +#endif /*defined(LODEPNG_COMPILE_PNG) || defined(LODEPNG_COMPILE_ENCODER)*/ + + +/* ////////////////////////////////////////////////////////////////////////// */ + +#ifdef LODEPNG_COMPILE_PNG +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS +/*returns 1 if success, 0 if failure ==> nothing done*/ +static unsigned string_resize(char** out, size_t size) +{ + char* data = (char*)lodepng_realloc(*out, size + 1); + if(data) + { + data[size] = 0; /*null termination char*/ + *out = data; + } + return data != 0; +} + +/*init a {char*, size_t} pair for use as string*/ +static void string_init(char** out) +{ + *out = NULL; + string_resize(out, 0); +} + +/*free the above pair again*/ +static void string_cleanup(char** out) +{ + lodepng_free(*out); + *out = NULL; +} + +static void string_set(char** out, const char* in) +{ + size_t insize = strlen(in), i = 0; + if(string_resize(out, insize)) + { + for(i = 0; i < insize; i++) + { + (*out)[i] = in[i]; + } + } +} +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ +#endif /*LODEPNG_COMPILE_PNG*/ + +/* ////////////////////////////////////////////////////////////////////////// */ + +unsigned lodepng_read32bitInt(const unsigned char* buffer) +{ + return (unsigned)((buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3]); +} + +#if defined(LODEPNG_COMPILE_PNG) || defined(LODEPNG_COMPILE_ENCODER) +/*buffer must have at least 4 allocated bytes available*/ +static void lodepng_set32bitInt(unsigned char* buffer, unsigned value) +{ + buffer[0] = (unsigned char)((value >> 24) & 0xff); + buffer[1] = (unsigned char)((value >> 16) & 0xff); + buffer[2] = (unsigned char)((value >> 8) & 0xff); + buffer[3] = (unsigned char)((value ) & 0xff); +} +#endif /*defined(LODEPNG_COMPILE_PNG) || defined(LODEPNG_COMPILE_ENCODER)*/ + +#ifdef LODEPNG_COMPILE_ENCODER +static void lodepng_add32bitInt(ucvector* buffer, unsigned value) +{ + ucvector_resize(buffer, buffer->size + 4); /*todo: give error if resize failed*/ + lodepng_set32bitInt(&buffer->data[buffer->size - 4], value); +} +#endif /*LODEPNG_COMPILE_ENCODER*/ + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / File IO / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +#ifdef LODEPNG_COMPILE_DISK + +unsigned lodepng_load_file(unsigned char** out, size_t* outsize, const char* filename) +{ + FILE* file; + long size; + + /*provide some proper output values if error will happen*/ + *out = 0; + *outsize = 0; + + file = fopen(filename, "rb"); + if(!file) return 78; + + /*get filesize:*/ + fseek(file , 0 , SEEK_END); + size = ftell(file); + rewind(file); + + /*read contents of the file into the vector*/ + *outsize = 0; + *out = (unsigned char*)lodepng_malloc((size_t)size); + if(size && (*out)) (*outsize) = fread(*out, 1, (size_t)size, file); + + fclose(file); + if(!(*out) && size) return 83; /*the above malloc failed*/ + return 0; +} + +/*write given buffer to the file, overwriting the file, it doesn't append to it.*/ +unsigned lodepng_save_file(const unsigned char* buffer, size_t buffersize, const char* filename) +{ + FILE* file; + file = fopen(filename, "wb" ); + if(!file) return 79; + fwrite((char*)buffer , 1 , buffersize, file); + fclose(file); + return 0; +} + +#endif /*LODEPNG_COMPILE_DISK*/ + +/* ////////////////////////////////////////////////////////////////////////// */ +/* ////////////////////////////////////////////////////////////////////////// */ +/* // End of common code and tools. Begin of Zlib related code. // */ +/* ////////////////////////////////////////////////////////////////////////// */ +/* ////////////////////////////////////////////////////////////////////////// */ + +#ifdef LODEPNG_COMPILE_ZLIB +#ifdef LODEPNG_COMPILE_ENCODER +/*TODO: this ignores potential out of memory errors*/ +#define addBitToStream(/*size_t**/ bitpointer, /*ucvector**/ bitstream, /*unsigned char*/ bit)\ +{\ + /*add a new byte at the end*/\ + if(((*bitpointer) & 7) == 0) ucvector_push_back(bitstream, (unsigned char)0);\ + /*earlier bit of huffman code is in a lesser significant bit of an earlier byte*/\ + (bitstream->data[bitstream->size - 1]) |= (bit << ((*bitpointer) & 0x7));\ + (*bitpointer)++;\ +} + +static void addBitsToStream(size_t* bitpointer, ucvector* bitstream, unsigned value, size_t nbits) +{ + size_t i; + for(i = 0; i < nbits; i++) addBitToStream(bitpointer, bitstream, (unsigned char)((value >> i) & 1)); +} + +static void addBitsToStreamReversed(size_t* bitpointer, ucvector* bitstream, unsigned value, size_t nbits) +{ + size_t i; + for(i = 0; i < nbits; i++) addBitToStream(bitpointer, bitstream, (unsigned char)((value >> (nbits - 1 - i)) & 1)); +} +#endif /*LODEPNG_COMPILE_ENCODER*/ + +#ifdef LODEPNG_COMPILE_DECODER + +#define READBIT(bitpointer, bitstream) ((bitstream[bitpointer >> 3] >> (bitpointer & 0x7)) & (unsigned char)1) + +static unsigned char readBitFromStream(size_t* bitpointer, const unsigned char* bitstream) +{ + unsigned char result = (unsigned char)(READBIT(*bitpointer, bitstream)); + (*bitpointer)++; + return result; +} + +static unsigned readBitsFromStream(size_t* bitpointer, const unsigned char* bitstream, size_t nbits) +{ + unsigned result = 0, i; + for(i = 0; i < nbits; i++) + { + result += ((unsigned)READBIT(*bitpointer, bitstream)) << i; + (*bitpointer)++; + } + return result; +} +#endif /*LODEPNG_COMPILE_DECODER*/ + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / Deflate - Huffman / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +#define FIRST_LENGTH_CODE_INDEX 257 +#define LAST_LENGTH_CODE_INDEX 285 +/*256 literals, the end code, some length codes, and 2 unused codes*/ +#define NUM_DEFLATE_CODE_SYMBOLS 288 +/*the distance codes have their own symbols, 30 used, 2 unused*/ +#define NUM_DISTANCE_SYMBOLS 32 +/*the code length codes. 0-15: code lengths, 16: copy previous 3-6 times, 17: 3-10 zeros, 18: 11-138 zeros*/ +#define NUM_CODE_LENGTH_CODES 19 + +/*the base lengths represented by codes 257-285*/ +static const unsigned LENGTHBASE[29] + = {3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, + 67, 83, 99, 115, 131, 163, 195, 227, 258}; + +/*the extra bits used by codes 257-285 (added to base length)*/ +static const unsigned LENGTHEXTRA[29] + = {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, + 4, 4, 4, 4, 5, 5, 5, 5, 0}; + +/*the base backwards distances (the bits of distance codes appear after length codes and use their own huffman tree)*/ +static const unsigned DISTANCEBASE[30] + = {1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, + 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577}; + +/*the extra bits of backwards distances (added to base)*/ +static const unsigned DISTANCEEXTRA[30] + = {0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, + 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13}; + +/*the order in which "code length alphabet code lengths" are stored, out of this +the huffman tree of the dynamic huffman tree lengths is generated*/ +static const unsigned CLCL_ORDER[NUM_CODE_LENGTH_CODES] + = {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + +/* ////////////////////////////////////////////////////////////////////////// */ + +/* +Huffman tree struct, containing multiple representations of the tree +*/ +typedef struct HuffmanTree +{ + unsigned* tree2d; + unsigned* tree1d; + unsigned* lengths; /*the lengths of the codes of the 1d-tree*/ + unsigned maxbitlen; /*maximum number of bits a single code can get*/ + unsigned numcodes; /*number of symbols in the alphabet = number of codes*/ +} HuffmanTree; + +/*function used for debug purposes to draw the tree in ascii art with C++*/ +/* +static void HuffmanTree_draw(HuffmanTree* tree) +{ + std::cout << "tree. length: " << tree->numcodes << " maxbitlen: " << tree->maxbitlen << std::endl; + for(size_t i = 0; i < tree->tree1d.size; i++) + { + if(tree->lengths.data[i]) + std::cout << i << " " << tree->tree1d.data[i] << " " << tree->lengths.data[i] << std::endl; + } + std::cout << std::endl; +}*/ + +static void HuffmanTree_init(HuffmanTree* tree) +{ + tree->tree2d = 0; + tree->tree1d = 0; + tree->lengths = 0; +} + +static void HuffmanTree_cleanup(HuffmanTree* tree) +{ + lodepng_free(tree->tree2d); + lodepng_free(tree->tree1d); + lodepng_free(tree->lengths); +} + +/*the tree representation used by the decoder. return value is error*/ +static unsigned HuffmanTree_make2DTree(HuffmanTree* tree) +{ + unsigned nodefilled = 0; /*up to which node it is filled*/ + unsigned treepos = 0; /*position in the tree (1 of the numcodes columns)*/ + unsigned n, i; + + tree->tree2d = (unsigned*)lodepng_malloc(tree->numcodes * 2 * sizeof(unsigned)); + if(!tree->tree2d) return 83; /*alloc fail*/ + + /* + convert tree1d[] to tree2d[][]. In the 2D array, a value of 32767 means + uninited, a value >= numcodes is an address to another bit, a value < numcodes + is a code. The 2 rows are the 2 possible bit values (0 or 1), there are as + many columns as codes - 1. + A good huffmann tree has N * 2 - 1 nodes, of which N - 1 are internal nodes. + Here, the internal nodes are stored (what their 0 and 1 option point to). + There is only memory for such good tree currently, if there are more nodes + (due to too long length codes), error 55 will happen + */ + for(n = 0; n < tree->numcodes * 2; n++) + { + tree->tree2d[n] = 32767; /*32767 here means the tree2d isn't filled there yet*/ + } + + for(n = 0; n < tree->numcodes; n++) /*the codes*/ + { + for(i = 0; i < tree->lengths[n]; i++) /*the bits for this code*/ + { + unsigned char bit = (unsigned char)((tree->tree1d[n] >> (tree->lengths[n] - i - 1)) & 1); + if(treepos > tree->numcodes - 2) return 55; /*oversubscribed, see comment in lodepng_error_text*/ + if(tree->tree2d[2 * treepos + bit] == 32767) /*not yet filled in*/ + { + if(i + 1 == tree->lengths[n]) /*last bit*/ + { + tree->tree2d[2 * treepos + bit] = n; /*put the current code in it*/ + treepos = 0; + } + else + { + /*put address of the next step in here, first that address has to be found of course + (it's just nodefilled + 1)...*/ + nodefilled++; + /*addresses encoded with numcodes added to it*/ + tree->tree2d[2 * treepos + bit] = nodefilled + tree->numcodes; + treepos = nodefilled; + } + } + else treepos = tree->tree2d[2 * treepos + bit] - tree->numcodes; + } + } + + for(n = 0; n < tree->numcodes * 2; n++) + { + if(tree->tree2d[n] == 32767) tree->tree2d[n] = 0; /*remove possible remaining 32767's*/ + } + + return 0; +} + +/* +Second step for the ...makeFromLengths and ...makeFromFrequencies functions. +numcodes, lengths and maxbitlen must already be filled in correctly. return +value is error. +*/ +static unsigned HuffmanTree_makeFromLengths2(HuffmanTree* tree) +{ + uivector blcount; + uivector nextcode; + unsigned bits, n, error = 0; + + uivector_init(&blcount); + uivector_init(&nextcode); + + tree->tree1d = (unsigned*)lodepng_malloc(tree->numcodes * sizeof(unsigned)); + if(!tree->tree1d) error = 83; /*alloc fail*/ + + if(!uivector_resizev(&blcount, tree->maxbitlen + 1, 0) + || !uivector_resizev(&nextcode, tree->maxbitlen + 1, 0)) + error = 83; /*alloc fail*/ + + if(!error) + { + /*step 1: count number of instances of each code length*/ + for(bits = 0; bits < tree->numcodes; bits++) blcount.data[tree->lengths[bits]]++; + /*step 2: generate the nextcode values*/ + for(bits = 1; bits <= tree->maxbitlen; bits++) + { + nextcode.data[bits] = (nextcode.data[bits - 1] + blcount.data[bits - 1]) << 1; + } + /*step 3: generate all the codes*/ + for(n = 0; n < tree->numcodes; n++) + { + if(tree->lengths[n] != 0) tree->tree1d[n] = nextcode.data[tree->lengths[n]]++; + } + } + + uivector_cleanup(&blcount); + uivector_cleanup(&nextcode); + + if(!error) return HuffmanTree_make2DTree(tree); + else return error; +} + +/* +given the code lengths (as stored in the PNG file), generate the tree as defined +by Deflate. maxbitlen is the maximum bits that a code in the tree can have. +return value is error. +*/ +static unsigned HuffmanTree_makeFromLengths(HuffmanTree* tree, const unsigned* bitlen, + size_t numcodes, unsigned maxbitlen) +{ + unsigned i; + tree->lengths = (unsigned*)lodepng_malloc(numcodes * sizeof(unsigned)); + if(!tree->lengths) return 83; /*alloc fail*/ + for(i = 0; i < numcodes; i++) tree->lengths[i] = bitlen[i]; + tree->numcodes = (unsigned)numcodes; /*number of symbols*/ + tree->maxbitlen = maxbitlen; + return HuffmanTree_makeFromLengths2(tree); +} + +#ifdef LODEPNG_COMPILE_ENCODER + +/* +A coin, this is the terminology used for the package-merge algorithm and the +coin collector's problem. This is used to generate the huffman tree. +A coin can be multiple coins (when they're merged) +*/ +typedef struct Coin +{ + uivector symbols; + float weight; /*the sum of all weights in this coin*/ +} Coin; + +static void coin_init(Coin* c) +{ + uivector_init(&c->symbols); +} + +/*argument c is void* so that this dtor can be given as function pointer to the vector resize function*/ +static void coin_cleanup(void* c) +{ + uivector_cleanup(&((Coin*)c)->symbols); +} + +static void coin_copy(Coin* c1, const Coin* c2) +{ + c1->weight = c2->weight; + uivector_copy(&c1->symbols, &c2->symbols); +} + +static void add_coins(Coin* c1, const Coin* c2) +{ + size_t i; + for(i = 0; i < c2->symbols.size; i++) uivector_push_back(&c1->symbols, c2->symbols.data[i]); + c1->weight += c2->weight; +} + +static void init_coins(Coin* coins, size_t num) +{ + size_t i; + for(i = 0; i < num; i++) coin_init(&coins[i]); +} + +static void cleanup_coins(Coin* coins, size_t num) +{ + size_t i; + for(i = 0; i < num; i++) coin_cleanup(&coins[i]); +} + +static int coin_compare(const void* a, const void* b) { + float wa = ((const Coin*)a)->weight; + float wb = ((const Coin*)b)->weight; + return wa > wb ? 1 : wa < wb ? -1 : 0; +} + +static unsigned append_symbol_coins(Coin* coins, const unsigned* frequencies, unsigned numcodes, size_t sum) +{ + unsigned i; + unsigned j = 0; /*index of present symbols*/ + for(i = 0; i < numcodes; i++) + { + if(frequencies[i] != 0) /*only include symbols that are present*/ + { + coins[j].weight = frequencies[i] / (float)sum; + uivector_push_back(&coins[j].symbols, i); + j++; + } + } + return 0; +} + +unsigned lodepng_huffman_code_lengths(unsigned* lengths, const unsigned* frequencies, + size_t numcodes, unsigned maxbitlen) +{ + unsigned i, j; + size_t sum = 0, numpresent = 0; + unsigned error = 0; + Coin* coins; /*the coins of the currently calculated row*/ + Coin* prev_row; /*the previous row of coins*/ + size_t numcoins; + size_t coinmem; + + if(numcodes == 0) return 80; /*error: a tree of 0 symbols is not supposed to be made*/ + + for(i = 0; i < numcodes; i++) + { + if(frequencies[i] > 0) + { + numpresent++; + sum += frequencies[i]; + } + } + + for(i = 0; i < numcodes; i++) lengths[i] = 0; + + /*ensure at least two present symbols. There should be at least one symbol + according to RFC 1951 section 3.2.7. To decoders incorrectly require two. To + make these work as well ensure there are at least two symbols. The + Package-Merge code below also doesn't work correctly if there's only one + symbol, it'd give it the theoritical 0 bits but in practice zlib wants 1 bit*/ + if(numpresent == 0) + { + lengths[0] = lengths[1] = 1; /*note that for RFC 1951 section 3.2.7, only lengths[0] = 1 is needed*/ + } + else if(numpresent == 1) + { + for(i = 0; i < numcodes; i++) + { + if(frequencies[i]) + { + lengths[i] = 1; + lengths[i == 0 ? 1 : 0] = 1; + break; + } + } + } + else + { + /*Package-Merge algorithm represented by coin collector's problem + For every symbol, maxbitlen coins will be created*/ + + coinmem = numpresent * 2; /*max amount of coins needed with the current algo*/ + coins = (Coin*)lodepng_malloc(sizeof(Coin) * coinmem); + prev_row = (Coin*)lodepng_malloc(sizeof(Coin) * coinmem); + if(!coins || !prev_row) + { + lodepng_free(coins); + lodepng_free(prev_row); + return 83; /*alloc fail*/ + } + init_coins(coins, coinmem); + init_coins(prev_row, coinmem); + + /*first row, lowest denominator*/ + error = append_symbol_coins(coins, frequencies, numcodes, sum); + numcoins = numpresent; + qsort(coins, numcoins, sizeof(Coin), coin_compare); + if(!error) + { + unsigned numprev = 0; + for(j = 1; j <= maxbitlen && !error; j++) /*each of the remaining rows*/ + { + unsigned tempnum; + Coin* tempcoins; + /*swap prev_row and coins, and their amounts*/ + tempcoins = prev_row; prev_row = coins; coins = tempcoins; + tempnum = numprev; numprev = numcoins; numcoins = tempnum; + + cleanup_coins(coins, numcoins); + init_coins(coins, numcoins); + + numcoins = 0; + + /*fill in the merged coins of the previous row*/ + for(i = 0; i + 1 < numprev; i += 2) + { + /*merge prev_row[i] and prev_row[i + 1] into new coin*/ + Coin* coin = &coins[numcoins++]; + coin_copy(coin, &prev_row[i]); + add_coins(coin, &prev_row[i + 1]); + } + /*fill in all the original symbols again*/ + if(j < maxbitlen) + { + error = append_symbol_coins(coins + numcoins, frequencies, numcodes, sum); + numcoins += numpresent; + } + qsort(coins, numcoins, sizeof(Coin), coin_compare); + } + } + + if(!error) + { + /*calculate the lenghts of each symbol, as the amount of times a coin of each symbol is used*/ + for(i = 0; i < numpresent - 1; i++) + { + Coin* coin = &coins[i]; + for(j = 0; j < coin->symbols.size; j++) lengths[coin->symbols.data[j]]++; + } + } + + cleanup_coins(coins, coinmem); + lodepng_free(coins); + cleanup_coins(prev_row, coinmem); + lodepng_free(prev_row); + } + + return error; +} + +/*Create the Huffman tree given the symbol frequencies*/ +static unsigned HuffmanTree_makeFromFrequencies(HuffmanTree* tree, const unsigned* frequencies, + size_t mincodes, size_t numcodes, unsigned maxbitlen) +{ + unsigned error = 0; + while(!frequencies[numcodes - 1] && numcodes > mincodes) numcodes--; /*trim zeroes*/ + tree->maxbitlen = maxbitlen; + tree->numcodes = (unsigned)numcodes; /*number of symbols*/ + tree->lengths = (unsigned*)lodepng_realloc(tree->lengths, numcodes * sizeof(unsigned)); + if(!tree->lengths) return 83; /*alloc fail*/ + /*initialize all lengths to 0*/ + memset(tree->lengths, 0, numcodes * sizeof(unsigned)); + + error = lodepng_huffman_code_lengths(tree->lengths, frequencies, numcodes, maxbitlen); + if(!error) error = HuffmanTree_makeFromLengths2(tree); + return error; +} + +static unsigned HuffmanTree_getCode(const HuffmanTree* tree, unsigned index) +{ + return tree->tree1d[index]; +} + +static unsigned HuffmanTree_getLength(const HuffmanTree* tree, unsigned index) +{ + return tree->lengths[index]; +} +#endif /*LODEPNG_COMPILE_ENCODER*/ + +/*get the literal and length code tree of a deflated block with fixed tree, as per the deflate specification*/ +static unsigned generateFixedLitLenTree(HuffmanTree* tree) +{ + unsigned i, error = 0; + unsigned* bitlen = (unsigned*)lodepng_malloc(NUM_DEFLATE_CODE_SYMBOLS * sizeof(unsigned)); + if(!bitlen) return 83; /*alloc fail*/ + + /*288 possible codes: 0-255=literals, 256=endcode, 257-285=lengthcodes, 286-287=unused*/ + for(i = 0; i <= 143; i++) bitlen[i] = 8; + for(i = 144; i <= 255; i++) bitlen[i] = 9; + for(i = 256; i <= 279; i++) bitlen[i] = 7; + for(i = 280; i <= 287; i++) bitlen[i] = 8; + + error = HuffmanTree_makeFromLengths(tree, bitlen, NUM_DEFLATE_CODE_SYMBOLS, 15); + + lodepng_free(bitlen); + return error; +} + +/*get the distance code tree of a deflated block with fixed tree, as specified in the deflate specification*/ +static unsigned generateFixedDistanceTree(HuffmanTree* tree) +{ + unsigned i, error = 0; + unsigned* bitlen = (unsigned*)lodepng_malloc(NUM_DISTANCE_SYMBOLS * sizeof(unsigned)); + if(!bitlen) return 83; /*alloc fail*/ + + /*there are 32 distance codes, but 30-31 are unused*/ + for(i = 0; i < NUM_DISTANCE_SYMBOLS; i++) bitlen[i] = 5; + error = HuffmanTree_makeFromLengths(tree, bitlen, NUM_DISTANCE_SYMBOLS, 15); + + lodepng_free(bitlen); + return error; +} + +#ifdef LODEPNG_COMPILE_DECODER + +/* +returns the code, or (unsigned)(-1) if error happened +inbitlength is the length of the complete buffer, in bits (so its byte length times 8) +*/ +static unsigned huffmanDecodeSymbol(const unsigned char* in, size_t* bp, + const HuffmanTree* codetree, size_t inbitlength) +{ + unsigned treepos = 0, ct; + for(;;) + { + if(*bp >= inbitlength) return (unsigned)(-1); /*error: end of input memory reached without endcode*/ + /* + decode the symbol from the tree. The "readBitFromStream" code is inlined in + the expression below because this is the biggest bottleneck while decoding + */ + ct = codetree->tree2d[(treepos << 1) + READBIT(*bp, in)]; + (*bp)++; + if(ct < codetree->numcodes) return ct; /*the symbol is decoded, return it*/ + else treepos = ct - codetree->numcodes; /*symbol not yet decoded, instead move tree position*/ + + if(treepos >= codetree->numcodes) return (unsigned)(-1); /*error: it appeared outside the codetree*/ + } +} +#endif /*LODEPNG_COMPILE_DECODER*/ + +#ifdef LODEPNG_COMPILE_DECODER + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / Inflator (Decompressor) / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +/*get the tree of a deflated block with fixed tree, as specified in the deflate specification*/ +static void getTreeInflateFixed(HuffmanTree* tree_ll, HuffmanTree* tree_d) +{ + /*TODO: check for out of memory errors*/ + generateFixedLitLenTree(tree_ll); + generateFixedDistanceTree(tree_d); +} + +/*get the tree of a deflated block with dynamic tree, the tree itself is also Huffman compressed with a known tree*/ +static unsigned getTreeInflateDynamic(HuffmanTree* tree_ll, HuffmanTree* tree_d, + const unsigned char* in, size_t* bp, size_t inlength) +{ + /*make sure that length values that aren't filled in will be 0, or a wrong tree will be generated*/ + unsigned error = 0; + unsigned n, HLIT, HDIST, HCLEN, i; + size_t inbitlength = inlength * 8; + + /*see comments in deflateDynamic for explanation of the context and these variables, it is analogous*/ + unsigned* bitlen_ll = 0; /*lit,len code lengths*/ + unsigned* bitlen_d = 0; /*dist code lengths*/ + /*code length code lengths ("clcl"), the bit lengths of the huffman tree used to compress bitlen_ll and bitlen_d*/ + unsigned* bitlen_cl = 0; + HuffmanTree tree_cl; /*the code tree for code length codes (the huffman tree for compressed huffman trees)*/ + + if((*bp) >> 3 >= inlength - 2) return 49; /*error: the bit pointer is or will go past the memory*/ + + /*number of literal/length codes + 257. Unlike the spec, the value 257 is added to it here already*/ + HLIT = readBitsFromStream(bp, in, 5) + 257; + /*number of distance codes. Unlike the spec, the value 1 is added to it here already*/ + HDIST = readBitsFromStream(bp, in, 5) + 1; + /*number of code length codes. Unlike the spec, the value 4 is added to it here already*/ + HCLEN = readBitsFromStream(bp, in, 4) + 4; + + HuffmanTree_init(&tree_cl); + + while(!error) + { + /*read the code length codes out of 3 * (amount of code length codes) bits*/ + + bitlen_cl = (unsigned*)lodepng_malloc(NUM_CODE_LENGTH_CODES * sizeof(unsigned)); + if(!bitlen_cl) ERROR_BREAK(83 /*alloc fail*/); + + for(i = 0; i < NUM_CODE_LENGTH_CODES; i++) + { + if(i < HCLEN) bitlen_cl[CLCL_ORDER[i]] = readBitsFromStream(bp, in, 3); + else bitlen_cl[CLCL_ORDER[i]] = 0; /*if not, it must stay 0*/ + } + + error = HuffmanTree_makeFromLengths(&tree_cl, bitlen_cl, NUM_CODE_LENGTH_CODES, 7); + if(error) break; + + /*now we can use this tree to read the lengths for the tree that this function will return*/ + bitlen_ll = (unsigned*)lodepng_malloc(NUM_DEFLATE_CODE_SYMBOLS * sizeof(unsigned)); + bitlen_d = (unsigned*)lodepng_malloc(NUM_DISTANCE_SYMBOLS * sizeof(unsigned)); + if(!bitlen_ll || !bitlen_d) ERROR_BREAK(83 /*alloc fail*/); + for(i = 0; i < NUM_DEFLATE_CODE_SYMBOLS; i++) bitlen_ll[i] = 0; + for(i = 0; i < NUM_DISTANCE_SYMBOLS; i++) bitlen_d[i] = 0; + + /*i is the current symbol we're reading in the part that contains the code lengths of lit/len and dist codes*/ + i = 0; + while(i < HLIT + HDIST) + { + unsigned code = huffmanDecodeSymbol(in, bp, &tree_cl, inbitlength); + if(code <= 15) /*a length code*/ + { + if(i < HLIT) bitlen_ll[i] = code; + else bitlen_d[i - HLIT] = code; + i++; + } + else if(code == 16) /*repeat previous*/ + { + unsigned replength = 3; /*read in the 2 bits that indicate repeat length (3-6)*/ + unsigned value; /*set value to the previous code*/ + + if(*bp >= inbitlength) ERROR_BREAK(50); /*error, bit pointer jumps past memory*/ + if (i == 0) ERROR_BREAK(54); /*can't repeat previous if i is 0*/ + + replength += readBitsFromStream(bp, in, 2); + + if(i < HLIT + 1) value = bitlen_ll[i - 1]; + else value = bitlen_d[i - HLIT - 1]; + /*repeat this value in the next lengths*/ + for(n = 0; n < replength; n++) + { + if(i >= HLIT + HDIST) ERROR_BREAK(13); /*error: i is larger than the amount of codes*/ + if(i < HLIT) bitlen_ll[i] = value; + else bitlen_d[i - HLIT] = value; + i++; + } + } + else if(code == 17) /*repeat "0" 3-10 times*/ + { + unsigned replength = 3; /*read in the bits that indicate repeat length*/ + if(*bp >= inbitlength) ERROR_BREAK(50); /*error, bit pointer jumps past memory*/ + + replength += readBitsFromStream(bp, in, 3); + + /*repeat this value in the next lengths*/ + for(n = 0; n < replength; n++) + { + if(i >= HLIT + HDIST) ERROR_BREAK(14); /*error: i is larger than the amount of codes*/ + + if(i < HLIT) bitlen_ll[i] = 0; + else bitlen_d[i - HLIT] = 0; + i++; + } + } + else if(code == 18) /*repeat "0" 11-138 times*/ + { + unsigned replength = 11; /*read in the bits that indicate repeat length*/ + if(*bp >= inbitlength) ERROR_BREAK(50); /*error, bit pointer jumps past memory*/ + + replength += readBitsFromStream(bp, in, 7); + + /*repeat this value in the next lengths*/ + for(n = 0; n < replength; n++) + { + if(i >= HLIT + HDIST) ERROR_BREAK(15); /*error: i is larger than the amount of codes*/ + + if(i < HLIT) bitlen_ll[i] = 0; + else bitlen_d[i - HLIT] = 0; + i++; + } + } + else /*if(code == (unsigned)(-1))*/ /*huffmanDecodeSymbol returns (unsigned)(-1) in case of error*/ + { + if(code == (unsigned)(-1)) + { + /*return error code 10 or 11 depending on the situation that happened in huffmanDecodeSymbol + (10=no endcode, 11=wrong jump outside of tree)*/ + error = (*bp) > inbitlength ? 10 : 11; + } + else error = 16; /*unexisting code, this can never happen*/ + break; + } + } + if(error) break; + + if(bitlen_ll[256] == 0) ERROR_BREAK(64); /*the length of the end code 256 must be larger than 0*/ + + /*now we've finally got HLIT and HDIST, so generate the code trees, and the function is done*/ + error = HuffmanTree_makeFromLengths(tree_ll, bitlen_ll, NUM_DEFLATE_CODE_SYMBOLS, 15); + if(error) break; + error = HuffmanTree_makeFromLengths(tree_d, bitlen_d, NUM_DISTANCE_SYMBOLS, 15); + + break; /*end of error-while*/ + } + + lodepng_free(bitlen_cl); + lodepng_free(bitlen_ll); + lodepng_free(bitlen_d); + HuffmanTree_cleanup(&tree_cl); + + return error; +} + +/*inflate a block with dynamic of fixed Huffman tree*/ +static unsigned inflateHuffmanBlock(ucvector* out, const unsigned char* in, size_t* bp, + size_t* pos, size_t inlength, unsigned btype) +{ + unsigned error = 0; + HuffmanTree tree_ll; /*the huffman tree for literal and length codes*/ + HuffmanTree tree_d; /*the huffman tree for distance codes*/ + size_t inbitlength = inlength * 8; + + HuffmanTree_init(&tree_ll); + HuffmanTree_init(&tree_d); + + if(btype == 1) getTreeInflateFixed(&tree_ll, &tree_d); + else if(btype == 2) error = getTreeInflateDynamic(&tree_ll, &tree_d, in, bp, inlength); + + while(!error) /*decode all symbols until end reached, breaks at end code*/ + { + /*code_ll is literal, length or end code*/ + unsigned code_ll = huffmanDecodeSymbol(in, bp, &tree_ll, inbitlength); + if(code_ll <= 255) /*literal symbol*/ + { + if((*pos) >= out->size) + { + /*reserve more room at once*/ + if(!ucvector_resize(out, ((*pos) + 1) * 2)) ERROR_BREAK(83 /*alloc fail*/); + } + out->data[(*pos)] = (unsigned char)(code_ll); + (*pos)++; + } + else if(code_ll >= FIRST_LENGTH_CODE_INDEX && code_ll <= LAST_LENGTH_CODE_INDEX) /*length code*/ + { + unsigned code_d, distance; + unsigned numextrabits_l, numextrabits_d; /*extra bits for length and distance*/ + size_t start, forward, backward, length; + + /*part 1: get length base*/ + length = LENGTHBASE[code_ll - FIRST_LENGTH_CODE_INDEX]; + + /*part 2: get extra bits and add the value of that to length*/ + numextrabits_l = LENGTHEXTRA[code_ll - FIRST_LENGTH_CODE_INDEX]; + if(*bp >= inbitlength) ERROR_BREAK(51); /*error, bit pointer will jump past memory*/ + length += readBitsFromStream(bp, in, numextrabits_l); + + /*part 3: get distance code*/ + code_d = huffmanDecodeSymbol(in, bp, &tree_d, inbitlength); + if(code_d > 29) + { + if(code_ll == (unsigned)(-1)) /*huffmanDecodeSymbol returns (unsigned)(-1) in case of error*/ + { + /*return error code 10 or 11 depending on the situation that happened in huffmanDecodeSymbol + (10=no endcode, 11=wrong jump outside of tree)*/ + error = (*bp) > inlength * 8 ? 10 : 11; + } + else error = 18; /*error: invalid distance code (30-31 are never used)*/ + break; + } + distance = DISTANCEBASE[code_d]; + + /*part 4: get extra bits from distance*/ + numextrabits_d = DISTANCEEXTRA[code_d]; + if(*bp >= inbitlength) ERROR_BREAK(51); /*error, bit pointer will jump past memory*/ + + distance += readBitsFromStream(bp, in, numextrabits_d); + + /*part 5: fill in all the out[n] values based on the length and dist*/ + start = (*pos); + if(distance > start) ERROR_BREAK(52); /*too long backward distance*/ + backward = start - distance; + if((*pos) + length >= out->size) + { + /*reserve more room at once*/ + if(!ucvector_resize(out, ((*pos) + length) * 2)) ERROR_BREAK(83 /*alloc fail*/); + } + + for(forward = 0; forward < length; forward++) + { + out->data[(*pos)] = out->data[backward]; + (*pos)++; + backward++; + if(backward >= start) backward = start - distance; + } + } + else if(code_ll == 256) + { + break; /*end code, break the loop*/ + } + else /*if(code == (unsigned)(-1))*/ /*huffmanDecodeSymbol returns (unsigned)(-1) in case of error*/ + { + /*return error code 10 or 11 depending on the situation that happened in huffmanDecodeSymbol + (10=no endcode, 11=wrong jump outside of tree)*/ + error = (*bp) > inlength * 8 ? 10 : 11; + break; + } + } + + HuffmanTree_cleanup(&tree_ll); + HuffmanTree_cleanup(&tree_d); + + return error; +} + +static unsigned inflateNoCompression(ucvector* out, const unsigned char* in, size_t* bp, size_t* pos, size_t inlength) +{ + /*go to first boundary of byte*/ + size_t p; + unsigned LEN, NLEN, n, error = 0; + while(((*bp) & 0x7) != 0) (*bp)++; + p = (*bp) / 8; /*byte position*/ + + /*read LEN (2 bytes) and NLEN (2 bytes)*/ + if(p >= inlength - 4) return 52; /*error, bit pointer will jump past memory*/ + LEN = in[p] + 256u * in[p + 1]; p += 2; + NLEN = in[p] + 256u * in[p + 1]; p += 2; + + /*check if 16-bit NLEN is really the one's complement of LEN*/ + if(LEN + NLEN != 65535) return 21; /*error: NLEN is not one's complement of LEN*/ + + if((*pos) + LEN >= out->size) + { + if(!ucvector_resize(out, (*pos) + LEN)) return 83; /*alloc fail*/ + } + + /*read the literal data: LEN bytes are now stored in the out buffer*/ + if(p + LEN > inlength) return 23; /*error: reading outside of in buffer*/ + for(n = 0; n < LEN; n++) out->data[(*pos)++] = in[p++]; + + (*bp) = p * 8; + + return error; +} + +static unsigned lodepng_inflatev(ucvector* out, + const unsigned char* in, size_t insize, + const LodePNGDecompressSettings* settings) +{ + /*bit pointer in the "in" data, current byte is bp >> 3, current bit is bp & 0x7 (from lsb to msb of the byte)*/ + size_t bp = 0; + unsigned BFINAL = 0; + size_t pos = 0; /*byte position in the out buffer*/ + + unsigned error = 0; + + (void)settings; + + while(!BFINAL) + { + unsigned BTYPE; + if(bp + 2 >= insize * 8) return 52; /*error, bit pointer will jump past memory*/ + BFINAL = readBitFromStream(&bp, in); + BTYPE = 1u * readBitFromStream(&bp, in); + BTYPE += 2u * readBitFromStream(&bp, in); + + if(BTYPE == 3) return 20; /*error: invalid BTYPE*/ + else if(BTYPE == 0) error = inflateNoCompression(out, in, &bp, &pos, insize); /*no compression*/ + else error = inflateHuffmanBlock(out, in, &bp, &pos, insize, BTYPE); /*compression, BTYPE 01 or 10*/ + + if(error) return error; + } + + /*Only now we know the true size of out, resize it to that*/ + if(!ucvector_resize(out, pos)) error = 83; /*alloc fail*/ + + return error; +} + +unsigned lodepng_inflate(unsigned char** out, size_t* outsize, + const unsigned char* in, size_t insize, + const LodePNGDecompressSettings* settings) +{ + unsigned error; + ucvector v; + ucvector_init_buffer(&v, *out, *outsize); + error = lodepng_inflatev(&v, in, insize, settings); + *out = v.data; + *outsize = v.size; + return error; +} + +static unsigned inflate(unsigned char** out, size_t* outsize, + const unsigned char* in, size_t insize, + const LodePNGDecompressSettings* settings) +{ + if(settings->custom_inflate) + { + return settings->custom_inflate(out, outsize, in, insize, settings); + } + else + { + return lodepng_inflate(out, outsize, in, insize, settings); + } +} + +#endif /*LODEPNG_COMPILE_DECODER*/ + +#ifdef LODEPNG_COMPILE_ENCODER + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / Deflator (Compressor) / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +static const size_t MAX_SUPPORTED_DEFLATE_LENGTH = 258; + +/*bitlen is the size in bits of the code*/ +static void addHuffmanSymbol(size_t* bp, ucvector* compressed, unsigned code, unsigned bitlen) +{ + addBitsToStreamReversed(bp, compressed, code, bitlen); +} + +/*search the index in the array, that has the largest value smaller than or equal to the given value, +given array must be sorted (if no value is smaller, it returns the size of the given array)*/ +static size_t searchCodeIndex(const unsigned* array, size_t array_size, size_t value) +{ + /*linear search implementation*/ + /*for(size_t i = 1; i < array_size; i++) if(array[i] > value) return i - 1; + return array_size - 1;*/ + + /*binary search implementation (not that much faster) (precondition: array_size > 0)*/ + size_t left = 1; + size_t right = array_size - 1; + while(left <= right) + { + size_t mid = (left + right) / 2; + if(array[mid] <= value) left = mid + 1; /*the value to find is more to the right*/ + else if(array[mid - 1] > value) right = mid - 1; /*the value to find is more to the left*/ + else return mid - 1; + } + return array_size - 1; +} + +static void addLengthDistance(uivector* values, size_t length, size_t distance) +{ + /*values in encoded vector are those used by deflate: + 0-255: literal bytes + 256: end + 257-285: length/distance pair (length code, followed by extra length bits, distance code, extra distance bits) + 286-287: invalid*/ + + unsigned length_code = (unsigned)searchCodeIndex(LENGTHBASE, 29, length); + unsigned extra_length = (unsigned)(length - LENGTHBASE[length_code]); + unsigned dist_code = (unsigned)searchCodeIndex(DISTANCEBASE, 30, distance); + unsigned extra_distance = (unsigned)(distance - DISTANCEBASE[dist_code]); + + uivector_push_back(values, length_code + FIRST_LENGTH_CODE_INDEX); + uivector_push_back(values, extra_length); + uivector_push_back(values, dist_code); + uivector_push_back(values, extra_distance); +} + +/*3 bytes of data get encoded into two bytes. The hash cannot use more than 3 +bytes as input because 3 is the minimum match length for deflate*/ +static const unsigned HASH_NUM_VALUES = 65536; +static const unsigned HASH_BIT_MASK = 65535; /*HASH_NUM_VALUES - 1, but C90 does not like that as initializer*/ + +typedef struct Hash +{ + int* head; /*hash value to head circular pos - can be outdated if went around window*/ + /*circular pos to prev circular pos*/ + unsigned short* chain; + int* val; /*circular pos to hash value*/ + + /*TODO: do this not only for zeros but for any repeated byte. However for PNG + it's always going to be the zeros that dominate, so not important for PNG*/ + int* headz; /*similar to head, but for chainz*/ + unsigned short* chainz; /*those with same amount of zeros*/ + unsigned short* zeros; /*length of zeros streak, used as a second hash chain*/ +} Hash; + +static unsigned hash_init(Hash* hash, unsigned windowsize) +{ + unsigned i; + hash->head = (int*)lodepng_malloc(sizeof(int) * HASH_NUM_VALUES); + hash->val = (int*)lodepng_malloc(sizeof(int) * windowsize); + hash->chain = (unsigned short*)lodepng_malloc(sizeof(unsigned short) * windowsize); + + hash->zeros = (unsigned short*)lodepng_malloc(sizeof(unsigned short) * windowsize); + hash->headz = (int*)lodepng_malloc(sizeof(int) * (MAX_SUPPORTED_DEFLATE_LENGTH + 1)); + hash->chainz = (unsigned short*)lodepng_malloc(sizeof(unsigned short) * windowsize); + + if(!hash->head || !hash->chain || !hash->val || !hash->headz|| !hash->chainz || !hash->zeros) + { + return 83; /*alloc fail*/ + } + + /*initialize hash table*/ + for(i = 0; i < HASH_NUM_VALUES; i++) hash->head[i] = -1; + for(i = 0; i < windowsize; i++) hash->val[i] = -1; + for(i = 0; i < windowsize; i++) hash->chain[i] = i; /*same value as index indicates uninitialized*/ + + for(i = 0; i <= MAX_SUPPORTED_DEFLATE_LENGTH; i++) hash->headz[i] = -1; + for(i = 0; i < windowsize; i++) hash->chainz[i] = i; /*same value as index indicates uninitialized*/ + + return 0; +} + +static void hash_cleanup(Hash* hash) +{ + lodepng_free(hash->head); + lodepng_free(hash->val); + lodepng_free(hash->chain); + + lodepng_free(hash->zeros); + lodepng_free(hash->headz); + lodepng_free(hash->chainz); +} + + + +static unsigned getHash(const unsigned char* data, size_t size, size_t pos) +{ + unsigned result = 0; + if (pos + 2 < size) + { + /*A simple shift and xor hash is used. Since the data of PNGs is dominated + by zeroes due to the filters, a better hash does not have a significant + effect on speed in traversing the chain, and causes more time spend on + calculating the hash.*/ + result ^= (unsigned)(data[pos + 0] << 0u); + result ^= (unsigned)(data[pos + 1] << 4u); + result ^= (unsigned)(data[pos + 2] << 8u); + } else { + size_t amount, i; + if(pos >= size) return 0; + amount = size - pos; + for(i = 0; i < amount; i++) result ^= (unsigned)(data[pos + i] << (i * 8u)); + } + return result & HASH_BIT_MASK; +} + +static unsigned countZeros(const unsigned char* data, size_t size, size_t pos) +{ + const unsigned char* start = data + pos; + const unsigned char* end = start + MAX_SUPPORTED_DEFLATE_LENGTH; + if(end > data + size) end = data + size; + data = start; + while (data != end && *data == 0) data++; + /*subtracting two addresses returned as 32-bit number (max value is MAX_SUPPORTED_DEFLATE_LENGTH)*/ + return (unsigned)(data - start); +} + +/*wpos = pos & (windowsize - 1)*/ +static void updateHashChain(Hash* hash, size_t wpos, unsigned hashval, unsigned short numzeros) +{ + hash->val[wpos] = (int)hashval; + if(hash->head[hashval] != -1) hash->chain[wpos] = hash->head[hashval]; + hash->head[hashval] = wpos; + + hash->zeros[wpos] = numzeros; + if(hash->headz[numzeros] != -1) hash->chainz[wpos] = hash->headz[numzeros]; + hash->headz[numzeros] = wpos; +} + +/* +LZ77-encode the data. Return value is error code. The input are raw bytes, the output +is in the form of unsigned integers with codes representing for example literal bytes, or +length/distance pairs. +It uses a hash table technique to let it encode faster. When doing LZ77 encoding, a +sliding window (of windowsize) is used, and all past bytes in that window can be used as +the "dictionary". A brute force search through all possible distances would be slow, and +this hash technique is one out of several ways to speed this up. +*/ +static unsigned encodeLZ77(uivector* out, Hash* hash, + const unsigned char* in, size_t inpos, size_t insize, unsigned windowsize, + unsigned minmatch, unsigned nicematch, unsigned lazymatching) +{ + size_t pos; + unsigned i, error = 0; + /*for large window lengths, assume the user wants no compression loss. Otherwise, max hash chain length speedup.*/ + unsigned maxchainlength = windowsize >= 8192 ? windowsize : windowsize / 8; + unsigned maxlazymatch = windowsize >= 8192 ? MAX_SUPPORTED_DEFLATE_LENGTH : 64; + + unsigned usezeros = 1; /*not sure if setting it to false for windowsize < 8192 is better or worse*/ + unsigned numzeros = 0; + + unsigned offset; /*the offset represents the distance in LZ77 terminology*/ + unsigned length; + unsigned lazy = 0; + unsigned lazylength = 0, lazyoffset = 0; + unsigned hashval; + unsigned current_offset, current_length; + unsigned prev_offset; + const unsigned char *lastptr, *foreptr, *backptr; + unsigned hashpos; + + if(windowsize <= 0 || windowsize > 32768) return 60; /*error: windowsize smaller/larger than allowed*/ + if((windowsize & (windowsize - 1)) != 0) return 90; /*error: must be power of two*/ + + if(nicematch > MAX_SUPPORTED_DEFLATE_LENGTH) nicematch = MAX_SUPPORTED_DEFLATE_LENGTH; + + for(pos = inpos; pos < insize; pos++) + { + size_t wpos = pos & (windowsize - 1); /*position for in 'circular' hash buffers*/ + unsigned chainlength = 0; + + hashval = getHash(in, insize, pos); + + if(usezeros && hashval == 0) + { + if (numzeros == 0) numzeros = countZeros(in, insize, pos); + else if (pos + numzeros > insize || in[pos + numzeros - 1] != 0) numzeros--; + } + else + { + numzeros = 0; + } + + updateHashChain(hash, wpos, hashval, numzeros); + + /*the length and offset found for the current position*/ + length = 0; + offset = 0; + + hashpos = hash->chain[wpos]; + + lastptr = &in[insize < pos + MAX_SUPPORTED_DEFLATE_LENGTH ? insize : pos + MAX_SUPPORTED_DEFLATE_LENGTH]; + + /*search for the longest string*/ + prev_offset = 0; + for(;;) + { + if(chainlength++ >= maxchainlength) break; + current_offset = hashpos <= wpos ? wpos - hashpos : wpos - hashpos + windowsize; + + if(current_offset < prev_offset) break; /*stop when went completely around the circular buffer*/ + prev_offset = current_offset; + if(current_offset > 0) + { + /*test the next characters*/ + foreptr = &in[pos]; + backptr = &in[pos - current_offset]; + + /*common case in PNGs is lots of zeros. Quickly skip over them as a speedup*/ + if(numzeros >= 3) + { + unsigned skip = hash->zeros[hashpos]; + if(skip > numzeros) skip = numzeros; + backptr += skip; + foreptr += skip; + } + + while(foreptr != lastptr && *backptr == *foreptr) /*maximum supported length by deflate is max length*/ + { + ++backptr; + ++foreptr; + } + current_length = (unsigned)(foreptr - &in[pos]); + + if(current_length > length) + { + length = current_length; /*the longest length*/ + offset = current_offset; /*the offset that is related to this longest length*/ + /*jump out once a length of max length is found (speed gain). This also jumps + out if length is MAX_SUPPORTED_DEFLATE_LENGTH*/ + if(current_length >= nicematch) break; + } + } + + if(hashpos == hash->chain[hashpos]) break; + + if(numzeros >= 3 && length > numzeros) { + hashpos = hash->chainz[hashpos]; + if(hash->zeros[hashpos] != numzeros) break; + } else { + hashpos = hash->chain[hashpos]; + /*outdated hash value, happens if particular value was not encountered in whole last window*/ + if(hash->val[hashpos] != (int)hashval) break; + } + } + + if(lazymatching) + { + if(!lazy && length >= 3 && length <= maxlazymatch && length < MAX_SUPPORTED_DEFLATE_LENGTH) + { + lazy = 1; + lazylength = length; + lazyoffset = offset; + continue; /*try the next byte*/ + } + if(lazy) + { + lazy = 0; + if(pos == 0) ERROR_BREAK(81); + if(length > lazylength + 1) + { + /*push the previous character as literal*/ + if(!uivector_push_back(out, in[pos - 1])) ERROR_BREAK(83 /*alloc fail*/); + } + else + { + length = lazylength; + offset = lazyoffset; + hash->head[hashval] = -1; /*the same hashchain update will be done, this ensures no wrong alteration*/ + hash->headz[numzeros] = -1; /*idem*/ + pos--; + } + } + } + if(length >= 3 && offset > windowsize) ERROR_BREAK(86 /*too big (or overflown negative) offset*/); + + /*encode it as length/distance pair or literal value*/ + if(length < 3) /*only lengths of 3 or higher are supported as length/distance pair*/ + { + if(!uivector_push_back(out, in[pos])) ERROR_BREAK(83 /*alloc fail*/); + } + else if(length < minmatch || (length == 3 && offset > 4096)) + { + /*compensate for the fact that longer offsets have more extra bits, a + length of only 3 may be not worth it then*/ + if(!uivector_push_back(out, in[pos])) ERROR_BREAK(83 /*alloc fail*/); + } + else + { + addLengthDistance(out, length, offset); + for(i = 1; i < length; i++) + { + pos++; + wpos = pos & (windowsize - 1); + hashval = getHash(in, insize, pos); + if(usezeros && hashval == 0) + { + if (numzeros == 0) numzeros = countZeros(in, insize, pos); + else if (pos + numzeros > insize || in[pos + numzeros - 1] != 0) numzeros--; + } + else + { + numzeros = 0; + } + updateHashChain(hash, wpos, hashval, numzeros); + } + } + } /*end of the loop through each character of input*/ + + return error; +} + +/* /////////////////////////////////////////////////////////////////////////// */ + +static unsigned deflateNoCompression(ucvector* out, const unsigned char* data, size_t datasize) +{ + /*non compressed deflate block data: 1 bit BFINAL,2 bits BTYPE,(5 bits): it jumps to start of next byte, + 2 bytes LEN, 2 bytes NLEN, LEN bytes literal DATA*/ + + size_t i, j, numdeflateblocks = (datasize + 65534) / 65535; + unsigned datapos = 0; + for(i = 0; i < numdeflateblocks; i++) + { + unsigned BFINAL, BTYPE, LEN, NLEN; + unsigned char firstbyte; + + BFINAL = (i == numdeflateblocks - 1); + BTYPE = 0; + + firstbyte = (unsigned char)(BFINAL + ((BTYPE & 1) << 1) + ((BTYPE & 2) << 1)); + ucvector_push_back(out, firstbyte); + + LEN = 65535; + if(datasize - datapos < 65535) LEN = (unsigned)datasize - datapos; + NLEN = 65535 - LEN; + + ucvector_push_back(out, (unsigned char)(LEN % 256)); + ucvector_push_back(out, (unsigned char)(LEN / 256)); + ucvector_push_back(out, (unsigned char)(NLEN % 256)); + ucvector_push_back(out, (unsigned char)(NLEN / 256)); + + /*Decompressed data*/ + for(j = 0; j < 65535 && datapos < datasize; j++) + { + ucvector_push_back(out, data[datapos++]); + } + } + + return 0; +} + +/* +write the lz77-encoded data, which has lit, len and dist codes, to compressed stream using huffman trees. +tree_ll: the tree for lit and len codes. +tree_d: the tree for distance codes. +*/ +static void writeLZ77data(size_t* bp, ucvector* out, const uivector* lz77_encoded, + const HuffmanTree* tree_ll, const HuffmanTree* tree_d) +{ + size_t i = 0; + for(i = 0; i < lz77_encoded->size; i++) + { + unsigned val = lz77_encoded->data[i]; + addHuffmanSymbol(bp, out, HuffmanTree_getCode(tree_ll, val), HuffmanTree_getLength(tree_ll, val)); + if(val > 256) /*for a length code, 3 more things have to be added*/ + { + unsigned length_index = val - FIRST_LENGTH_CODE_INDEX; + unsigned n_length_extra_bits = LENGTHEXTRA[length_index]; + unsigned length_extra_bits = lz77_encoded->data[++i]; + + unsigned distance_code = lz77_encoded->data[++i]; + + unsigned distance_index = distance_code; + unsigned n_distance_extra_bits = DISTANCEEXTRA[distance_index]; + unsigned distance_extra_bits = lz77_encoded->data[++i]; + + addBitsToStream(bp, out, length_extra_bits, n_length_extra_bits); + addHuffmanSymbol(bp, out, HuffmanTree_getCode(tree_d, distance_code), + HuffmanTree_getLength(tree_d, distance_code)); + addBitsToStream(bp, out, distance_extra_bits, n_distance_extra_bits); + } + } +} + +/*Deflate for a block of type "dynamic", that is, with freely, optimally, created huffman trees*/ +static unsigned deflateDynamic(ucvector* out, size_t* bp, Hash* hash, + const unsigned char* data, size_t datapos, size_t dataend, + const LodePNGCompressSettings* settings, unsigned final) +{ + unsigned error = 0; + + /* + A block is compressed as follows: The PNG data is lz77 encoded, resulting in + literal bytes and length/distance pairs. This is then huffman compressed with + two huffman trees. One huffman tree is used for the lit and len values ("ll"), + another huffman tree is used for the dist values ("d"). These two trees are + stored using their code lengths, and to compress even more these code lengths + are also run-length encoded and huffman compressed. This gives a huffman tree + of code lengths "cl". The code lenghts used to describe this third tree are + the code length code lengths ("clcl"). + */ + + /*The lz77 encoded data, represented with integers since there will also be length and distance codes in it*/ + uivector lz77_encoded; + HuffmanTree tree_ll; /*tree for lit,len values*/ + HuffmanTree tree_d; /*tree for distance codes*/ + HuffmanTree tree_cl; /*tree for encoding the code lengths representing tree_ll and tree_d*/ + uivector frequencies_ll; /*frequency of lit,len codes*/ + uivector frequencies_d; /*frequency of dist codes*/ + uivector frequencies_cl; /*frequency of code length codes*/ + uivector bitlen_lld; /*lit,len,dist code lenghts (int bits), literally (without repeat codes).*/ + uivector bitlen_lld_e; /*bitlen_lld encoded with repeat codes (this is a rudemtary run length compression)*/ + /*bitlen_cl is the code length code lengths ("clcl"). The bit lengths of codes to represent tree_cl + (these are written as is in the file, it would be crazy to compress these using yet another huffman + tree that needs to be represented by yet another set of code lengths)*/ + uivector bitlen_cl; + size_t datasize = dataend - datapos; + + /* + Due to the huffman compression of huffman tree representations ("two levels"), there are some anologies: + bitlen_lld is to tree_cl what data is to tree_ll and tree_d. + bitlen_lld_e is to bitlen_lld what lz77_encoded is to data. + bitlen_cl is to bitlen_lld_e what bitlen_lld is to lz77_encoded. + */ + + unsigned BFINAL = final; + size_t numcodes_ll, numcodes_d, i; + unsigned HLIT, HDIST, HCLEN; + + uivector_init(&lz77_encoded); + HuffmanTree_init(&tree_ll); + HuffmanTree_init(&tree_d); + HuffmanTree_init(&tree_cl); + uivector_init(&frequencies_ll); + uivector_init(&frequencies_d); + uivector_init(&frequencies_cl); + uivector_init(&bitlen_lld); + uivector_init(&bitlen_lld_e); + uivector_init(&bitlen_cl); + + /*This while loop never loops due to a break at the end, it is here to + allow breaking out of it to the cleanup phase on error conditions.*/ + while(!error) + { + if(settings->use_lz77) + { + error = encodeLZ77(&lz77_encoded, hash, data, datapos, dataend, settings->windowsize, + settings->minmatch, settings->nicematch, settings->lazymatching); + if(error) break; + } + else + { + if(!uivector_resize(&lz77_encoded, datasize)) ERROR_BREAK(83 /*alloc fail*/); + for(i = datapos; i < dataend; i++) lz77_encoded.data[i] = data[i]; /*no LZ77, but still will be Huffman compressed*/ + } + + if(!uivector_resizev(&frequencies_ll, 286, 0)) ERROR_BREAK(83 /*alloc fail*/); + if(!uivector_resizev(&frequencies_d, 30, 0)) ERROR_BREAK(83 /*alloc fail*/); + + /*Count the frequencies of lit, len and dist codes*/ + for(i = 0; i < lz77_encoded.size; i++) + { + unsigned symbol = lz77_encoded.data[i]; + frequencies_ll.data[symbol]++; + if(symbol > 256) + { + unsigned dist = lz77_encoded.data[i + 2]; + frequencies_d.data[dist]++; + i += 3; + } + } + frequencies_ll.data[256] = 1; /*there will be exactly 1 end code, at the end of the block*/ + + /*Make both huffman trees, one for the lit and len codes, one for the dist codes*/ + error = HuffmanTree_makeFromFrequencies(&tree_ll, frequencies_ll.data, 257, frequencies_ll.size, 15); + if(error) break; + /*2, not 1, is chosen for mincodes: some buggy PNG decoders require at least 2 symbols in the dist tree*/ + error = HuffmanTree_makeFromFrequencies(&tree_d, frequencies_d.data, 2, frequencies_d.size, 15); + if(error) break; + + numcodes_ll = tree_ll.numcodes; if(numcodes_ll > 286) numcodes_ll = 286; + numcodes_d = tree_d.numcodes; if(numcodes_d > 30) numcodes_d = 30; + /*store the code lengths of both generated trees in bitlen_lld*/ + for(i = 0; i < numcodes_ll; i++) uivector_push_back(&bitlen_lld, HuffmanTree_getLength(&tree_ll, (unsigned)i)); + for(i = 0; i < numcodes_d; i++) uivector_push_back(&bitlen_lld, HuffmanTree_getLength(&tree_d, (unsigned)i)); + + /*run-length compress bitlen_ldd into bitlen_lld_e by using repeat codes 16 (copy length 3-6 times), + 17 (3-10 zeroes), 18 (11-138 zeroes)*/ + for(i = 0; i < (unsigned)bitlen_lld.size; i++) + { + unsigned j = 0; /*amount of repititions*/ + while(i + j + 1 < (unsigned)bitlen_lld.size && bitlen_lld.data[i + j + 1] == bitlen_lld.data[i]) j++; + + if(bitlen_lld.data[i] == 0 && j >= 2) /*repeat code for zeroes*/ + { + j++; /*include the first zero*/ + if(j <= 10) /*repeat code 17 supports max 10 zeroes*/ + { + uivector_push_back(&bitlen_lld_e, 17); + uivector_push_back(&bitlen_lld_e, j - 3); + } + else /*repeat code 18 supports max 138 zeroes*/ + { + if(j > 138) j = 138; + uivector_push_back(&bitlen_lld_e, 18); + uivector_push_back(&bitlen_lld_e, j - 11); + } + i += (j - 1); + } + else if(j >= 3) /*repeat code for value other than zero*/ + { + size_t k; + unsigned num = j / 6, rest = j % 6; + uivector_push_back(&bitlen_lld_e, bitlen_lld.data[i]); + for(k = 0; k < num; k++) + { + uivector_push_back(&bitlen_lld_e, 16); + uivector_push_back(&bitlen_lld_e, 6 - 3); + } + if(rest >= 3) + { + uivector_push_back(&bitlen_lld_e, 16); + uivector_push_back(&bitlen_lld_e, rest - 3); + } + else j -= rest; + i += j; + } + else /*too short to benefit from repeat code*/ + { + uivector_push_back(&bitlen_lld_e, bitlen_lld.data[i]); + } + } + + /*generate tree_cl, the huffmantree of huffmantrees*/ + + if(!uivector_resizev(&frequencies_cl, NUM_CODE_LENGTH_CODES, 0)) ERROR_BREAK(83 /*alloc fail*/); + for(i = 0; i < bitlen_lld_e.size; i++) + { + frequencies_cl.data[bitlen_lld_e.data[i]]++; + /*after a repeat code come the bits that specify the number of repetitions, + those don't need to be in the frequencies_cl calculation*/ + if(bitlen_lld_e.data[i] >= 16) i++; + } + + error = HuffmanTree_makeFromFrequencies(&tree_cl, frequencies_cl.data, + frequencies_cl.size, frequencies_cl.size, 7); + if(error) break; + + if(!uivector_resize(&bitlen_cl, tree_cl.numcodes)) ERROR_BREAK(83 /*alloc fail*/); + for(i = 0; i < tree_cl.numcodes; i++) + { + /*lenghts of code length tree is in the order as specified by deflate*/ + bitlen_cl.data[i] = HuffmanTree_getLength(&tree_cl, CLCL_ORDER[i]); + } + while(bitlen_cl.data[bitlen_cl.size - 1] == 0 && bitlen_cl.size > 4) + { + /*remove zeros at the end, but minimum size must be 4*/ + if(!uivector_resize(&bitlen_cl, bitlen_cl.size - 1)) ERROR_BREAK(83 /*alloc fail*/); + } + if(error) break; + + /* + Write everything into the output + + After the BFINAL and BTYPE, the dynamic block consists out of the following: + - 5 bits HLIT, 5 bits HDIST, 4 bits HCLEN + - (HCLEN+4)*3 bits code lengths of code length alphabet + - HLIT + 257 code lenghts of lit/length alphabet (encoded using the code length + alphabet, + possible repetition codes 16, 17, 18) + - HDIST + 1 code lengths of distance alphabet (encoded using the code length + alphabet, + possible repetition codes 16, 17, 18) + - compressed data + - 256 (end code) + */ + + /*Write block type*/ + addBitToStream(bp, out, BFINAL); + addBitToStream(bp, out, 0); /*first bit of BTYPE "dynamic"*/ + addBitToStream(bp, out, 1); /*second bit of BTYPE "dynamic"*/ + + /*write the HLIT, HDIST and HCLEN values*/ + HLIT = (unsigned)(numcodes_ll - 257); + HDIST = (unsigned)(numcodes_d - 1); + HCLEN = (unsigned)bitlen_cl.size - 4; + /*trim zeroes for HCLEN. HLIT and HDIST were already trimmed at tree creation*/ + while(!bitlen_cl.data[HCLEN + 4 - 1] && HCLEN > 0) HCLEN--; + addBitsToStream(bp, out, HLIT, 5); + addBitsToStream(bp, out, HDIST, 5); + addBitsToStream(bp, out, HCLEN, 4); + + /*write the code lenghts of the code length alphabet*/ + for(i = 0; i < HCLEN + 4; i++) addBitsToStream(bp, out, bitlen_cl.data[i], 3); + + /*write the lenghts of the lit/len AND the dist alphabet*/ + for(i = 0; i < bitlen_lld_e.size; i++) + { + addHuffmanSymbol(bp, out, HuffmanTree_getCode(&tree_cl, bitlen_lld_e.data[i]), + HuffmanTree_getLength(&tree_cl, bitlen_lld_e.data[i])); + /*extra bits of repeat codes*/ + if(bitlen_lld_e.data[i] == 16) addBitsToStream(bp, out, bitlen_lld_e.data[++i], 2); + else if(bitlen_lld_e.data[i] == 17) addBitsToStream(bp, out, bitlen_lld_e.data[++i], 3); + else if(bitlen_lld_e.data[i] == 18) addBitsToStream(bp, out, bitlen_lld_e.data[++i], 7); + } + + /*write the compressed data symbols*/ + writeLZ77data(bp, out, &lz77_encoded, &tree_ll, &tree_d); + /*error: the length of the end code 256 must be larger than 0*/ + if(HuffmanTree_getLength(&tree_ll, 256) == 0) ERROR_BREAK(64); + + /*write the end code*/ + addHuffmanSymbol(bp, out, HuffmanTree_getCode(&tree_ll, 256), HuffmanTree_getLength(&tree_ll, 256)); + + break; /*end of error-while*/ + } + + /*cleanup*/ + uivector_cleanup(&lz77_encoded); + HuffmanTree_cleanup(&tree_ll); + HuffmanTree_cleanup(&tree_d); + HuffmanTree_cleanup(&tree_cl); + uivector_cleanup(&frequencies_ll); + uivector_cleanup(&frequencies_d); + uivector_cleanup(&frequencies_cl); + uivector_cleanup(&bitlen_lld_e); + uivector_cleanup(&bitlen_lld); + uivector_cleanup(&bitlen_cl); + + return error; +} + +static unsigned deflateFixed(ucvector* out, size_t* bp, Hash* hash, + const unsigned char* data, + size_t datapos, size_t dataend, + const LodePNGCompressSettings* settings, unsigned final) +{ + HuffmanTree tree_ll; /*tree for literal values and length codes*/ + HuffmanTree tree_d; /*tree for distance codes*/ + + unsigned BFINAL = final; + unsigned error = 0; + size_t i; + + HuffmanTree_init(&tree_ll); + HuffmanTree_init(&tree_d); + + generateFixedLitLenTree(&tree_ll); + generateFixedDistanceTree(&tree_d); + + addBitToStream(bp, out, BFINAL); + addBitToStream(bp, out, 1); /*first bit of BTYPE*/ + addBitToStream(bp, out, 0); /*second bit of BTYPE*/ + + if(settings->use_lz77) /*LZ77 encoded*/ + { + uivector lz77_encoded; + uivector_init(&lz77_encoded); + error = encodeLZ77(&lz77_encoded, hash, data, datapos, dataend, settings->windowsize, + settings->minmatch, settings->nicematch, settings->lazymatching); + if(!error) writeLZ77data(bp, out, &lz77_encoded, &tree_ll, &tree_d); + uivector_cleanup(&lz77_encoded); + } + else /*no LZ77, but still will be Huffman compressed*/ + { + for(i = datapos; i < dataend; i++) + { + addHuffmanSymbol(bp, out, HuffmanTree_getCode(&tree_ll, data[i]), HuffmanTree_getLength(&tree_ll, data[i])); + } + } + /*add END code*/ + if(!error) addHuffmanSymbol(bp, out, HuffmanTree_getCode(&tree_ll, 256), HuffmanTree_getLength(&tree_ll, 256)); + + /*cleanup*/ + HuffmanTree_cleanup(&tree_ll); + HuffmanTree_cleanup(&tree_d); + + return error; +} + +static unsigned lodepng_deflatev(ucvector* out, const unsigned char* in, size_t insize, + const LodePNGCompressSettings* settings) +{ + unsigned error = 0; + size_t i, blocksize, numdeflateblocks; + size_t bp = 0; /*the bit pointer*/ + Hash hash; + + if(settings->btype > 2) return 61; + else if(settings->btype == 0) return deflateNoCompression(out, in, insize); + else if(settings->btype == 1) blocksize = insize; + else /*if(settings->btype == 2)*/ + { + blocksize = insize / 8 + 8; + if(blocksize < 65535) blocksize = 65535; + } + + numdeflateblocks = (insize + blocksize - 1) / blocksize; + if(numdeflateblocks == 0) numdeflateblocks = 1; + + error = hash_init(&hash, settings->windowsize); + if(error) return error; + + for(i = 0; i < numdeflateblocks && !error; i++) + { + unsigned final = (i == numdeflateblocks - 1); + size_t start = i * blocksize; + size_t end = start + blocksize; + if(end > insize) end = insize; + + if(settings->btype == 1) error = deflateFixed(out, &bp, &hash, in, start, end, settings, final); + else if(settings->btype == 2) error = deflateDynamic(out, &bp, &hash, in, start, end, settings, final); + } + + hash_cleanup(&hash); + + return error; +} + +unsigned lodepng_deflate(unsigned char** out, size_t* outsize, + const unsigned char* in, size_t insize, + const LodePNGCompressSettings* settings) +{ + unsigned error; + ucvector v; + ucvector_init_buffer(&v, *out, *outsize); + error = lodepng_deflatev(&v, in, insize, settings); + *out = v.data; + *outsize = v.size; + return error; +} + +static unsigned deflate(unsigned char** out, size_t* outsize, + const unsigned char* in, size_t insize, + const LodePNGCompressSettings* settings) +{ + if(settings->custom_deflate) + { + return settings->custom_deflate(out, outsize, in, insize, settings); + } + else + { + return lodepng_deflate(out, outsize, in, insize, settings); + } +} + +#endif /*LODEPNG_COMPILE_DECODER*/ + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / Adler32 */ +/* ////////////////////////////////////////////////////////////////////////// */ + +static unsigned update_adler32(unsigned adler, const unsigned char* data, unsigned len) +{ + unsigned s1 = adler & 0xffff; + unsigned s2 = (adler >> 16) & 0xffff; + + while(len > 0) + { + /*at least 5550 sums can be done before the sums overflow, saving a lot of module divisions*/ + unsigned amount = len > 5550 ? 5550 : len; + len -= amount; + while(amount > 0) + { + s1 += (*data++); + s2 += s1; + amount--; + } + s1 %= 65521; + s2 %= 65521; + } + + return (s2 << 16) | s1; +} + +/*Return the adler32 of the bytes data[0..len-1]*/ +static unsigned adler32(const unsigned char* data, unsigned len) +{ + return update_adler32(1L, data, len); +} + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / Zlib / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +#ifdef LODEPNG_COMPILE_DECODER + +unsigned lodepng_zlib_decompress(unsigned char** out, size_t* outsize, const unsigned char* in, + size_t insize, const LodePNGDecompressSettings* settings) +{ + unsigned error = 0; + unsigned CM, CINFO, FDICT; + + if(insize < 2) return 53; /*error, size of zlib data too small*/ + /*read information from zlib header*/ + if((in[0] * 256 + in[1]) % 31 != 0) + { + /*error: 256 * in[0] + in[1] must be a multiple of 31, the FCHECK value is supposed to be made that way*/ + return 24; + } + + CM = in[0] & 15; + CINFO = (in[0] >> 4) & 15; + /*FCHECK = in[1] & 31;*/ /*FCHECK is already tested above*/ + FDICT = (in[1] >> 5) & 1; + /*FLEVEL = (in[1] >> 6) & 3;*/ /*FLEVEL is not used here*/ + + if(CM != 8 || CINFO > 7) + { + /*error: only compression method 8: inflate with sliding window of 32k is supported by the PNG spec*/ + return 25; + } + if(FDICT != 0) + { + /*error: the specification of PNG says about the zlib stream: + "The additional flags shall not specify a preset dictionary."*/ + return 26; + } + + error = inflate(out, outsize, in + 2, insize - 2, settings); + if(error) return error; + + if(!settings->ignore_adler32) + { + unsigned ADLER32 = lodepng_read32bitInt(&in[insize - 4]); + unsigned checksum = adler32(*out, (unsigned)(*outsize)); + if(checksum != ADLER32) return 58; /*error, adler checksum not correct, data must be corrupted*/ + } + + return 0; /*no error*/ +} + +static unsigned zlib_decompress(unsigned char** out, size_t* outsize, const unsigned char* in, + size_t insize, const LodePNGDecompressSettings* settings) +{ + if(settings->custom_zlib) + { + return settings->custom_zlib(out, outsize, in, insize, settings); + } + else + { + return lodepng_zlib_decompress(out, outsize, in, insize, settings); + } +} + +#endif /*LODEPNG_COMPILE_DECODER*/ + +#ifdef LODEPNG_COMPILE_ENCODER + +unsigned lodepng_zlib_compress(unsigned char** out, size_t* outsize, const unsigned char* in, + size_t insize, const LodePNGCompressSettings* settings) +{ + /*initially, *out must be NULL and outsize 0, if you just give some random *out + that's pointing to a non allocated buffer, this'll crash*/ + ucvector outv; + size_t i; + unsigned error; + unsigned char* deflatedata = 0; + size_t deflatesize = 0; + + unsigned ADLER32; + /*zlib data: 1 byte CMF (CM+CINFO), 1 byte FLG, deflate data, 4 byte ADLER32 checksum of the Decompressed data*/ + unsigned CMF = 120; /*0b01111000: CM 8, CINFO 7. With CINFO 7, any window size up to 32768 can be used.*/ + unsigned FLEVEL = 0; + unsigned FDICT = 0; + unsigned CMFFLG = 256 * CMF + FDICT * 32 + FLEVEL * 64; + unsigned FCHECK = 31 - CMFFLG % 31; + CMFFLG += FCHECK; + + /*ucvector-controlled version of the output buffer, for dynamic array*/ + ucvector_init_buffer(&outv, *out, *outsize); + + ucvector_push_back(&outv, (unsigned char)(CMFFLG / 256)); + ucvector_push_back(&outv, (unsigned char)(CMFFLG % 256)); + + error = deflate(&deflatedata, &deflatesize, in, insize, settings); + + if(!error) + { + ADLER32 = adler32(in, (unsigned)insize); + for(i = 0; i < deflatesize; i++) ucvector_push_back(&outv, deflatedata[i]); + lodepng_free(deflatedata); + lodepng_add32bitInt(&outv, ADLER32); + } + + *out = outv.data; + *outsize = outv.size; + + return error; +} + +/* compress using the default or custom zlib function */ +static unsigned zlib_compress(unsigned char** out, size_t* outsize, const unsigned char* in, + size_t insize, const LodePNGCompressSettings* settings) +{ + if(settings->custom_zlib) + { + return settings->custom_zlib(out, outsize, in, insize, settings); + } + else + { + return lodepng_zlib_compress(out, outsize, in, insize, settings); + } +} + +#endif /*LODEPNG_COMPILE_ENCODER*/ + +#else /*no LODEPNG_COMPILE_ZLIB*/ + +#ifdef LODEPNG_COMPILE_DECODER +static unsigned zlib_decompress(unsigned char** out, size_t* outsize, const unsigned char* in, + size_t insize, const LodePNGDecompressSettings* settings) +{ + if (!settings->custom_zlib) return 87; /*no custom zlib function provided */ + return settings->custom_zlib(out, outsize, in, insize, settings); +} +#endif /*LODEPNG_COMPILE_DECODER*/ +#ifdef LODEPNG_COMPILE_ENCODER +static unsigned zlib_compress(unsigned char** out, size_t* outsize, const unsigned char* in, + size_t insize, const LodePNGCompressSettings* settings) +{ + if (!settings->custom_zlib) return 87; /*no custom zlib function provided */ + return settings->custom_zlib(out, outsize, in, insize, settings); +} +#endif /*LODEPNG_COMPILE_ENCODER*/ + +#endif /*LODEPNG_COMPILE_ZLIB*/ + +/* ////////////////////////////////////////////////////////////////////////// */ + +#ifdef LODEPNG_COMPILE_ENCODER + +/*this is a good tradeoff between speed and compression ratio*/ +#define DEFAULT_WINDOWSIZE 2048 + +void lodepng_compress_settings_init(LodePNGCompressSettings* settings) +{ + /*compress with dynamic huffman tree (not in the mathematical sense, just not the predefined one)*/ + settings->btype = 2; + settings->use_lz77 = 1; + settings->windowsize = DEFAULT_WINDOWSIZE; + settings->minmatch = 3; + settings->nicematch = 128; + settings->lazymatching = 1; + + settings->custom_zlib = 0; + settings->custom_deflate = 0; + settings->custom_context = 0; +} + +const LodePNGCompressSettings lodepng_default_compress_settings = {2, 1, DEFAULT_WINDOWSIZE, 3, 128, 1, 0, 0, 0}; + + +#endif /*LODEPNG_COMPILE_ENCODER*/ + +#ifdef LODEPNG_COMPILE_DECODER + +void lodepng_decompress_settings_init(LodePNGDecompressSettings* settings) +{ + settings->ignore_adler32 = 0; + + settings->custom_zlib = 0; + settings->custom_inflate = 0; + settings->custom_context = 0; +} + +const LodePNGDecompressSettings lodepng_default_decompress_settings = {0, 0, 0, 0}; + +#endif /*LODEPNG_COMPILE_DECODER*/ + +/* ////////////////////////////////////////////////////////////////////////// */ +/* ////////////////////////////////////////////////////////////////////////// */ +/* // End of Zlib related code. Begin of PNG related code. // */ +/* ////////////////////////////////////////////////////////////////////////// */ +/* ////////////////////////////////////////////////////////////////////////// */ + +#ifdef LODEPNG_COMPILE_PNG + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / CRC32 / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +/* CRC polynomial: 0xedb88320 */ +static unsigned lodepng_crc32_table[256] = { + 0u, 1996959894u, 3993919788u, 2567524794u, 124634137u, 1886057615u, 3915621685u, 2657392035u, + 249268274u, 2044508324u, 3772115230u, 2547177864u, 162941995u, 2125561021u, 3887607047u, 2428444049u, + 498536548u, 1789927666u, 4089016648u, 2227061214u, 450548861u, 1843258603u, 4107580753u, 2211677639u, + 325883990u, 1684777152u, 4251122042u, 2321926636u, 335633487u, 1661365465u, 4195302755u, 2366115317u, + 997073096u, 1281953886u, 3579855332u, 2724688242u, 1006888145u, 1258607687u, 3524101629u, 2768942443u, + 901097722u, 1119000684u, 3686517206u, 2898065728u, 853044451u, 1172266101u, 3705015759u, 2882616665u, + 651767980u, 1373503546u, 3369554304u, 3218104598u, 565507253u, 1454621731u, 3485111705u, 3099436303u, + 671266974u, 1594198024u, 3322730930u, 2970347812u, 795835527u, 1483230225u, 3244367275u, 3060149565u, + 1994146192u, 31158534u, 2563907772u, 4023717930u, 1907459465u, 112637215u, 2680153253u, 3904427059u, + 2013776290u, 251722036u, 2517215374u, 3775830040u, 2137656763u, 141376813u, 2439277719u, 3865271297u, + 1802195444u, 476864866u, 2238001368u, 4066508878u, 1812370925u, 453092731u, 2181625025u, 4111451223u, + 1706088902u, 314042704u, 2344532202u, 4240017532u, 1658658271u, 366619977u, 2362670323u, 4224994405u, + 1303535960u, 984961486u, 2747007092u, 3569037538u, 1256170817u, 1037604311u, 2765210733u, 3554079995u, + 1131014506u, 879679996u, 2909243462u, 3663771856u, 1141124467u, 855842277u, 2852801631u, 3708648649u, + 1342533948u, 654459306u, 3188396048u, 3373015174u, 1466479909u, 544179635u, 3110523913u, 3462522015u, + 1591671054u, 702138776u, 2966460450u, 3352799412u, 1504918807u, 783551873u, 3082640443u, 3233442989u, + 3988292384u, 2596254646u, 62317068u, 1957810842u, 3939845945u, 2647816111u, 81470997u, 1943803523u, + 3814918930u, 2489596804u, 225274430u, 2053790376u, 3826175755u, 2466906013u, 167816743u, 2097651377u, + 4027552580u, 2265490386u, 503444072u, 1762050814u, 4150417245u, 2154129355u, 426522225u, 1852507879u, + 4275313526u, 2312317920u, 282753626u, 1742555852u, 4189708143u, 2394877945u, 397917763u, 1622183637u, + 3604390888u, 2714866558u, 953729732u, 1340076626u, 3518719985u, 2797360999u, 1068828381u, 1219638859u, + 3624741850u, 2936675148u, 906185462u, 1090812512u, 3747672003u, 2825379669u, 829329135u, 1181335161u, + 3412177804u, 3160834842u, 628085408u, 1382605366u, 3423369109u, 3138078467u, 570562233u, 1426400815u, + 3317316542u, 2998733608u, 733239954u, 1555261956u, 3268935591u, 3050360625u, 752459403u, 1541320221u, + 2607071920u, 3965973030u, 1969922972u, 40735498u, 2617837225u, 3943577151u, 1913087877u, 83908371u, + 2512341634u, 3803740692u, 2075208622u, 213261112u, 2463272603u, 3855990285u, 2094854071u, 198958881u, + 2262029012u, 4057260610u, 1759359992u, 534414190u, 2176718541u, 4139329115u, 1873836001u, 414664567u, + 2282248934u, 4279200368u, 1711684554u, 285281116u, 2405801727u, 4167216745u, 1634467795u, 376229701u, + 2685067896u, 3608007406u, 1308918612u, 956543938u, 2808555105u, 3495958263u, 1231636301u, 1047427035u, + 2932959818u, 3654703836u, 1088359270u, 936918000u, 2847714899u, 3736837829u, 1202900863u, 817233897u, + 3183342108u, 3401237130u, 1404277552u, 615818150u, 3134207493u, 3453421203u, 1423857449u, 601450431u, + 3009837614u, 3294710456u, 1567103746u, 711928724u, 3020668471u, 3272380065u, 1510334235u, 755167117u +}; + +/*Return the CRC of the bytes buf[0..len-1].*/ +unsigned lodepng_crc32(const unsigned char* buf, size_t len) +{ + unsigned c = 0xffffffffL; + size_t n; + + for(n = 0; n < len; n++) + { + c = lodepng_crc32_table[(c ^ buf[n]) & 0xff] ^ (c >> 8); + } + return c ^ 0xffffffffL; +} + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / Reading and writing single bits and bytes from/to stream for LodePNG / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +static unsigned char readBitFromReversedStream(size_t* bitpointer, const unsigned char* bitstream) +{ + unsigned char result = (unsigned char)((bitstream[(*bitpointer) >> 3] >> (7 - ((*bitpointer) & 0x7))) & 1); + (*bitpointer)++; + return result; +} + +static unsigned readBitsFromReversedStream(size_t* bitpointer, const unsigned char* bitstream, size_t nbits) +{ + unsigned result = 0; + size_t i; + for(i = nbits - 1; i < nbits; i--) + { + result += (unsigned)readBitFromReversedStream(bitpointer, bitstream) << i; + } + return result; +} + +#ifdef LODEPNG_COMPILE_DECODER +static void setBitOfReversedStream0(size_t* bitpointer, unsigned char* bitstream, unsigned char bit) +{ + /*the current bit in bitstream must be 0 for this to work*/ + if(bit) + { + /*earlier bit of huffman code is in a lesser significant bit of an earlier byte*/ + bitstream[(*bitpointer) >> 3] |= (bit << (7 - ((*bitpointer) & 0x7))); + } + (*bitpointer)++; +} +#endif /*LODEPNG_COMPILE_DECODER*/ + +static void setBitOfReversedStream(size_t* bitpointer, unsigned char* bitstream, unsigned char bit) +{ + /*the current bit in bitstream may be 0 or 1 for this to work*/ + if(bit == 0) bitstream[(*bitpointer) >> 3] &= (unsigned char)(~(1 << (7 - ((*bitpointer) & 0x7)))); + else bitstream[(*bitpointer) >> 3] |= (1 << (7 - ((*bitpointer) & 0x7))); + (*bitpointer)++; +} + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / PNG chunks / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +unsigned lodepng_chunk_length(const unsigned char* chunk) +{ + return lodepng_read32bitInt(&chunk[0]); +} + +void lodepng_chunk_type(char type[5], const unsigned char* chunk) +{ + unsigned i; + for(i = 0; i < 4; i++) type[i] = (char)chunk[4 + i]; + type[4] = 0; /*null termination char*/ +} + +unsigned char lodepng_chunk_type_equals(const unsigned char* chunk, const char* type) +{ + if(strlen(type) != 4) return 0; + return (chunk[4] == type[0] && chunk[5] == type[1] && chunk[6] == type[2] && chunk[7] == type[3]); +} + +unsigned char lodepng_chunk_ancillary(const unsigned char* chunk) +{ + return((chunk[4] & 32) != 0); +} + +unsigned char lodepng_chunk_private(const unsigned char* chunk) +{ + return((chunk[6] & 32) != 0); +} + +unsigned char lodepng_chunk_safetocopy(const unsigned char* chunk) +{ + return((chunk[7] & 32) != 0); +} + +unsigned char* lodepng_chunk_data(unsigned char* chunk) +{ + return &chunk[8]; +} + +const unsigned char* lodepng_chunk_data_const(const unsigned char* chunk) +{ + return &chunk[8]; +} + +unsigned lodepng_chunk_check_crc(const unsigned char* chunk) +{ + unsigned length = lodepng_chunk_length(chunk); + unsigned CRC = lodepng_read32bitInt(&chunk[length + 8]); + /*the CRC is taken of the data and the 4 chunk type letters, not the length*/ + unsigned checksum = lodepng_crc32(&chunk[4], length + 4); + if(CRC != checksum) return 1; + else return 0; +} + +void lodepng_chunk_generate_crc(unsigned char* chunk) +{ + unsigned length = lodepng_chunk_length(chunk); + unsigned CRC = lodepng_crc32(&chunk[4], length + 4); + lodepng_set32bitInt(chunk + 8 + length, CRC); +} + +unsigned char* lodepng_chunk_next(unsigned char* chunk) +{ + unsigned total_chunk_length = lodepng_chunk_length(chunk) + 12; + return &chunk[total_chunk_length]; +} + +const unsigned char* lodepng_chunk_next_const(const unsigned char* chunk) +{ + unsigned total_chunk_length = lodepng_chunk_length(chunk) + 12; + return &chunk[total_chunk_length]; +} + +unsigned lodepng_chunk_append(unsigned char** out, size_t* outlength, const unsigned char* chunk) +{ + unsigned i; + unsigned total_chunk_length = lodepng_chunk_length(chunk) + 12; + unsigned char *chunk_start, *new_buffer; + size_t new_length = (*outlength) + total_chunk_length; + if(new_length < total_chunk_length || new_length < (*outlength)) return 77; /*integer overflow happened*/ + + new_buffer = (unsigned char*)lodepng_realloc(*out, new_length); + if(!new_buffer) return 83; /*alloc fail*/ + (*out) = new_buffer; + (*outlength) = new_length; + chunk_start = &(*out)[new_length - total_chunk_length]; + + for(i = 0; i < total_chunk_length; i++) chunk_start[i] = chunk[i]; + + return 0; +} + +unsigned lodepng_chunk_create(unsigned char** out, size_t* outlength, unsigned length, + const char* type, const unsigned char* data) +{ + unsigned i; + unsigned char *chunk, *new_buffer; + size_t new_length = (*outlength) + length + 12; + if(new_length < length + 12 || new_length < (*outlength)) return 77; /*integer overflow happened*/ + new_buffer = (unsigned char*)lodepng_realloc(*out, new_length); + if(!new_buffer) return 83; /*alloc fail*/ + (*out) = new_buffer; + (*outlength) = new_length; + chunk = &(*out)[(*outlength) - length - 12]; + + /*1: length*/ + lodepng_set32bitInt(chunk, (unsigned)length); + + /*2: chunk name (4 letters)*/ + chunk[4] = (unsigned char)type[0]; + chunk[5] = (unsigned char)type[1]; + chunk[6] = (unsigned char)type[2]; + chunk[7] = (unsigned char)type[3]; + + /*3: the data*/ + for(i = 0; i < length; i++) chunk[8 + i] = data[i]; + + /*4: CRC (of the chunkname characters and the data)*/ + lodepng_chunk_generate_crc(chunk); + + return 0; +} + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / Color types and such / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +/*return type is a LodePNG error code*/ +static unsigned checkColorValidity(LodePNGColorType colortype, unsigned bd) /*bd = bitdepth*/ +{ + switch(colortype) + { + case 0: if(!(bd == 1 || bd == 2 || bd == 4 || bd == 8 || bd == 16)) return 37; break; /*grey*/ + case 2: if(!( bd == 8 || bd == 16)) return 37; break; /*RGB*/ + case 3: if(!(bd == 1 || bd == 2 || bd == 4 || bd == 8 )) return 37; break; /*palette*/ + case 4: if(!( bd == 8 || bd == 16)) return 37; break; /*grey + alpha*/ + case 6: if(!( bd == 8 || bd == 16)) return 37; break; /*RGBA*/ + default: return 31; + } + return 0; /*allowed color type / bits combination*/ +} + +static unsigned getNumColorChannels(LodePNGColorType colortype) +{ + switch(colortype) + { + case 0: return 1; /*grey*/ + case 2: return 3; /*RGB*/ + case 3: return 1; /*palette*/ + case 4: return 2; /*grey + alpha*/ + case 6: return 4; /*RGBA*/ + } + return 0; /*unexisting color type*/ +} + +static unsigned lodepng_get_bpp_lct(LodePNGColorType colortype, unsigned bitdepth) +{ + /*bits per pixel is amount of channels * bits per channel*/ + return getNumColorChannels(colortype) * bitdepth; +} + +/* ////////////////////////////////////////////////////////////////////////// */ + +void lodepng_color_mode_init(LodePNGColorMode* info) +{ + info->key_defined = 0; + info->key_r = info->key_g = info->key_b = 0; + info->colortype = LCT_RGBA; + info->bitdepth = 8; + info->palette = 0; + info->palettesize = 0; +} + +void lodepng_color_mode_cleanup(LodePNGColorMode* info) +{ + lodepng_palette_clear(info); +} + +unsigned lodepng_color_mode_copy(LodePNGColorMode* dest, const LodePNGColorMode* source) +{ + size_t i; + lodepng_color_mode_cleanup(dest); + *dest = *source; + if(source->palette) + { + dest->palette = (unsigned char*)lodepng_malloc(1024); + if(!dest->palette && source->palettesize) return 83; /*alloc fail*/ + for(i = 0; i < source->palettesize * 4; i++) dest->palette[i] = source->palette[i]; + } + return 0; +} + +static int lodepng_color_mode_equal(const LodePNGColorMode* a, const LodePNGColorMode* b) +{ + size_t i; + if(a->colortype != b->colortype) return 0; + if(a->bitdepth != b->bitdepth) return 0; + if(a->key_defined != b->key_defined) return 0; + if(a->key_defined) + { + if(a->key_r != b->key_r) return 0; + if(a->key_g != b->key_g) return 0; + if(a->key_b != b->key_b) return 0; + } + if(a->palettesize != b->palettesize) return 0; + for(i = 0; i < a->palettesize * 4; i++) + { + if(a->palette[i] != b->palette[i]) return 0; + } + return 1; +} + +void lodepng_palette_clear(LodePNGColorMode* info) +{ + if(info->palette) lodepng_free(info->palette); + info->palette = 0; + info->palettesize = 0; +} + +unsigned lodepng_palette_add(LodePNGColorMode* info, + unsigned char r, unsigned char g, unsigned char b, unsigned char a) +{ + unsigned char* data; + /*the same resize technique as C++ std::vectors is used, and here it's made so that for a palette with + the max of 256 colors, it'll have the exact alloc size*/ + if(!info->palette) /*allocate palette if empty*/ + { + /*room for 256 colors with 4 bytes each*/ + data = (unsigned char*)lodepng_realloc(info->palette, 1024); + if(!data) return 83; /*alloc fail*/ + else info->palette = data; + } + info->palette[4 * info->palettesize + 0] = r; + info->palette[4 * info->palettesize + 1] = g; + info->palette[4 * info->palettesize + 2] = b; + info->palette[4 * info->palettesize + 3] = a; + info->palettesize++; + return 0; +} + +unsigned lodepng_get_bpp(const LodePNGColorMode* info) +{ + /*calculate bits per pixel out of colortype and bitdepth*/ + return lodepng_get_bpp_lct(info->colortype, info->bitdepth); +} + +unsigned lodepng_get_channels(const LodePNGColorMode* info) +{ + return getNumColorChannels(info->colortype); +} + +unsigned lodepng_is_greyscale_type(const LodePNGColorMode* info) +{ + return info->colortype == LCT_GREY || info->colortype == LCT_GREY_ALPHA; +} + +unsigned lodepng_is_alpha_type(const LodePNGColorMode* info) +{ + return (info->colortype & 4) != 0; /*4 or 6*/ +} + +unsigned lodepng_is_palette_type(const LodePNGColorMode* info) +{ + return info->colortype == LCT_PALETTE; +} + +unsigned lodepng_has_palette_alpha(const LodePNGColorMode* info) +{ + size_t i; + for(i = 0; i < info->palettesize; i++) + { + if(info->palette[i * 4 + 3] < 255) return 1; + } + return 0; +} + +unsigned lodepng_can_have_alpha(const LodePNGColorMode* info) +{ + return info->key_defined + || lodepng_is_alpha_type(info) + || lodepng_has_palette_alpha(info); +} + +size_t lodepng_get_raw_size(unsigned w, unsigned h, const LodePNGColorMode* color) +{ + return (w * h * lodepng_get_bpp(color) + 7) / 8; +} + +size_t lodepng_get_raw_size_lct(unsigned w, unsigned h, LodePNGColorType colortype, unsigned bitdepth) +{ + return (w * h * lodepng_get_bpp_lct(colortype, bitdepth) + 7) / 8; +} + +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + +static void LodePNGUnknownChunks_init(LodePNGInfo* info) +{ + unsigned i; + for(i = 0; i < 3; i++) info->unknown_chunks_data[i] = 0; + for(i = 0; i < 3; i++) info->unknown_chunks_size[i] = 0; +} + +static void LodePNGUnknownChunks_cleanup(LodePNGInfo* info) +{ + unsigned i; + for(i = 0; i < 3; i++) lodepng_free(info->unknown_chunks_data[i]); +} + +static unsigned LodePNGUnknownChunks_copy(LodePNGInfo* dest, const LodePNGInfo* src) +{ + unsigned i; + + LodePNGUnknownChunks_cleanup(dest); + + for(i = 0; i < 3; i++) + { + size_t j; + dest->unknown_chunks_size[i] = src->unknown_chunks_size[i]; + dest->unknown_chunks_data[i] = (unsigned char*)lodepng_malloc(src->unknown_chunks_size[i]); + if(!dest->unknown_chunks_data[i] && dest->unknown_chunks_size[i]) return 83; /*alloc fail*/ + for(j = 0; j < src->unknown_chunks_size[i]; j++) + { + dest->unknown_chunks_data[i][j] = src->unknown_chunks_data[i][j]; + } + } + + return 0; +} + +/******************************************************************************/ + +static void LodePNGText_init(LodePNGInfo* info) +{ + info->text_num = 0; + info->text_keys = NULL; + info->text_strings = NULL; +} + +static void LodePNGText_cleanup(LodePNGInfo* info) +{ + size_t i; + for(i = 0; i < info->text_num; i++) + { + string_cleanup(&info->text_keys[i]); + string_cleanup(&info->text_strings[i]); + } + lodepng_free(info->text_keys); + lodepng_free(info->text_strings); +} + +static unsigned LodePNGText_copy(LodePNGInfo* dest, const LodePNGInfo* source) +{ + size_t i = 0; + dest->text_keys = 0; + dest->text_strings = 0; + dest->text_num = 0; + for(i = 0; i < source->text_num; i++) + { + CERROR_TRY_RETURN(lodepng_add_text(dest, source->text_keys[i], source->text_strings[i])); + } + return 0; +} + +void lodepng_clear_text(LodePNGInfo* info) +{ + LodePNGText_cleanup(info); +} + +unsigned lodepng_add_text(LodePNGInfo* info, const char* key, const char* str) +{ + char** new_keys = (char**)(lodepng_realloc(info->text_keys, sizeof(char*) * (info->text_num + 1))); + char** new_strings = (char**)(lodepng_realloc(info->text_strings, sizeof(char*) * (info->text_num + 1))); + if(!new_keys || !new_strings) + { + lodepng_free(new_keys); + lodepng_free(new_strings); + return 83; /*alloc fail*/ + } + + info->text_num++; + info->text_keys = new_keys; + info->text_strings = new_strings; + + string_init(&info->text_keys[info->text_num - 1]); + string_set(&info->text_keys[info->text_num - 1], key); + + string_init(&info->text_strings[info->text_num - 1]); + string_set(&info->text_strings[info->text_num - 1], str); + + return 0; +} + +/******************************************************************************/ + +static void LodePNGIText_init(LodePNGInfo* info) +{ + info->itext_num = 0; + info->itext_keys = NULL; + info->itext_langtags = NULL; + info->itext_transkeys = NULL; + info->itext_strings = NULL; +} + +static void LodePNGIText_cleanup(LodePNGInfo* info) +{ + size_t i; + for(i = 0; i < info->itext_num; i++) + { + string_cleanup(&info->itext_keys[i]); + string_cleanup(&info->itext_langtags[i]); + string_cleanup(&info->itext_transkeys[i]); + string_cleanup(&info->itext_strings[i]); + } + lodepng_free(info->itext_keys); + lodepng_free(info->itext_langtags); + lodepng_free(info->itext_transkeys); + lodepng_free(info->itext_strings); +} + +static unsigned LodePNGIText_copy(LodePNGInfo* dest, const LodePNGInfo* source) +{ + size_t i = 0; + dest->itext_keys = 0; + dest->itext_langtags = 0; + dest->itext_transkeys = 0; + dest->itext_strings = 0; + dest->itext_num = 0; + for(i = 0; i < source->itext_num; i++) + { + CERROR_TRY_RETURN(lodepng_add_itext(dest, source->itext_keys[i], source->itext_langtags[i], + source->itext_transkeys[i], source->itext_strings[i])); + } + return 0; +} + +void lodepng_clear_itext(LodePNGInfo* info) +{ + LodePNGIText_cleanup(info); +} + +unsigned lodepng_add_itext(LodePNGInfo* info, const char* key, const char* langtag, + const char* transkey, const char* str) +{ + char** new_keys = (char**)(lodepng_realloc(info->itext_keys, sizeof(char*) * (info->itext_num + 1))); + char** new_langtags = (char**)(lodepng_realloc(info->itext_langtags, sizeof(char*) * (info->itext_num + 1))); + char** new_transkeys = (char**)(lodepng_realloc(info->itext_transkeys, sizeof(char*) * (info->itext_num + 1))); + char** new_strings = (char**)(lodepng_realloc(info->itext_strings, sizeof(char*) * (info->itext_num + 1))); + if(!new_keys || !new_langtags || !new_transkeys || !new_strings) + { + lodepng_free(new_keys); + lodepng_free(new_langtags); + lodepng_free(new_transkeys); + lodepng_free(new_strings); + return 83; /*alloc fail*/ + } + + info->itext_num++; + info->itext_keys = new_keys; + info->itext_langtags = new_langtags; + info->itext_transkeys = new_transkeys; + info->itext_strings = new_strings; + + string_init(&info->itext_keys[info->itext_num - 1]); + string_set(&info->itext_keys[info->itext_num - 1], key); + + string_init(&info->itext_langtags[info->itext_num - 1]); + string_set(&info->itext_langtags[info->itext_num - 1], langtag); + + string_init(&info->itext_transkeys[info->itext_num - 1]); + string_set(&info->itext_transkeys[info->itext_num - 1], transkey); + + string_init(&info->itext_strings[info->itext_num - 1]); + string_set(&info->itext_strings[info->itext_num - 1], str); + + return 0; +} +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + +void lodepng_info_init(LodePNGInfo* info) +{ + lodepng_color_mode_init(&info->color); + info->interlace_method = 0; + info->compression_method = 0; + info->filter_method = 0; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + info->background_defined = 0; + info->background_r = info->background_g = info->background_b = 0; + + LodePNGText_init(info); + LodePNGIText_init(info); + + info->time_defined = 0; + info->phys_defined = 0; + + LodePNGUnknownChunks_init(info); +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ +} + +void lodepng_info_cleanup(LodePNGInfo* info) +{ + lodepng_color_mode_cleanup(&info->color); +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + LodePNGText_cleanup(info); + LodePNGIText_cleanup(info); + + LodePNGUnknownChunks_cleanup(info); +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ +} + +unsigned lodepng_info_copy(LodePNGInfo* dest, const LodePNGInfo* source) +{ + lodepng_info_cleanup(dest); + *dest = *source; + lodepng_color_mode_init(&dest->color); + CERROR_TRY_RETURN(lodepng_color_mode_copy(&dest->color, &source->color)); + +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + CERROR_TRY_RETURN(LodePNGText_copy(dest, source)); + CERROR_TRY_RETURN(LodePNGIText_copy(dest, source)); + + LodePNGUnknownChunks_init(dest); + CERROR_TRY_RETURN(LodePNGUnknownChunks_copy(dest, source)); +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + return 0; +} + +void lodepng_info_swap(LodePNGInfo* a, LodePNGInfo* b) +{ + LodePNGInfo temp = *a; + *a = *b; + *b = temp; +} + +/* ////////////////////////////////////////////////////////////////////////// */ + +/*index: bitgroup index, bits: bitgroup size(1, 2 or 4), in: bitgroup value, out: octet array to add bits to*/ +static void addColorBits(unsigned char* out, size_t index, unsigned bits, unsigned in) +{ + unsigned m = bits == 1 ? 7 : bits == 2 ? 3 : 1; /*8 / bits - 1*/ + /*p = the partial index in the byte, e.g. with 4 palettebits it is 0 for first half or 1 for second half*/ + unsigned p = index & m; + in &= (1u << bits) - 1u; /*filter out any other bits of the input value*/ + in = in << (bits * (m - p)); + if(p == 0) out[index * bits / 8] = in; + else out[index * bits / 8] |= in; +} + +typedef struct ColorTree ColorTree; + +/* +One node of a color tree +This is the data structure used to count the number of unique colors and to get a palette +index for a color. It's like an octree, but because the alpha channel is used too, each +node has 16 instead of 8 children. +*/ +struct ColorTree +{ + ColorTree* children[16]; /*up to 16 pointers to ColorTree of next level*/ + int index; /*the payload. Only has a meaningful value if this is in the last level*/ +}; + +static void color_tree_init(ColorTree* tree) +{ + int i; + for(i = 0; i < 16; i++) tree->children[i] = 0; + tree->index = -1; +} + +static void color_tree_cleanup(ColorTree* tree) +{ + int i; + for(i = 0; i < 16; i++) + { + if(tree->children[i]) + { + color_tree_cleanup(tree->children[i]); + lodepng_free(tree->children[i]); + } + } +} + +/*returns -1 if color not present, its index otherwise*/ +static int color_tree_get(ColorTree* tree, unsigned char r, unsigned char g, unsigned char b, unsigned char a) +{ + int bit = 0; + for(bit = 0; bit < 8; bit++) + { + int i = 8 * ((r >> bit) & 1) + 4 * ((g >> bit) & 1) + 2 * ((b >> bit) & 1) + 1 * ((a >> bit) & 1); + if(!tree->children[i]) return -1; + else tree = tree->children[i]; + } + return tree ? tree->index : -1; +} + +#ifdef LODEPNG_COMPILE_ENCODER +static int color_tree_has(ColorTree* tree, unsigned char r, unsigned char g, unsigned char b, unsigned char a) +{ + return color_tree_get(tree, r, g, b, a) >= 0; +} +#endif /*LODEPNG_COMPILE_ENCODER*/ + +/*color is not allowed to already exist. +Index should be >= 0 (it's signed to be compatible with using -1 for "doesn't exist")*/ +static void color_tree_add(ColorTree* tree, + unsigned char r, unsigned char g, unsigned char b, unsigned char a, unsigned index) +{ + int bit; + for(bit = 0; bit < 8; bit++) + { + int i = 8 * ((r >> bit) & 1) + 4 * ((g >> bit) & 1) + 2 * ((b >> bit) & 1) + 1 * ((a >> bit) & 1); + if(!tree->children[i]) + { + tree->children[i] = (ColorTree*)lodepng_malloc(sizeof(ColorTree)); + color_tree_init(tree->children[i]); + } + tree = tree->children[i]; + } + tree->index = (int)index; +} + +/*put a pixel, given its RGBA color, into image of any color type*/ +static unsigned rgba8ToPixel(unsigned char* out, size_t i, + const LodePNGColorMode* mode, ColorTree* tree /*for palette*/, + unsigned char r, unsigned char g, unsigned char b, unsigned char a) +{ + if(mode->colortype == LCT_GREY) + { + unsigned char grey = r; /*((unsigned short)r + g + b) / 3*/; + if(mode->bitdepth == 8) out[i] = grey; + else if(mode->bitdepth == 16) out[i * 2 + 0] = out[i * 2 + 1] = grey; + else + { + /*take the most significant bits of grey*/ + grey = (grey >> (8 - mode->bitdepth)) & ((1 << mode->bitdepth) - 1); + addColorBits(out, i, mode->bitdepth, grey); + } + } + else if(mode->colortype == LCT_RGB) + { + if(mode->bitdepth == 8) + { + out[i * 3 + 0] = r; + out[i * 3 + 1] = g; + out[i * 3 + 2] = b; + } + else + { + out[i * 6 + 0] = out[i * 6 + 1] = r; + out[i * 6 + 2] = out[i * 6 + 3] = g; + out[i * 6 + 4] = out[i * 6 + 5] = b; + } + } + else if(mode->colortype == LCT_PALETTE) + { + int index = color_tree_get(tree, r, g, b, a); + if(index < 0) return 82; /*color not in palette*/ + if(mode->bitdepth == 8) out[i] = index; + else addColorBits(out, i, mode->bitdepth, (unsigned)index); + } + else if(mode->colortype == LCT_GREY_ALPHA) + { + unsigned char grey = r; /*((unsigned short)r + g + b) / 3*/; + if(mode->bitdepth == 8) + { + out[i * 2 + 0] = grey; + out[i * 2 + 1] = a; + } + else if(mode->bitdepth == 16) + { + out[i * 4 + 0] = out[i * 4 + 1] = grey; + out[i * 4 + 2] = out[i * 4 + 3] = a; + } + } + else if(mode->colortype == LCT_RGBA) + { + if(mode->bitdepth == 8) + { + out[i * 4 + 0] = r; + out[i * 4 + 1] = g; + out[i * 4 + 2] = b; + out[i * 4 + 3] = a; + } + else + { + out[i * 8 + 0] = out[i * 8 + 1] = r; + out[i * 8 + 2] = out[i * 8 + 3] = g; + out[i * 8 + 4] = out[i * 8 + 5] = b; + out[i * 8 + 6] = out[i * 8 + 7] = a; + } + } + + return 0; /*no error*/ +} + +/*put a pixel, given its RGBA16 color, into image of any color 16-bitdepth type*/ +static unsigned rgba16ToPixel(unsigned char* out, size_t i, + const LodePNGColorMode* mode, + unsigned short r, unsigned short g, unsigned short b, unsigned short a) +{ + if(mode->bitdepth != 16) return 85; /*must be 16 for this function*/ + if(mode->colortype == LCT_GREY) + { + unsigned short grey = r; /*((unsigned)r + g + b) / 3*/; + out[i * 2 + 0] = (grey >> 8) & 255; + out[i * 2 + 1] = grey & 255; + } + else if(mode->colortype == LCT_RGB) + { + out[i * 6 + 0] = (r >> 8) & 255; + out[i * 6 + 1] = r & 255; + out[i * 6 + 2] = (g >> 8) & 255; + out[i * 6 + 3] = g & 255; + out[i * 6 + 4] = (b >> 8) & 255; + out[i * 6 + 5] = b & 255; + } + else if(mode->colortype == LCT_GREY_ALPHA) + { + unsigned short grey = r; /*((unsigned)r + g + b) / 3*/; + out[i * 4 + 0] = (grey >> 8) & 255; + out[i * 4 + 1] = grey & 255; + out[i * 4 + 2] = (a >> 8) & 255; + out[i * 4 + 3] = a & 255; + } + else if(mode->colortype == LCT_RGBA) + { + out[i * 8 + 0] = (r >> 8) & 255; + out[i * 8 + 1] = r & 255; + out[i * 8 + 2] = (g >> 8) & 255; + out[i * 8 + 3] = g & 255; + out[i * 8 + 4] = (b >> 8) & 255; + out[i * 8 + 5] = b & 255; + out[i * 8 + 6] = (a >> 8) & 255; + out[i * 8 + 7] = a & 255; + } + + return 0; /*no error*/ +} + +/*Get RGBA8 color of pixel with index i (y * width + x) from the raw image with given color type.*/ +static unsigned getPixelColorRGBA8(unsigned char* r, unsigned char* g, + unsigned char* b, unsigned char* a, + const unsigned char* in, size_t i, + const LodePNGColorMode* mode, + unsigned fix_png) +{ + if(mode->colortype == LCT_GREY) + { + if(mode->bitdepth == 8) + { + *r = *g = *b = in[i]; + if(mode->key_defined && *r == mode->key_r) *a = 0; + else *a = 255; + } + else if(mode->bitdepth == 16) + { + *r = *g = *b = in[i * 2 + 0]; + if(mode->key_defined && 256U * in[i * 2 + 0] + in[i * 2 + 1] == mode->key_r) *a = 0; + else *a = 255; + } + else + { + unsigned highest = ((1U << mode->bitdepth) - 1U); /*highest possible value for this bit depth*/ + size_t j = i * mode->bitdepth; + unsigned value = readBitsFromReversedStream(&j, in, mode->bitdepth); + *r = *g = *b = (value * 255) / highest; + if(mode->key_defined && value == mode->key_r) *a = 0; + else *a = 255; + } + } + else if(mode->colortype == LCT_RGB) + { + if(mode->bitdepth == 8) + { + *r = in[i * 3 + 0]; *g = in[i * 3 + 1]; *b = in[i * 3 + 2]; + if(mode->key_defined && *r == mode->key_r && *g == mode->key_g && *b == mode->key_b) *a = 0; + else *a = 255; + } + else + { + *r = in[i * 6 + 0]; + *g = in[i * 6 + 2]; + *b = in[i * 6 + 4]; + if(mode->key_defined && 256U * in[i * 6 + 0] + in[i * 6 + 1] == mode->key_r + && 256U * in[i * 6 + 2] + in[i * 6 + 3] == mode->key_g + && 256U * in[i * 6 + 4] + in[i * 6 + 5] == mode->key_b) *a = 0; + else *a = 255; + } + } + else if(mode->colortype == LCT_PALETTE) + { + unsigned index; + if(mode->bitdepth == 8) index = in[i]; + else + { + size_t j = i * mode->bitdepth; + index = readBitsFromReversedStream(&j, in, mode->bitdepth); + } + + if(index >= mode->palettesize) + { + /*This is an error according to the PNG spec, but fix_png can ignore it*/ + if(!fix_png) return (mode->bitdepth == 8 ? 46 : 47); /*index out of palette*/ + *r = *g = *b = 0; + *a = 255; + } + else + { + *r = mode->palette[index * 4 + 0]; + *g = mode->palette[index * 4 + 1]; + *b = mode->palette[index * 4 + 2]; + *a = mode->palette[index * 4 + 3]; + } + } + else if(mode->colortype == LCT_GREY_ALPHA) + { + if(mode->bitdepth == 8) + { + *r = *g = *b = in[i * 2 + 0]; + *a = in[i * 2 + 1]; + } + else + { + *r = *g = *b = in[i * 4 + 0]; + *a = in[i * 4 + 2]; + } + } + else if(mode->colortype == LCT_RGBA) + { + if(mode->bitdepth == 8) + { + *r = in[i * 4 + 0]; + *g = in[i * 4 + 1]; + *b = in[i * 4 + 2]; + *a = in[i * 4 + 3]; + } + else + { + *r = in[i * 8 + 0]; + *g = in[i * 8 + 2]; + *b = in[i * 8 + 4]; + *a = in[i * 8 + 6]; + } + } + + return 0; /*no error*/ +} + +/*Similar to getPixelColorRGBA8, but with all the for loops inside of the color +mode test cases, optimized to convert the colors much faster, when converting +to RGBA or RGB with 8 bit per cannel. buffer must be RGBA or RGB output with +enough memory, if has_alpha is true the output is RGBA. mode has the color mode +of the input buffer.*/ +static unsigned getPixelColorsRGBA8(unsigned char* buffer, size_t numpixels, + unsigned has_alpha, const unsigned char* in, + const LodePNGColorMode* mode, + unsigned fix_png) +{ + unsigned num_channels = has_alpha ? 4 : 3; + size_t i; + if(mode->colortype == LCT_GREY) + { + if(mode->bitdepth == 8) + { + for(i = 0; i < numpixels; i++, buffer += num_channels) + { + buffer[0] = buffer[1] = buffer[2] = in[i]; + if(has_alpha) buffer[3] = mode->key_defined && in[i] == mode->key_r ? 0 : 255; + } + } + else if(mode->bitdepth == 16) + { + for(i = 0; i < numpixels; i++, buffer += num_channels) + { + buffer[0] = buffer[1] = buffer[2] = in[i * 2]; + if(has_alpha) buffer[3] = mode->key_defined && 256U * in[i * 2 + 0] + in[i * 2 + 1] == mode->key_r ? 0 : 255; + } + } + else + { + unsigned highest = ((1U << mode->bitdepth) - 1U); /*highest possible value for this bit depth*/ + size_t j = 0; + for(i = 0; i < numpixels; i++, buffer += num_channels) + { + unsigned value = readBitsFromReversedStream(&j, in, mode->bitdepth); + buffer[0] = buffer[1] = buffer[2] = (value * 255) / highest; + if(has_alpha) buffer[3] = mode->key_defined && value == mode->key_r ? 0 : 255; + } + } + } + else if(mode->colortype == LCT_RGB) + { + if(mode->bitdepth == 8) + { + for(i = 0; i < numpixels; i++, buffer += num_channels) + { + buffer[0] = in[i * 3 + 0]; + buffer[1] = in[i * 3 + 1]; + buffer[2] = in[i * 3 + 2]; + if(has_alpha) buffer[3] = mode->key_defined && buffer[0] == mode->key_r + && buffer[1]== mode->key_g && buffer[2] == mode->key_b ? 0 : 255; + } + } + else + { + for(i = 0; i < numpixels; i++, buffer += num_channels) + { + buffer[0] = in[i * 6 + 0]; + buffer[1] = in[i * 6 + 2]; + buffer[2] = in[i * 6 + 4]; + if(has_alpha) buffer[3] = mode->key_defined + && 256U * in[i * 6 + 0] + in[i * 6 + 1] == mode->key_r + && 256U * in[i * 6 + 2] + in[i * 6 + 3] == mode->key_g + && 256U * in[i * 6 + 4] + in[i * 6 + 5] == mode->key_b ? 0 : 255; + } + } + } + else if(mode->colortype == LCT_PALETTE) + { + unsigned index; + size_t j = 0; + for(i = 0; i < numpixels; i++, buffer += num_channels) + { + if(mode->bitdepth == 8) index = in[i]; + else index = readBitsFromReversedStream(&j, in, mode->bitdepth); + + if(index >= mode->palettesize) + { + /*This is an error according to the PNG spec, but fix_png can ignore it*/ + if(!fix_png) return (mode->bitdepth == 8 ? 46 : 47); /*index out of palette*/ + buffer[0] = buffer[1] = buffer[2] = 0; + if(has_alpha) buffer[3] = 255; + } + else + { + buffer[0] = mode->palette[index * 4 + 0]; + buffer[1] = mode->palette[index * 4 + 1]; + buffer[2] = mode->palette[index * 4 + 2]; + if(has_alpha) buffer[3] = mode->palette[index * 4 + 3]; + } + } + } + else if(mode->colortype == LCT_GREY_ALPHA) + { + if(mode->bitdepth == 8) + { + for(i = 0; i < numpixels; i++, buffer += num_channels) + { + buffer[0] = buffer[1] = buffer[2] = in[i * 2 + 0]; + if(has_alpha) buffer[3] = in[i * 2 + 1]; + } + } + else + { + for(i = 0; i < numpixels; i++, buffer += num_channels) + { + buffer[0] = buffer[1] = buffer[2] = in[i * 4 + 0]; + if(has_alpha) buffer[3] = in[i * 4 + 2]; + } + } + } + else if(mode->colortype == LCT_RGBA) + { + if(mode->bitdepth == 8) + { + for(i = 0; i < numpixels; i++, buffer += num_channels) + { + buffer[0] = in[i * 4 + 0]; + buffer[1] = in[i * 4 + 1]; + buffer[2] = in[i * 4 + 2]; + if(has_alpha) buffer[3] = in[i * 4 + 3]; + } + } + else + { + for(i = 0; i < numpixels; i++, buffer += num_channels) + { + buffer[0] = in[i * 8 + 0]; + buffer[1] = in[i * 8 + 2]; + buffer[2] = in[i * 8 + 4]; + if(has_alpha) buffer[3] = in[i * 8 + 6]; + } + } + } + + return 0; /*no error*/ +} + +/*Get RGBA16 color of pixel with index i (y * width + x) from the raw image with +given color type, but the given color type must be 16-bit itself.*/ +static unsigned getPixelColorRGBA16(unsigned short* r, unsigned short* g, unsigned short* b, unsigned short* a, + const unsigned char* in, size_t i, const LodePNGColorMode* mode) +{ + if(mode->bitdepth != 16) return 85; /*error: this function only supports 16-bit input*/ + + if(mode->colortype == LCT_GREY) + { + *r = *g = *b = 256 * in[i * 2 + 0] + in[i * 2 + 1]; + if(mode->key_defined && 256U * in[i * 2 + 0] + in[i * 2 + 1] == mode->key_r) *a = 0; + else *a = 65535; + } + else if(mode->colortype == LCT_RGB) + { + *r = 256 * in[i * 6 + 0] + in[i * 6 + 1]; + *g = 256 * in[i * 6 + 2] + in[i * 6 + 3]; + *b = 256 * in[i * 6 + 4] + in[i * 6 + 5]; + if(mode->key_defined && 256U * in[i * 6 + 0] + in[i * 6 + 1] == mode->key_r + && 256U * in[i * 6 + 2] + in[i * 6 + 3] == mode->key_g + && 256U * in[i * 6 + 4] + in[i * 6 + 5] == mode->key_b) *a = 0; + else *a = 65535; + } + else if(mode->colortype == LCT_GREY_ALPHA) + { + *r = *g = *b = 256 * in[i * 4 + 0] + in[i * 4 + 1]; + *a = 256 * in[i * 4 + 2] + in[i * 4 + 3]; + } + else if(mode->colortype == LCT_RGBA) + { + *r = 256 * in[i * 8 + 0] + in[i * 8 + 1]; + *g = 256 * in[i * 8 + 2] + in[i * 8 + 3]; + *b = 256 * in[i * 8 + 4] + in[i * 8 + 5]; + *a = 256 * in[i * 8 + 6] + in[i * 8 + 7]; + } + else return 85; /*error: this function only supports 16-bit input, not palettes*/ + + return 0; /*no error*/ +} + +/* +converts from any color type to 24-bit or 32-bit (later maybe more supported). return value = LodePNG error code +the out buffer must have (w * h * bpp + 7) / 8 bytes, where bpp is the bits per pixel of the output color type +(lodepng_get_bpp) for < 8 bpp images, there may _not_ be padding bits at the end of scanlines. +*/ +unsigned lodepng_convert(unsigned char* out, const unsigned char* in, + LodePNGColorMode* mode_out, const LodePNGColorMode* mode_in, + unsigned w, unsigned h, unsigned fix_png) +{ + unsigned error = 0; + size_t i; + ColorTree tree; + size_t numpixels = w * h; + + if(lodepng_color_mode_equal(mode_out, mode_in)) + { + size_t numbytes = lodepng_get_raw_size(w, h, mode_in); + for(i = 0; i < numbytes; i++) out[i] = in[i]; + return error; + } + + if(mode_out->colortype == LCT_PALETTE) + { + size_t palsize = 1u << mode_out->bitdepth; + if(mode_out->palettesize < palsize) palsize = mode_out->palettesize; + color_tree_init(&tree); + for(i = 0; i < palsize; i++) + { + unsigned char* p = &mode_out->palette[i * 4]; + color_tree_add(&tree, p[0], p[1], p[2], p[3], i); + } + } + + if(mode_in->bitdepth == 16 && mode_out->bitdepth == 16) + { + for(i = 0; i < numpixels; i++) + { + unsigned short r = 0, g = 0, b = 0, a = 0; + error = getPixelColorRGBA16(&r, &g, &b, &a, in, i, mode_in); + if(error) break; + error = rgba16ToPixel(out, i, mode_out, r, g, b, a); + if(error) break; + } + } + else if(mode_out->bitdepth == 8 && mode_out->colortype == LCT_RGBA) + { + error = getPixelColorsRGBA8(out, numpixels, 1, in, mode_in, fix_png); + } + else if(mode_out->bitdepth == 8 && mode_out->colortype == LCT_RGB) + { + error = getPixelColorsRGBA8(out, numpixels, 0, in, mode_in, fix_png); + } + else + { + unsigned char r = 0, g = 0, b = 0, a = 0; + for(i = 0; i < numpixels; i++) + { + error = getPixelColorRGBA8(&r, &g, &b, &a, in, i, mode_in, fix_png); + if(error) break; + error = rgba8ToPixel(out, i, mode_out, &tree, r, g, b, a); + if(error) break; + } + } + + if(mode_out->colortype == LCT_PALETTE) + { + color_tree_cleanup(&tree); + } + + return error; +} + +#ifdef LODEPNG_COMPILE_ENCODER + +typedef struct ColorProfile +{ + unsigned char sixteenbit; /*needs more than 8 bits per channel*/ + unsigned char sixteenbit_done; + + + unsigned char colored; /*not greyscale*/ + unsigned char colored_done; + + unsigned char key; /*a color key is required, or more*/ + unsigned short key_r; /*these values are always in 16-bit bitdepth in the profile*/ + unsigned short key_g; + unsigned short key_b; + unsigned char alpha; /*alpha channel, or alpha palette, required*/ + unsigned char alpha_done; + + unsigned numcolors; + ColorTree tree; /*for listing the counted colors, up to 256*/ + unsigned char* palette; /*size 1024. Remember up to the first 256 RGBA colors*/ + unsigned maxnumcolors; /*if more than that amount counted*/ + unsigned char numcolors_done; + + unsigned greybits; /*amount of bits required for greyscale (1, 2, 4, 8). Does not take 16 bit into account.*/ + unsigned char greybits_done; + +} ColorProfile; + +static void color_profile_init(ColorProfile* profile, const LodePNGColorMode* mode) +{ + profile->sixteenbit = 0; + profile->sixteenbit_done = mode->bitdepth == 16 ? 0 : 1; + + profile->colored = 0; + profile->colored_done = lodepng_is_greyscale_type(mode) ? 1 : 0; + + profile->key = 0; + profile->alpha = 0; + profile->alpha_done = lodepng_can_have_alpha(mode) ? 0 : 1; + + profile->numcolors = 0; + color_tree_init(&profile->tree); + profile->palette = (unsigned char*)lodepng_malloc(1024); + profile->maxnumcolors = 257; + if(lodepng_get_bpp(mode) <= 8) + { + unsigned bpp = lodepng_get_bpp(mode); + profile->maxnumcolors = bpp == 1 ? 2 : (bpp == 2 ? 4 : (bpp == 4 ? 16 : 256)); + } + profile->numcolors_done = 0; + + profile->greybits = 1; + profile->greybits_done = lodepng_get_bpp(mode) == 1 ? 1 : 0; +} + +static void color_profile_cleanup(ColorProfile* profile) +{ + color_tree_cleanup(&profile->tree); + lodepng_free(profile->palette); +} + +/*function used for debug purposes with C++*/ +/*void printColorProfile(ColorProfile* p) +{ + std::cout << "sixteenbit: " << (int)p->sixteenbit << std::endl; + std::cout << "sixteenbit_done: " << (int)p->sixteenbit_done << std::endl; + std::cout << "colored: " << (int)p->colored << std::endl; + std::cout << "colored_done: " << (int)p->colored_done << std::endl; + std::cout << "key: " << (int)p->key << std::endl; + std::cout << "key_r: " << (int)p->key_r << std::endl; + std::cout << "key_g: " << (int)p->key_g << std::endl; + std::cout << "key_b: " << (int)p->key_b << std::endl; + std::cout << "alpha: " << (int)p->alpha << std::endl; + std::cout << "alpha_done: " << (int)p->alpha_done << std::endl; + std::cout << "numcolors: " << (int)p->numcolors << std::endl; + std::cout << "maxnumcolors: " << (int)p->maxnumcolors << std::endl; + std::cout << "numcolors_done: " << (int)p->numcolors_done << std::endl; + std::cout << "greybits: " << (int)p->greybits << std::endl; + std::cout << "greybits_done: " << (int)p->greybits_done << std::endl; +}*/ + +/*Returns how many bits needed to represent given value (max 8 bit)*/ +unsigned getValueRequiredBits(unsigned short value) +{ + if(value == 0 || value == 255) return 1; + /*The scaling of 2-bit and 4-bit values uses multiples of 85 and 17*/ + if(value % 17 == 0) return value % 85 == 0 ? 2 : 4; + return 8; +} + +/*profile must already have been inited with mode. +It's ok to set some parameters of profile to done already.*/ +static unsigned get_color_profile(ColorProfile* profile, + const unsigned char* in, + size_t numpixels /*must be full image size, for certain filesize based choices*/, + const LodePNGColorMode* mode, + unsigned fix_png) +{ + unsigned error = 0; + size_t i; + + if(mode->bitdepth == 16) + { + for(i = 0; i < numpixels; i++) + { + unsigned short r, g, b, a; + error = getPixelColorRGBA16(&r, &g, &b, &a, in, i, mode); + if(error) break; + + /*a color is considered good for 8-bit if the first byte and the second byte are equal, + (so if it's divisible through 257), NOT necessarily if the second byte is 0*/ + if(!profile->sixteenbit_done + && (((r & 255) != ((r >> 8) & 255)) + || ((g & 255) != ((g >> 8) & 255)) + || ((b & 255) != ((b >> 8) & 255)))) + { + profile->sixteenbit = 1; + profile->sixteenbit_done = 1; + profile->greybits_done = 1; /*greybits is not applicable anymore at 16-bit*/ + profile->numcolors_done = 1; /*counting colors no longer useful, palette doesn't support 16-bit*/ + } + + if(!profile->colored_done && (r != g || r != b)) + { + profile->colored = 1; + profile->colored_done = 1; + profile->greybits_done = 1; /*greybits is not applicable anymore*/ + } + + if(!profile->alpha_done && a != 65535) + { + /*only use color key if numpixels large enough to justify tRNS chunk size*/ + if(a == 0 && numpixels > 16 && !(profile->key && (r != profile->key_r || g != profile->key_g || b != profile->key_b))) + { + if(!profile->alpha && !profile->key) + { + profile->key = 1; + profile->key_r = r; + profile->key_g = g; + profile->key_b = b; + } + } + else + { + profile->alpha = 1; + profile->alpha_done = 1; + profile->greybits_done = 1; /*greybits is not applicable anymore*/ + } + } + + /* Color key cannot be used if an opaque pixel also has that RGB color. */ + if(!profile->alpha_done && a == 65535 && profile->key + && r == profile->key_r && g == profile->key_g && b == profile->key_b) + { + profile->alpha = 1; + profile->alpha_done = 1; + profile->greybits_done = 1; /*greybits is not applicable anymore*/ + } + + if(!profile->greybits_done) + { + /*assuming 8-bit r, this test does not care about 16-bit*/ + unsigned bits = getValueRequiredBits(r); + if(bits > profile->greybits) profile->greybits = bits; + if(profile->greybits >= 8) profile->greybits_done = 1; + } + + if(!profile->numcolors_done) + { + /*assuming 8-bit rgba, this test does not care about 16-bit*/ + if(!color_tree_has(&profile->tree, (unsigned char)r, (unsigned char)g, (unsigned char)b, (unsigned char)a)) + { + color_tree_add(&profile->tree, (unsigned char)r, (unsigned char)g, (unsigned char)b, (unsigned char)a, + profile->numcolors); + if(profile->numcolors < 256) + { + unsigned char* p = profile->palette; + unsigned i = profile->numcolors; + p[i * 4 + 0] = (unsigned char)r; + p[i * 4 + 1] = (unsigned char)g; + p[i * 4 + 2] = (unsigned char)b; + p[i * 4 + 3] = (unsigned char)a; + } + profile->numcolors++; + if(profile->numcolors >= profile->maxnumcolors) profile->numcolors_done = 1; + } + } + + if(profile->alpha_done && profile->numcolors_done + && profile->colored_done && profile->sixteenbit_done && profile->greybits_done) + { + break; + } + }; + } + else /* < 16-bit */ + { + for(i = 0; i < numpixels; i++) + { + unsigned char r = 0, g = 0, b = 0, a = 0; + error = getPixelColorRGBA8(&r, &g, &b, &a, in, i, mode, fix_png); + if(error) break; + + if(!profile->colored_done && (r != g || r != b)) + { + profile->colored = 1; + profile->colored_done = 1; + profile->greybits_done = 1; /*greybits is not applicable anymore*/ + } + + if(!profile->alpha_done && a != 255) + { + if(a == 0 && !(profile->key && (r != profile->key_r || g != profile->key_g || b != profile->key_b))) + { + if(!profile->key) + { + profile->key = 1; + profile->key_r = r; + profile->key_g = g; + profile->key_b = b; + } + } + else + { + profile->alpha = 1; + profile->alpha_done = 1; + profile->greybits_done = 1; /*greybits is not applicable anymore*/ + } + } + + /* Color key cannot be used if an opaque pixel also has that RGB color. */ + if(!profile->alpha_done && a == 255 && profile->key + && r == profile->key_r && g == profile->key_g && b == profile->key_b) + { + profile->alpha = 1; + profile->alpha_done = 1; + profile->greybits_done = 1; /*greybits is not applicable anymore*/ + } + + if(!profile->greybits_done) + { + unsigned bits = getValueRequiredBits(r); + if(bits > profile->greybits) profile->greybits = bits; + if(profile->greybits >= 8) profile->greybits_done = 1; + } + + if(!profile->numcolors_done) + { + if(!color_tree_has(&profile->tree, r, g, b, a)) + { + color_tree_add(&profile->tree, r, g, b, a, profile->numcolors); + if(profile->numcolors < 256) + { + unsigned char* p = profile->palette; + unsigned i = profile->numcolors; + p[i * 4 + 0] = r; + p[i * 4 + 1] = g; + p[i * 4 + 2] = b; + p[i * 4 + 3] = a; + } + profile->numcolors++; + if(profile->numcolors >= profile->maxnumcolors) profile->numcolors_done = 1; + } + } + + if(profile->alpha_done && profile->numcolors_done && profile->colored_done && profile->greybits_done) + { + break; + } + }; + } + + /*make the profile's key always 16-bit for consistency*/ + if(mode->bitdepth < 16) + { + /*repeat each byte twice*/ + profile->key_r *= 257; + profile->key_g *= 257; + profile->key_b *= 257; + } + + return error; +} + +static void setColorKeyFrom16bit(LodePNGColorMode* mode_out, unsigned r, unsigned g, unsigned b, unsigned bitdepth) +{ + unsigned mask = (1u << bitdepth) - 1u; + mode_out->key_defined = 1; + mode_out->key_r = r & mask; + mode_out->key_g = g & mask; + mode_out->key_b = b & mask; +} + +/*updates values of mode with a potentially smaller color model. mode_out should +contain the user chosen color model, but will be overwritten with the new chosen one.*/ +unsigned lodepng_auto_choose_color(LodePNGColorMode* mode_out, + const unsigned char* image, unsigned w, unsigned h, + const LodePNGColorMode* mode_in, + LodePNGAutoConvert auto_convert) +{ + ColorProfile profile; + unsigned error = 0; + int no_nibbles = auto_convert == LAC_AUTO_NO_NIBBLES || auto_convert == LAC_AUTO_NO_NIBBLES_NO_PALETTE; + int no_palette = auto_convert == LAC_AUTO_NO_PALETTE || auto_convert == LAC_AUTO_NO_NIBBLES_NO_PALETTE; + + if(auto_convert == LAC_ALPHA) + { + if(mode_out->colortype != LCT_RGBA && mode_out->colortype != LCT_GREY_ALPHA) return 0; + } + + color_profile_init(&profile, mode_in); + if(auto_convert == LAC_ALPHA) + { + profile.colored_done = 1; + profile.greybits_done = 1; + profile.numcolors_done = 1; + profile.sixteenbit_done = 1; + } + error = get_color_profile(&profile, image, w * h, mode_in, 0 /*fix_png*/); + if(!error && auto_convert == LAC_ALPHA) + { + if(!profile.alpha) + { + mode_out->colortype = (mode_out->colortype == LCT_RGBA ? LCT_RGB : LCT_GREY); + if(profile.key) setColorKeyFrom16bit(mode_out, profile.key_r, profile.key_g, profile.key_b, mode_out->bitdepth); + } + } + else if(!error && auto_convert != LAC_ALPHA) + { + mode_out->key_defined = 0; + + if(profile.sixteenbit) + { + mode_out->bitdepth = 16; + if(profile.alpha) + { + mode_out->colortype = profile.colored ? LCT_RGBA : LCT_GREY_ALPHA; + } + else + { + mode_out->colortype = profile.colored ? LCT_RGB : LCT_GREY; + if(profile.key) setColorKeyFrom16bit(mode_out, profile.key_r, profile.key_g, profile.key_b, mode_out->bitdepth); + } + } + else /*less than 16 bits per channel*/ + { + /*don't add palette overhead if image hasn't got a lot of pixels*/ + unsigned n = profile.numcolors; + int palette_ok = !no_palette && n <= 256 && (n * 2 < w * h); + unsigned palettebits = n <= 2 ? 1 : (n <= 4 ? 2 : (n <= 16 ? 4 : 8)); + int grey_ok = !profile.colored && !profile.alpha; /*grey without alpha, with potentially low bits*/ + if(palette_ok || grey_ok) + { + if(!palette_ok || (grey_ok && profile.greybits <= palettebits)) + { + unsigned grey = profile.key_r; + mode_out->colortype = LCT_GREY; + mode_out->bitdepth = profile.greybits; + if(profile.key) setColorKeyFrom16bit(mode_out, grey, grey, grey, mode_out->bitdepth); + } + else + { + /*fill in the palette*/ + unsigned i; + unsigned char* p = profile.palette; + /*remove potential earlier palette*/ + lodepng_palette_clear(mode_out); + for(i = 0; i < profile.numcolors; i++) + { + error = lodepng_palette_add(mode_out, p[i * 4 + 0], p[i * 4 + 1], p[i * 4 + 2], p[i * 4 + 3]); + if(error) break; + } + + mode_out->colortype = LCT_PALETTE; + mode_out->bitdepth = palettebits; + } + } + else /*8-bit per channel*/ + { + mode_out->bitdepth = 8; + if(profile.alpha) + { + mode_out->colortype = profile.colored ? LCT_RGBA : LCT_GREY_ALPHA; + } + else + { + mode_out->colortype = profile.colored ? LCT_RGB : LCT_GREY /*LCT_GREY normally won't occur, already done earlier*/; + if(profile.key) setColorKeyFrom16bit(mode_out, profile.key_r, profile.key_g, profile.key_b, mode_out->bitdepth); + } + } + } + } + + color_profile_cleanup(&profile); + + if(mode_out->colortype == LCT_PALETTE && mode_in->palettesize == mode_out->palettesize) + { + /*In this case keep the palette order of the input, so that the user can choose an optimal one*/ + size_t i; + for(i = 0; i < mode_in->palettesize * 4; i++) + { + mode_out->palette[i] = mode_in->palette[i]; + } + } + + if(no_nibbles && mode_out->bitdepth < 8) + { + /*palette can keep its small amount of colors, as long as no indices use it*/ + mode_out->bitdepth = 8; + } + + return error; +} + +#endif /* #ifdef LODEPNG_COMPILE_ENCODER */ + +/* +Paeth predicter, used by PNG filter type 4 +The parameters are of type short, but should come from unsigned chars, the shorts +are only needed to make the paeth calculation correct. +*/ +static unsigned char paethPredictor(short a, short b, short c) +{ + short pa = abs(b - c); + short pb = abs(a - c); + short pc = abs(a + b - c - c); + + if(pc < pa && pc < pb) return (unsigned char)c; + else if(pb < pa) return (unsigned char)b; + else return (unsigned char)a; +} + +/*shared values used by multiple Adam7 related functions*/ + +static const unsigned ADAM7_IX[7] = { 0, 4, 0, 2, 0, 1, 0 }; /*x start values*/ +static const unsigned ADAM7_IY[7] = { 0, 0, 4, 0, 2, 0, 1 }; /*y start values*/ +static const unsigned ADAM7_DX[7] = { 8, 8, 4, 4, 2, 2, 1 }; /*x delta values*/ +static const unsigned ADAM7_DY[7] = { 8, 8, 8, 4, 4, 2, 2 }; /*y delta values*/ + +/* +Outputs various dimensions and positions in the image related to the Adam7 reduced images. +passw: output containing the width of the 7 passes +passh: output containing the height of the 7 passes +filter_passstart: output containing the index of the start and end of each + reduced image with filter bytes +padded_passstart output containing the index of the start and end of each + reduced image when without filter bytes but with padded scanlines +passstart: output containing the index of the start and end of each reduced + image without padding between scanlines, but still padding between the images +w, h: width and height of non-interlaced image +bpp: bits per pixel +"padded" is only relevant if bpp is less than 8 and a scanline or image does not + end at a full byte +*/ +static void Adam7_getpassvalues(unsigned passw[7], unsigned passh[7], size_t filter_passstart[8], + size_t padded_passstart[8], size_t passstart[8], unsigned w, unsigned h, unsigned bpp) +{ + /*the passstart values have 8 values: the 8th one indicates the byte after the end of the 7th (= last) pass*/ + unsigned i; + + /*calculate width and height in pixels of each pass*/ + for(i = 0; i < 7; i++) + { + passw[i] = (w + ADAM7_DX[i] - ADAM7_IX[i] - 1) / ADAM7_DX[i]; + passh[i] = (h + ADAM7_DY[i] - ADAM7_IY[i] - 1) / ADAM7_DY[i]; + if(passw[i] == 0) passh[i] = 0; + if(passh[i] == 0) passw[i] = 0; + } + + filter_passstart[0] = padded_passstart[0] = passstart[0] = 0; + for(i = 0; i < 7; i++) + { + /*if passw[i] is 0, it's 0 bytes, not 1 (no filtertype-byte)*/ + filter_passstart[i + 1] = filter_passstart[i] + + ((passw[i] && passh[i]) ? passh[i] * (1 + (passw[i] * bpp + 7) / 8) : 0); + /*bits padded if needed to fill full byte at end of each scanline*/ + padded_passstart[i + 1] = padded_passstart[i] + passh[i] * ((passw[i] * bpp + 7) / 8); + /*only padded at end of reduced image*/ + passstart[i + 1] = passstart[i] + (passh[i] * passw[i] * bpp + 7) / 8; + } +} + +#ifdef LODEPNG_COMPILE_DECODER + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / PNG Decoder / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +/*read the information from the header and store it in the LodePNGInfo. return value is error*/ +unsigned lodepng_inspect(unsigned* w, unsigned* h, LodePNGState* state, + const unsigned char* in, size_t insize) +{ + LodePNGInfo* info = &state->info_png; + if(insize == 0 || in == 0) + { + CERROR_RETURN_ERROR(state->error, 48); /*error: the given data is empty*/ + } + if(insize < 29) + { + CERROR_RETURN_ERROR(state->error, 27); /*error: the data length is smaller than the length of a PNG header*/ + } + + /*when decoding a new PNG image, make sure all parameters created after previous decoding are reset*/ + lodepng_info_cleanup(info); + lodepng_info_init(info); + + if(in[0] != 137 || in[1] != 80 || in[2] != 78 || in[3] != 71 + || in[4] != 13 || in[5] != 10 || in[6] != 26 || in[7] != 10) + { + CERROR_RETURN_ERROR(state->error, 28); /*error: the first 8 bytes are not the correct PNG signature*/ + } + if(in[12] != 'I' || in[13] != 'H' || in[14] != 'D' || in[15] != 'R') + { + CERROR_RETURN_ERROR(state->error, 29); /*error: it doesn't start with a IHDR chunk!*/ + } + + /*read the values given in the header*/ + *w = lodepng_read32bitInt(&in[16]); + *h = lodepng_read32bitInt(&in[20]); + info->color.bitdepth = in[24]; + info->color.colortype = (LodePNGColorType)in[25]; + info->compression_method = in[26]; + info->filter_method = in[27]; + info->interlace_method = in[28]; + + if(!state->decoder.ignore_crc) + { + unsigned CRC = lodepng_read32bitInt(&in[29]); + unsigned checksum = lodepng_crc32(&in[12], 17); + if(CRC != checksum) + { + CERROR_RETURN_ERROR(state->error, 57); /*invalid CRC*/ + } + } + + /*error: only compression method 0 is allowed in the specification*/ + if(info->compression_method != 0) CERROR_RETURN_ERROR(state->error, 32); + /*error: only filter method 0 is allowed in the specification*/ + if(info->filter_method != 0) CERROR_RETURN_ERROR(state->error, 33); + /*error: only interlace methods 0 and 1 exist in the specification*/ + if(info->interlace_method > 1) CERROR_RETURN_ERROR(state->error, 34); + + state->error = checkColorValidity(info->color.colortype, info->color.bitdepth); + return state->error; +} + +static unsigned unfilterScanline(unsigned char* recon, const unsigned char* scanline, const unsigned char* precon, + size_t bytewidth, unsigned char filterType, size_t length) +{ + /* + For PNG filter method 0 + unfilter a PNG image scanline by scanline. when the pixels are smaller than 1 byte, + the filter works byte per byte (bytewidth = 1) + precon is the previous unfiltered scanline, recon the result, scanline the current one + the incoming scanlines do NOT include the filtertype byte, that one is given in the parameter filterType instead + recon and scanline MAY be the same memory address! precon must be disjoint. + */ + + size_t i; + switch(filterType) + { + case 0: + for(i = 0; i < length; i++) recon[i] = scanline[i]; + break; + case 1: + for(i = 0; i < bytewidth; i++) recon[i] = scanline[i]; + for(i = bytewidth; i < length; i++) recon[i] = scanline[i] + recon[i - bytewidth]; + break; + case 2: + if(precon) + { + for(i = 0; i < length; i++) recon[i] = scanline[i] + precon[i]; + } + else + { + for(i = 0; i < length; i++) recon[i] = scanline[i]; + } + break; + case 3: + if(precon) + { + for(i = 0; i < bytewidth; i++) recon[i] = scanline[i] + precon[i] / 2; + for(i = bytewidth; i < length; i++) recon[i] = scanline[i] + ((recon[i - bytewidth] + precon[i]) / 2); + } + else + { + for(i = 0; i < bytewidth; i++) recon[i] = scanline[i]; + for(i = bytewidth; i < length; i++) recon[i] = scanline[i] + recon[i - bytewidth] / 2; + } + break; + case 4: + if(precon) + { + for(i = 0; i < bytewidth; i++) + { + recon[i] = (scanline[i] + precon[i]); /*paethPredictor(0, precon[i], 0) is always precon[i]*/ + } + for(i = bytewidth; i < length; i++) + { + recon[i] = (scanline[i] + paethPredictor(recon[i - bytewidth], precon[i], precon[i - bytewidth])); + } + } + else + { + for(i = 0; i < bytewidth; i++) + { + recon[i] = scanline[i]; + } + for(i = bytewidth; i < length; i++) + { + /*paethPredictor(recon[i - bytewidth], 0, 0) is always recon[i - bytewidth]*/ + recon[i] = (scanline[i] + recon[i - bytewidth]); + } + } + break; + default: return 36; /*error: unexisting filter type given*/ + } + return 0; +} + +static unsigned unfilter(unsigned char* out, const unsigned char* in, unsigned w, unsigned h, unsigned bpp) +{ + /* + For PNG filter method 0 + this function unfilters a single image (e.g. without interlacing this is called once, with Adam7 seven times) + out must have enough bytes allocated already, in must have the scanlines + 1 filtertype byte per scanline + w and h are image dimensions or dimensions of reduced image, bpp is bits per pixel + in and out are allowed to be the same memory address (but aren't the same size since in has the extra filter bytes) + */ + + unsigned y; + unsigned char* prevline = 0; + + /*bytewidth is used for filtering, is 1 when bpp < 8, number of bytes per pixel otherwise*/ + size_t bytewidth = (bpp + 7) / 8; + size_t linebytes = (w * bpp + 7) / 8; + + for(y = 0; y < h; y++) + { + size_t outindex = linebytes * y; + size_t inindex = (1 + linebytes) * y; /*the extra filterbyte added to each row*/ + unsigned char filterType = in[inindex]; + + CERROR_TRY_RETURN(unfilterScanline(&out[outindex], &in[inindex + 1], prevline, bytewidth, filterType, linebytes)); + + prevline = &out[outindex]; + } + + return 0; +} + +/* +in: Adam7 interlaced image, with no padding bits between scanlines, but between + reduced images so that each reduced image starts at a byte. +out: the same pixels, but re-ordered so that they're now a non-interlaced image with size w*h +bpp: bits per pixel +out has the following size in bits: w * h * bpp. +in is possibly bigger due to padding bits between reduced images. +out must be big enough AND must be 0 everywhere if bpp < 8 in the current implementation +(because that's likely a little bit faster) +NOTE: comments about padding bits are only relevant if bpp < 8 +*/ +static void Adam7_deinterlace(unsigned char* out, const unsigned char* in, unsigned w, unsigned h, unsigned bpp) +{ + unsigned passw[7], passh[7]; + size_t filter_passstart[8], padded_passstart[8], passstart[8]; + unsigned i; + + Adam7_getpassvalues(passw, passh, filter_passstart, padded_passstart, passstart, w, h, bpp); + + if(bpp >= 8) + { + for(i = 0; i < 7; i++) + { + unsigned x, y, b; + size_t bytewidth = bpp / 8; + for(y = 0; y < passh[i]; y++) + for(x = 0; x < passw[i]; x++) + { + size_t pixelinstart = passstart[i] + (y * passw[i] + x) * bytewidth; + size_t pixeloutstart = ((ADAM7_IY[i] + y * ADAM7_DY[i]) * w + ADAM7_IX[i] + x * ADAM7_DX[i]) * bytewidth; + for(b = 0; b < bytewidth; b++) + { + out[pixeloutstart + b] = in[pixelinstart + b]; + } + } + } + } + else /*bpp < 8: Adam7 with pixels < 8 bit is a bit trickier: with bit pointers*/ + { + for(i = 0; i < 7; i++) + { + unsigned x, y, b; + unsigned ilinebits = bpp * passw[i]; + unsigned olinebits = bpp * w; + size_t obp, ibp; /*bit pointers (for out and in buffer)*/ + for(y = 0; y < passh[i]; y++) + for(x = 0; x < passw[i]; x++) + { + ibp = (8 * passstart[i]) + (y * ilinebits + x * bpp); + obp = (ADAM7_IY[i] + y * ADAM7_DY[i]) * olinebits + (ADAM7_IX[i] + x * ADAM7_DX[i]) * bpp; + for(b = 0; b < bpp; b++) + { + unsigned char bit = readBitFromReversedStream(&ibp, in); + /*note that this function assumes the out buffer is completely 0, use setBitOfReversedStream otherwise*/ + setBitOfReversedStream0(&obp, out, bit); + } + } + } + } +} + +static void removePaddingBits(unsigned char* out, const unsigned char* in, + size_t olinebits, size_t ilinebits, unsigned h) +{ + /* + After filtering there are still padding bits if scanlines have non multiple of 8 bit amounts. They need + to be removed (except at last scanline of (Adam7-reduced) image) before working with pure image buffers + for the Adam7 code, the color convert code and the output to the user. + in and out are allowed to be the same buffer, in may also be higher but still overlapping; in must + have >= ilinebits*h bits, out must have >= olinebits*h bits, olinebits must be <= ilinebits + also used to move bits after earlier such operations happened, e.g. in a sequence of reduced images from Adam7 + only useful if (ilinebits - olinebits) is a value in the range 1..7 + */ + unsigned y; + size_t diff = ilinebits - olinebits; + size_t ibp = 0, obp = 0; /*input and output bit pointers*/ + for(y = 0; y < h; y++) + { + size_t x; + for(x = 0; x < olinebits; x++) + { + unsigned char bit = readBitFromReversedStream(&ibp, in); + setBitOfReversedStream(&obp, out, bit); + } + ibp += diff; + } +} + +/*out must be buffer big enough to contain full image, and in must contain the full decompressed data from +the IDAT chunks (with filter index bytes and possible padding bits) +return value is error*/ +static unsigned postProcessScanlines(unsigned char* out, unsigned char* in, + unsigned w, unsigned h, const LodePNGInfo* info_png) +{ + /* + This function converts the filtered-padded-interlaced data into pure 2D image buffer with the PNG's colortype. + Steps: + *) if no Adam7: 1) unfilter 2) remove padding bits (= posible extra bits per scanline if bpp < 8) + *) if adam7: 1) 7x unfilter 2) 7x remove padding bits 3) Adam7_deinterlace + NOTE: the in buffer will be overwritten with intermediate data! + */ + unsigned bpp = lodepng_get_bpp(&info_png->color); + if(bpp == 0) return 31; /*error: invalid colortype*/ + + if(info_png->interlace_method == 0) + { + if(bpp < 8 && w * bpp != ((w * bpp + 7) / 8) * 8) + { + CERROR_TRY_RETURN(unfilter(in, in, w, h, bpp)); + removePaddingBits(out, in, w * bpp, ((w * bpp + 7) / 8) * 8, h); + } + /*we can immediatly filter into the out buffer, no other steps needed*/ + else CERROR_TRY_RETURN(unfilter(out, in, w, h, bpp)); + } + else /*interlace_method is 1 (Adam7)*/ + { + unsigned passw[7], passh[7]; size_t filter_passstart[8], padded_passstart[8], passstart[8]; + unsigned i; + + Adam7_getpassvalues(passw, passh, filter_passstart, padded_passstart, passstart, w, h, bpp); + + for(i = 0; i < 7; i++) + { + CERROR_TRY_RETURN(unfilter(&in[padded_passstart[i]], &in[filter_passstart[i]], passw[i], passh[i], bpp)); + /*TODO: possible efficiency improvement: if in this reduced image the bits fit nicely in 1 scanline, + move bytes instead of bits or move not at all*/ + if(bpp < 8) + { + /*remove padding bits in scanlines; after this there still may be padding + bits between the different reduced images: each reduced image still starts nicely at a byte*/ + removePaddingBits(&in[passstart[i]], &in[padded_passstart[i]], passw[i] * bpp, + ((passw[i] * bpp + 7) / 8) * 8, passh[i]); + } + } + + Adam7_deinterlace(out, in, w, h, bpp); + } + + return 0; +} + +static unsigned readChunk_PLTE(LodePNGColorMode* color, const unsigned char* data, size_t chunkLength) +{ + unsigned pos = 0, i; + if(color->palette) lodepng_free(color->palette); + color->palettesize = chunkLength / 3; + color->palette = (unsigned char*)lodepng_malloc(4 * color->palettesize); + if(!color->palette && color->palettesize) + { + color->palettesize = 0; + return 83; /*alloc fail*/ + } + if(color->palettesize > 256) return 38; /*error: palette too big*/ + + for(i = 0; i < color->palettesize; i++) + { + color->palette[4 * i + 0] = data[pos++]; /*R*/ + color->palette[4 * i + 1] = data[pos++]; /*G*/ + color->palette[4 * i + 2] = data[pos++]; /*B*/ + color->palette[4 * i + 3] = 255; /*alpha*/ + } + + return 0; /* OK */ +} + +static unsigned readChunk_tRNS(LodePNGColorMode* color, const unsigned char* data, size_t chunkLength) +{ + unsigned i; + if(color->colortype == LCT_PALETTE) + { + /*error: more alpha values given than there are palette entries*/ + if(chunkLength > color->palettesize) return 38; + + for(i = 0; i < chunkLength; i++) color->palette[4 * i + 3] = data[i]; + } + else if(color->colortype == LCT_GREY) + { + /*error: this chunk must be 2 bytes for greyscale image*/ + if(chunkLength != 2) return 30; + + color->key_defined = 1; + color->key_r = color->key_g = color->key_b = 256u * data[0] + data[1]; + } + else if(color->colortype == LCT_RGB) + { + /*error: this chunk must be 6 bytes for RGB image*/ + if(chunkLength != 6) return 41; + + color->key_defined = 1; + color->key_r = 256u * data[0] + data[1]; + color->key_g = 256u * data[2] + data[3]; + color->key_b = 256u * data[4] + data[5]; + } + else return 42; /*error: tRNS chunk not allowed for other color models*/ + + return 0; /* OK */ +} + + +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS +/*background color chunk (bKGD)*/ +static unsigned readChunk_bKGD(LodePNGInfo* info, const unsigned char* data, size_t chunkLength) +{ + if(info->color.colortype == LCT_PALETTE) + { + /*error: this chunk must be 1 byte for indexed color image*/ + if(chunkLength != 1) return 43; + + info->background_defined = 1; + info->background_r = info->background_g = info->background_b = data[0]; + } + else if(info->color.colortype == LCT_GREY || info->color.colortype == LCT_GREY_ALPHA) + { + /*error: this chunk must be 2 bytes for greyscale image*/ + if(chunkLength != 2) return 44; + + info->background_defined = 1; + info->background_r = info->background_g = info->background_b = 256u * data[0] + data[1]; + } + else if(info->color.colortype == LCT_RGB || info->color.colortype == LCT_RGBA) + { + /*error: this chunk must be 6 bytes for greyscale image*/ + if(chunkLength != 6) return 45; + + info->background_defined = 1; + info->background_r = 256u * data[0] + data[1]; + info->background_g = 256u * data[2] + data[3]; + info->background_b = 256u * data[4] + data[5]; + } + + return 0; /* OK */ +} + +/*text chunk (tEXt)*/ +static unsigned readChunk_tEXt(LodePNGInfo* info, const unsigned char* data, size_t chunkLength) +{ + unsigned error = 0; + char *key = 0, *str = 0; + unsigned i; + + while(!error) /*not really a while loop, only used to break on error*/ + { + unsigned length, string2_begin; + + length = 0; + while(length < chunkLength && data[length] != 0) length++; + /*even though it's not allowed by the standard, no error is thrown if + there's no null termination char, if the text is empty*/ + if(length < 1 || length > 79) CERROR_BREAK(error, 89); /*keyword too short or long*/ + + key = (char*)lodepng_malloc(length + 1); + if(!key) CERROR_BREAK(error, 83); /*alloc fail*/ + + key[length] = 0; + for(i = 0; i < length; i++) key[i] = (char)data[i]; + + string2_begin = length + 1; /*skip keyword null terminator*/ + + length = chunkLength < string2_begin ? 0 : chunkLength - string2_begin; + str = (char*)lodepng_malloc(length + 1); + if(!str) CERROR_BREAK(error, 83); /*alloc fail*/ + + str[length] = 0; + for(i = 0; i < length; i++) str[i] = (char)data[string2_begin + i]; + + error = lodepng_add_text(info, key, str); + + break; + } + + lodepng_free(key); + lodepng_free(str); + + return error; +} + +/*compressed text chunk (zTXt)*/ +static unsigned readChunk_zTXt(LodePNGInfo* info, const LodePNGDecompressSettings* zlibsettings, + const unsigned char* data, size_t chunkLength) +{ + unsigned error = 0; + unsigned i; + + unsigned length, string2_begin; + char *key = 0; + ucvector decoded; + + ucvector_init(&decoded); + + while(!error) /*not really a while loop, only used to break on error*/ + { + for(length = 0; length < chunkLength && data[length] != 0; length++) ; + if(length + 2 >= chunkLength) CERROR_BREAK(error, 75); /*no null termination, corrupt?*/ + if(length < 1 || length > 79) CERROR_BREAK(error, 89); /*keyword too short or long*/ + + key = (char*)lodepng_malloc(length + 1); + if(!key) CERROR_BREAK(error, 83); /*alloc fail*/ + + key[length] = 0; + for(i = 0; i < length; i++) key[i] = (char)data[i]; + + if(data[length + 1] != 0) CERROR_BREAK(error, 72); /*the 0 byte indicating compression must be 0*/ + + string2_begin = length + 2; + if(string2_begin > chunkLength) CERROR_BREAK(error, 75); /*no null termination, corrupt?*/ + + length = chunkLength - string2_begin; + /*will fail if zlib error, e.g. if length is too small*/ + error = zlib_decompress(&decoded.data, &decoded.size, + (unsigned char*)(&data[string2_begin]), + length, zlibsettings); + if(error) break; + ucvector_push_back(&decoded, 0); + + error = lodepng_add_text(info, key, (char*)decoded.data); + + break; + } + + lodepng_free(key); + ucvector_cleanup(&decoded); + + return error; +} + +/*international text chunk (iTXt)*/ +static unsigned readChunk_iTXt(LodePNGInfo* info, const LodePNGDecompressSettings* zlibsettings, + const unsigned char* data, size_t chunkLength) +{ + unsigned error = 0; + unsigned i; + + unsigned length, begin, compressed; + char *key = 0, *langtag = 0, *transkey = 0; + ucvector decoded; + ucvector_init(&decoded); + + while(!error) /*not really a while loop, only used to break on error*/ + { + /*Quick check if the chunk length isn't too small. Even without check + it'd still fail with other error checks below if it's too short. This just gives a different error code.*/ + if(chunkLength < 5) CERROR_BREAK(error, 30); /*iTXt chunk too short*/ + + /*read the key*/ + for(length = 0; length < chunkLength && data[length] != 0; length++) ; + if(length + 3 >= chunkLength) CERROR_BREAK(error, 75); /*no null termination char, corrupt?*/ + if(length < 1 || length > 79) CERROR_BREAK(error, 89); /*keyword too short or long*/ + + key = (char*)lodepng_malloc(length + 1); + if(!key) CERROR_BREAK(error, 83); /*alloc fail*/ + + key[length] = 0; + for(i = 0; i < length; i++) key[i] = (char)data[i]; + + /*read the compression method*/ + compressed = data[length + 1]; + if(data[length + 2] != 0) CERROR_BREAK(error, 72); /*the 0 byte indicating compression must be 0*/ + + /*even though it's not allowed by the standard, no error is thrown if + there's no null termination char, if the text is empty for the next 3 texts*/ + + /*read the langtag*/ + begin = length + 3; + length = 0; + for(i = begin; i < chunkLength && data[i] != 0; i++) length++; + + langtag = (char*)lodepng_malloc(length + 1); + if(!langtag) CERROR_BREAK(error, 83); /*alloc fail*/ + + langtag[length] = 0; + for(i = 0; i < length; i++) langtag[i] = (char)data[begin + i]; + + /*read the transkey*/ + begin += length + 1; + length = 0; + for(i = begin; i < chunkLength && data[i] != 0; i++) length++; + + transkey = (char*)lodepng_malloc(length + 1); + if(!transkey) CERROR_BREAK(error, 83); /*alloc fail*/ + + transkey[length] = 0; + for(i = 0; i < length; i++) transkey[i] = (char)data[begin + i]; + + /*read the actual text*/ + begin += length + 1; + + length = chunkLength < begin ? 0 : chunkLength - begin; + + if(compressed) + { + /*will fail if zlib error, e.g. if length is too small*/ + error = zlib_decompress(&decoded.data, &decoded.size, + (unsigned char*)(&data[begin]), + length, zlibsettings); + if(error) break; + if(decoded.allocsize < decoded.size) decoded.allocsize = decoded.size; + ucvector_push_back(&decoded, 0); + } + else + { + if(!ucvector_resize(&decoded, length + 1)) CERROR_BREAK(error, 83 /*alloc fail*/); + + decoded.data[length] = 0; + for(i = 0; i < length; i++) decoded.data[i] = data[begin + i]; + } + + error = lodepng_add_itext(info, key, langtag, transkey, (char*)decoded.data); + + break; + } + + lodepng_free(key); + lodepng_free(langtag); + lodepng_free(transkey); + ucvector_cleanup(&decoded); + + return error; +} + +static unsigned readChunk_tIME(LodePNGInfo* info, const unsigned char* data, size_t chunkLength) +{ + if(chunkLength != 7) return 73; /*invalid tIME chunk size*/ + + info->time_defined = 1; + info->time.year = 256u * data[0] + data[1]; + info->time.month = data[2]; + info->time.day = data[3]; + info->time.hour = data[4]; + info->time.minute = data[5]; + info->time.second = data[6]; + + return 0; /* OK */ +} + +static unsigned readChunk_pHYs(LodePNGInfo* info, const unsigned char* data, size_t chunkLength) +{ + if(chunkLength != 9) return 74; /*invalid pHYs chunk size*/ + + info->phys_defined = 1; + info->phys_x = 16777216u * data[0] + 65536u * data[1] + 256u * data[2] + data[3]; + info->phys_y = 16777216u * data[4] + 65536u * data[5] + 256u * data[6] + data[7]; + info->phys_unit = data[8]; + + return 0; /* OK */ +} +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + +/*read a PNG, the result will be in the same color type as the PNG (hence "generic")*/ +static void decodeGeneric(unsigned char** out, unsigned* w, unsigned* h, + LodePNGState* state, + const unsigned char* in, size_t insize) +{ + unsigned char IEND = 0; + const unsigned char* chunk; + size_t i; + ucvector idat; /*the data from idat chunks*/ + ucvector scanlines; + + /*for unknown chunk order*/ + unsigned unknown = 0; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + unsigned critical_pos = 1; /*1 = after IHDR, 2 = after PLTE, 3 = after IDAT*/ +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + + /*provide some proper output values if error will happen*/ + *out = 0; + + state->error = lodepng_inspect(w, h, state, in, insize); /*reads header and resets other parameters in state->info_png*/ + if(state->error) return; + + ucvector_init(&idat); + chunk = &in[33]; /*first byte of the first chunk after the header*/ + + /*loop through the chunks, ignoring unknown chunks and stopping at IEND chunk. + IDAT data is put at the start of the in buffer*/ + while(!IEND && !state->error) + { + unsigned chunkLength; + const unsigned char* data; /*the data in the chunk*/ + + /*error: size of the in buffer too small to contain next chunk*/ + if((size_t)((chunk - in) + 12) > insize || chunk < in) CERROR_BREAK(state->error, 30); + + /*length of the data of the chunk, excluding the length bytes, chunk type and CRC bytes*/ + chunkLength = lodepng_chunk_length(chunk); + /*error: chunk length larger than the max PNG chunk size*/ + if(chunkLength > 2147483647) CERROR_BREAK(state->error, 63); + + if((size_t)((chunk - in) + chunkLength + 12) > insize || (chunk + chunkLength + 12) < in) + { + CERROR_BREAK(state->error, 64); /*error: size of the in buffer too small to contain next chunk*/ + } + + data = lodepng_chunk_data_const(chunk); + + /*IDAT chunk, containing compressed image data*/ + if(lodepng_chunk_type_equals(chunk, "IDAT")) + { + size_t oldsize = idat.size; + if(!ucvector_resize(&idat, oldsize + chunkLength)) CERROR_BREAK(state->error, 83 /*alloc fail*/); + for(i = 0; i < chunkLength; i++) idat.data[oldsize + i] = data[i]; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + critical_pos = 3; +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + } + /*IEND chunk*/ + else if(lodepng_chunk_type_equals(chunk, "IEND")) + { + IEND = 1; + } + /*palette chunk (PLTE)*/ + else if(lodepng_chunk_type_equals(chunk, "PLTE")) + { + state->error = readChunk_PLTE(&state->info_png.color, data, chunkLength); + if(state->error) break; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + critical_pos = 2; +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + } + /*palette transparency chunk (tRNS)*/ + else if(lodepng_chunk_type_equals(chunk, "tRNS")) + { + state->error = readChunk_tRNS(&state->info_png.color, data, chunkLength); + if(state->error) break; + } +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + /*background color chunk (bKGD)*/ + else if(lodepng_chunk_type_equals(chunk, "bKGD")) + { + state->error = readChunk_bKGD(&state->info_png, data, chunkLength); + if(state->error) break; + } + /*text chunk (tEXt)*/ + else if(lodepng_chunk_type_equals(chunk, "tEXt")) + { + if(state->decoder.read_text_chunks) + { + state->error = readChunk_tEXt(&state->info_png, data, chunkLength); + if(state->error) break; + } + } + /*compressed text chunk (zTXt)*/ + else if(lodepng_chunk_type_equals(chunk, "zTXt")) + { + if(state->decoder.read_text_chunks) + { + state->error = readChunk_zTXt(&state->info_png, &state->decoder.zlibsettings, data, chunkLength); + if(state->error) break; + } + } + /*international text chunk (iTXt)*/ + else if(lodepng_chunk_type_equals(chunk, "iTXt")) + { + if(state->decoder.read_text_chunks) + { + state->error = readChunk_iTXt(&state->info_png, &state->decoder.zlibsettings, data, chunkLength); + if(state->error) break; + } + } + else if(lodepng_chunk_type_equals(chunk, "tIME")) + { + state->error = readChunk_tIME(&state->info_png, data, chunkLength); + if(state->error) break; + } + else if(lodepng_chunk_type_equals(chunk, "pHYs")) + { + state->error = readChunk_pHYs(&state->info_png, data, chunkLength); + if(state->error) break; + } +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + else /*it's not an implemented chunk type, so ignore it: skip over the data*/ + { + /*error: unknown critical chunk (5th bit of first byte of chunk type is 0)*/ + if(!lodepng_chunk_ancillary(chunk)) CERROR_BREAK(state->error, 69); + + unknown = 1; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + if(state->decoder.remember_unknown_chunks) + { + state->error = lodepng_chunk_append(&state->info_png.unknown_chunks_data[critical_pos - 1], + &state->info_png.unknown_chunks_size[critical_pos - 1], chunk); + if(state->error) break; + } +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + } + + if(!state->decoder.ignore_crc && !unknown) /*check CRC if wanted, only on known chunk types*/ + { + if(lodepng_chunk_check_crc(chunk)) CERROR_BREAK(state->error, 57); /*invalid CRC*/ + } + + if(!IEND) chunk = lodepng_chunk_next_const(chunk); + } + + ucvector_init(&scanlines); + if(!state->error) + { + /*maximum final image length is already reserved in the vector's length - this is not really necessary*/ + if(!ucvector_resize(&scanlines, lodepng_get_raw_size(*w, *h, &state->info_png.color) + *h)) + { + state->error = 83; /*alloc fail*/ + } + } + if(!state->error) + { + /*decompress with the Zlib decompressor*/ + state->error = zlib_decompress(&scanlines.data, &scanlines.size, idat.data, + idat.size, &state->decoder.zlibsettings); + } + ucvector_cleanup(&idat); + + if(!state->error) + { + ucvector outv; + ucvector_init(&outv); + if(!ucvector_resizev(&outv, + lodepng_get_raw_size(*w, *h, &state->info_png.color), 0)) state->error = 83; /*alloc fail*/ + if(!state->error) state->error = postProcessScanlines(outv.data, scanlines.data, *w, *h, &state->info_png); + *out = outv.data; + } + ucvector_cleanup(&scanlines); +} + +unsigned lodepng_decode(unsigned char** out, unsigned* w, unsigned* h, + LodePNGState* state, + const unsigned char* in, size_t insize) +{ + *out = 0; + decodeGeneric(out, w, h, state, in, insize); + if(state->error) return state->error; + if(!state->decoder.color_convert || lodepng_color_mode_equal(&state->info_raw, &state->info_png.color)) + { + /*same color type, no copying or converting of data needed*/ + /*store the info_png color settings on the info_raw so that the info_raw still reflects what colortype + the raw image has to the end user*/ + if(!state->decoder.color_convert) + { + state->error = lodepng_color_mode_copy(&state->info_raw, &state->info_png.color); + if(state->error) return state->error; + } + } + else + { + /*color conversion needed; sort of copy of the data*/ + unsigned char* data = *out; + size_t outsize; + + /*TODO: check if this works according to the statement in the documentation: "The converter can convert + from greyscale input color type, to 8-bit greyscale or greyscale with alpha"*/ + if(!(state->info_raw.colortype == LCT_RGB || state->info_raw.colortype == LCT_RGBA) + && !(state->info_raw.bitdepth == 8)) + { + return 56; /*unsupported color mode conversion*/ + } + + outsize = lodepng_get_raw_size(*w, *h, &state->info_raw); + *out = (unsigned char*)lodepng_malloc(outsize); + if(!(*out)) + { + state->error = 83; /*alloc fail*/ + } + else state->error = lodepng_convert(*out, data, &state->info_raw, &state->info_png.color, *w, *h, state->decoder.fix_png); + lodepng_free(data); + } + return state->error; +} + +unsigned lodepng_decode_memory(unsigned char** out, unsigned* w, unsigned* h, const unsigned char* in, + size_t insize, LodePNGColorType colortype, unsigned bitdepth) +{ + unsigned error; + LodePNGState state; + lodepng_state_init(&state); + state.info_raw.colortype = colortype; + state.info_raw.bitdepth = bitdepth; + error = lodepng_decode(out, w, h, &state, in, insize); + lodepng_state_cleanup(&state); + return error; +} + +unsigned lodepng_decode32(unsigned char** out, unsigned* w, unsigned* h, const unsigned char* in, size_t insize) +{ + return lodepng_decode_memory(out, w, h, in, insize, LCT_RGBA, 8); +} + +unsigned lodepng_decode24(unsigned char** out, unsigned* w, unsigned* h, const unsigned char* in, size_t insize) +{ + return lodepng_decode_memory(out, w, h, in, insize, LCT_RGB, 8); +} + +#ifdef LODEPNG_COMPILE_DISK +unsigned lodepng_decode_file(unsigned char** out, unsigned* w, unsigned* h, const char* filename, + LodePNGColorType colortype, unsigned bitdepth) +{ + unsigned char* buffer; + size_t buffersize; + unsigned error; + error = lodepng_load_file(&buffer, &buffersize, filename); + if(!error) error = lodepng_decode_memory(out, w, h, buffer, buffersize, colortype, bitdepth); + lodepng_free(buffer); + return error; +} + +unsigned lodepng_decode32_file(unsigned char** out, unsigned* w, unsigned* h, const char* filename) +{ + return lodepng_decode_file(out, w, h, filename, LCT_RGBA, 8); +} + +unsigned lodepng_decode24_file(unsigned char** out, unsigned* w, unsigned* h, const char* filename) +{ + return lodepng_decode_file(out, w, h, filename, LCT_RGB, 8); +} +#endif /*LODEPNG_COMPILE_DISK*/ + +void lodepng_decoder_settings_init(LodePNGDecoderSettings* settings) +{ + settings->color_convert = 1; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + settings->read_text_chunks = 1; + settings->remember_unknown_chunks = 0; +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + settings->ignore_crc = 0; + settings->fix_png = 0; + lodepng_decompress_settings_init(&settings->zlibsettings); +} + +#endif /*LODEPNG_COMPILE_DECODER*/ + +#if defined(LODEPNG_COMPILE_DECODER) || defined(LODEPNG_COMPILE_ENCODER) + +void lodepng_state_init(LodePNGState* state) +{ +#ifdef LODEPNG_COMPILE_DECODER + lodepng_decoder_settings_init(&state->decoder); +#endif /*LODEPNG_COMPILE_DECODER*/ +#ifdef LODEPNG_COMPILE_ENCODER + lodepng_encoder_settings_init(&state->encoder); +#endif /*LODEPNG_COMPILE_ENCODER*/ + lodepng_color_mode_init(&state->info_raw); + lodepng_info_init(&state->info_png); + state->error = 1; +} + +void lodepng_state_cleanup(LodePNGState* state) +{ + lodepng_color_mode_cleanup(&state->info_raw); + lodepng_info_cleanup(&state->info_png); +} + +void lodepng_state_copy(LodePNGState* dest, const LodePNGState* source) +{ + lodepng_state_cleanup(dest); + *dest = *source; + lodepng_color_mode_init(&dest->info_raw); + lodepng_info_init(&dest->info_png); + dest->error = lodepng_color_mode_copy(&dest->info_raw, &source->info_raw); if(dest->error) return; + dest->error = lodepng_info_copy(&dest->info_png, &source->info_png); if(dest->error) return; +} + +#endif /* defined(LODEPNG_COMPILE_DECODER) || defined(LODEPNG_COMPILE_ENCODER) */ + +#ifdef LODEPNG_COMPILE_ENCODER + +/* ////////////////////////////////////////////////////////////////////////// */ +/* / PNG Encoder / */ +/* ////////////////////////////////////////////////////////////////////////// */ + +/*chunkName must be string of 4 characters*/ +static unsigned addChunk(ucvector* out, const char* chunkName, const unsigned char* data, size_t length) +{ + CERROR_TRY_RETURN(lodepng_chunk_create(&out->data, &out->size, (unsigned)length, chunkName, data)); + out->allocsize = out->size; /*fix the allocsize again*/ + return 0; +} + +static void writeSignature(ucvector* out) +{ + /*8 bytes PNG signature, aka the magic bytes*/ + ucvector_push_back(out, 137); + ucvector_push_back(out, 80); + ucvector_push_back(out, 78); + ucvector_push_back(out, 71); + ucvector_push_back(out, 13); + ucvector_push_back(out, 10); + ucvector_push_back(out, 26); + ucvector_push_back(out, 10); +} + +static unsigned addChunk_IHDR(ucvector* out, unsigned w, unsigned h, + LodePNGColorType colortype, unsigned bitdepth, unsigned interlace_method) +{ + unsigned error = 0; + ucvector header; + ucvector_init(&header); + + lodepng_add32bitInt(&header, w); /*width*/ + lodepng_add32bitInt(&header, h); /*height*/ + ucvector_push_back(&header, (unsigned char)bitdepth); /*bit depth*/ + ucvector_push_back(&header, (unsigned char)colortype); /*color type*/ + ucvector_push_back(&header, 0); /*compression method*/ + ucvector_push_back(&header, 0); /*filter method*/ + ucvector_push_back(&header, interlace_method); /*interlace method*/ + + error = addChunk(out, "IHDR", header.data, header.size); + ucvector_cleanup(&header); + + return error; +} + +static unsigned addChunk_PLTE(ucvector* out, const LodePNGColorMode* info) +{ + unsigned error = 0; + size_t i; + ucvector PLTE; + ucvector_init(&PLTE); + for(i = 0; i < info->palettesize * 4; i++) + { + /*add all channels except alpha channel*/ + if(i % 4 != 3) ucvector_push_back(&PLTE, info->palette[i]); + } + error = addChunk(out, "PLTE", PLTE.data, PLTE.size); + ucvector_cleanup(&PLTE); + + return error; +} + +static unsigned addChunk_tRNS(ucvector* out, const LodePNGColorMode* info) +{ + unsigned error = 0; + size_t i; + ucvector tRNS; + ucvector_init(&tRNS); + if(info->colortype == LCT_PALETTE) + { + size_t amount = info->palettesize; + /*the tail of palette values that all have 255 as alpha, does not have to be encoded*/ + for(i = info->palettesize; i > 0; i--) + { + if(info->palette[4 * (i - 1) + 3] == 255) amount--; + else break; + } + /*add only alpha channel*/ + for(i = 0; i < amount; i++) ucvector_push_back(&tRNS, info->palette[4 * i + 3]); + } + else if(info->colortype == LCT_GREY) + { + if(info->key_defined) + { + ucvector_push_back(&tRNS, (unsigned char)(info->key_r / 256)); + ucvector_push_back(&tRNS, (unsigned char)(info->key_r % 256)); + } + } + else if(info->colortype == LCT_RGB) + { + if(info->key_defined) + { + ucvector_push_back(&tRNS, (unsigned char)(info->key_r / 256)); + ucvector_push_back(&tRNS, (unsigned char)(info->key_r % 256)); + ucvector_push_back(&tRNS, (unsigned char)(info->key_g / 256)); + ucvector_push_back(&tRNS, (unsigned char)(info->key_g % 256)); + ucvector_push_back(&tRNS, (unsigned char)(info->key_b / 256)); + ucvector_push_back(&tRNS, (unsigned char)(info->key_b % 256)); + } + } + + error = addChunk(out, "tRNS", tRNS.data, tRNS.size); + ucvector_cleanup(&tRNS); + + return error; +} + +static unsigned addChunk_IDAT(ucvector* out, const unsigned char* data, size_t datasize, + LodePNGCompressSettings* zlibsettings) +{ + ucvector zlibdata; + unsigned error = 0; + + /*compress with the Zlib compressor*/ + ucvector_init(&zlibdata); + error = zlib_compress(&zlibdata.data, &zlibdata.size, data, datasize, zlibsettings); + if(!error) error = addChunk(out, "IDAT", zlibdata.data, zlibdata.size); + ucvector_cleanup(&zlibdata); + + return error; +} + +static unsigned addChunk_IEND(ucvector* out) +{ + unsigned error = 0; + error = addChunk(out, "IEND", 0, 0); + return error; +} + +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + +static unsigned addChunk_tEXt(ucvector* out, const char* keyword, const char* textstring) +{ + unsigned error = 0; + size_t i; + ucvector text; + ucvector_init(&text); + for(i = 0; keyword[i] != 0; i++) ucvector_push_back(&text, (unsigned char)keyword[i]); + if(i < 1 || i > 79) return 89; /*error: invalid keyword size*/ + ucvector_push_back(&text, 0); /*0 termination char*/ + for(i = 0; textstring[i] != 0; i++) ucvector_push_back(&text, (unsigned char)textstring[i]); + error = addChunk(out, "tEXt", text.data, text.size); + ucvector_cleanup(&text); + + return error; +} + +static unsigned addChunk_zTXt(ucvector* out, const char* keyword, const char* textstring, + LodePNGCompressSettings* zlibsettings) +{ + unsigned error = 0; + ucvector data, compressed; + size_t i, textsize = strlen(textstring); + + ucvector_init(&data); + ucvector_init(&compressed); + for(i = 0; keyword[i] != 0; i++) ucvector_push_back(&data, (unsigned char)keyword[i]); + if(i < 1 || i > 79) return 89; /*error: invalid keyword size*/ + ucvector_push_back(&data, 0); /*0 termination char*/ + ucvector_push_back(&data, 0); /*compression method: 0*/ + + error = zlib_compress(&compressed.data, &compressed.size, + (unsigned char*)textstring, textsize, zlibsettings); + if(!error) + { + for(i = 0; i < compressed.size; i++) ucvector_push_back(&data, compressed.data[i]); + error = addChunk(out, "zTXt", data.data, data.size); + } + + ucvector_cleanup(&compressed); + ucvector_cleanup(&data); + return error; +} + +static unsigned addChunk_iTXt(ucvector* out, unsigned compressed, const char* keyword, const char* langtag, + const char* transkey, const char* textstring, LodePNGCompressSettings* zlibsettings) +{ + unsigned error = 0; + ucvector data; + size_t i, textsize = strlen(textstring); + + ucvector_init(&data); + + for(i = 0; keyword[i] != 0; i++) ucvector_push_back(&data, (unsigned char)keyword[i]); + if(i < 1 || i > 79) return 89; /*error: invalid keyword size*/ + ucvector_push_back(&data, 0); /*null termination char*/ + ucvector_push_back(&data, compressed ? 1 : 0); /*compression flag*/ + ucvector_push_back(&data, 0); /*compression method*/ + for(i = 0; langtag[i] != 0; i++) ucvector_push_back(&data, (unsigned char)langtag[i]); + ucvector_push_back(&data, 0); /*null termination char*/ + for(i = 0; transkey[i] != 0; i++) ucvector_push_back(&data, (unsigned char)transkey[i]); + ucvector_push_back(&data, 0); /*null termination char*/ + + if(compressed) + { + ucvector compressed_data; + ucvector_init(&compressed_data); + error = zlib_compress(&compressed_data.data, &compressed_data.size, + (unsigned char*)textstring, textsize, zlibsettings); + if(!error) + { + for(i = 0; i < compressed_data.size; i++) ucvector_push_back(&data, compressed_data.data[i]); + } + ucvector_cleanup(&compressed_data); + } + else /*not compressed*/ + { + for(i = 0; textstring[i] != 0; i++) ucvector_push_back(&data, (unsigned char)textstring[i]); + } + + if(!error) error = addChunk(out, "iTXt", data.data, data.size); + ucvector_cleanup(&data); + return error; +} + +static unsigned addChunk_bKGD(ucvector* out, const LodePNGInfo* info) +{ + unsigned error = 0; + ucvector bKGD; + ucvector_init(&bKGD); + if(info->color.colortype == LCT_GREY || info->color.colortype == LCT_GREY_ALPHA) + { + ucvector_push_back(&bKGD, (unsigned char)(info->background_r / 256)); + ucvector_push_back(&bKGD, (unsigned char)(info->background_r % 256)); + } + else if(info->color.colortype == LCT_RGB || info->color.colortype == LCT_RGBA) + { + ucvector_push_back(&bKGD, (unsigned char)(info->background_r / 256)); + ucvector_push_back(&bKGD, (unsigned char)(info->background_r % 256)); + ucvector_push_back(&bKGD, (unsigned char)(info->background_g / 256)); + ucvector_push_back(&bKGD, (unsigned char)(info->background_g % 256)); + ucvector_push_back(&bKGD, (unsigned char)(info->background_b / 256)); + ucvector_push_back(&bKGD, (unsigned char)(info->background_b % 256)); + } + else if(info->color.colortype == LCT_PALETTE) + { + ucvector_push_back(&bKGD, (unsigned char)(info->background_r % 256)); /*palette index*/ + } + + error = addChunk(out, "bKGD", bKGD.data, bKGD.size); + ucvector_cleanup(&bKGD); + + return error; +} + +static unsigned addChunk_tIME(ucvector* out, const LodePNGTime* time) +{ + unsigned error = 0; + unsigned char* data = (unsigned char*)lodepng_malloc(7); + if(!data) return 83; /*alloc fail*/ + data[0] = (unsigned char)(time->year / 256); + data[1] = (unsigned char)(time->year % 256); + data[2] = (unsigned char)time->month; + data[3] = (unsigned char)time->day; + data[4] = (unsigned char)time->hour; + data[5] = (unsigned char)time->minute; + data[6] = (unsigned char)time->second; + error = addChunk(out, "tIME", data, 7); + lodepng_free(data); + return error; +} + +static unsigned addChunk_pHYs(ucvector* out, const LodePNGInfo* info) +{ + unsigned error = 0; + ucvector data; + ucvector_init(&data); + + lodepng_add32bitInt(&data, info->phys_x); + lodepng_add32bitInt(&data, info->phys_y); + ucvector_push_back(&data, info->phys_unit); + + error = addChunk(out, "pHYs", data.data, data.size); + ucvector_cleanup(&data); + + return error; +} + +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + +static void filterScanline(unsigned char* out, const unsigned char* scanline, const unsigned char* prevline, + size_t length, size_t bytewidth, unsigned char filterType) +{ + size_t i; + switch(filterType) + { + case 0: /*None*/ + for(i = 0; i < length; i++) out[i] = scanline[i]; + break; + case 1: /*Sub*/ + if(prevline) + { + for(i = 0; i < bytewidth; i++) out[i] = scanline[i]; + for(i = bytewidth; i < length; i++) out[i] = scanline[i] - scanline[i - bytewidth]; + } + else + { + for(i = 0; i < bytewidth; i++) out[i] = scanline[i]; + for(i = bytewidth; i < length; i++) out[i] = scanline[i] - scanline[i - bytewidth]; + } + break; + case 2: /*Up*/ + if(prevline) + { + for(i = 0; i < length; i++) out[i] = scanline[i] - prevline[i]; + } + else + { + for(i = 0; i < length; i++) out[i] = scanline[i]; + } + break; + case 3: /*Average*/ + if(prevline) + { + for(i = 0; i < bytewidth; i++) out[i] = scanline[i] - prevline[i] / 2; + for(i = bytewidth; i < length; i++) out[i] = scanline[i] - ((scanline[i - bytewidth] + prevline[i]) / 2); + } + else + { + for(i = 0; i < bytewidth; i++) out[i] = scanline[i]; + for(i = bytewidth; i < length; i++) out[i] = scanline[i] - scanline[i - bytewidth] / 2; + } + break; + case 4: /*Paeth*/ + if(prevline) + { + /*paethPredictor(0, prevline[i], 0) is always prevline[i]*/ + for(i = 0; i < bytewidth; i++) out[i] = (scanline[i] - prevline[i]); + for(i = bytewidth; i < length; i++) + { + out[i] = (scanline[i] - paethPredictor(scanline[i - bytewidth], prevline[i], prevline[i - bytewidth])); + } + } + else + { + for(i = 0; i < bytewidth; i++) out[i] = scanline[i]; + /*paethPredictor(scanline[i - bytewidth], 0, 0) is always scanline[i - bytewidth]*/ + for(i = bytewidth; i < length; i++) out[i] = (scanline[i] - scanline[i - bytewidth]); + } + break; + default: return; /*unexisting filter type given*/ + } +} + +/* log2 approximation. A slight bit faster than std::log. */ +static float flog2(float f) +{ + float result = 0; + while(f > 32) { result += 4; f /= 16; } + while(f > 2) { result++; f /= 2; } + return result + 1.442695f * (f * f * f / 3 - 3 * f * f / 2 + 3 * f - 1.83333f); +} + +static unsigned filter(unsigned char* out, const unsigned char* in, unsigned w, unsigned h, + const LodePNGColorMode* info, const LodePNGEncoderSettings* settings) +{ + /* + For PNG filter method 0 + out must be a buffer with as size: h + (w * h * bpp + 7) / 8, because there are + the scanlines with 1 extra byte per scanline + */ + + unsigned bpp = lodepng_get_bpp(info); + /*the width of a scanline in bytes, not including the filter type*/ + size_t linebytes = (w * bpp + 7) / 8; + /*bytewidth is used for filtering, is 1 when bpp < 8, number of bytes per pixel otherwise*/ + size_t bytewidth = (bpp + 7) / 8; + const unsigned char* prevline = 0; + unsigned x, y; + unsigned error = 0; + LodePNGFilterStrategy strategy = settings->filter_strategy; + + /* + There is a heuristic called the minimum sum of absolute differences heuristic, suggested by the PNG standard: + * If the image type is Palette, or the bit depth is smaller than 8, then do not filter the image (i.e. + use fixed filtering, with the filter None). + * (The other case) If the image type is Grayscale or RGB (with or without Alpha), and the bit depth is + not smaller than 8, then use adaptive filtering heuristic as follows: independently for each row, apply + all five filters and select the filter that produces the smallest sum of absolute values per row. + This heuristic is used if filter strategy is LFS_MINSUM and filter_palette_zero is true. + + If filter_palette_zero is true and filter_strategy is not LFS_MINSUM, the above heuristic is followed, + but for "the other case", whatever strategy filter_strategy is set to instead of the minimum sum + heuristic is used. + */ + if(settings->filter_palette_zero && + (info->colortype == LCT_PALETTE || info->bitdepth < 8)) strategy = LFS_ZERO; + + if(bpp == 0) return 31; /*error: invalid color type*/ + + if(strategy == LFS_ZERO) + { + for(y = 0; y < h; y++) + { + size_t outindex = (1 + linebytes) * y; /*the extra filterbyte added to each row*/ + size_t inindex = linebytes * y; + out[outindex] = 0; /*filter type byte*/ + filterScanline(&out[outindex + 1], &in[inindex], prevline, linebytes, bytewidth, 0); + prevline = &in[inindex]; + } + } + else if(strategy == LFS_MINSUM) + { + /*adaptive filtering*/ + size_t sum[5]; + ucvector attempt[5]; /*five filtering attempts, one for each filter type*/ + size_t smallest = 0; + unsigned char type, bestType = 0; + + for(type = 0; type < 5; type++) + { + ucvector_init(&attempt[type]); + if(!ucvector_resize(&attempt[type], linebytes)) return 83; /*alloc fail*/ + } + + if(!error) + { + for(y = 0; y < h; y++) + { + /*try the 5 filter types*/ + for(type = 0; type < 5; type++) + { + filterScanline(attempt[type].data, &in[y * linebytes], prevline, linebytes, bytewidth, type); + + /*calculate the sum of the result*/ + sum[type] = 0; + if(type == 0) + { + for(x = 0; x < linebytes; x++) sum[type] += (unsigned char)(attempt[type].data[x]); + } + else + { + for(x = 0; x < linebytes; x++) + { + /*For differences, each byte should be treated as signed, values above 127 are negative + (converted to signed char). Filtertype 0 isn't a difference though, so use unsigned there. + This means filtertype 0 is almost never chosen, but that is justified.*/ + unsigned char s = attempt[type].data[x]; + sum[type] += s < 128 ? s : (255U - s); + } + } + + /*check if this is smallest sum (or if type == 0 it's the first case so always store the values)*/ + if(type == 0 || sum[type] < smallest) + { + bestType = type; + smallest = sum[type]; + } + } + + prevline = &in[y * linebytes]; + + /*now fill the out values*/ + out[y * (linebytes + 1)] = bestType; /*the first byte of a scanline will be the filter type*/ + for(x = 0; x < linebytes; x++) out[y * (linebytes + 1) + 1 + x] = attempt[bestType].data[x]; + } + } + + for(type = 0; type < 5; type++) ucvector_cleanup(&attempt[type]); + } + else if(strategy == LFS_ENTROPY) + { + float sum[5]; + ucvector attempt[5]; /*five filtering attempts, one for each filter type*/ + float smallest = 0; + unsigned type, bestType = 0; + unsigned count[256]; + + for(type = 0; type < 5; type++) + { + ucvector_init(&attempt[type]); + if(!ucvector_resize(&attempt[type], linebytes)) return 83; /*alloc fail*/ + } + + for(y = 0; y < h; y++) + { + /*try the 5 filter types*/ + for(type = 0; type < 5; type++) + { + filterScanline(attempt[type].data, &in[y * linebytes], prevline, linebytes, bytewidth, type); + for(x = 0; x < 256; x++) count[x] = 0; + for(x = 0; x < linebytes; x++) count[attempt[type].data[x]]++; + count[type]++; /*the filter type itself is part of the scanline*/ + sum[type] = 0; + for(x = 0; x < 256; x++) + { + float p = count[x] / (float)(linebytes + 1); + sum[type] += count[x] == 0 ? 0 : flog2(1 / p) * p; + } + /*check if this is smallest sum (or if type == 0 it's the first case so always store the values)*/ + if(type == 0 || sum[type] < smallest) + { + bestType = type; + smallest = sum[type]; + } + } + + prevline = &in[y * linebytes]; + + /*now fill the out values*/ + out[y * (linebytes + 1)] = bestType; /*the first byte of a scanline will be the filter type*/ + for(x = 0; x < linebytes; x++) out[y * (linebytes + 1) + 1 + x] = attempt[bestType].data[x]; + } + + for(type = 0; type < 5; type++) ucvector_cleanup(&attempt[type]); + } + else if(strategy == LFS_PREDEFINED) + { + for(y = 0; y < h; y++) + { + size_t outindex = (1 + linebytes) * y; /*the extra filterbyte added to each row*/ + size_t inindex = linebytes * y; + unsigned char type = settings->predefined_filters[y]; + out[outindex] = type; /*filter type byte*/ + filterScanline(&out[outindex + 1], &in[inindex], prevline, linebytes, bytewidth, type); + prevline = &in[inindex]; + } + } + else if(strategy == LFS_BRUTE_FORCE) + { + /*brute force filter chooser. + deflate the scanline after every filter attempt to see which one deflates best. + This is very slow and gives only slightly smaller, sometimes even larger, result*/ + size_t size[5]; + ucvector attempt[5]; /*five filtering attempts, one for each filter type*/ + size_t smallest = 0; + unsigned type = 0, bestType = 0; + unsigned char* dummy; + LodePNGCompressSettings zlibsettings = settings->zlibsettings; + /*use fixed tree on the attempts so that the tree is not adapted to the filtertype on purpose, + to simulate the true case where the tree is the same for the whole image. Sometimes it gives + better result with dynamic tree anyway. Using the fixed tree sometimes gives worse, but in rare + cases better compression. It does make this a bit less slow, so it's worth doing this.*/ + zlibsettings.btype = 1; + /*a custom encoder likely doesn't read the btype setting and is optimized for complete PNG + images only, so disable it*/ + zlibsettings.custom_zlib = 0; + zlibsettings.custom_deflate = 0; + for(type = 0; type < 5; type++) + { + ucvector_init(&attempt[type]); + ucvector_resize(&attempt[type], linebytes); /*todo: give error if resize failed*/ + } + for(y = 0; y < h; y++) /*try the 5 filter types*/ + { + for(type = 0; type < 5; type++) + { + unsigned testsize = attempt[type].size; + /*if(testsize > 8) testsize /= 8;*/ /*it already works good enough by testing a part of the row*/ + + filterScanline(attempt[type].data, &in[y * linebytes], prevline, linebytes, bytewidth, type); + size[type] = 0; + dummy = 0; + zlib_compress(&dummy, &size[type], attempt[type].data, testsize, &zlibsettings); + lodepng_free(dummy); + /*check if this is smallest size (or if type == 0 it's the first case so always store the values)*/ + if(type == 0 || size[type] < smallest) + { + bestType = type; + smallest = size[type]; + } + } + prevline = &in[y * linebytes]; + out[y * (linebytes + 1)] = bestType; /*the first byte of a scanline will be the filter type*/ + for(x = 0; x < linebytes; x++) out[y * (linebytes + 1) + 1 + x] = attempt[bestType].data[x]; + } + for(type = 0; type < 5; type++) ucvector_cleanup(&attempt[type]); + } + else return 88; /* unknown filter strategy */ + + return error; +} + +static void addPaddingBits(unsigned char* out, const unsigned char* in, + size_t olinebits, size_t ilinebits, unsigned h) +{ + /*The opposite of the removePaddingBits function + olinebits must be >= ilinebits*/ + unsigned y; + size_t diff = olinebits - ilinebits; + size_t obp = 0, ibp = 0; /*bit pointers*/ + for(y = 0; y < h; y++) + { + size_t x; + for(x = 0; x < ilinebits; x++) + { + unsigned char bit = readBitFromReversedStream(&ibp, in); + setBitOfReversedStream(&obp, out, bit); + } + /*obp += diff; --> no, fill in some value in the padding bits too, to avoid + "Use of uninitialised value of size ###" warning from valgrind*/ + for(x = 0; x < diff; x++) setBitOfReversedStream(&obp, out, 0); + } +} + +/* +in: non-interlaced image with size w*h +out: the same pixels, but re-ordered according to PNG's Adam7 interlacing, with + no padding bits between scanlines, but between reduced images so that each + reduced image starts at a byte. +bpp: bits per pixel +there are no padding bits, not between scanlines, not between reduced images +in has the following size in bits: w * h * bpp. +out is possibly bigger due to padding bits between reduced images +NOTE: comments about padding bits are only relevant if bpp < 8 +*/ +static void Adam7_interlace(unsigned char* out, const unsigned char* in, unsigned w, unsigned h, unsigned bpp) +{ + unsigned passw[7], passh[7]; + size_t filter_passstart[8], padded_passstart[8], passstart[8]; + unsigned i; + + Adam7_getpassvalues(passw, passh, filter_passstart, padded_passstart, passstart, w, h, bpp); + + if(bpp >= 8) + { + for(i = 0; i < 7; i++) + { + unsigned x, y, b; + size_t bytewidth = bpp / 8; + for(y = 0; y < passh[i]; y++) + for(x = 0; x < passw[i]; x++) + { + size_t pixelinstart = ((ADAM7_IY[i] + y * ADAM7_DY[i]) * w + ADAM7_IX[i] + x * ADAM7_DX[i]) * bytewidth; + size_t pixeloutstart = passstart[i] + (y * passw[i] + x) * bytewidth; + for(b = 0; b < bytewidth; b++) + { + out[pixeloutstart + b] = in[pixelinstart + b]; + } + } + } + } + else /*bpp < 8: Adam7 with pixels < 8 bit is a bit trickier: with bit pointers*/ + { + for(i = 0; i < 7; i++) + { + unsigned x, y, b; + unsigned ilinebits = bpp * passw[i]; + unsigned olinebits = bpp * w; + size_t obp, ibp; /*bit pointers (for out and in buffer)*/ + for(y = 0; y < passh[i]; y++) + for(x = 0; x < passw[i]; x++) + { + ibp = (ADAM7_IY[i] + y * ADAM7_DY[i]) * olinebits + (ADAM7_IX[i] + x * ADAM7_DX[i]) * bpp; + obp = (8 * passstart[i]) + (y * ilinebits + x * bpp); + for(b = 0; b < bpp; b++) + { + unsigned char bit = readBitFromReversedStream(&ibp, in); + setBitOfReversedStream(&obp, out, bit); + } + } + } + } +} + +/*out must be buffer big enough to contain uncompressed IDAT chunk data, and in must contain the full image. +return value is error**/ +static unsigned preProcessScanlines(unsigned char** out, size_t* outsize, const unsigned char* in, + unsigned w, unsigned h, + const LodePNGInfo* info_png, const LodePNGEncoderSettings* settings) +{ + /* + This function converts the pure 2D image with the PNG's colortype, into filtered-padded-interlaced data. Steps: + *) if no Adam7: 1) add padding bits (= posible extra bits per scanline if bpp < 8) 2) filter + *) if adam7: 1) Adam7_interlace 2) 7x add padding bits 3) 7x filter + */ + unsigned bpp = lodepng_get_bpp(&info_png->color); + unsigned error = 0; + + if(info_png->interlace_method == 0) + { + *outsize = h + (h * ((w * bpp + 7) / 8)); /*image size plus an extra byte per scanline + possible padding bits*/ + *out = (unsigned char*)lodepng_malloc(*outsize); + if(!(*out) && (*outsize)) error = 83; /*alloc fail*/ + + if(!error) + { + /*non multiple of 8 bits per scanline, padding bits needed per scanline*/ + if(bpp < 8 && w * bpp != ((w * bpp + 7) / 8) * 8) + { + unsigned char* padded = (unsigned char*)lodepng_malloc(h * ((w * bpp + 7) / 8)); + if(!padded) error = 83; /*alloc fail*/ + if(!error) + { + addPaddingBits(padded, in, ((w * bpp + 7) / 8) * 8, w * bpp, h); + error = filter(*out, padded, w, h, &info_png->color, settings); + } + lodepng_free(padded); + } + else + { + /*we can immediatly filter into the out buffer, no other steps needed*/ + error = filter(*out, in, w, h, &info_png->color, settings); + } + } + } + else /*interlace_method is 1 (Adam7)*/ + { + unsigned passw[7], passh[7]; + size_t filter_passstart[8], padded_passstart[8], passstart[8]; + unsigned char* adam7; + + Adam7_getpassvalues(passw, passh, filter_passstart, padded_passstart, passstart, w, h, bpp); + + *outsize = filter_passstart[7]; /*image size plus an extra byte per scanline + possible padding bits*/ + *out = (unsigned char*)lodepng_malloc(*outsize); + if(!(*out)) error = 83; /*alloc fail*/ + + adam7 = (unsigned char*)lodepng_malloc(passstart[7]); + if(!adam7 && passstart[7]) error = 83; /*alloc fail*/ + + if(!error) + { + unsigned i; + + Adam7_interlace(adam7, in, w, h, bpp); + for(i = 0; i < 7; i++) + { + if(bpp < 8) + { + unsigned char* padded = (unsigned char*)lodepng_malloc(padded_passstart[i + 1] - padded_passstart[i]); + if(!padded) ERROR_BREAK(83); /*alloc fail*/ + addPaddingBits(padded, &adam7[passstart[i]], + ((passw[i] * bpp + 7) / 8) * 8, passw[i] * bpp, passh[i]); + error = filter(&(*out)[filter_passstart[i]], padded, + passw[i], passh[i], &info_png->color, settings); + lodepng_free(padded); + } + else + { + error = filter(&(*out)[filter_passstart[i]], &adam7[padded_passstart[i]], + passw[i], passh[i], &info_png->color, settings); + } + + if(error) break; + } + } + + lodepng_free(adam7); + } + + return error; +} + +/* +palette must have 4 * palettesize bytes allocated, and given in format RGBARGBARGBARGBA... +returns 0 if the palette is opaque, +returns 1 if the palette has a single color with alpha 0 ==> color key +returns 2 if the palette is semi-translucent. +*/ +static unsigned getPaletteTranslucency(const unsigned char* palette, size_t palettesize) +{ + size_t i; + unsigned key = 0; + unsigned r = 0, g = 0, b = 0; /*the value of the color with alpha 0, so long as color keying is possible*/ + for(i = 0; i < palettesize; i++) + { + if(!key && palette[4 * i + 3] == 0) + { + r = palette[4 * i + 0]; g = palette[4 * i + 1]; b = palette[4 * i + 2]; + key = 1; + i = (size_t)(-1); /*restart from beginning, to detect earlier opaque colors with key's value*/ + } + else if(palette[4 * i + 3] != 255) return 2; + /*when key, no opaque RGB may have key's RGB*/ + else if(key && r == palette[i * 4 + 0] && g == palette[i * 4 + 1] && b == palette[i * 4 + 2]) return 2; + } + return key; +} + +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS +static unsigned addUnknownChunks(ucvector* out, unsigned char* data, size_t datasize) +{ + unsigned char* inchunk = data; + while((size_t)(inchunk - data) < datasize) + { + CERROR_TRY_RETURN(lodepng_chunk_append(&out->data, &out->size, inchunk)); + out->allocsize = out->size; /*fix the allocsize again*/ + inchunk = lodepng_chunk_next(inchunk); + } + return 0; +} +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + +unsigned lodepng_encode(unsigned char** out, size_t* outsize, + const unsigned char* image, unsigned w, unsigned h, + LodePNGState* state) +{ + LodePNGInfo info; + ucvector outv; + unsigned char* data = 0; /*uncompressed version of the IDAT chunk data*/ + size_t datasize = 0; + + /*provide some proper output values if error will happen*/ + *out = 0; + *outsize = 0; + state->error = 0; + + lodepng_info_init(&info); + lodepng_info_copy(&info, &state->info_png); + + if((info.color.colortype == LCT_PALETTE || state->encoder.force_palette) + && (info.color.palettesize == 0 || info.color.palettesize > 256)) + { + state->error = 68; /*invalid palette size, it is only allowed to be 1-256*/ + return state->error; + } + + if(state->encoder.auto_convert != LAC_NO) + { + state->error = lodepng_auto_choose_color(&info.color, image, w, h, &state->info_raw, + state->encoder.auto_convert); + } + if(state->error) return state->error; + + if(state->encoder.zlibsettings.btype > 2) + { + CERROR_RETURN_ERROR(state->error, 61); /*error: unexisting btype*/ + } + if(state->info_png.interlace_method > 1) + { + CERROR_RETURN_ERROR(state->error, 71); /*error: unexisting interlace mode*/ + } + + state->error = checkColorValidity(info.color.colortype, info.color.bitdepth); + if(state->error) return state->error; /*error: unexisting color type given*/ + state->error = checkColorValidity(state->info_raw.colortype, state->info_raw.bitdepth); + if(state->error) return state->error; /*error: unexisting color type given*/ + + if(!lodepng_color_mode_equal(&state->info_raw, &info.color)) + { + unsigned char* converted; + size_t size = (w * h * lodepng_get_bpp(&info.color) + 7) / 8; + + converted = (unsigned char*)lodepng_malloc(size); + if(!converted && size) state->error = 83; /*alloc fail*/ + if(!state->error) + { + state->error = lodepng_convert(converted, image, &info.color, &state->info_raw, w, h, 0 /*fix_png*/); + } + if(!state->error) preProcessScanlines(&data, &datasize, converted, w, h, &info, &state->encoder); + lodepng_free(converted); + } + else preProcessScanlines(&data, &datasize, image, w, h, &info, &state->encoder); + + ucvector_init(&outv); + while(!state->error) /*while only executed once, to break on error*/ + { +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + size_t i; +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + /*write signature and chunks*/ + writeSignature(&outv); + /*IHDR*/ + addChunk_IHDR(&outv, w, h, info.color.colortype, info.color.bitdepth, info.interlace_method); +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + /*unknown chunks between IHDR and PLTE*/ + if(info.unknown_chunks_data[0]) + { + state->error = addUnknownChunks(&outv, info.unknown_chunks_data[0], info.unknown_chunks_size[0]); + if(state->error) break; + } +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + /*PLTE*/ + if(info.color.colortype == LCT_PALETTE) + { + addChunk_PLTE(&outv, &info.color); + } + if(state->encoder.force_palette && (info.color.colortype == LCT_RGB || info.color.colortype == LCT_RGBA)) + { + addChunk_PLTE(&outv, &info.color); + } + /*tRNS*/ + if(info.color.colortype == LCT_PALETTE && getPaletteTranslucency(info.color.palette, info.color.palettesize) != 0) + { + addChunk_tRNS(&outv, &info.color); + } + if((info.color.colortype == LCT_GREY || info.color.colortype == LCT_RGB) && info.color.key_defined) + { + addChunk_tRNS(&outv, &info.color); + } +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + /*bKGD (must come between PLTE and the IDAt chunks*/ + if(info.background_defined) addChunk_bKGD(&outv, &info); + /*pHYs (must come before the IDAT chunks)*/ + if(info.phys_defined) addChunk_pHYs(&outv, &info); + + /*unknown chunks between PLTE and IDAT*/ + if(info.unknown_chunks_data[1]) + { + state->error = addUnknownChunks(&outv, info.unknown_chunks_data[1], info.unknown_chunks_size[1]); + if(state->error) break; + } +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + /*IDAT (multiple IDAT chunks must be consecutive)*/ + state->error = addChunk_IDAT(&outv, data, datasize, &state->encoder.zlibsettings); + if(state->error) break; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + /*tIME*/ + if(info.time_defined) addChunk_tIME(&outv, &info.time); + /*tEXt and/or zTXt*/ + for(i = 0; i < info.text_num; i++) + { + if(strlen(info.text_keys[i]) > 79) + { + state->error = 66; /*text chunk too large*/ + break; + } + if(strlen(info.text_keys[i]) < 1) + { + state->error = 67; /*text chunk too small*/ + break; + } + if(state->encoder.text_compression) + { + addChunk_zTXt(&outv, info.text_keys[i], info.text_strings[i], &state->encoder.zlibsettings); + } + else + { + addChunk_tEXt(&outv, info.text_keys[i], info.text_strings[i]); + } + } + /*LodePNG version id in text chunk*/ + if(state->encoder.add_id) + { + unsigned alread_added_id_text = 0; + for(i = 0; i < info.text_num; i++) + { + if(!strcmp(info.text_keys[i], "LodePNG")) + { + alread_added_id_text = 1; + break; + } + } + if(alread_added_id_text == 0) + { + addChunk_tEXt(&outv, "LodePNG", VERSION_STRING); /*it's shorter as tEXt than as zTXt chunk*/ + } + } + /*iTXt*/ + for(i = 0; i < info.itext_num; i++) + { + if(strlen(info.itext_keys[i]) > 79) + { + state->error = 66; /*text chunk too large*/ + break; + } + if(strlen(info.itext_keys[i]) < 1) + { + state->error = 67; /*text chunk too small*/ + break; + } + addChunk_iTXt(&outv, state->encoder.text_compression, + info.itext_keys[i], info.itext_langtags[i], info.itext_transkeys[i], info.itext_strings[i], + &state->encoder.zlibsettings); + } + + /*unknown chunks between IDAT and IEND*/ + if(info.unknown_chunks_data[2]) + { + state->error = addUnknownChunks(&outv, info.unknown_chunks_data[2], info.unknown_chunks_size[2]); + if(state->error) break; + } +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + addChunk_IEND(&outv); + + break; /*this isn't really a while loop; no error happened so break out now!*/ + } + + lodepng_info_cleanup(&info); + lodepng_free(data); + /*instead of cleaning the vector up, give it to the output*/ + *out = outv.data; + *outsize = outv.size; + + return state->error; +} + +unsigned lodepng_encode_memory(unsigned char** out, size_t* outsize, const unsigned char* image, + unsigned w, unsigned h, LodePNGColorType colortype, unsigned bitdepth) +{ + unsigned error; + LodePNGState state; + lodepng_state_init(&state); + state.info_raw.colortype = colortype; + state.info_raw.bitdepth = bitdepth; + state.info_png.color.colortype = colortype; + state.info_png.color.bitdepth = bitdepth; + lodepng_encode(out, outsize, image, w, h, &state); + error = state.error; + lodepng_state_cleanup(&state); + return error; +} + +unsigned lodepng_encode32(unsigned char** out, size_t* outsize, const unsigned char* image, unsigned w, unsigned h) +{ + return lodepng_encode_memory(out, outsize, image, w, h, LCT_RGBA, 8); +} + +unsigned lodepng_encode24(unsigned char** out, size_t* outsize, const unsigned char* image, unsigned w, unsigned h) +{ + return lodepng_encode_memory(out, outsize, image, w, h, LCT_RGB, 8); +} + +#ifdef LODEPNG_COMPILE_DISK +unsigned lodepng_encode_file(const char* filename, const unsigned char* image, unsigned w, unsigned h, + LodePNGColorType colortype, unsigned bitdepth) +{ + unsigned char* buffer; + size_t buffersize; + unsigned error = lodepng_encode_memory(&buffer, &buffersize, image, w, h, colortype, bitdepth); + if(!error) error = lodepng_save_file(buffer, buffersize, filename); + lodepng_free(buffer); + return error; +} + +unsigned lodepng_encode32_file(const char* filename, const unsigned char* image, unsigned w, unsigned h) +{ + return lodepng_encode_file(filename, image, w, h, LCT_RGBA, 8); +} + +unsigned lodepng_encode24_file(const char* filename, const unsigned char* image, unsigned w, unsigned h) +{ + return lodepng_encode_file(filename, image, w, h, LCT_RGB, 8); +} +#endif /*LODEPNG_COMPILE_DISK*/ + +void lodepng_encoder_settings_init(LodePNGEncoderSettings* settings) +{ + lodepng_compress_settings_init(&settings->zlibsettings); + settings->filter_palette_zero = 1; + settings->filter_strategy = LFS_MINSUM; + settings->auto_convert = LAC_AUTO; + settings->force_palette = 0; + settings->predefined_filters = 0; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + settings->add_id = 0; + settings->text_compression = 1; +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ +} + +#endif /*LODEPNG_COMPILE_ENCODER*/ +#endif /*LODEPNG_COMPILE_PNG*/ + +#ifdef LODEPNG_COMPILE_ERROR_TEXT +/* +This returns the description of a numerical error code in English. This is also +the documentation of all the error codes. +*/ +const char* lodepng_error_text(unsigned code) +{ + switch(code) + { + case 0: return "no error, everything went ok"; + case 1: return "nothing done yet"; /*the Encoder/Decoder has done nothing yet, error checking makes no sense yet*/ + case 10: return "end of input memory reached without huffman end code"; /*while huffman decoding*/ + case 11: return "error in code tree made it jump outside of huffman tree"; /*while huffman decoding*/ + case 13: return "problem while processing dynamic deflate block"; + case 14: return "problem while processing dynamic deflate block"; + case 15: return "problem while processing dynamic deflate block"; + case 16: return "unexisting code while processing dynamic deflate block"; + case 17: return "end of out buffer memory reached while inflating"; + case 18: return "invalid distance code while inflating"; + case 19: return "end of out buffer memory reached while inflating"; + case 20: return "invalid deflate block BTYPE encountered while decoding"; + case 21: return "NLEN is not ones complement of LEN in a deflate block"; + /*end of out buffer memory reached while inflating: + This can happen if the inflated deflate data is longer than the amount of bytes required to fill up + all the pixels of the image, given the color depth and image dimensions. Something that doesn't + happen in a normal, well encoded, PNG image.*/ + case 22: return "end of out buffer memory reached while inflating"; + case 23: return "end of in buffer memory reached while inflating"; + case 24: return "invalid FCHECK in zlib header"; + case 25: return "invalid compression method in zlib header"; + case 26: return "FDICT encountered in zlib header while it's not used for PNG"; + case 27: return "PNG file is smaller than a PNG header"; + /*Checks the magic file header, the first 8 bytes of the PNG file*/ + case 28: return "incorrect PNG signature, it's no PNG or corrupted"; + case 29: return "first chunk is not the header chunk"; + case 30: return "chunk length too large, chunk broken off at end of file"; + case 31: return "illegal PNG color type or bpp"; + case 32: return "illegal PNG compression method"; + case 33: return "illegal PNG filter method"; + case 34: return "illegal PNG interlace method"; + case 35: return "chunk length of a chunk is too large or the chunk too small"; + case 36: return "illegal PNG filter type encountered"; + case 37: return "illegal bit depth for this color type given"; + case 38: return "the palette is too big"; /*more than 256 colors*/ + case 39: return "more palette alpha values given in tRNS chunk than there are colors in the palette"; + case 40: return "tRNS chunk has wrong size for greyscale image"; + case 41: return "tRNS chunk has wrong size for RGB image"; + case 42: return "tRNS chunk appeared while it was not allowed for this color type"; + case 43: return "bKGD chunk has wrong size for palette image"; + case 44: return "bKGD chunk has wrong size for greyscale image"; + case 45: return "bKGD chunk has wrong size for RGB image"; + /*Is the palette too small?*/ + case 46: return "a value in indexed image is larger than the palette size (bitdepth = 8)"; + /*Is the palette too small?*/ + case 47: return "a value in indexed image is larger than the palette size (bitdepth < 8)"; + /*the input data is empty, maybe a PNG file doesn't exist or is in the wrong path*/ + case 48: return "empty input or file doesn't exist"; + case 49: return "jumped past memory while generating dynamic huffman tree"; + case 50: return "jumped past memory while generating dynamic huffman tree"; + case 51: return "jumped past memory while inflating huffman block"; + case 52: return "jumped past memory while inflating"; + case 53: return "size of zlib data too small"; + case 54: return "repeat symbol in tree while there was no value symbol yet"; + /*jumped past tree while generating huffman tree, this could be when the + tree will have more leaves than symbols after generating it out of the + given lenghts. They call this an oversubscribed dynamic bit lengths tree in zlib.*/ + case 55: return "jumped past tree while generating huffman tree"; + case 56: return "given output image colortype or bitdepth not supported for color conversion"; + case 57: return "invalid CRC encountered (checking CRC can be disabled)"; + case 58: return "invalid ADLER32 encountered (checking ADLER32 can be disabled)"; + case 59: return "requested color conversion not supported"; + case 60: return "invalid window size given in the settings of the encoder (must be 0-32768)"; + case 61: return "invalid BTYPE given in the settings of the encoder (only 0, 1 and 2 are allowed)"; + /*LodePNG leaves the choice of RGB to greyscale conversion formula to the user.*/ + case 62: return "conversion from color to greyscale not supported"; + case 63: return "length of a chunk too long, max allowed for PNG is 2147483647 bytes per chunk"; /*(2^31-1)*/ + /*this would result in the inability of a deflated block to ever contain an end code. It must be at least 1.*/ + case 64: return "the length of the END symbol 256 in the Huffman tree is 0"; + case 66: return "the length of a text chunk keyword given to the encoder is longer than the maximum of 79 bytes"; + case 67: return "the length of a text chunk keyword given to the encoder is smaller than the minimum of 1 byte"; + case 68: return "tried to encode a PLTE chunk with a palette that has less than 1 or more than 256 colors"; + case 69: return "unknown chunk type with 'critical' flag encountered by the decoder"; + case 71: return "unexisting interlace mode given to encoder (must be 0 or 1)"; + case 72: return "while decoding, unexisting compression method encountering in zTXt or iTXt chunk (it must be 0)"; + case 73: return "invalid tIME chunk size"; + case 74: return "invalid pHYs chunk size"; + /*length could be wrong, or data chopped off*/ + case 75: return "no null termination char found while decoding text chunk"; + case 76: return "iTXt chunk too short to contain required bytes"; + case 77: return "integer overflow in buffer size"; + case 78: return "failed to open file for reading"; /*file doesn't exist or couldn't be opened for reading*/ + case 79: return "failed to open file for writing"; + case 80: return "tried creating a tree of 0 symbols"; + case 81: return "lazy matching at pos 0 is impossible"; + case 82: return "color conversion to palette requested while a color isn't in palette"; + case 83: return "memory allocation failed"; + case 84: return "given image too small to contain all pixels to be encoded"; + case 85: return "internal color conversion bug"; + case 86: return "impossible offset in lz77 encoding (internal bug)"; + case 87: return "must provide custom zlib function pointer if LODEPNG_COMPILE_ZLIB is not defined"; + case 88: return "invalid filter strategy given for LodePNGEncoderSettings.filter_strategy"; + case 89: return "text chunk keyword too short or long: must have size 1-79"; + /*the windowsize in the LodePNGCompressSettings. Requiring POT(==> & instead of %) makes encoding 12% faster.*/ + case 90: return "windowsize must be a power of two"; + } + return "unknown error code"; +} +#endif /*LODEPNG_COMPILE_ERROR_TEXT*/ + +/* ////////////////////////////////////////////////////////////////////////// */ +/* ////////////////////////////////////////////////////////////////////////// */ +/* // C++ Wrapper // */ +/* ////////////////////////////////////////////////////////////////////////// */ +/* ////////////////////////////////////////////////////////////////////////// */ + +#ifdef LODEPNG_COMPILE_CPP +namespace lodepng +{ + +#ifdef LODEPNG_COMPILE_DISK +void load_file(std::vector& buffer, const std::string& filename) +{ + std::ifstream file(filename.c_str(), std::ios::in|std::ios::binary|std::ios::ate); + + /*get filesize*/ + std::streamsize size = 0; + if(file.seekg(0, std::ios::end).good()) size = file.tellg(); + if(file.seekg(0, std::ios::beg).good()) size -= file.tellg(); + + /*read contents of the file into the vector*/ + buffer.resize(size_t(size)); + if(size > 0) file.read((char*)(&buffer[0]), size); +} + +/*write given buffer to the file, overwriting the file, it doesn't append to it.*/ +void save_file(const std::vector& buffer, const std::string& filename) +{ + std::ofstream file(filename.c_str(), std::ios::out|std::ios::binary); + file.write(buffer.empty() ? 0 : (char*)&buffer[0], std::streamsize(buffer.size())); +} +#endif //LODEPNG_COMPILE_DISK + +#ifdef LODEPNG_COMPILE_ZLIB +#ifdef LODEPNG_COMPILE_DECODER +unsigned decompress(std::vector& out, const unsigned char* in, size_t insize, + const LodePNGDecompressSettings& settings) +{ + unsigned char* buffer = 0; + size_t buffersize = 0; + unsigned error = zlib_decompress(&buffer, &buffersize, in, insize, &settings); + if(buffer) + { + out.insert(out.end(), &buffer[0], &buffer[buffersize]); + lodepng_free(buffer); + } + return error; +} + +unsigned decompress(std::vector& out, const std::vector& in, + const LodePNGDecompressSettings& settings) +{ + return decompress(out, in.empty() ? 0 : &in[0], in.size(), settings); +} +#endif //LODEPNG_COMPILE_DECODER + +#ifdef LODEPNG_COMPILE_ENCODER +unsigned compress(std::vector& out, const unsigned char* in, size_t insize, + const LodePNGCompressSettings& settings) +{ + unsigned char* buffer = 0; + size_t buffersize = 0; + unsigned error = zlib_compress(&buffer, &buffersize, in, insize, &settings); + if(buffer) + { + out.insert(out.end(), &buffer[0], &buffer[buffersize]); + lodepng_free(buffer); + } + return error; +} + +unsigned compress(std::vector& out, const std::vector& in, + const LodePNGCompressSettings& settings) +{ + return compress(out, in.empty() ? 0 : &in[0], in.size(), settings); +} +#endif //LODEPNG_COMPILE_ENCODER +#endif //LODEPNG_COMPILE_ZLIB + + +#ifdef LODEPNG_COMPILE_PNG + +State::State() +{ + lodepng_state_init(this); +} + +State::State(const State& other) +{ + lodepng_state_init(this); + lodepng_state_copy(this, &other); +} + +State::~State() +{ + lodepng_state_cleanup(this); +} + +State& State::operator=(const State& other) +{ + lodepng_state_copy(this, &other); + return *this; +} + +#ifdef LODEPNG_COMPILE_DECODER + +unsigned decode(std::vector& out, unsigned& w, unsigned& h, const unsigned char* in, + size_t insize, LodePNGColorType colortype, unsigned bitdepth) +{ + unsigned char* buffer; + unsigned error = lodepng_decode_memory(&buffer, &w, &h, in, insize, colortype, bitdepth); + if(buffer && !error) + { + State state; + state.info_raw.colortype = colortype; + state.info_raw.bitdepth = bitdepth; + size_t buffersize = lodepng_get_raw_size(w, h, &state.info_raw); + out.insert(out.end(), &buffer[0], &buffer[buffersize]); + lodepng_free(buffer); + } + return error; +} + +unsigned decode(std::vector& out, unsigned& w, unsigned& h, + const std::vector& in, LodePNGColorType colortype, unsigned bitdepth) +{ + return decode(out, w, h, in.empty() ? 0 : &in[0], (unsigned)in.size(), colortype, bitdepth); +} + +unsigned decode(std::vector& out, unsigned& w, unsigned& h, + State& state, + const unsigned char* in, size_t insize) +{ + unsigned char* buffer = NULL; + unsigned error = lodepng_decode(&buffer, &w, &h, &state, in, insize); + if(buffer && !error) + { + size_t buffersize = lodepng_get_raw_size(w, h, &state.info_raw); + out.insert(out.end(), &buffer[0], &buffer[buffersize]); + } + lodepng_free(buffer); + return error; +} + +unsigned decode(std::vector& out, unsigned& w, unsigned& h, + State& state, + const std::vector& in) +{ + return decode(out, w, h, state, in.empty() ? 0 : &in[0], in.size()); +} + +#ifdef LODEPNG_COMPILE_DISK +unsigned decode(std::vector& out, unsigned& w, unsigned& h, const std::string& filename, + LodePNGColorType colortype, unsigned bitdepth) +{ + std::vector buffer; + load_file(buffer, filename); + return decode(out, w, h, buffer, colortype, bitdepth); +} +#endif //LODEPNG_COMPILE_DECODER +#endif //LODEPNG_COMPILE_DISK + +#ifdef LODEPNG_COMPILE_ENCODER +unsigned encode(std::vector& out, const unsigned char* in, unsigned w, unsigned h, + LodePNGColorType colortype, unsigned bitdepth) +{ + unsigned char* buffer; + size_t buffersize; + unsigned error = lodepng_encode_memory(&buffer, &buffersize, in, w, h, colortype, bitdepth); + if(buffer) + { + out.insert(out.end(), &buffer[0], &buffer[buffersize]); + lodepng_free(buffer); + } + return error; +} + +unsigned encode(std::vector& out, + const std::vector& in, unsigned w, unsigned h, + LodePNGColorType colortype, unsigned bitdepth) +{ + if(lodepng_get_raw_size_lct(w, h, colortype, bitdepth) > in.size()) return 84; + return encode(out, in.empty() ? 0 : &in[0], w, h, colortype, bitdepth); +} + +unsigned encode(std::vector& out, + const unsigned char* in, unsigned w, unsigned h, + State& state) +{ + unsigned char* buffer; + size_t buffersize; + unsigned error = lodepng_encode(&buffer, &buffersize, in, w, h, &state); + if(buffer) + { + out.insert(out.end(), &buffer[0], &buffer[buffersize]); + lodepng_free(buffer); + } + return error; +} + +unsigned encode(std::vector& out, + const std::vector& in, unsigned w, unsigned h, + State& state) +{ + if(lodepng_get_raw_size(w, h, &state.info_raw) > in.size()) return 84; + return encode(out, in.empty() ? 0 : &in[0], w, h, state); +} + +#ifdef LODEPNG_COMPILE_DISK +unsigned encode(const std::string& filename, + const unsigned char* in, unsigned w, unsigned h, + LodePNGColorType colortype, unsigned bitdepth) +{ + std::vector buffer; + unsigned error = encode(buffer, in, w, h, colortype, bitdepth); + if(!error) save_file(buffer, filename); + return error; +} + +unsigned encode(const std::string& filename, + const std::vector& in, unsigned w, unsigned h, + LodePNGColorType colortype, unsigned bitdepth) +{ + if(lodepng_get_raw_size_lct(w, h, colortype, bitdepth) > in.size()) return 84; + return encode(filename, in.empty() ? 0 : &in[0], w, h, colortype, bitdepth); +} +#endif //LODEPNG_COMPILE_DISK +#endif //LODEPNG_COMPILE_ENCODER +#endif //LODEPNG_COMPILE_PNG +} //namespace lodepng +#endif /*LODEPNG_COMPILE_CPP*/ diff --git a/GameLib/lodepng.h b/GameLib/lodepng.h new file mode 100644 index 0000000..a4f5bd2 --- /dev/null +++ b/GameLib/lodepng.h @@ -0,0 +1,1710 @@ +/* +LodePNG version 20140624 + +Copyright (c) 2005-2014 Lode Vandevenne + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. +*/ + +#ifndef LODEPNG_H +#define LODEPNG_H + +#include /*for size_t*/ + +#ifdef __cplusplus +#include +#include +#endif /*__cplusplus*/ + +/* +The following #defines are used to create code sections. They can be disabled +to disable code sections, which can give faster compile time and smaller binary. +The "NO_COMPILE" defines are designed to be used to pass as defines to the +compiler command to disable them without modifying this header, e.g. +-DLODEPNG_NO_COMPILE_ZLIB for gcc. +*/ +/*deflate & zlib. If disabled, you must specify alternative zlib functions in +the custom_zlib field of the compress and decompress settings*/ +#ifndef LODEPNG_NO_COMPILE_ZLIB +#define LODEPNG_COMPILE_ZLIB +#endif +/*png encoder and png decoder*/ +#ifndef LODEPNG_NO_COMPILE_PNG +#define LODEPNG_COMPILE_PNG +#endif +/*deflate&zlib decoder and png decoder*/ +#ifndef LODEPNG_NO_COMPILE_DECODER +#define LODEPNG_COMPILE_DECODER +#endif +/*deflate&zlib encoder and png encoder*/ +#ifndef LODEPNG_NO_COMPILE_ENCODER +#define LODEPNG_COMPILE_ENCODER +#endif +/*the optional built in harddisk file loading and saving functions*/ +#ifndef LODEPNG_NO_COMPILE_DISK +#define LODEPNG_COMPILE_DISK +#endif +/*support for chunks other than IHDR, IDAT, PLTE, tRNS, IEND: ancillary and unknown chunks*/ +#ifndef LODEPNG_NO_COMPILE_ANCILLARY_CHUNKS +#define LODEPNG_COMPILE_ANCILLARY_CHUNKS +#endif +/*ability to convert error numerical codes to English text string*/ +#ifndef LODEPNG_NO_COMPILE_ERROR_TEXT +#define LODEPNG_COMPILE_ERROR_TEXT +#endif +/*Compile the default allocators (C's free, malloc and realloc). If you disable this, +you can define the functions lodepng_free, lodepng_malloc and lodepng_realloc in your +source files with custom allocators.*/ +#ifndef LODEPNG_NO_COMPILE_ALLOCATORS +#define LODEPNG_COMPILE_ALLOCATORS +#endif +/*compile the C++ version (you can disable the C++ wrapper here even when compiling for C++)*/ +#ifdef __cplusplus +#ifndef LODEPNG_NO_COMPILE_CPP +#define LODEPNG_COMPILE_CPP +#endif +#endif + +#ifdef LODEPNG_COMPILE_PNG +/*The PNG color types (also used for raw).*/ +typedef enum LodePNGColorType +{ + LCT_GREY = 0, /*greyscale: 1,2,4,8,16 bit*/ + LCT_RGB = 2, /*RGB: 8,16 bit*/ + LCT_PALETTE = 3, /*palette: 1,2,4,8 bit*/ + LCT_GREY_ALPHA = 4, /*greyscale with alpha: 8,16 bit*/ + LCT_RGBA = 6 /*RGB with alpha: 8,16 bit*/ +} LodePNGColorType; + +#ifdef LODEPNG_COMPILE_DECODER +/* +Converts PNG data in memory to raw pixel data. +out: Output parameter. Pointer to buffer that will contain the raw pixel data. + After decoding, its size is w * h * (bytes per pixel) bytes larger than + initially. Bytes per pixel depends on colortype and bitdepth. + Must be freed after usage with free(*out). + Note: for 16-bit per channel colors, uses big endian format like PNG does. +w: Output parameter. Pointer to width of pixel data. +h: Output parameter. Pointer to height of pixel data. +in: Memory buffer with the PNG file. +insize: size of the in buffer. +colortype: the desired color type for the raw output image. See explanation on PNG color types. +bitdepth: the desired bit depth for the raw output image. See explanation on PNG color types. +Return value: LodePNG error code (0 means no error). +*/ +unsigned lodepng_decode_memory(unsigned char** out, unsigned* w, unsigned* h, + const unsigned char* in, size_t insize, + LodePNGColorType colortype, unsigned bitdepth); + +/*Same as lodepng_decode_memory, but always decodes to 32-bit RGBA raw image*/ +unsigned lodepng_decode32(unsigned char** out, unsigned* w, unsigned* h, + const unsigned char* in, size_t insize); + +/*Same as lodepng_decode_memory, but always decodes to 24-bit RGB raw image*/ +unsigned lodepng_decode24(unsigned char** out, unsigned* w, unsigned* h, + const unsigned char* in, size_t insize); + +#ifdef LODEPNG_COMPILE_DISK +/* +Load PNG from disk, from file with given name. +Same as the other decode functions, but instead takes a filename as input. +*/ +unsigned lodepng_decode_file(unsigned char** out, unsigned* w, unsigned* h, + const char* filename, + LodePNGColorType colortype, unsigned bitdepth); + +/*Same as lodepng_decode_file, but always decodes to 32-bit RGBA raw image.*/ +unsigned lodepng_decode32_file(unsigned char** out, unsigned* w, unsigned* h, + const char* filename); + +/*Same as lodepng_decode_file, but always decodes to 24-bit RGB raw image.*/ +unsigned lodepng_decode24_file(unsigned char** out, unsigned* w, unsigned* h, + const char* filename); +#endif /*LODEPNG_COMPILE_DISK*/ +#endif /*LODEPNG_COMPILE_DECODER*/ + + +#ifdef LODEPNG_COMPILE_ENCODER +/* +Converts raw pixel data into a PNG image in memory. The colortype and bitdepth + of the output PNG image cannot be chosen, they are automatically determined + by the colortype, bitdepth and content of the input pixel data. + Note: for 16-bit per channel colors, needs big endian format like PNG does. +out: Output parameter. Pointer to buffer that will contain the PNG image data. + Must be freed after usage with free(*out). +outsize: Output parameter. Pointer to the size in bytes of the out buffer. +image: The raw pixel data to encode. The size of this buffer should be + w * h * (bytes per pixel), bytes per pixel depends on colortype and bitdepth. +w: width of the raw pixel data in pixels. +h: height of the raw pixel data in pixels. +colortype: the color type of the raw input image. See explanation on PNG color types. +bitdepth: the bit depth of the raw input image. See explanation on PNG color types. +Return value: LodePNG error code (0 means no error). +*/ +unsigned lodepng_encode_memory(unsigned char** out, size_t* outsize, + const unsigned char* image, unsigned w, unsigned h, + LodePNGColorType colortype, unsigned bitdepth); + +/*Same as lodepng_encode_memory, but always encodes from 32-bit RGBA raw image.*/ +unsigned lodepng_encode32(unsigned char** out, size_t* outsize, + const unsigned char* image, unsigned w, unsigned h); + +/*Same as lodepng_encode_memory, but always encodes from 24-bit RGB raw image.*/ +unsigned lodepng_encode24(unsigned char** out, size_t* outsize, + const unsigned char* image, unsigned w, unsigned h); + +#ifdef LODEPNG_COMPILE_DISK +/* +Converts raw pixel data into a PNG file on disk. +Same as the other encode functions, but instead takes a filename as output. +NOTE: This overwrites existing files without warning! +*/ +unsigned lodepng_encode_file(const char* filename, + const unsigned char* image, unsigned w, unsigned h, + LodePNGColorType colortype, unsigned bitdepth); + +/*Same as lodepng_encode_file, but always encodes from 32-bit RGBA raw image.*/ +unsigned lodepng_encode32_file(const char* filename, + const unsigned char* image, unsigned w, unsigned h); + +/*Same as lodepng_encode_file, but always encodes from 24-bit RGB raw image.*/ +unsigned lodepng_encode24_file(const char* filename, + const unsigned char* image, unsigned w, unsigned h); +#endif /*LODEPNG_COMPILE_DISK*/ +#endif /*LODEPNG_COMPILE_ENCODER*/ + + +#ifdef LODEPNG_COMPILE_CPP +namespace lodepng +{ +#ifdef LODEPNG_COMPILE_DECODER +/*Same as lodepng_decode_memory, but decodes to an std::vector.*/ +unsigned decode(std::vector& out, unsigned& w, unsigned& h, + const unsigned char* in, size_t insize, + LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); +unsigned decode(std::vector& out, unsigned& w, unsigned& h, + const std::vector& in, + LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); +#ifdef LODEPNG_COMPILE_DISK +/* +Converts PNG file from disk to raw pixel data in memory. +Same as the other decode functions, but instead takes a filename as input. +*/ +unsigned decode(std::vector& out, unsigned& w, unsigned& h, + const std::string& filename, + LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); +#endif //LODEPNG_COMPILE_DISK +#endif //LODEPNG_COMPILE_DECODER + +#ifdef LODEPNG_COMPILE_ENCODER +/*Same as lodepng_encode_memory, but encodes to an std::vector.*/ +unsigned encode(std::vector& out, + const unsigned char* in, unsigned w, unsigned h, + LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); +unsigned encode(std::vector& out, + const std::vector& in, unsigned w, unsigned h, + LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); +#ifdef LODEPNG_COMPILE_DISK +/* +Converts 32-bit RGBA raw pixel data into a PNG file on disk. +Same as the other encode functions, but instead takes a filename as output. +NOTE: This overwrites existing files without warning! +*/ +unsigned encode(const std::string& filename, + const unsigned char* in, unsigned w, unsigned h, + LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); +unsigned encode(const std::string& filename, + const std::vector& in, unsigned w, unsigned h, + LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); +#endif //LODEPNG_COMPILE_DISK +#endif //LODEPNG_COMPILE_ENCODER +} //namespace lodepng +#endif /*LODEPNG_COMPILE_CPP*/ +#endif /*LODEPNG_COMPILE_PNG*/ + +#ifdef LODEPNG_COMPILE_ERROR_TEXT +/*Returns an English description of the numerical error code.*/ +const char* lodepng_error_text(unsigned code); +#endif /*LODEPNG_COMPILE_ERROR_TEXT*/ + +#ifdef LODEPNG_COMPILE_DECODER +/*Settings for zlib decompression*/ +typedef struct LodePNGDecompressSettings LodePNGDecompressSettings; +struct LodePNGDecompressSettings +{ + unsigned ignore_adler32; /*if 1, continue and don't give an error message if the Adler32 checksum is corrupted*/ + + /*use custom zlib decoder instead of built in one (default: null)*/ + unsigned (*custom_zlib)(unsigned char**, size_t*, + const unsigned char*, size_t, + const LodePNGDecompressSettings*); + /*use custom deflate decoder instead of built in one (default: null) + if custom_zlib is used, custom_deflate is ignored since only the built in + zlib function will call custom_deflate*/ + unsigned (*custom_inflate)(unsigned char**, size_t*, + const unsigned char*, size_t, + const LodePNGDecompressSettings*); + + const void* custom_context; /*optional custom settings for custom functions*/ +}; + +extern const LodePNGDecompressSettings lodepng_default_decompress_settings; +void lodepng_decompress_settings_init(LodePNGDecompressSettings* settings); +#endif /*LODEPNG_COMPILE_DECODER*/ + +#ifdef LODEPNG_COMPILE_ENCODER +/* +Settings for zlib compression. Tweaking these settings tweaks the balance +between speed and compression ratio. +*/ +typedef struct LodePNGCompressSettings LodePNGCompressSettings; +struct LodePNGCompressSettings /*deflate = compress*/ +{ + /*LZ77 related settings*/ + unsigned btype; /*the block type for LZ (0, 1, 2 or 3, see zlib standard). Should be 2 for proper compression.*/ + unsigned use_lz77; /*whether or not to use LZ77. Should be 1 for proper compression.*/ + unsigned windowsize; /*must be a power of two <= 32768. higher compresses more but is slower. Default value: 2048.*/ + unsigned minmatch; /*mininum lz77 length. 3 is normally best, 6 can be better for some PNGs. Default: 0*/ + unsigned nicematch; /*stop searching if >= this length found. Set to 258 for best compression. Default: 128*/ + unsigned lazymatching; /*use lazy matching: better compression but a bit slower. Default: true*/ + + /*use custom zlib encoder instead of built in one (default: null)*/ + unsigned (*custom_zlib)(unsigned char**, size_t*, + const unsigned char*, size_t, + const LodePNGCompressSettings*); + /*use custom deflate encoder instead of built in one (default: null) + if custom_zlib is used, custom_deflate is ignored since only the built in + zlib function will call custom_deflate*/ + unsigned (*custom_deflate)(unsigned char**, size_t*, + const unsigned char*, size_t, + const LodePNGCompressSettings*); + + const void* custom_context; /*optional custom settings for custom functions*/ +}; + +extern const LodePNGCompressSettings lodepng_default_compress_settings; +void lodepng_compress_settings_init(LodePNGCompressSettings* settings); +#endif /*LODEPNG_COMPILE_ENCODER*/ + +#ifdef LODEPNG_COMPILE_PNG +/* +Color mode of an image. Contains all information required to decode the pixel +bits to RGBA colors. This information is the same as used in the PNG file +format, and is used both for PNG and raw image data in LodePNG. +*/ +typedef struct LodePNGColorMode +{ + /*header (IHDR)*/ + LodePNGColorType colortype; /*color type, see PNG standard or documentation further in this header file*/ + unsigned bitdepth; /*bits per sample, see PNG standard or documentation further in this header file*/ + + /* + palette (PLTE and tRNS) + + Dynamically allocated with the colors of the palette, including alpha. + When encoding a PNG, to store your colors in the palette of the LodePNGColorMode, first use + lodepng_palette_clear, then for each color use lodepng_palette_add. + If you encode an image without alpha with palette, don't forget to put value 255 in each A byte of the palette. + + When decoding, by default you can ignore this palette, since LodePNG already + fills the palette colors in the pixels of the raw RGBA output. + + The palette is only supported for color type 3. + */ + unsigned char* palette; /*palette in RGBARGBA... order. When allocated, must be either 0, or have size 1024*/ + size_t palettesize; /*palette size in number of colors (amount of bytes is 4 * palettesize)*/ + + /* + transparent color key (tRNS) + + This color uses the same bit depth as the bitdepth value in this struct, which can be 1-bit to 16-bit. + For greyscale PNGs, r, g and b will all 3 be set to the same. + + When decoding, by default you can ignore this information, since LodePNG sets + pixels with this key to transparent already in the raw RGBA output. + + The color key is only supported for color types 0 and 2. + */ + unsigned key_defined; /*is a transparent color key given? 0 = false, 1 = true*/ + unsigned key_r; /*red/greyscale component of color key*/ + unsigned key_g; /*green component of color key*/ + unsigned key_b; /*blue component of color key*/ +} LodePNGColorMode; + +/*init, cleanup and copy functions to use with this struct*/ +void lodepng_color_mode_init(LodePNGColorMode* info); +void lodepng_color_mode_cleanup(LodePNGColorMode* info); +/*return value is error code (0 means no error)*/ +unsigned lodepng_color_mode_copy(LodePNGColorMode* dest, const LodePNGColorMode* source); + +void lodepng_palette_clear(LodePNGColorMode* info); +/*add 1 color to the palette*/ +unsigned lodepng_palette_add(LodePNGColorMode* info, + unsigned char r, unsigned char g, unsigned char b, unsigned char a); + +/*get the total amount of bits per pixel, based on colortype and bitdepth in the struct*/ +unsigned lodepng_get_bpp(const LodePNGColorMode* info); +/*get the amount of color channels used, based on colortype in the struct. +If a palette is used, it counts as 1 channel.*/ +unsigned lodepng_get_channels(const LodePNGColorMode* info); +/*is it a greyscale type? (only colortype 0 or 4)*/ +unsigned lodepng_is_greyscale_type(const LodePNGColorMode* info); +/*has it got an alpha channel? (only colortype 2 or 6)*/ +unsigned lodepng_is_alpha_type(const LodePNGColorMode* info); +/*has it got a palette? (only colortype 3)*/ +unsigned lodepng_is_palette_type(const LodePNGColorMode* info); +/*only returns true if there is a palette and there is a value in the palette with alpha < 255. +Loops through the palette to check this.*/ +unsigned lodepng_has_palette_alpha(const LodePNGColorMode* info); +/* +Check if the given color info indicates the possibility of having non-opaque pixels in the PNG image. +Returns true if the image can have translucent or invisible pixels (it still be opaque if it doesn't use such pixels). +Returns false if the image can only have opaque pixels. +In detail, it returns true only if it's a color type with alpha, or has a palette with non-opaque values, +or if "key_defined" is true. +*/ +unsigned lodepng_can_have_alpha(const LodePNGColorMode* info); +/*Returns the byte size of a raw image buffer with given width, height and color mode*/ +size_t lodepng_get_raw_size(unsigned w, unsigned h, const LodePNGColorMode* color); + +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS +/*The information of a Time chunk in PNG.*/ +typedef struct LodePNGTime +{ + unsigned year; /*2 bytes used (0-65535)*/ + unsigned month; /*1-12*/ + unsigned day; /*1-31*/ + unsigned hour; /*0-23*/ + unsigned minute; /*0-59*/ + unsigned second; /*0-60 (to allow for leap seconds)*/ +} LodePNGTime; +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + +/*Information about the PNG image, except pixels, width and height.*/ +typedef struct LodePNGInfo +{ + /*header (IHDR), palette (PLTE) and transparency (tRNS) chunks*/ + unsigned compression_method;/*compression method of the original file. Always 0.*/ + unsigned filter_method; /*filter method of the original file*/ + unsigned interlace_method; /*interlace method of the original file*/ + LodePNGColorMode color; /*color type and bits, palette and transparency of the PNG file*/ + +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + /* + suggested background color chunk (bKGD) + This color uses the same color mode as the PNG (except alpha channel), which can be 1-bit to 16-bit. + + For greyscale PNGs, r, g and b will all 3 be set to the same. When encoding + the encoder writes the red one. For palette PNGs: When decoding, the RGB value + will be stored, not a palette index. But when encoding, specify the index of + the palette in background_r, the other two are then ignored. + + The decoder does not use this background color to edit the color of pixels. + */ + unsigned background_defined; /*is a suggested background color given?*/ + unsigned background_r; /*red component of suggested background color*/ + unsigned background_g; /*green component of suggested background color*/ + unsigned background_b; /*blue component of suggested background color*/ + + /* + non-international text chunks (tEXt and zTXt) + + The char** arrays each contain num strings. The actual messages are in + text_strings, while text_keys are keywords that give a short description what + the actual text represents, e.g. Title, Author, Description, or anything else. + + A keyword is minimum 1 character and maximum 79 characters long. It's + discouraged to use a single line length longer than 79 characters for texts. + + Don't allocate these text buffers yourself. Use the init/cleanup functions + correctly and use lodepng_add_text and lodepng_clear_text. + */ + size_t text_num; /*the amount of texts in these char** buffers (there may be more texts in itext)*/ + char** text_keys; /*the keyword of a text chunk (e.g. "Comment")*/ + char** text_strings; /*the actual text*/ + + /* + international text chunks (iTXt) + Similar to the non-international text chunks, but with additional strings + "langtags" and "transkeys". + */ + size_t itext_num; /*the amount of international texts in this PNG*/ + char** itext_keys; /*the English keyword of the text chunk (e.g. "Comment")*/ + char** itext_langtags; /*language tag for this text's language, ISO/IEC 646 string, e.g. ISO 639 language tag*/ + char** itext_transkeys; /*keyword translated to the international language - UTF-8 string*/ + char** itext_strings; /*the actual international text - UTF-8 string*/ + + /*time chunk (tIME)*/ + unsigned time_defined; /*set to 1 to make the encoder generate a tIME chunk*/ + LodePNGTime time; + + /*phys chunk (pHYs)*/ + unsigned phys_defined; /*if 0, there is no pHYs chunk and the values below are undefined, if 1 else there is one*/ + unsigned phys_x; /*pixels per unit in x direction*/ + unsigned phys_y; /*pixels per unit in y direction*/ + unsigned phys_unit; /*may be 0 (unknown unit) or 1 (metre)*/ + + /* + unknown chunks + There are 3 buffers, one for each position in the PNG where unknown chunks can appear + each buffer contains all unknown chunks for that position consecutively + The 3 buffers are the unknown chunks between certain critical chunks: + 0: IHDR-PLTE, 1: PLTE-IDAT, 2: IDAT-IEND + Do not allocate or traverse this data yourself. Use the chunk traversing functions declared + later, such as lodepng_chunk_next and lodepng_chunk_append, to read/write this struct. + */ + unsigned char* unknown_chunks_data[3]; + size_t unknown_chunks_size[3]; /*size in bytes of the unknown chunks, given for protection*/ +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ +} LodePNGInfo; + +/*init, cleanup and copy functions to use with this struct*/ +void lodepng_info_init(LodePNGInfo* info); +void lodepng_info_cleanup(LodePNGInfo* info); +/*return value is error code (0 means no error)*/ +unsigned lodepng_info_copy(LodePNGInfo* dest, const LodePNGInfo* source); + +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS +void lodepng_clear_text(LodePNGInfo* info); /*use this to clear the texts again after you filled them in*/ +unsigned lodepng_add_text(LodePNGInfo* info, const char* key, const char* str); /*push back both texts at once*/ + +void lodepng_clear_itext(LodePNGInfo* info); /*use this to clear the itexts again after you filled them in*/ +unsigned lodepng_add_itext(LodePNGInfo* info, const char* key, const char* langtag, + const char* transkey, const char* str); /*push back the 4 texts of 1 chunk at once*/ +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + +/* +Converts raw buffer from one color type to another color type, based on +LodePNGColorMode structs to describe the input and output color type. +See the reference manual at the end of this header file to see which color conversions are supported. +return value = LodePNG error code (0 if all went ok, an error if the conversion isn't supported) +The out buffer must have size (w * h * bpp + 7) / 8, where bpp is the bits per pixel +of the output color type (lodepng_get_bpp) +The fix_png value works as described in struct LodePNGDecoderSettings. +Note: for 16-bit per channel colors, uses big endian format like PNG does. +*/ +unsigned lodepng_convert(unsigned char* out, const unsigned char* in, + LodePNGColorMode* mode_out, const LodePNGColorMode* mode_in, + unsigned w, unsigned h, unsigned fix_png); + +#ifdef LODEPNG_COMPILE_DECODER +/* +Settings for the decoder. This contains settings for the PNG and the Zlib +decoder, but not the Info settings from the Info structs. +*/ +typedef struct LodePNGDecoderSettings +{ + LodePNGDecompressSettings zlibsettings; /*in here is the setting to ignore Adler32 checksums*/ + + unsigned ignore_crc; /*ignore CRC checksums*/ + /* + The fix_png setting, if 1, makes the decoder tolerant towards some PNG images + that do not correctly follow the PNG specification. This only supports errors + that are fixable, were found in images that are actually used on the web, and + are silently tolerated by other decoders as well. Currently only one such fix + is implemented: if a palette index is out of bounds given the palette size, + interpret it as opaque black. + By default this value is 0, which makes it stop with an error on such images. + */ + unsigned fix_png; + unsigned color_convert; /*whether to convert the PNG to the color type you want. Default: yes*/ + +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + unsigned read_text_chunks; /*if false but remember_unknown_chunks is true, they're stored in the unknown chunks*/ + /*store all bytes from unknown chunks in the LodePNGInfo (off by default, useful for a png editor)*/ + unsigned remember_unknown_chunks; +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ +} LodePNGDecoderSettings; + +void lodepng_decoder_settings_init(LodePNGDecoderSettings* settings); +#endif /*LODEPNG_COMPILE_DECODER*/ + +#ifdef LODEPNG_COMPILE_ENCODER +/*automatically use color type with less bits per pixel if losslessly possible. Default: AUTO*/ +typedef enum LodePNGFilterStrategy +{ + /*every filter at zero*/ + LFS_ZERO, + /*Use filter that gives minumum sum, as described in the official PNG filter heuristic.*/ + LFS_MINSUM, + /*Use the filter type that gives smallest Shannon entropy for this scanline. Depending + on the image, this is better or worse than minsum.*/ + LFS_ENTROPY, + /* + Brute-force-search PNG filters by compressing each filter for each scanline. + Experimental, very slow, and only rarely gives better compression than MINSUM. + */ + LFS_BRUTE_FORCE, + /*use predefined_filters buffer: you specify the filter type for each scanline*/ + LFS_PREDEFINED +} LodePNGFilterStrategy; + +/*automatically use color type with less bits per pixel if losslessly possible. Default: LAC_AUTO*/ +typedef enum LodePNGAutoConvert +{ + LAC_NO, /*use color type user requested*/ + LAC_ALPHA, /*use color type user requested, but if only opaque pixels and RGBA or grey+alpha, use RGB or grey*/ + LAC_AUTO, /*use PNG color type that can losslessly represent the uncompressed image the smallest possible*/ + /* + like AUTO, but do not choose 1, 2 or 4 bit per pixel types. + sometimes a PNG image compresses worse if less than 8 bits per pixels. + */ + LAC_AUTO_NO_NIBBLES, + /* + like AUTO, but never choose palette color type. For small images, encoding + the palette may take more bytes than what is gained. Note that AUTO also + already prevents encoding the palette for extremely small images, but that may + not be sufficient because due to the compression it cannot predict when to + switch. + */ + LAC_AUTO_NO_PALETTE, + LAC_AUTO_NO_NIBBLES_NO_PALETTE +} LodePNGAutoConvert; + + +/* +Automatically chooses color type that gives smallest amount of bits in the +output image, e.g. grey if there are only greyscale pixels, palette if there +are less than 256 colors, ... +The auto_convert parameter allows limiting it to not use palette, ... +*/ +unsigned lodepng_auto_choose_color(LodePNGColorMode* mode_out, + const unsigned char* image, unsigned w, unsigned h, + const LodePNGColorMode* mode_in, + LodePNGAutoConvert auto_convert); + +/*Settings for the encoder.*/ +typedef struct LodePNGEncoderSettings +{ + LodePNGCompressSettings zlibsettings; /*settings for the zlib encoder, such as window size, ...*/ + + LodePNGAutoConvert auto_convert; /*how to automatically choose output PNG color type, if at all*/ + + /*If true, follows the official PNG heuristic: if the PNG uses a palette or lower than + 8 bit depth, set all filters to zero. Otherwise use the filter_strategy. Note that to + completely follow the official PNG heuristic, filter_palette_zero must be true and + filter_strategy must be LFS_MINSUM*/ + unsigned filter_palette_zero; + /*Which filter strategy to use when not using zeroes due to filter_palette_zero. + Set filter_palette_zero to 0 to ensure always using your chosen strategy. Default: LFS_MINSUM*/ + LodePNGFilterStrategy filter_strategy; + /*used if filter_strategy is LFS_PREDEFINED. In that case, this must point to a buffer with + the same length as the amount of scanlines in the image, and each value must <= 5. You + have to cleanup this buffer, LodePNG will never free it. Don't forget that filter_palette_zero + must be set to 0 to ensure this is also used on palette or low bitdepth images.*/ + const unsigned char* predefined_filters; + + /*force creating a PLTE chunk if colortype is 2 or 6 (= a suggested palette). + If colortype is 3, PLTE is _always_ created.*/ + unsigned force_palette; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + /*add LodePNG identifier and version as a text chunk, for debugging*/ + unsigned add_id; + /*encode text chunks as zTXt chunks instead of tEXt chunks, and use compression in iTXt chunks*/ + unsigned text_compression; +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ +} LodePNGEncoderSettings; + +void lodepng_encoder_settings_init(LodePNGEncoderSettings* settings); +#endif /*LODEPNG_COMPILE_ENCODER*/ + + +#if defined(LODEPNG_COMPILE_DECODER) || defined(LODEPNG_COMPILE_ENCODER) +/*The settings, state and information for extended encoding and decoding.*/ +typedef struct LodePNGState +{ +#ifdef LODEPNG_COMPILE_DECODER + LodePNGDecoderSettings decoder; /*the decoding settings*/ +#endif /*LODEPNG_COMPILE_DECODER*/ +#ifdef LODEPNG_COMPILE_ENCODER + LodePNGEncoderSettings encoder; /*the encoding settings*/ +#endif /*LODEPNG_COMPILE_ENCODER*/ + LodePNGColorMode info_raw; /*specifies the format in which you would like to get the raw pixel buffer*/ + LodePNGInfo info_png; /*info of the PNG image obtained after decoding*/ + unsigned error; +#ifdef LODEPNG_COMPILE_CPP + //For the lodepng::State subclass. + virtual ~LodePNGState(){} +#endif +} LodePNGState; + +/*init, cleanup and copy functions to use with this struct*/ +void lodepng_state_init(LodePNGState* state); +void lodepng_state_cleanup(LodePNGState* state); +void lodepng_state_copy(LodePNGState* dest, const LodePNGState* source); +#endif /* defined(LODEPNG_COMPILE_DECODER) || defined(LODEPNG_COMPILE_ENCODER) */ + +#ifdef LODEPNG_COMPILE_DECODER +/* +Same as lodepng_decode_memory, but uses a LodePNGState to allow custom settings and +getting much more information about the PNG image and color mode. +*/ +unsigned lodepng_decode(unsigned char** out, unsigned* w, unsigned* h, + LodePNGState* state, + const unsigned char* in, size_t insize); + +/* +Read the PNG header, but not the actual data. This returns only the information +that is in the header chunk of the PNG, such as width, height and color type. The +information is placed in the info_png field of the LodePNGState. +*/ +unsigned lodepng_inspect(unsigned* w, unsigned* h, + LodePNGState* state, + const unsigned char* in, size_t insize); +#endif /*LODEPNG_COMPILE_DECODER*/ + + +#ifdef LODEPNG_COMPILE_ENCODER +/*This function allocates the out buffer with standard malloc and stores the size in *outsize.*/ +unsigned lodepng_encode(unsigned char** out, size_t* outsize, + const unsigned char* image, unsigned w, unsigned h, + LodePNGState* state); +#endif /*LODEPNG_COMPILE_ENCODER*/ + +/* +The lodepng_chunk functions are normally not needed, except to traverse the +unknown chunks stored in the LodePNGInfo struct, or add new ones to it. +It also allows traversing the chunks of an encoded PNG file yourself. + +PNG standard chunk naming conventions: +First byte: uppercase = critical, lowercase = ancillary +Second byte: uppercase = public, lowercase = private +Third byte: must be uppercase +Fourth byte: uppercase = unsafe to copy, lowercase = safe to copy +*/ + +/*get the length of the data of the chunk. Total chunk length has 12 bytes more.*/ +unsigned lodepng_chunk_length(const unsigned char* chunk); + +/*puts the 4-byte type in null terminated string*/ +void lodepng_chunk_type(char type[5], const unsigned char* chunk); + +/*check if the type is the given type*/ +unsigned char lodepng_chunk_type_equals(const unsigned char* chunk, const char* type); + +/*0: it's one of the critical chunk types, 1: it's an ancillary chunk (see PNG standard)*/ +unsigned char lodepng_chunk_ancillary(const unsigned char* chunk); + +/*0: public, 1: private (see PNG standard)*/ +unsigned char lodepng_chunk_private(const unsigned char* chunk); + +/*0: the chunk is unsafe to copy, 1: the chunk is safe to copy (see PNG standard)*/ +unsigned char lodepng_chunk_safetocopy(const unsigned char* chunk); + +/*get pointer to the data of the chunk, where the input points to the header of the chunk*/ +unsigned char* lodepng_chunk_data(unsigned char* chunk); +const unsigned char* lodepng_chunk_data_const(const unsigned char* chunk); + +/*returns 0 if the crc is correct, 1 if it's incorrect (0 for OK as usual!)*/ +unsigned lodepng_chunk_check_crc(const unsigned char* chunk); + +/*generates the correct CRC from the data and puts it in the last 4 bytes of the chunk*/ +void lodepng_chunk_generate_crc(unsigned char* chunk); + +/*iterate to next chunks. don't use on IEND chunk, as there is no next chunk then*/ +unsigned char* lodepng_chunk_next(unsigned char* chunk); +const unsigned char* lodepng_chunk_next_const(const unsigned char* chunk); + +/* +Appends chunk to the data in out. The given chunk should already have its chunk header. +The out variable and outlength are updated to reflect the new reallocated buffer. +Returns error code (0 if it went ok) +*/ +unsigned lodepng_chunk_append(unsigned char** out, size_t* outlength, const unsigned char* chunk); + +/* +Appends new chunk to out. The chunk to append is given by giving its length, type +and data separately. The type is a 4-letter string. +The out variable and outlength are updated to reflect the new reallocated buffer. +Returne error code (0 if it went ok) +*/ +unsigned lodepng_chunk_create(unsigned char** out, size_t* outlength, unsigned length, + const char* type, const unsigned char* data); + + +/*Calculate CRC32 of buffer*/ +unsigned lodepng_crc32(const unsigned char* buf, size_t len); +#endif /*LODEPNG_COMPILE_PNG*/ + + +#ifdef LODEPNG_COMPILE_ZLIB +/* +This zlib part can be used independently to zlib compress and decompress a +buffer. It cannot be used to create gzip files however, and it only supports the +part of zlib that is required for PNG, it does not support dictionaries. +*/ + +#ifdef LODEPNG_COMPILE_DECODER +/*Inflate a buffer. Inflate is the decompression step of deflate. Out buffer must be freed after use.*/ +unsigned lodepng_inflate(unsigned char** out, size_t* outsize, + const unsigned char* in, size_t insize, + const LodePNGDecompressSettings* settings); + +/* +Decompresses Zlib data. Reallocates the out buffer and appends the data. The +data must be according to the zlib specification. +Either, *out must be NULL and *outsize must be 0, or, *out must be a valid +buffer and *outsize its size in bytes. out must be freed by user after usage. +*/ +unsigned lodepng_zlib_decompress(unsigned char** out, size_t* outsize, + const unsigned char* in, size_t insize, + const LodePNGDecompressSettings* settings); +#endif /*LODEPNG_COMPILE_DECODER*/ + +#ifdef LODEPNG_COMPILE_ENCODER +/* +Compresses data with Zlib. Reallocates the out buffer and appends the data. +Zlib adds a small header and trailer around the deflate data. +The data is output in the format of the zlib specification. +Either, *out must be NULL and *outsize must be 0, or, *out must be a valid +buffer and *outsize its size in bytes. out must be freed by user after usage. +*/ +unsigned lodepng_zlib_compress(unsigned char** out, size_t* outsize, + const unsigned char* in, size_t insize, + const LodePNGCompressSettings* settings); + +/* +Find length-limited Huffman code for given frequencies. This function is in the +public interface only for tests, it's used internally by lodepng_deflate. +*/ +unsigned lodepng_huffman_code_lengths(unsigned* lengths, const unsigned* frequencies, + size_t numcodes, unsigned maxbitlen); + +/*Compress a buffer with deflate. See RFC 1951. Out buffer must be freed after use.*/ +unsigned lodepng_deflate(unsigned char** out, size_t* outsize, + const unsigned char* in, size_t insize, + const LodePNGCompressSettings* settings); + +#endif /*LODEPNG_COMPILE_ENCODER*/ +#endif /*LODEPNG_COMPILE_ZLIB*/ + +#ifdef LODEPNG_COMPILE_DISK +/* +Load a file from disk into buffer. The function allocates the out buffer, and +after usage you should free it. +out: output parameter, contains pointer to loaded buffer. +outsize: output parameter, size of the allocated out buffer +filename: the path to the file to load +return value: error code (0 means ok) +*/ +unsigned lodepng_load_file(unsigned char** out, size_t* outsize, const char* filename); + +/* +Save a file from buffer to disk. Warning, if it exists, this function overwrites +the file without warning! +buffer: the buffer to write +buffersize: size of the buffer to write +filename: the path to the file to save to +return value: error code (0 means ok) +*/ +unsigned lodepng_save_file(const unsigned char* buffer, size_t buffersize, const char* filename); +#endif /*LODEPNG_COMPILE_DISK*/ + +#ifdef LODEPNG_COMPILE_CPP +//The LodePNG C++ wrapper uses std::vectors instead of manually allocated memory buffers. +namespace lodepng +{ +#ifdef LODEPNG_COMPILE_PNG +class State : public LodePNGState +{ + public: + State(); + State(const State& other); + virtual ~State(); + State& operator=(const State& other); +}; + +#ifdef LODEPNG_COMPILE_DECODER +//Same as other lodepng::decode, but using a State for more settings and information. +unsigned decode(std::vector& out, unsigned& w, unsigned& h, + State& state, + const unsigned char* in, size_t insize); +unsigned decode(std::vector& out, unsigned& w, unsigned& h, + State& state, + const std::vector& in); +#endif /*LODEPNG_COMPILE_DECODER*/ + +#ifdef LODEPNG_COMPILE_ENCODER +//Same as other lodepng::encode, but using a State for more settings and information. +unsigned encode(std::vector& out, + const unsigned char* in, unsigned w, unsigned h, + State& state); +unsigned encode(std::vector& out, + const std::vector& in, unsigned w, unsigned h, + State& state); +#endif /*LODEPNG_COMPILE_ENCODER*/ + +#ifdef LODEPNG_COMPILE_DISK +/* +Load a file from disk into an std::vector. If the vector is empty, then either +the file doesn't exist or is an empty file. +*/ +void load_file(std::vector& buffer, const std::string& filename); + +/* +Save the binary data in an std::vector to a file on disk. The file is overwritten +without warning. +*/ +void save_file(const std::vector& buffer, const std::string& filename); +#endif //LODEPNG_COMPILE_DISK +#endif //LODEPNG_COMPILE_PNG + +#ifdef LODEPNG_COMPILE_ZLIB +#ifdef LODEPNG_COMPILE_DECODER +//Zlib-decompress an unsigned char buffer +unsigned decompress(std::vector& out, const unsigned char* in, size_t insize, + const LodePNGDecompressSettings& settings = lodepng_default_decompress_settings); + +//Zlib-decompress an std::vector +unsigned decompress(std::vector& out, const std::vector& in, + const LodePNGDecompressSettings& settings = lodepng_default_decompress_settings); +#endif //LODEPNG_COMPILE_DECODER + +#ifdef LODEPNG_COMPILE_ENCODER +//Zlib-compress an unsigned char buffer +unsigned compress(std::vector& out, const unsigned char* in, size_t insize, + const LodePNGCompressSettings& settings = lodepng_default_compress_settings); + +//Zlib-compress an std::vector +unsigned compress(std::vector& out, const std::vector& in, + const LodePNGCompressSettings& settings = lodepng_default_compress_settings); +#endif //LODEPNG_COMPILE_ENCODER +#endif //LODEPNG_COMPILE_ZLIB +} //namespace lodepng +#endif /*LODEPNG_COMPILE_CPP*/ + +/* +TODO: +[.] test if there are no memory leaks or security exploits - done a lot but needs to be checked often +[.] check compatibility with vareous compilers - done but needs to be redone for every newer version +[X] converting color to 16-bit per channel types +[ ] read all public PNG chunk types (but never let the color profile and gamma ones touch RGB values) +[ ] make sure encoder generates no chunks with size > (2^31)-1 +[ ] partial decoding (stream processing) +[X] let the "isFullyOpaque" function check color keys and transparent palettes too +[X] better name for the variables "codes", "codesD", "codelengthcodes", "clcl" and "lldl" +[ ] don't stop decoding on errors like 69, 57, 58 (make warnings) +[ ] make option to choose if the raw image with non multiple of 8 bits per scanline should have padding bits or not +[ ] let the C++ wrapper catch exceptions coming from the standard library and return LodePNG error codes +*/ + +#endif /*LODEPNG_H inclusion guard*/ + +/* +LodePNG Documentation +--------------------- + +0. table of contents +-------------------- + + 1. about + 1.1. supported features + 1.2. features not supported + 2. C and C++ version + 3. security + 4. decoding + 5. encoding + 6. color conversions + 6.1. PNG color types + 6.2. color conversions + 6.3. padding bits + 6.4. A note about 16-bits per channel and endianness + 7. error values + 8. chunks and PNG editing + 9. compiler support + 10. examples + 10.1. decoder C++ example + 10.2. decoder C example + 11. changes + 12. contact information + + +1. about +-------- + +PNG is a file format to store raster images losslessly with good compression, +supporting different color types and alpha channel. + +LodePNG is a PNG codec according to the Portable Network Graphics (PNG) +Specification (Second Edition) - W3C Recommendation 10 November 2003. + +The specifications used are: + +*) Portable Network Graphics (PNG) Specification (Second Edition): + http://www.w3.org/TR/2003/REC-PNG-20031110 +*) RFC 1950 ZLIB Compressed Data Format version 3.3: + http://www.gzip.org/zlib/rfc-zlib.html +*) RFC 1951 DEFLATE Compressed Data Format Specification ver 1.3: + http://www.gzip.org/zlib/rfc-deflate.html + +The most recent version of LodePNG can currently be found at +http://lodev.org/lodepng/ + +LodePNG works both in C (ISO C90) and C++, with a C++ wrapper that adds +extra functionality. + +LodePNG exists out of two files: +-lodepng.h: the header file for both C and C++ +-lodepng.c(pp): give it the name lodepng.c or lodepng.cpp (or .cc) depending on your usage + +If you want to start using LodePNG right away without reading this doc, get the +examples from the LodePNG website to see how to use it in code, or check the +smaller examples in chapter 13 here. + +LodePNG is simple but only supports the basic requirements. To achieve +simplicity, the following design choices were made: There are no dependencies +on any external library. There are functions to decode and encode a PNG with +a single function call, and extended versions of these functions taking a +LodePNGState struct allowing to specify or get more information. By default +the colors of the raw image are always RGB or RGBA, no matter what color type +the PNG file uses. To read and write files, there are simple functions to +convert the files to/from buffers in memory. + +This all makes LodePNG suitable for loading textures in games, demos and small +programs, ... It's less suitable for full fledged image editors, loading PNGs +over network (it requires all the image data to be available before decoding can +begin), life-critical systems, ... + +1.1. supported features +----------------------- + +The following features are supported by the decoder: + +*) decoding of PNGs with any color type, bit depth and interlace mode, to a 24- or 32-bit color raw image, + or the same color type as the PNG +*) encoding of PNGs, from any raw image to 24- or 32-bit color, or the same color type as the raw image +*) Adam7 interlace and deinterlace for any color type +*) loading the image from harddisk or decoding it from a buffer from other sources than harddisk +*) support for alpha channels, including RGBA color model, translucent palettes and color keying +*) zlib decompression (inflate) +*) zlib compression (deflate) +*) CRC32 and ADLER32 checksums +*) handling of unknown chunks, allowing making a PNG editor that stores custom and unknown chunks. +*) the following chunks are supported (generated/interpreted) by both encoder and decoder: + IHDR: header information + PLTE: color palette + IDAT: pixel data + IEND: the final chunk + tRNS: transparency for palettized images + tEXt: textual information + zTXt: compressed textual information + iTXt: international textual information + bKGD: suggested background color + pHYs: physical dimensions + tIME: modification time + +1.2. features not supported +--------------------------- + +The following features are _not_ supported: + +*) some features needed to make a conformant PNG-Editor might be still missing. +*) partial loading/stream processing. All data must be available and is processed in one call. +*) The following public chunks are not supported but treated as unknown chunks by LodePNG + cHRM, gAMA, iCCP, sRGB, sBIT, hIST, sPLT + Some of these are not supported on purpose: LodePNG wants to provide the RGB values + stored in the pixels, not values modified by system dependent gamma or color models. + + +2. C and C++ version +-------------------- + +The C version uses buffers allocated with alloc that you need to free() +yourself. You need to use init and cleanup functions for each struct whenever +using a struct from the C version to avoid exploits and memory leaks. + +The C++ version has extra functions with std::vectors in the interface and the +lodepng::State class which is a LodePNGState with constructor and destructor. + +These files work without modification for both C and C++ compilers because all +the additional C++ code is in "#ifdef __cplusplus" blocks that make C-compilers +ignore it, and the C code is made to compile both with strict ISO C90 and C++. + +To use the C++ version, you need to rename the source file to lodepng.cpp +(instead of lodepng.c), and compile it with a C++ compiler. + +To use the C version, you need to rename the source file to lodepng.c (instead +of lodepng.cpp), and compile it with a C compiler. + + +3. Security +----------- + +Even if carefully designed, it's always possible that LodePNG contains possible +exploits. If you discover one, please let me know, and it will be fixed. + +When using LodePNG, care has to be taken with the C version of LodePNG, as well +as the C-style structs when working with C++. The following conventions are used +for all C-style structs: + +-if a struct has a corresponding init function, always call the init function when making a new one +-if a struct has a corresponding cleanup function, call it before the struct disappears to avoid memory leaks +-if a struct has a corresponding copy function, use the copy function instead of "=". + The destination must also be inited already. + + +4. Decoding +----------- + +Decoding converts a PNG compressed image to a raw pixel buffer. + +Most documentation on using the decoder is at its declarations in the header +above. For C, simple decoding can be done with functions such as +lodepng_decode32, and more advanced decoding can be done with the struct +LodePNGState and lodepng_decode. For C++, all decoding can be done with the +various lodepng::decode functions, and lodepng::State can be used for advanced +features. + +When using the LodePNGState, it uses the following fields for decoding: +*) LodePNGInfo info_png: it stores extra information about the PNG (the input) in here +*) LodePNGColorMode info_raw: here you can say what color mode of the raw image (the output) you want to get +*) LodePNGDecoderSettings decoder: you can specify a few extra settings for the decoder to use + +LodePNGInfo info_png +-------------------- + +After decoding, this contains extra information of the PNG image, except the actual +pixels, width and height because these are already gotten directly from the decoder +functions. + +It contains for example the original color type of the PNG image, text comments, +suggested background color, etc... More details about the LodePNGInfo struct are +at its declaration documentation. + +LodePNGColorMode info_raw +------------------------- + +When decoding, here you can specify which color type you want +the resulting raw image to be. If this is different from the colortype of the +PNG, then the decoder will automatically convert the result. This conversion +always works, except if you want it to convert a color PNG to greyscale or to +a palette with missing colors. + +By default, 32-bit color is used for the result. + +LodePNGDecoderSettings decoder +------------------------------ + +The settings can be used to ignore the errors created by invalid CRC and Adler32 +chunks, and to disable the decoding of tEXt chunks. + +There's also a setting color_convert, true by default. If false, no conversion +is done, the resulting data will be as it was in the PNG (after decompression) +and you'll have to puzzle the colors of the pixels together yourself using the +color type information in the LodePNGInfo. + + +5. Encoding +----------- + +Encoding converts a raw pixel buffer to a PNG compressed image. + +Most documentation on using the encoder is at its declarations in the header +above. For C, simple encoding can be done with functions such as +lodepng_encode32, and more advanced decoding can be done with the struct +LodePNGState and lodepng_encode. For C++, all encoding can be done with the +various lodepng::encode functions, and lodepng::State can be used for advanced +features. + +Like the decoder, the encoder can also give errors. However it gives less errors +since the encoder input is trusted, the decoder input (a PNG image that could +be forged by anyone) is not trusted. + +When using the LodePNGState, it uses the following fields for encoding: +*) LodePNGInfo info_png: here you specify how you want the PNG (the output) to be. +*) LodePNGColorMode info_raw: here you say what color type of the raw image (the input) has +*) LodePNGEncoderSettings encoder: you can specify a few settings for the encoder to use + +LodePNGInfo info_png +-------------------- + +When encoding, you use this the opposite way as when decoding: for encoding, +you fill in the values you want the PNG to have before encoding. By default it's +not needed to specify a color type for the PNG since it's automatically chosen, +but it's possible to choose it yourself given the right settings. + +The encoder will not always exactly match the LodePNGInfo struct you give, +it tries as close as possible. Some things are ignored by the encoder. The +encoder uses, for example, the following settings from it when applicable: +colortype and bitdepth, text chunks, time chunk, the color key, the palette, the +background color, the interlace method, unknown chunks, ... + +When encoding to a PNG with colortype 3, the encoder will generate a PLTE chunk. +If the palette contains any colors for which the alpha channel is not 255 (so +there are translucent colors in the palette), it'll add a tRNS chunk. + +LodePNGColorMode info_raw +------------------------- + +You specify the color type of the raw image that you give to the input here, +including a possible transparent color key and palette you happen to be using in +your raw image data. + +By default, 32-bit color is assumed, meaning your input has to be in RGBA +format with 4 bytes (unsigned chars) per pixel. + +LodePNGEncoderSettings encoder +------------------------------ + +The following settings are supported (some are in sub-structs): +*) auto_convert: when this option is enabled, the encoder will +automatically choose the smallest possible color mode (including color key) that +can encode the colors of all pixels without information loss. +*) btype: the block type for LZ77. 0 = uncompressed, 1 = fixed huffman tree, + 2 = dynamic huffman tree (best compression). Should be 2 for proper + compression. +*) use_lz77: whether or not to use LZ77 for compressed block types. Should be + true for proper compression. +*) windowsize: the window size used by the LZ77 encoder (1 - 32768). Has value + 2048 by default, but can be set to 32768 for better, but slow, compression. +*) force_palette: if colortype is 2 or 6, you can make the encoder write a PLTE + chunk if force_palette is true. This can used as suggested palette to convert + to by viewers that don't support more than 256 colors (if those still exist) +*) add_id: add text chunk "Encoder: LodePNG " to the image. +*) text_compression: default 1. If 1, it'll store texts as zTXt instead of tEXt chunks. + zTXt chunks use zlib compression on the text. This gives a smaller result on + large texts but a larger result on small texts (such as a single program name). + It's all tEXt or all zTXt though, there's no separate setting per text yet. + + +6. color conversions +-------------------- + +An important thing to note about LodePNG, is that the color type of the PNG, and +the color type of the raw image, are completely independent. By default, when +you decode a PNG, you get the result as a raw image in the color type you want, +no matter whether the PNG was encoded with a palette, greyscale or RGBA color. +And if you encode an image, by default LodePNG will automatically choose the PNG +color type that gives good compression based on the values of colors and amount +of colors in the image. It can be configured to let you control it instead as +well, though. + +To be able to do this, LodePNG does conversions from one color mode to another. +It can convert from almost any color type to any other color type, except the +following conversions: RGB to greyscale is not supported, and converting to a +palette when the palette doesn't have a required color is not supported. This is +not supported on purpose: this is information loss which requires a color +reduction algorithm that is beyong the scope of a PNG encoder (yes, RGB to grey +is easy, but there are multiple ways if you want to give some channels more +weight). + +By default, when decoding, you get the raw image in 32-bit RGBA or 24-bit RGB +color, no matter what color type the PNG has. And by default when encoding, +LodePNG automatically picks the best color model for the output PNG, and expects +the input image to be 32-bit RGBA or 24-bit RGB. So, unless you want to control +the color format of the images yourself, you can skip this chapter. + +6.1. PNG color types +-------------------- + +A PNG image can have many color types, ranging from 1-bit color to 64-bit color, +as well as palettized color modes. After the zlib decompression and unfiltering +in the PNG image is done, the raw pixel data will have that color type and thus +a certain amount of bits per pixel. If you want the output raw image after +decoding to have another color type, a conversion is done by LodePNG. + +The PNG specification gives the following color types: + +0: greyscale, bit depths 1, 2, 4, 8, 16 +2: RGB, bit depths 8 and 16 +3: palette, bit depths 1, 2, 4 and 8 +4: greyscale with alpha, bit depths 8 and 16 +6: RGBA, bit depths 8 and 16 + +Bit depth is the amount of bits per pixel per color channel. So the total amount +of bits per pixel is: amount of channels * bitdepth. + +6.2. color conversions +---------------------- + +As explained in the sections about the encoder and decoder, you can specify +color types and bit depths in info_png and info_raw to change the default +behaviour. + +If, when decoding, you want the raw image to be something else than the default, +you need to set the color type and bit depth you want in the LodePNGColorMode, +or the parameters of the simple function of LodePNG you're using. + +If, when encoding, you use another color type than the default in the input +image, you need to specify its color type and bit depth in the LodePNGColorMode +of the raw image, or use the parameters of the simplefunction of LodePNG you're +using. + +If, when encoding, you don't want LodePNG to choose the output PNG color type +but control it yourself, you need to set auto_convert in the encoder settings +to LAC_NONE, and specify the color type you want in the LodePNGInfo of the +encoder. + +If you do any of the above, LodePNG may need to do a color conversion, which +follows the rules below, and may sometimes not be allowed. + +To avoid some confusion: +-the decoder converts from PNG to raw image +-the encoder converts from raw image to PNG +-the colortype and bitdepth in LodePNGColorMode info_raw, are those of the raw image +-the colortype and bitdepth in the color field of LodePNGInfo info_png, are those of the PNG +-when encoding, the color type in LodePNGInfo is ignored if auto_convert + is enabled, it is automatically generated instead +-when decoding, the color type in LodePNGInfo is set by the decoder to that of the original + PNG image, but it can be ignored since the raw image has the color type you requested instead +-if the color type of the LodePNGColorMode and PNG image aren't the same, a conversion + between the color types is done if the color types are supported. If it is not + supported, an error is returned. If the types are the same, no conversion is done. +-even though some conversions aren't supported, LodePNG supports loading PNGs from any + colortype and saving PNGs to any colortype, sometimes it just requires preparing + the raw image correctly before encoding. +-both encoder and decoder use the same color converter. + +Non supported color conversions: +-color to greyscale: no error is thrown, but the result will look ugly because +only the red channel is taken +-anything, to palette when that palette does not have that color in it: in this +case an error is thrown + +Supported color conversions: +-anything to 8-bit RGB, 8-bit RGBA, 16-bit RGB, 16-bit RGBA +-any grey or grey+alpha, to grey or grey+alpha +-anything to a palette, as long as the palette has the requested colors in it +-removing alpha channel +-higher to smaller bitdepth, and vice versa + +If you want no color conversion to be done: +-In the encoder, you can make it save a PNG with any color type by giving the +raw color mode and LodePNGInfo the same color mode, and setting auto_convert to +LAC_NO. +-In the decoder, you can make it store the pixel data in the same color type +as the PNG has, by setting the color_convert setting to false. Settings in +info_raw are then ignored. + +The function lodepng_convert does the color conversion. It is available in the +interface but normally isn't needed since the encoder and decoder already call +it. + +6.3. padding bits +----------------- + +In the PNG file format, if a less than 8-bit per pixel color type is used and the scanlines +have a bit amount that isn't a multiple of 8, then padding bits are used so that each +scanline starts at a fresh byte. But that is NOT true for the LodePNG raw input and output. +The raw input image you give to the encoder, and the raw output image you get from the decoder +will NOT have these padding bits, e.g. in the case of a 1-bit image with a width +of 7 pixels, the first pixel of the second scanline will the the 8th bit of the first byte, +not the first bit of a new byte. + +6.4. A note about 16-bits per channel and endianness +---------------------------------------------------- + +LodePNG uses unsigned char arrays for 16-bit per channel colors too, just like +for any other color format. The 16-bit values are stored in big endian (most +significant byte first) in these arrays. This is the opposite order of the +little endian used by x86 CPU's. + +LodePNG always uses big endian because the PNG file format does so internally. +Conversions to other formats than PNG uses internally are not supported by +LodePNG on purpose, there are myriads of formats, including endianness of 16-bit +colors, the order in which you store R, G, B and A, and so on. Supporting and +converting to/from all that is outside the scope of LodePNG. + +This may mean that, depending on your use case, you may want to convert the big +endian output of LodePNG to little endian with a for loop. This is certainly not +always needed, many applications and libraries support big endian 16-bit colors +anyway, but it means you cannot simply cast the unsigned char* buffer to an +unsigned short* buffer on x86 CPUs. + + +7. error values +--------------- + +All functions in LodePNG that return an error code, return 0 if everything went +OK, or a non-zero code if there was an error. + +The meaning of the LodePNG error values can be retrieved with the function +lodepng_error_text: given the numerical error code, it returns a description +of the error in English as a string. + +Check the implementation of lodepng_error_text to see the meaning of each code. + + +8. chunks and PNG editing +------------------------- + +If you want to add extra chunks to a PNG you encode, or use LodePNG for a PNG +editor that should follow the rules about handling of unknown chunks, or if your +program is able to read other types of chunks than the ones handled by LodePNG, +then that's possible with the chunk functions of LodePNG. + +A PNG chunk has the following layout: + +4 bytes length +4 bytes type name +length bytes data +4 bytes CRC + +8.1. iterating through chunks +----------------------------- + +If you have a buffer containing the PNG image data, then the first chunk (the +IHDR chunk) starts at byte number 8 of that buffer. The first 8 bytes are the +signature of the PNG and are not part of a chunk. But if you start at byte 8 +then you have a chunk, and can check the following things of it. + +NOTE: none of these functions check for memory buffer boundaries. To avoid +exploits, always make sure the buffer contains all the data of the chunks. +When using lodepng_chunk_next, make sure the returned value is within the +allocated memory. + +unsigned lodepng_chunk_length(const unsigned char* chunk): + +Get the length of the chunk's data. The total chunk length is this length + 12. + +void lodepng_chunk_type(char type[5], const unsigned char* chunk): +unsigned char lodepng_chunk_type_equals(const unsigned char* chunk, const char* type): + +Get the type of the chunk or compare if it's a certain type + +unsigned char lodepng_chunk_critical(const unsigned char* chunk): +unsigned char lodepng_chunk_private(const unsigned char* chunk): +unsigned char lodepng_chunk_safetocopy(const unsigned char* chunk): + +Check if the chunk is critical in the PNG standard (only IHDR, PLTE, IDAT and IEND are). +Check if the chunk is private (public chunks are part of the standard, private ones not). +Check if the chunk is safe to copy. If it's not, then, when modifying data in a critical +chunk, unsafe to copy chunks of the old image may NOT be saved in the new one if your +program doesn't handle that type of unknown chunk. + +unsigned char* lodepng_chunk_data(unsigned char* chunk): +const unsigned char* lodepng_chunk_data_const(const unsigned char* chunk): + +Get a pointer to the start of the data of the chunk. + +unsigned lodepng_chunk_check_crc(const unsigned char* chunk): +void lodepng_chunk_generate_crc(unsigned char* chunk): + +Check if the crc is correct or generate a correct one. + +unsigned char* lodepng_chunk_next(unsigned char* chunk): +const unsigned char* lodepng_chunk_next_const(const unsigned char* chunk): + +Iterate to the next chunk. This works if you have a buffer with consecutive chunks. Note that these +functions do no boundary checking of the allocated data whatsoever, so make sure there is enough +data available in the buffer to be able to go to the next chunk. + +unsigned lodepng_chunk_append(unsigned char** out, size_t* outlength, const unsigned char* chunk): +unsigned lodepng_chunk_create(unsigned char** out, size_t* outlength, unsigned length, + const char* type, const unsigned char* data): + +These functions are used to create new chunks that are appended to the data in *out that has +length *outlength. The append function appends an existing chunk to the new data. The create +function creates a new chunk with the given parameters and appends it. Type is the 4-letter +name of the chunk. + +8.2. chunks in info_png +----------------------- + +The LodePNGInfo struct contains fields with the unknown chunk in it. It has 3 +buffers (each with size) to contain 3 types of unknown chunks: +the ones that come before the PLTE chunk, the ones that come between the PLTE +and the IDAT chunks, and the ones that come after the IDAT chunks. +It's necessary to make the distionction between these 3 cases because the PNG +standard forces to keep the ordering of unknown chunks compared to the critical +chunks, but does not force any other ordering rules. + +info_png.unknown_chunks_data[0] is the chunks before PLTE +info_png.unknown_chunks_data[1] is the chunks after PLTE, before IDAT +info_png.unknown_chunks_data[2] is the chunks after IDAT + +The chunks in these 3 buffers can be iterated through and read by using the same +way described in the previous subchapter. + +When using the decoder to decode a PNG, you can make it store all unknown chunks +if you set the option settings.remember_unknown_chunks to 1. By default, this +option is off (0). + +The encoder will always encode unknown chunks that are stored in the info_png. +If you need it to add a particular chunk that isn't known by LodePNG, you can +use lodepng_chunk_append or lodepng_chunk_create to the chunk data in +info_png.unknown_chunks_data[x]. + +Chunks that are known by LodePNG should not be added in that way. E.g. to make +LodePNG add a bKGD chunk, set background_defined to true and add the correct +parameters there instead. + + +9. compiler support +------------------- + +No libraries other than the current standard C library are needed to compile +LodePNG. For the C++ version, only the standard C++ library is needed on top. +Add the files lodepng.c(pp) and lodepng.h to your project, include +lodepng.h where needed, and your program can read/write PNG files. + +It is compatible with C90 and up, and C++03 and up. + +If performance is important, use optimization when compiling! For both the +encoder and decoder, this makes a large difference. + +Make sure that LodePNG is compiled with the same compiler of the same version +and with the same settings as the rest of the program, or the interfaces with +std::vectors and std::strings in C++ can be incompatible. + +CHAR_BITS must be 8 or higher, because LodePNG uses unsigned chars for octets. + +*) gcc and g++ + +LodePNG is developed in gcc so this compiler is natively supported. It gives no +warnings with compiler options "-Wall -Wextra -pedantic -ansi", with gcc and g++ +version 4.7.1 on Linux, 32-bit and 64-bit. + +*) Clang + +Fully supported and warning-free. + +*) Mingw + +The Mingw compiler (a port of gcc for Windows) should be fully supported by +LodePNG. + +*) Visual Studio and Visual C++ Express Edition + +LodePNG should be warning-free with warning level W4. Two warnings were disabled +with pragmas though: warning 4244 about implicit conversions, and warning 4996 +where it wants to use a non-standard function fopen_s instead of the standard C +fopen. + +Visual Studio may want "stdafx.h" files to be included in each source file and +give an error "unexpected end of file while looking for precompiled header". +This is not standard C++ and will not be added to the stock LodePNG. You can +disable it for lodepng.cpp only by right clicking it, Properties, C/C++, +Precompiled Headers, and set it to Not Using Precompiled Headers there. + +NOTE: Modern versions of VS should be fully supported, but old versions, e.g. +VS6, are not guaranteed to work. + +*) Compilers on Macintosh + +LodePNG has been reported to work both with gcc and LLVM for Macintosh, both for +C and C++. + +*) Other Compilers + +If you encounter problems on any compilers, feel free to let me know and I may +try to fix it if the compiler is modern and standards complient. + + +10. examples +------------ + +This decoder example shows the most basic usage of LodePNG. More complex +examples can be found on the LodePNG website. + +10.1. decoder C++ example +------------------------- + +#include "lodepng.h" +#include + +int main(int argc, char *argv[]) +{ + const char* filename = argc > 1 ? argv[1] : "test.png"; + + //load and decode + std::vector image; + unsigned width, height; + unsigned error = lodepng::decode(image, width, height, filename); + + //if there's an error, display it + if(error) std::cout << "decoder error " << error << ": " << lodepng_error_text(error) << std::endl; + + //the pixels are now in the vector "image", 4 bytes per pixel, ordered RGBARGBA..., use it as texture, draw it, ... +} + +10.2. decoder C example +----------------------- + +#include "lodepng.h" + +int main(int argc, char *argv[]) +{ + unsigned error; + unsigned char* image; + size_t width, height; + const char* filename = argc > 1 ? argv[1] : "test.png"; + + error = lodepng_decode32_file(&image, &width, &height, filename); + + if(error) printf("decoder error %u: %s\n", error, lodepng_error_text(error)); + + / * use image here * / + + free(image); + return 0; +} + + +11. changes +----------- + +The version number of LodePNG is the date of the change given in the format +yyyymmdd. + +Some changes aren't backwards compatible. Those are indicated with a (!) +symbol. + +*) 09 jun 2014: Faster encoder by fixing hash bug and more zeros optimization. +*) 22 dec 2013: Power of two windowsize required for optimization. +*) 15 apr 2013: Fixed bug with LAC_ALPHA and color key. +*) 25 mar 2013: Added an optional feature to ignore some PNG errors (fix_png). +*) 11 mar 2013 (!): Bugfix with custom free. Changed from "my" to "lodepng_" + prefix for the custom allocators and made it possible with a new #define to + use custom ones in your project without needing to change lodepng's code. +*) 28 jan 2013: Bugfix with color key. +*) 27 okt 2012: Tweaks in text chunk keyword length error handling. +*) 8 okt 2012 (!): Added new filter strategy (entropy) and new auto color mode. + (no palette). Better deflate tree encoding. New compression tweak settings. + Faster color conversions while decoding. Some internal cleanups. +*) 23 sep 2012: Reduced warnings in Visual Studio a little bit. +*) 1 sep 2012 (!): Removed #define's for giving custom (de)compression functions + and made it work with function pointers instead. +*) 23 jun 2012: Added more filter strategies. Made it easier to use custom alloc + and free functions and toggle #defines from compiler flags. Small fixes. +*) 6 may 2012 (!): Made plugging in custom zlib/deflate functions more flexible. +*) 22 apr 2012 (!): Made interface more consistent, renaming a lot. Removed + redundant C++ codec classes. Reduced amount of structs. Everything changed, + but it is cleaner now imho and functionality remains the same. Also fixed + several bugs and shrinked the implementation code. Made new samples. +*) 6 nov 2011 (!): By default, the encoder now automatically chooses the best + PNG color model and bit depth, based on the amount and type of colors of the + raw image. For this, autoLeaveOutAlphaChannel replaced by auto_choose_color. +*) 9 okt 2011: simpler hash chain implementation for the encoder. +*) 8 sep 2011: lz77 encoder lazy matching instead of greedy matching. +*) 23 aug 2011: tweaked the zlib compression parameters after benchmarking. + A bug with the PNG filtertype heuristic was fixed, so that it chooses much + better ones (it's quite significant). A setting to do an experimental, slow, + brute force search for PNG filter types is added. +*) 17 aug 2011 (!): changed some C zlib related function names. +*) 16 aug 2011: made the code less wide (max 120 characters per line). +*) 17 apr 2011: code cleanup. Bugfixes. Convert low to 16-bit per sample colors. +*) 21 feb 2011: fixed compiling for C90. Fixed compiling with sections disabled. +*) 11 dec 2010: encoding is made faster, based on suggestion by Peter Eastman + to optimize long sequences of zeros. +*) 13 nov 2010: added LodePNG_InfoColor_hasPaletteAlpha and + LodePNG_InfoColor_canHaveAlpha functions for convenience. +*) 7 nov 2010: added LodePNG_error_text function to get error code description. +*) 30 okt 2010: made decoding slightly faster +*) 26 okt 2010: (!) changed some C function and struct names (more consistent). + Reorganized the documentation and the declaration order in the header. +*) 08 aug 2010: only changed some comments and external samples. +*) 05 jul 2010: fixed bug thanks to warnings in the new gcc version. +*) 14 mar 2010: fixed bug where too much memory was allocated for char buffers. +*) 02 sep 2008: fixed bug where it could create empty tree that linux apps could + read by ignoring the problem but windows apps couldn't. +*) 06 jun 2008: added more error checks for out of memory cases. +*) 26 apr 2008: added a few more checks here and there to ensure more safety. +*) 06 mar 2008: crash with encoding of strings fixed +*) 02 feb 2008: support for international text chunks added (iTXt) +*) 23 jan 2008: small cleanups, and #defines to divide code in sections +*) 20 jan 2008: support for unknown chunks allowing using LodePNG for an editor. +*) 18 jan 2008: support for tIME and pHYs chunks added to encoder and decoder. +*) 17 jan 2008: ability to encode and decode compressed zTXt chunks added + Also vareous fixes, such as in the deflate and the padding bits code. +*) 13 jan 2008: Added ability to encode Adam7-interlaced images. Improved + filtering code of encoder. +*) 07 jan 2008: (!) changed LodePNG to use ISO C90 instead of C++. A + C++ wrapper around this provides an interface almost identical to before. + Having LodePNG be pure ISO C90 makes it more portable. The C and C++ code + are together in these files but it works both for C and C++ compilers. +*) 29 dec 2007: (!) changed most integer types to unsigned int + other tweaks +*) 30 aug 2007: bug fixed which makes this Borland C++ compatible +*) 09 aug 2007: some VS2005 warnings removed again +*) 21 jul 2007: deflate code placed in new namespace separate from zlib code +*) 08 jun 2007: fixed bug with 2- and 4-bit color, and small interlaced images +*) 04 jun 2007: improved support for Visual Studio 2005: crash with accessing + invalid std::vector element [0] fixed, and level 3 and 4 warnings removed +*) 02 jun 2007: made the encoder add a tag with version by default +*) 27 may 2007: zlib and png code separated (but still in the same file), + simple encoder/decoder functions added for more simple usage cases +*) 19 may 2007: minor fixes, some code cleaning, new error added (error 69), + moved some examples from here to lodepng_examples.cpp +*) 12 may 2007: palette decoding bug fixed +*) 24 apr 2007: changed the license from BSD to the zlib license +*) 11 mar 2007: very simple addition: ability to encode bKGD chunks. +*) 04 mar 2007: (!) tEXt chunk related fixes, and support for encoding + palettized PNG images. Plus little interface change with palette and texts. +*) 03 mar 2007: Made it encode dynamic Huffman shorter with repeat codes. + Fixed a bug where the end code of a block had length 0 in the Huffman tree. +*) 26 feb 2007: Huffman compression with dynamic trees (BTYPE 2) now implemented + and supported by the encoder, resulting in smaller PNGs at the output. +*) 27 jan 2007: Made the Adler-32 test faster so that a timewaste is gone. +*) 24 jan 2007: gave encoder an error interface. Added color conversion from any + greyscale type to 8-bit greyscale with or without alpha. +*) 21 jan 2007: (!) Totally changed the interface. It allows more color types + to convert to and is more uniform. See the manual for how it works now. +*) 07 jan 2007: Some cleanup & fixes, and a few changes over the last days: + encode/decode custom tEXt chunks, separate classes for zlib & deflate, and + at last made the decoder give errors for incorrect Adler32 or Crc. +*) 01 jan 2007: Fixed bug with encoding PNGs with less than 8 bits per channel. +*) 29 dec 2006: Added support for encoding images without alpha channel, and + cleaned out code as well as making certain parts faster. +*) 28 dec 2006: Added "Settings" to the encoder. +*) 26 dec 2006: The encoder now does LZ77 encoding and produces much smaller files now. + Removed some code duplication in the decoder. Fixed little bug in an example. +*) 09 dec 2006: (!) Placed output parameters of public functions as first parameter. + Fixed a bug of the decoder with 16-bit per color. +*) 15 okt 2006: Changed documentation structure +*) 09 okt 2006: Encoder class added. It encodes a valid PNG image from the + given image buffer, however for now it's not compressed. +*) 08 sep 2006: (!) Changed to interface with a Decoder class +*) 30 jul 2006: (!) LodePNG_InfoPng , width and height are now retrieved in different + way. Renamed decodePNG to decodePNGGeneric. +*) 29 jul 2006: (!) Changed the interface: image info is now returned as a + struct of type LodePNG::LodePNG_Info, instead of a vector, which was a bit clumsy. +*) 28 jul 2006: Cleaned the code and added new error checks. + Corrected terminology "deflate" into "inflate". +*) 23 jun 2006: Added SDL example in the documentation in the header, this + example allows easy debugging by displaying the PNG and its transparency. +*) 22 jun 2006: (!) Changed way to obtain error value. Added + loadFile function for convenience. Made decodePNG32 faster. +*) 21 jun 2006: (!) Changed type of info vector to unsigned. + Changed position of palette in info vector. Fixed an important bug that + happened on PNGs with an uncompressed block. +*) 16 jun 2006: Internally changed unsigned into unsigned where + needed, and performed some optimizations. +*) 07 jun 2006: (!) Renamed functions to decodePNG and placed them + in LodePNG namespace. Changed the order of the parameters. Rewrote the + documentation in the header. Renamed files to lodepng.cpp and lodepng.h +*) 22 apr 2006: Optimized and improved some code +*) 07 sep 2005: (!) Changed to std::vector interface +*) 12 aug 2005: Initial release (C++, decoder only) + + +12. contact information +----------------------- + +Feel free to contact me with suggestions, problems, comments, ... concerning +LodePNG. If you encounter a PNG image that doesn't work properly with this +decoder, feel free to send it and I'll use it to find and fix the problem. + +My email address is (puzzle the account and domain together with an @ symbol): +Domain: gmail dot com. +Account: lode dot vandevenne. + + +Copyright (c) 2005-2014 Lode Vandevenne +*/ diff --git a/data/block.bmp b/data/block.bmp deleted file mode 100644 index 40bca7ce1c5b22a57a7eebbc60bc715ce9948fd2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16438 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 diff --git a/data/block.png b/data/block.png new file mode 100644 index 0000000000000000000000000000000000000000..16d2c24b924a3f4156c362e5162bf4c1f2129f93 GIT binary patch literal 4280 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hEk44ofy`glX=O&z`&N| z?e4W%r5Zturkb}NyOroCwEqia9bbV-W^u!##)FrPChfA{?F!#h8D zwa(0ytn>Z6?$?}Wxc1lKXkA-Dm2{pd?&zoM~sD0R#ujWi>v7R z!ug;4qobwQ#qH%FwL^ReAq-yZt`f*6rJ+ zT^Xt(r?s9t=f}dzy3)u;^Sj}Zg*vsMYJb?R;z2ZSxj@;bb z2`Vr77$&DZIM6tgK|oga?bnX-_xFy@umAV6oOxk*R(^i_%^W-Kc2(c7m0|u%U%ko_ z5fy#7e12V1(v7OOEk~N!`EBN%ooiiQ@crH0I>%#48#UOzt1)D(346_8o}05*@z>w) z_mdwUYW48*JGRKRd%@ML-*a5t+}Qf$?cYs2z|JRg;LXj=8!JCQt7Cj{W~TAF&rC{6 zNsbBmP2i)}NA7iJ&#%utGsCd<)c+si?0hl_E-ozhYd-siHj9af2r%@^S}%*b zaCWwN@ZyUFCnu@C@xQgJbTyO1#9(W6|9O8La@oVz#UvIK7^wTqSkSe9(V`}Xh?tl) zQ65Wu9UU2e&n|m+XC=di8=MYqZpSK3dv(RQm6ere&Y5$jonL;}Q}dZVEC(hkyI)G% zyi(}Hi;Ig{4)pZ!cul(Up5e{Cz0r&bJDCpr4P5MYx8(YTyzR!;*0Zbj&fA`Uzs!2V z*|f(eCMt6_s7>~qTENT8`{n!h^qQJI;gdJt%+b-+eR{N8{BD+bgD8Un(}f8=1?jfw zXJ@reR`*}DX_L^$k00~azGauMY54s7{NhE6m^NB4 zWo6~y=XWnEdOz>(QQqu1g=ZcdY~KCL>D%V>cFGKSx3-*A_Fi4a>pkg6PY(~%gNuvZ zZRNWdAr|hw03VPe0)ruA>%@ZiLba`%#WXi&t}b%;*&6F(BJz- z=xy0<_t*RO?TefGVRiU=HHLL@dv87N^qzEN%^IC76RCMNl|fspOBp_FWO9&gxP81& z*82aBsHIDm6kJ&mxQbOvPw(3c-*-1QHZxeHpOaaCZ_gsj>hJHqYV2Tga1_`V&agwH zE9vvi&FR$!`~LlU?c?pe_-4+x6SXU2zjv9QJ9q9|)+ert)nRKtt%$9xv}7#!@ZjKn zO@@${C03Vb8mG_k2@MUMV^?dHot+(8o?{@9VIrk@dXxLUINtjFw|g1iA8cl4Iq-a5 z^}9Vx2iltyVhULo?A<%Jx3_ndwXA)e4daI|FE8g+N=r-Ee)_ua7+1{{u1gsvR<&<` zELgChIIE>zD);`rxePykKA*q(lYpY4A`d6$!lOwav-bS>QNhN-QZXgOmbc-;g$rS< z4Tc*xZk+Bv*Xn7Z``52u{X)aE_w3)l-~HCr_>G4iGqkj}Znb3e@bK92P?KSjilM3L zRE9hI&i)g)cRk`^A%l{V(itv>nVg)Q_1CUksZhNz&$jx`r)STf|5n+fztJh5;mDCA z5h4u7q}s`1QLx zI~T7yeC(Lp)z@`*ca^dn5Y-N=P~EeBBa`Q}DN}3~F72~eaGBGgq~uHJR#o+*T)Vq> zi$47P`E%{8J=-@jdG7oB?e>|ICm(LjzFxKDt5k2B+v1I}j1T1h{rl$|zAmQlc4ArC zHZA98*@27g)#lHheR{P@i;jPP`}XaXmnA)2UAvYue2`zHv2E98#?@hKl^EXL z*!VbJ>ctPM%E)OmXU_C=6xdP!|DSr@`&X}$0s;c~8J4{)vHHBwxxHrH#h+3yG)h_W z)!)C$tNv_JwtKFipkPl&M@Aq+Md37Jw45GV9OSh^;hH8 z?(XgGUc7(*{!qq*rnvR>JIdbPT5k0G>C-@wqjs;WHtGBpc@eX#r1Rgue?8sZ)rV47 zs`}r_jfjvawVHdGH%*$SZQY_pih=3RdA|L%s9RkB(*67MK{-~-s`eo>3bGI828H-3bLLIrO<%Rk!gcqrW>h|2mv&~xLakXP)9?Jab$o$i^NOok z*|GggOM9iw&z<~mT)zIppP!%oc@>zLnfDq+bv?MZ?C89d>EGYqe}1f2y7K?OzsvvG zB^}{l`XL|AU^Vs2wv8Jn-mm%0JA3x*-)k2w&RJU-b*S#vlk_t)9!@L2x2G~@OGe=O zhd(wX9_DzkNt=Ox(&WjWljQ6F7@j_Tdg@$-o7cPg*55mH`AXHzO{p>_83FTE|DHJE z!DR7lSLUsWvu2%YX6N6uVZ(&4U%&1te=p}*^z_u!P1{%9mS^R?{^mlg-ln?0RZ=`` zb$`EJul@A%=TE@{-`6qBXy=zdceGo)`1-n7o61irvuDlPk$>Ng>A{zmmu;{E4QZR}kH6fQpy<4#?r&9CXlUX4dwX-TvXXp!c;YJ_vW7}8?su-w%Wj{&?@><%_c6MP0cYfs=6D9<#4r!?S^U?j^RTa-kS)paV*~&^v zAs_dBJSOeq>6utrX}Ngu;+H#m7<(UYsYoa&_~6R$<59Q%g*$itOrM`O&$4*g=YUWr zr>5wCKR-WTymTq+)2C1KDo>v}wW0cZo`|TZqM@N+Vq#*!9XUpsa4(CRA0Pf}X=^{; zl6iTLQO&*!`uqPp3Uqybq*M4x)>a)Ios!ep8zVG0nu?V{$wU;T2nvx1lT1nzC0Fl*MSh0g7(9-TdP>Q!Od%X@pPef<63Gaj&KIMLbJ zx&3$c=ZnEsB`*Z5t*k;m>P2tsF*Gz>#h0w%_UWUHOW|cMhR+NIZ*FXybTnz=PxED$ zm-`!ATF#8G`?+-0qRu20*>_hgw;wp*V3jwGkzpFcgEn62C9K?H6?-TCT)%AFHZ#9j zCY{{kdLg1SwU!^$($@C8^p2}1Z1vK|UUL^zFwU_q_lu5<-roA! z68iStyJKHpU;iJZ9~d6qe&mSDlxfqP7GK=))V}VIMH{blTX1bcia(ZZCp6~1Fnds=qxO>;GjLkQntXidYZm#w8t5>hul)e&~t{Z*q-MhT>y8Q_U znIgqoR z1rHq3Qd4a=vUD-rINm4gz4_*urQXwvzP`Fz`ts#V^X<8})7GwE|NP0x$&pb}UX$)@ z%@$woJNwwISyEn;j!c>)RQKtmy2{DT>F0}HU0JE4t*!j?MaHighRGFAP6$qV^85Y% z^LzH}k-He_=g0T_?Cj?u=Z|+w%$++Il-9GKhX4Ede12qjxcekE)*Gj%>swE6yO}d> ze%Qrbm7mq#-`VMWywxv~@xgw^4;L0X>*(n%yO@zuRb?fvALq0C?zxr0%dP(Ay1KG1 z_nCPpzW(o2mB^5gBjNG2Q_b`4Bt%C`gTyCI61tUR7Pq^s*V585WZRvtt}ctZKNac{ zckkZy@%By*3Yv78x#s)ba@#uvp`oJcesfN&joxmh9v&Qg_|2P~m21|#(K}f+=~KIW z-HDbK7Bdr*2`c6}Hx6976qGLQIZ5NR(RBUzb93g%w6(QeN-z*`kYTvPbl~Ub=f-Ac z(>8A0c;@Wcr>)%LGv?1fzh#Tby4c;*|_ zw93g_x1!WkR1ECx@9+HLqb4jYENof)%;&jBq;^N|;zu)hltfH;0 z{qvml`w!RFMuYNqUY;I1pNxmSy*=lF2u6p+Zi_qRjZ!+6ZQUx`q>%9A!^0J8*S_6T z{(hdHh%0A9!qzC)xqiz2Q(K210J&G!8J*Urqdjh=5?`S^ySr(PxH<%iQYC!U>U+R@W zJ8$!uN6mK@%cO|yd9qB*%p23s%f;-klRbL$C#x>Sy@?I zE3-Im@a}gqYEH79nq4f_>n7wH_FpF=R4r;60Exb(5P#OILZ!b^aob6{R)r zSOnhgh_gTNbk-g*2kC}u$JZUxD*taKE8M>LRPlvEQ~MJa!wnd08Jxqyu8B-O`Q-YA h3m@M1S=#-sXP*1Rqrs73Dgy%pgQu&X%Q~loCIBS!HR=EW literal 0 HcmV?d00001 diff --git a/data/bunny_left.bmp b/data/bunny_left.bmp deleted file mode 100644 index 20944b0b559be452e3a27010a5a794833922bc2c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4150 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 diff --git a/data/bunny_right.png b/data/bunny_right.png new file mode 100644 index 0000000000000000000000000000000000000000..b159463cab36f63a75195ad39ce569542304b087 GIT binary patch literal 1914 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}jKx9jP7LeL$-HD>VBjq9 zh%9Dc;1&j9Muu5)Bp4VN*h@TpUD@xk$%(Vb#pL)WGBB|7c)B=-L>zuQEjJ_NrsVPZ z@Aqa}8_%3RpP!wTXPE!y*4EQ? zZ*Oh=6QH4zdwZMi{vA7Ze4HzABE?Af_xJbHjb`#(%m~?0^74}V0mVQO+l>)CvDY&* zG6Yg0|1m1;>1yDWV5noevd6XNpg~XV-o1MR9R)TuDHvE*1Nr36jL=P8^_QO}MT}#>+af;ErAb8r-^UJd<(|VZe+3n`&wkArL zM@2_pKA0eI*dStSmZ*N*o`i>oT6e^(yR)X^zpK+MySIwF@8+@k96frpq@*Nc@#4j^ z%iiC6Yg76vPMT|`IF3MuUx<0|HLL65x(~8l5K(ZzFHhx+MO24?~c*SuB+QO zVg7u7tGUZIZ=PKG`dX^r9E*?s2h79cE}vQX?*9J#X{nWs%Q7{(l(f5=R6JD|X-qns z=BYOM&E4J8L$pFwx*l!U74!b|^78V%(c5x<##+s-WBFqu)cNP+`|tlZY}vBqfC0~$ zG~-1Yi&m|wJlZ9yT(|$f^?}JZ*FW|V{lh5W8Yr{3=qcCne);L5u8J~z!o6;uOM^I? z8dN-I_^3@fsWQ<+W&O5o-`o!-6s%gej_-km!JF^Dg(s<8ynEL-Iayg;FGgXePnKN& za;6P?R`Jwxhy1Fs)12s$awpIHWr@tU~3vnp)tg2Q}#d=|X6x|t*98mOVItsT3&?5+9k zUAwgY)YUIrx$>meX`?2EgpCnrqPOSi^0zvv-o1PG>4CSBl1D6WzPMtNt1|9-KeKKXz$B%_V#I^=s$Q z(4w6(O$rxo-}WvoH5C;Vo#CSv5~?b~weYpou65q&=jWAL%JAv^`&t2uevw{kUqV-!1m~#3vSQdymh5 zkEsS}h)8|^{g=Dp_hwarh7=t!;j?MRD?_@{&(8~ti}OoNRD4)4!$rwaY2t$Y`{yrQ zsMvJyflpY`Odq$6H*;e4R!x0=e!jA&&~pFzY62CfnkE@^Eiy1LaHy}hZ|9efN1o?z3sHgF{POO^!QFUA1c0 zo!4KFiMY<(UiCGrt-XC`-CwI&%M2|oPhPnqQdwDfXIE*rYqyx{G@VGNxVU+mQ@u78 zK6YERYSoIBD-&~adKN8Gx^??@<-b3b=km65cP&cT8nyZC*|T?TZEfAmX6OFf<@T8I zS65fpBk$>YbN3fN_uIH-%ar2h=Pq8lG^xl!X3_1p=Z+?AymRHsl%h8`Htsoe$Z7V` zq=zRaDwmX%ZAv>UrKPPcDJgj{$L#Zqi^`KuK3Q@2p+WX6v2c;6LLWX~FWvs<<#b(! zCwt=Z*DYG~$oqk$fz8~taSx7eNl!@|R-f2go|7{2qd`PZt%s)Zj+rDrs}`BE<(z+c04he7FbF`w`H ot;|vr>ZX5-so-Y*Ec%aE;FE)(T9|?!0|Nttr>mdKI;Vst07wFvNdN!< literal 0 HcmV?d00001 diff --git a/data/carnivoreplant_left.bmp b/data/carnivoreplant_left.bmp deleted file mode 100644 index 5109d15de97d24ece65b969c8a4d80549777d4af..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8246 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 literal 0 HcmV?d00001 diff --git a/data/carnivoreplant_right.bmp b/data/carnivoreplant_right.bmp deleted file mode 100644 index f6707eebb687d8424f09397bc07436441d5bf6db..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8246 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 literal 0 HcmV?d00001 diff --git a/data/earth/0.bmp b/data/earth/0.bmp deleted file mode 100644 index 1dbbb7d966b96d368655910020ae1a26539dc030..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4150 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 KAbn!*p8o)AXubLX diff --git a/data/earth/0.png b/data/earth/0.png new file mode 100644 index 0000000000000000000000000000000000000000..872989fa75f09fcf7be020b4037b17354510b9ce GIT binary patch literal 2682 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 literal 0 HcmV?d00001 diff --git a/data/earth/2.bmp b/data/earth/2.bmp deleted file mode 100644 index bc92eb4ea76fbe7efe7f25b29738aae11ce9705f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4150 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 Qw%<5~rI$j>Uy$t#0FF(f+W-In diff --git a/data/earth/4.png b/data/earth/4.png new file mode 100644 index 0000000000000000000000000000000000000000..2563dc4e1cde3e8dfeb38a47343da17bea4829de GIT binary patch literal 2705 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 literal 0 HcmV?d00001 diff --git a/data/earth/5.bmp b/data/earth/5.bmp deleted file mode 100644 index 3fc85d27e0fee73e1242df6e314941ffc718a3ae..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4150 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 E0NNs%%>V!Z diff --git a/data/earth/5.png b/data/earth/5.png new file mode 100644 index 0000000000000000000000000000000000000000..6e3712f08a658191001e034097e9cb7ab4fce807 GIT binary patch literal 2728 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 J%Q~loCIE?*CxQR~ literal 0 HcmV?d00001 diff --git a/data/earth/6.bmp b/data/earth/6.bmp deleted file mode 100644 index 7bab085c8088f60bd94d84dce6637af5f6b9df64..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4150 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 O1`fUmaC@AAfdK$`7`j~m diff --git a/data/earth/6.png b/data/earth/6.png new file mode 100644 index 0000000000000000000000000000000000000000..16fa591e24a3ec248def5212fe9c222f36778495 GIT binary patch literal 2914 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 diff --git a/data/earth/7.png b/data/earth/7.png new file mode 100644 index 0000000000000000000000000000000000000000..8fd0ecae86e0267e4431c749830fb451d3aed71a GIT binary patch literal 2994 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 literal 0 HcmV?d00001 diff --git a/data/earth/8.bmp b/data/earth/8.bmp deleted file mode 100644 index ce12062808d1dd58a6fba26c76a0621ab6af51a4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4150 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 P3=9mOu6{1-oD!M<-*j%8 literal 0 HcmV?d00001 diff --git a/data/earth/A.bmp b/data/earth/A.bmp deleted file mode 100644 index 78cf27933388e4c24317076594fdcb42fc57b14c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4150 zcmZ?rH4|U}12YB&1`P%V1_dZ)1hW_z7z7v?gt;LYtPn&*Eaqp3Sj^54v6z`5Vlf9p z#9}GNu=(G}0 z@`O(p6|_lWVP|J&R#8!5*U{18DJv^u5fT#OVqjoUXJBBE1UZ+1TU3pKOGJr*m5X0N zL4nP{z<@(YNQjkzfq{jSlaqPNmMx4K85xXB3KpQS1G$?SWDf%a11lpVBRdxt7aIcu z16YoOU(8rYLRL-8&_j(=&tH>~ja!I`M?`{6T-BUYT*+NgMO~X;P)Lt~nJtNdjk}yd zLbsJcKl~_zZpaD-Ex&3eb@wb*35_UbHcmGNMkY%Z78Wf@Nl9^jetsbaUI}>y4gnno zW;O{11_m)E7B*!8ArT!(Sw%x(Idw;FF$I5hr>GmE25#4RHS8ZU$XPyQ(C}K%pc}H6 zQN!aZi=_5$8B?Dva@HXSI8^O!GfL{dVGvdS&7ffYk3ru0H-oa{FD6yzzpP5uADN}~ zpD_t5U1H-CS;fi8)xgZmT+YD2SjoUCRKXysp3fj>-oq;@Jzdw(beX2H^)7KG-D4aQ zYIm9C&Hph->iuVsxB1VY>HD9-JncV&Mdp77-Qa%=QifmIR2_fGS%?19a*h2jtYP_| zTUO^kqnz1)1_{0Y46pz3C<9`Nar~mAluK$%B zWByAUy8P!;wfxU0YxYo1@R9*fvsJQ%R(D3=spkxoxs}uB} z!6^1WgL&$IM(67P46cp;8LadFGiV1w%vW-N=+O)N&t?$(pT{KZKf7_ne+H9;{|p9E z5ce8JgYDqda{tevZ1tZ>*7!ezycO783~KI>FqOB4m}!y-314mh{|pM&{~5IW|1-MQ z{pWTq|1T0g;Xily%>RsD9se0DGygM~r9$k`4TjLB$&hf-3;WMtTlAm7D)&EwKFBSJ zU~?E$Tp@nc@P^n83LoQy{|rWP{~6Rg{xj$V{$~L3t#TlG&Ch1I z>lCj3FC5tRpG`mbKcj2?e@>Uu|137y{~3)y@sj+X!6XS{7btxg$Ny(Ai2l!DTlk;R zuIN9baU8_WM)458g7|hN{~28B|1((ULgD}vRtAy(8LaalVeMG;pTV)}KdW`de@UN; z|88~b{(Gc1{nwAE{x6p_>%Uauy#H)oO%Q+Th5u(TOZm?L3I|ZwfYORV)PF{&ivPTR zZT|(mYW_1iRsLtN%=*uug%9?ydhBoNE3vSfu}F0EIs&&K=7CGuY(+XYlL< z+YfRNi(SEg+1Sbd9ZDDd4{TcV-=Sgqf0@kH{~3d)L&6Ib=gxKi89?C=N=N4DVD~V) z)&Ca>Z2d2rIQu_KK>vRRP&xwTBi+#d40dJz8G>j3XK-(U_!$&$Aa`44L-^(ykh}&8 zSA(ekEVeoSr6T+O>*X!^uUWY6zfkx%GKSS`W{|o_B{xkSZ z{Lkdx^j{>P`M+j#+kf4hMgQ5nn*THS_WkGasQJ(BS^J;Str22>z*MkX8SG0T{so1N zrVk`7`SgO#0;MAckbAWJ!QsjnFzG+1chi4?;O_sdUM>F_{3ris2$}t#A#mD%rr_!S zS%aqhXA7G2Uo5=uzd?N4f6eqc|CvK){pSy#@?Rxs+JEu*+5edWCjDm!nFG;lR|NJ8 zqi5THusiI_{xg8ES0~&*;QS9tU!ZWX&Hpd%U-w@xdBT5<#EJif6BhmFikkPIBXrt- zxun_uHFK8!mrI=WUm?h5Wfdb`_JG%=|7uq=YMwlTuAygPx&w8S^3|g zeChv$2|ND>wQc^d7g76P+A`?Bnsdy5oshEsl3vCCIjmCu3tIX97qhbeFQ}~ZUtHhi zzer%qf7YPM{~3HI{AU1#uY2=%U0E7_FvY>`M;c**MAXxxBtAV zmj8KmJ^nN4hyG`@Hv7+_E%TpMR^mUeg5G~2yX60z{@wo>eS7~i`1C>C;NAV7)vXqs zS7oDm|0^WU{I8t8=)Z_X_yGlcX0XJ}>p&yddfpH)xxKbL~>e|DqL|4a!I z{~3Ha{xgPf{bvZ1|Ielu@L$@u^1or;!vDI(>;4;*to<(VY{BL5iznEo@Su>NO^R{GDN?C_t}AmqPXSlfTof+hd0 z^Jo7T^{M>NXc+aM0hISZ<(IV5e+Coz{|v=E{~0{_{xir~{%6v^MT`H8MgjjBvRM8zgfaYQ z$YK1?8n5%8LB;kzgSyv$CjIdL>~^{TIV=+YGlA+KH~s$%@!bCzOqKsL7>oaBh~xXu z(8vFup<3oYw^!MJ8Q-%1Y;ofMxq1cuGgdMGXRu=a&!8pwpIJBHKSQ4Ue};aB{|rS8 z{~2N!{xe%@{AZOl{LkoQ`JW+=;Xgw(!+(YXhW|XphX2`(?EW(-*!*YEaQ@F=WcZ)K zSoJ@XgX@2$DuMqDHC+E0LOK641akgoXkz)#&@c3#sayWPV3Wyz)>xkZVu{lK?Uy+J z=W7x8&*;GVpV3bGKa0Ene}+nq{|sFqKZ5LM{Lk)f@SjcHREB}Aydino?5f=Ydee?edga-U)NN4%a z70vzMzQf_a+kD^uyv?Hj8N7M^Go`TpXX<19&oqtsKf^R8aM*HZbN}~k^!uN>HSNDp zzsP@vP}cv9@r?gPCy4#mnWg)mZ!-UX#!BY@%-L-JnHmKDbG1tS7pNEhAF(9jf7^q--e?LS8x$A8NURpFNl3zrjMo{}xLu|MN`~ z{Lj+P_Ft?;@;~oX{{KvqnE!LMaQ(NMXZ=5OYu10Y8S4L8y1D){=JNgLDlqsj)~oZM zt&aUaYYN+cy%vN2IlFWJTQ0Tw&zCFsU$a%~zxHC?|FL`G{-^KH_#dz}5NwbA42S<= zo5TO>EHU^i)Ft{)v_t%V;Fh5OA)CYhtIgB@FFIY~zt(*1|0XL<|BKEM{VzIE;=jvE zum2T?EB{Aqjr^~*R2v+2LX$=Qt1MLgFWM*mpR1Dlzk0XE|NMgm|0B0Y{a5W){jWV; z`@hjj`MI~u_N-o??%7>ew+RO z2W}1e@4qSFpW71mf36GM{-*9t{a1RV^k4q2{D1M=;{V0&jQuy^z=S{3_f7vl@8GZi?x5Y2* zUhQ9|lTE+6FK~b3J>UC_=Pb`3_H*q2*v_{7>%G+bZ|u6*zXdxBepTw9n*Yu?GUM;$1C#&FJwErZTeI6U&lb-QAsr!4{VV)W*@W6Gln#(y%A3V|oi&g3 zDNiZSJDzNwj~q!HAGm_J4)8?s>=Vosyv>=+`G_r({RLk(-xI+!!MnW4yf66T_+Ij+ z@IK~E=Y7JL!S_fsOZ0(ak>Ycma-HY4)wYjy({x`LBpbZ9&a(b$o@)NpFxl{U|>t~ zc6VX;4}uH!E}zW6z`$AH5n0T@z%2~Ij105pNH8!ku$OrHy0YJ6lM`n%JlZX=i-Cdb zyQhm|NW@{?X{Y;BuSXuOuby9f?|ba~b?a8W(@Q=s%cH`mxlORe#pqCnh7H@y1M&xs zI5q8WP@LRzP+3Vur8|<}!Bb_4hT?@|Ki-z@z8f2QH#9c%d+9sd?|aVQn|<(W#rwVc zwqD!5&p-Ol$M4_vy>G4BKH-qAu;Kqdj-Lx=F6;i)e@lGU^t1L18%vfL9Q(7~;_>{} zhm(}+4zGI=X!vpYt4A+Rzo`6V{gd0%{l6Ti*)ONs2XkLk7GJ;PyZwlH%cS;sp_?jK z)hqT0oKqPmh|5~8#F`SLj5 zW~=>dS>kIjRWNH=`lG*3{_i-o-eTsQj=GED*1xT5_Wdxi*}p^JlEtG1Y6 z%3nRd<@a}A|H$FCFVw#Bm++R{ND1LzL^vZ#}+uZ%&G};#SSl(Bv5Q<1atd zC|a&vHbZbn)FaRS*H=v^mpDxf3z^HN70}qW)@xJfm&yz4Dk^?z7G<6MEECLOl|Jo# zkLHaTuoRUlSPT5=6zvA1EFQ>V=?A33z8EI8o{bhRS zbTLhWahXvBZ&37w&WF4Aulo5qr9Djj&-<&jmu!w+5i{P{!F}3~ZASyUm`1wpjIB#g&if#vw7`E6<(V3FZ#1O>WUL zi646sE^wr6J*dfAd3#f)B3EqP=cBfK`ELRu`j5xkso2c_@TmCoo`&PBEKDKkZ;CB= zDl)epzL|RHoVaCO+QjDyX&Zzc7d-gLb458rdBRl3CvBH@L}&*3HZONnTd*`$p!(0P zgJQpTOS|}aYDjJ3^Qk?!rS)vzf$~HZkyp3#rmw$$XTfdxAnBt&pU$|)Zn=&{y&+n; zVCretw2G3n7i>)xJa=Of8`oSZ5poV=?mT*4WS+cG^@bU7K_487gujJ{&)Z2ou2;)gJtrjO z%WeVh!x=gn!tG_69CI4pEo{DjE@PVN+N}`>7_An1OIZAvJEQNtKo#3o@$6fx4$Nv= z_wmLT*2t938VO#u9Ql1m3f_yY@0lhNdRl#X@S?MV`%S-G_&Fu@QoyYV8{Qk~N^i54 z+iq^sm~rvgqQ*UqiEAYItSixtFAzODa2BU~y!6+szxBqRyP;a=v@$dGhIV0mbPz zifr{bQ(CX`dU;-8^LsX7n!(A0)y&7Gr!9%Rq#_zRQSolu0alYO-RWn9*_#)XvQMdM zR)fwpZ37AAX&juX6KJa z@8i>K=7(8G6m3)!s}9I+HfwWL6W_3iC^ZVb3QTcQTp*xyuhI0EXS*33vOFF zv)VDYG=v@ge6uU;a9sJ?OA`a63slc=707bj-I`#^lNjo(A0#9H_Tqh8wHJJxXJulS z9a(L8YYpSHr&1r9xh?K7v<;?zuD}>~-gj_s%yDy%p40a)_6`$4&ah7pBs`bNJCC?Uaz8(_UXi*od8KNB@syJvm!wWR{IrO7!u8iqi#aA8JN(gRN$w2MtGnupcrQgw zi1Ubwe3sg)&&zQBa_NOjS-w#nU;nPYY9&5fa0UDI*N3-k(qLT2^wi z&WS1uFR{E8J-KR8h66+2^Ua$#xBF?m(ORk*eCdo(qUh{rLO|(K{uC>ZAzR>`|rFyv0_D*`r2Covhw>s6d29Exk_iT=d?w- z?_Krwt`Xe5wN&rX!Lrna#Z{jw>bI_H^UeO9*Yo&ShJWJHBausfW|>B&W@f6NcC$Sp z{rvJN3)hL6H>KW$wJT*?RD_j0N-J4yzy0kqquHgaYBnlw`+acx9|N!b`<8zwef8&y zW2I=-A?ahUJRbAhdG~Jf$C77jrgh&hlil{N=f&N-53O%~*mA8VB-7G9*5c&LGd`=_ zmR}0&Ub}W}=Dg>=8De)gEu3xclhyli%A0RhdpAh8uTy{J7&^^%()jz??EGo@`~Pk;pM93EK{X)vXik*(Y;&LO-}6PA4?4`7 zJNMnZT#=Svp?TnR~vEinTuPSzYp2<=ghuO$JYG0T|Fme?Ft6Vb1NFJ70!9K ze&5}V_CGG$KYTuY_P4d$?`?7o{P1e^`mW#K-+%tMG=0Gu#&gpp7_!&?IBdQ1&*pgc z1%mef6l)i-+*K))?N(RTTJ=^e?xI2- zU##TOiMeZ6Hy=MvzWx6D(QVlGfF)n(2`Onk+ cLI3PmwTUYg-E_-kU|?YIboFyt=akR{0GMO3vH$=8 literal 0 HcmV?d00001 diff --git a/data/earth/B.bmp b/data/earth/B.bmp deleted file mode 100644 index 5e93c3845d7b99f39cea697c25e830f3106e656b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4150 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 Gg(3mW7?U6X diff --git a/data/earth/B.png b/data/earth/B.png new file mode 100644 index 0000000000000000000000000000000000000000..d30ead13647e5496ba301b22d3524c33e980f802 GIT binary patch literal 2903 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 literal 0 HcmV?d00001 diff --git a/data/earth/C.bmp b/data/earth/C.bmp deleted file mode 100644 index 4d547e2adf48e37005d293c395b0b9a8e18696bc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4150 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 diff --git a/data/earth/C.png b/data/earth/C.png new file mode 100644 index 0000000000000000000000000000000000000000..9384d0b7b72754544ea955e678c8aee6dab63ed8 GIT binary patch literal 2840 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 E03q_aX#fBK diff --git a/data/earth/D.png b/data/earth/D.png new file mode 100644 index 0000000000000000000000000000000000000000..a35633330263c23ef0c07239771218dd1406e4aa GIT binary patch literal 2924 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 FngE};cq;$^ literal 0 HcmV?d00001 diff --git a/data/earth/E.bmp b/data/earth/E.bmp deleted file mode 100644 index 7224c6f5200361afa846c541f94ddc3aff4cde81..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4150 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 UVf1KoV+fd{3+jI``ZaI@0FKLWH~;_u diff --git a/data/earth/E.png b/data/earth/E.png new file mode 100644 index 0000000000000000000000000000000000000000..ed0879e7b632f6ec81a2f91ae628eb07880288f6 GIT binary patch literal 2982 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 literal 0 HcmV?d00001 diff --git a/data/earth/F.bmp b/data/earth/F.bmp deleted file mode 100644 index 0843265e56863da9e0cd7d93ebbd2eab9bf06491..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4150 zcmZ?rH4|U}12YB&1`P%V1_dZ)1hW_z7z7v?gt;LYtPn&*EM{Two50BsFqw-XVlfj) zh{v;ziz8;SJ#WHti_rdq%nT8WL70UhVlg9wP9R7PGXtMA8-s=yH&gfmdx?zIB3!YH z1sMaUaU2IZ*R}|_U&7y`uciCkYB(UVg|@9AafWQOcGh4{$Tk3|39Nb+9KAvx;l{E zAPn*+2s1H6Eaqm2Sj^54u^8kBkQgt6|0FI3?LZa=1_mAm1_o)(=r;BV%XY9tMMW{O zva&MD%E~fr*|G%`MqsPK1StGK3`iIt+{M7au>8nfkh?(k!Z65QkUK%*Aj~eDxP+5A zXbLBTxHdln1A{CB1A{yR8@DwRw@9|Ri$A+g<{SYlpJ-MoDJkZ}#6;#}$Bwartb=1v zyfH8^aBy%y?0`ya-MW=gGkXchFAUH)2FZi$q%T)}Db~hNLjbDf>Ydcvdx5lSdcAHk#)M{?ovc+iU&YimA;^JZq3=AN% z!D)ukCXZQNU7fMNzaPc_;P?c&2b%Vv@h!k$mBY*+YsRdiW60wco))3+5qm?<#O;}g zq1O*4ZNGmE3fBJ_35O;ab8fnTPUK|tPsfq{XU zfq{XM!L13D2GQ*Xg*8MB6h@$Uidd`$j(3nARxW-9c0M;A1HS{x4iSG1gYy1shm`;4 zu*><+pcnR^K|A0-gQWf+Hf5XtvPRDD)HJmZ%4-;`XI8Mh%pjrrlR?Yx00XatCWD{? zD?{KkUWSOppfCaX78c&1JjV$Z0Qn!1KG?u+X62M+VCOYs5ZBtkAZ_%MRn6%?uSLv% z4vU2U3}z|+8BA0DGgxN-XOJ=Z&mf`upIK1m9}B<4HzqNSPYiMve;LHJ|1&7r|6x#a z*u=muqW})ih{c-V@P_yml%~xXK=};p00xkoKxv(Yk)21DfsH$lLC$<1gQWgX206?B z40@se84RQTGidq$XD~_p&tR7JpTRusKZBy(e+DUo{|ut){~4r>|1&5%LBzx~|1-## z{%26I{>&h$p8!q^kT?Lv2h1*4aNa`L&nly5$HyWl8_6hRa+XEW>MxU=*?&eYzyAz2 z1rR^0y8dTSbN|nv;`Eos5sAp zlzt4144&t{xfL$K+Lqx z|Ic8Y_@4pf29RInEdDbn+5HE_KaY9Le@3h9{|r_+{~0VY|1&7s{%4RghtR5SPZ`8C zwZQ4nsS1=QKsJKhV1N`KpuETA5f~{fVV^i($vN&9uYuoxM*UDonCk@nXK`?rl!LH~(gKg1&22gm&TmEOz^ajPpUj{X|5(Wka zP`L-PAC~4-!483>2eAE8Dmp^E2EI##484DG>IeL1&<}^Cb#<@*40a{|88p2AGw6mu z#FQNWGpRcN=hpT5FXdnJpVdD9KZ9$-e+I`2NLo>G{?DKt_@4np%UkVdVC9ry;1OqM z&;gg9ApeV?+0V?vBP`0K>a>hi)$tdTLHK`0-C#(1(+&O4;9T>c!K>>(gLNJxu9fWn zbL)8imoN+XuNKq&pUt`aKZ952e;$wO|D1MNko*bCr=a+fHGRP#q~y-P#?8l|>3^U@MmQdR1js5w_L)gVEvQdDB!=cciw;1$hQB25mWzjhD`a- z9?<(=%)RixsAc$nA)EOBLKcz#wS6-G8)nY>FB94OUpr&gf0elY|2%dX{~67a|1%gw z{bx}3{LiT7`jc0~zS+~$lV8cN7*aoh>P1Ky%_1x;EG=r6uz=Ul|38zuJGhJy@~r&t zP`>nk!i1gwgW5L#*NdqAFKrq0U(Gq@zfMTme@U<6|7>~z|M`ra{)?Jh{})iy{4b(u z{a?_%>_3Zp!+!=VXgrxD{%5pI|IcY0{+~zJ^A-b_umuB$0I2K}U|?beHB-1GWEI4f z?Zb}Ux0u z^`FsL{Xet1*nd`OvHv_W8vl9qeg3msW&CHbFNTyG*17)~Oq0R!#i3|^oq?6Zj)8$e zj=`lCR35u9FfeGbadMjoYdc)$lF|9kA!qoXQOOQc##p5NXSK=x&unP&pV3m_KU2KW zep!!e{C_SryZ?d~5&uQJ%Kx)_xBX{z zD*Mj>O2^thMxp{T%zp++z5mQodjEMf?f;7#dH$ER@CSz}gMj>h z20rP}49sk;3``85_MH?%Jp-gHV&^qtRpz2n#eW7_ zi~o$0`u~~4HU2XR$^U2I7WvO0!1kX(gz-NEH|q%o1_n^u64aIg<$eZXMP(^Yb;pNH zKD__gJ9+*yRx$r)uwwqtpe6aA!!Y>2RITZMuF2g08H*VIGsH0bXSUS%&nj#9pV7(k zKSLhFe}-s={|p5T|9OfH|Fao_%6^a=jQ=yp$^K`M7x~X1BmJL2o#{V=D8qjSLFR`H z3=9Sg9<8AC2eO}u*^I}O$y(rtV4%o|E^JT>mrbSo~)& z;rh>@$Mm1uPT)Vg1J8d3Ns#|p9x*U5fa-oo+k=6Dl}($=md#H1n{%Pd|IDq~|0VjQ z{xf*8|7VR8`mflp@?UGJ&VP;`j{i(KO#d0;nEnf;*!@=stoqNNrT5=ss>grtDc=8i zTlxPp*USGGjIj8x>YM*xASB>FLj=ozRwLH`(snZc6$4cMGe|N1XW(FZ$H2f40&W+9 ze9yqZ!7R@1A?zvtExkMAf8O@||3dvD{~1Hs{&OaC{8D)nEWUig2+l8FCltJD4q_lW*ys8amT8fyAqIi};kLP^noh9b8AEVeBF z#ZATk>qi>@XH{kY&%nj{l7WFCpMik^)Sd>VKRz)9$w13Y_s`ACn*SH>a^DrcTD_0_4Ks={+mMnD^67XZ!*pFf9jsJ{|VcZ{_8F<{Vz6M^1s%6 z?f)h#P5+C|5&bVZQR2VLO0WMFhb#X_Y>oV{wNx7%c0!Xy{;Moh{V&oj_Mbh0;KYLGXEL)I3F-DFs3oE^Md*?ASZz80~Lq3&=W1I+y1S%yz1YqOLPBb?aloi zvL*a?+TP4RO~+dPR3B{ok+>!8cgTj&e{O5s{~Iqi`ERw{=AYk&@PBE$GXACPO8p

ZVme9x8DDs!wkniR_#{5y?VU<$(hQ3Wn^VL$-u+{Dt8$t9GCzK ze~=sab*=X-zgoaOn$evbVg+u62%y_b6bja?V}H-AUL?~0w3ziPME z{fO*|{H5qjEzIvLx!1ySAoHaJA@&R@djf7<3q+m#zzb}3>z4H7{eICnN1mL7!w%sSqm95 zSz}njSnN3UmDQQj1UwmvIJy~=S=-rcIYQYa*c_SNS+W>o85go7vK(NG=h(+&Envgw S(dNbwFhv*C-(&P^-~<3z!{HYI diff --git a/data/earth/F.png b/data/earth/F.png new file mode 100644 index 0000000000000000000000000000000000000000..e99c02f4723ef8829b0806889d4dbae99a85f053 GIT binary patch literal 2994 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 literal 0 HcmV?d00001 diff --git a/data/flower_left.bmp b/data/flower_left.bmp deleted file mode 100644 index 1a7aca66d155cb0895ab60f9dd56ef350184901c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8246 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 literal 0 HcmV?d00001 diff --git a/data/flower_right.bmp b/data/flower_right.bmp deleted file mode 100644 index 1a7aca66d155cb0895ab60f9dd56ef350184901c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8246 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 literal 0 HcmV?d00001 diff --git a/data/heaven.bmp b/data/heaven.bmp deleted file mode 100644 index 9ea19341c9c2ef7fb9e4bd0fa9d3296cc678de7e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 65590 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ķe5(lMw5C*aDw>keu$DptSVNm!Y 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 diff --git a/data/heaven.png b/data/heaven.png new file mode 100644 index 0000000000000000000000000000000000000000..1feb3b6cd0e6f414f0f712ab2504fcca90f7c462 GIT binary patch literal 12146 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 A%>V!Z literal 0 HcmV?d00001 diff --git a/data/magikball.bmp b/data/magikball.bmp deleted file mode 100644 index 42f8c9ca8cb548a1d142cd21411b7be383555e70..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1078 zcmZ?rHDh4_12YB&1`P%V1_3B$WKaN$Gq5l)2y;U)L;yee9|F$)|NnnKew7eekU9{C z@E8~w7#Ntoe*J3l_wU~W|Ns97nPUVp5-Ja;{{R1P1mi&E6&V;9cCs@tykcNr_z%K8 zJw5*q960b6Di2c*rlDs4U%Ys+I!K;_f#D@91H)ex28O>{3=IGE85sV%OG^IF%gp=* zk_T(TLL5DM^!bh*JAP;|Fnlp#VEAvz!0_LRf#JUu1H*rL28RC=>g)g4*VlvG0}W{u zL#%ih7``s3um87x#*F`2Mn?aA85sV1F);j(XJi1gSIwC5zqP*p9|HqJAc{^1=b$tL z!@pn#hW`)Fp8fy)?AiZ|7#aT0Vr2M#w4veuv$JRa-#UBtzYYV#e?A6=6%Z{bWV;sw z!{1&;hX1>n82&$HV)*}!iQ)f`hWh_M_wWCI(%9&KG9$zPaz;paqUeNh{$F5X_U$_9G7sLl)4z~aQ z9qs@BU}E@h&A{-Voq^#vvd;hi|4%!5^yr0?hY$Ze%gy=!e|6RW|Gho`|G#_p|NqUK z|NmE2{{Nqs3pO*9kpYwz>tXu;|NmeA|NsAk|Nn!6hQUaYf#Hn<1H=FS-d_LzKX~x} z|AzHoH{Ct3|KF6>)-S!iy;1-F|8MyJ|No5t|NlP&nFCe;F~{Zq|Nn^$3=I2c%$V_C zgOTCCI0M69Q2IN1sg~V=S diff --git a/data/magikball.png b/data/magikball.png new file mode 100644 index 0000000000000000000000000000000000000000..73c21498f9ba32782844b638086af9fffa6742fd GIT binary patch literal 597 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s77>k44ofy`glX=O&z`$AH z5n0T@z%2~Ij105pNH8!ku$OrHy0YJ6lM`oFxa4z$mw|!txu=U`h{frxlMFM26D8W_ z|If;GZr1CP@nb!x#HwiZa)IA8D=|kF^}-hkg~GQVURwBKLXPVspR8$lqB2WTcC>t( z!Y97#nnKGoH4UkpWEIW0`1Y8G7lL>FIDGs(`}^ND|NnnH^xtAqko(nH9VZ#LHCP|e zJYaV04U^~shLFb$VHsgJ@|nGl&DdLGm!Ev>*n>072jZhY@0ujzS@*+Ue z{sX1H_a?n6&HTAl#WU~ct%WJvq&pPLQ{~ZnVEH-{|=WEcOpksM1>CiU+SxyUGw(jC( zN$_iqdQ$W~!z_E&{Q0w)rZM)pGQ79RPhEdEkKf0~<`?HlK?xS21yUQFH{WFV#{1#f z_ZPn=h3JT#|L$!1hm(!jLi_;hLD!q#e0}}Tzj1dGpZ_<&fNRZx3(pG@Po)@XO+Ou< z%qX~7`(*E%`@wf2>k#5 zp9#CnuoE?6U|@jZVdpsl9=guJ!0?@cf#E*`1H&x_28IR#>WP&;z`(#TlUT(Aq;5Y0 z1H&&34UPZ4zP|sNnVCUh@Lx|)FAs}*hzb{8US6;n(C`Ga6%-UeG!`SlLbOVE*BBTW z&M+`AfZ_pc5fa&d8eU}a_f$H2e<3ahiw ze1dEgC|sgML_|P-1mmSkmx7G@pPrunpNWa-KMM;BSR5^FeP?831lt7*D@jR7kUC_u z85$ZIKw@wVaxaPkBu;&O{eLblF0fiqT(YsTf!R`0Qvb1-4GQ=F92^{Aw;~fDGeB+z z=?Aev`a$-B*q|_CU|^_cU|;}+#SEC+K{Uv%$mW39ps)p*0}2NaZES1|b`!{akh!2R z0_g*pFCZWQmO~2TdQg0T#6cKj2NI4#^12Z${6T3AWGBdOkhvf>Ob^KYNM=`o#6fC6 zYSA$$TtM<5|AOQ|?ga6TjEul;1i2mLHjq3hY(Z)WVVD^pzhhI2EYHr)4o({&e<8aO z#0I4s5C(-A2!q@Oatk&yVPeSP017uoM#g`jIDyHd(;$C>{Dv+L3m1_4f`fz6r3vyu z?!cu8)n1c*0|rl*S2x$De(Hn}Gw0+yliF=;J&A(GzJ12&*;f2AJYf^_F3fz9Xt@zR2?*f^#J{4FzsIVzp$LPdy zVqH}I=9>zqH@!1U*cp?w{k9{+f@`~q!xemk-+Zt3NIs(<{UU$c|GNF{0!#ulkMKh@a})a|dIn6q|iP}ebusO*<}mlyY4i)s_# zNMK#S^5I|0maQ{WBQHrfYpV7d&hb&}^>}aFy(pn);yKG@nNh`0LwmK?nqD@s?Y;W? z;gP#P6ATm>`rH;D6Er+#{P5bX;5-I~xy5JO1ems7^O@Aree{v=$um*EW3&JAJV;ix zsxREC)X=_*fuXmwd(na^le|`1iTQuC^rr5YCdVq&_E>!kTNAcAN@cRj zLc?W++0y1(fyV`y(l%mH`Z@2e4y+5Gbz+eBy(!M!|@zCRfl7#KWV L{an^LB{Ts55cD5J literal 0 HcmV?d00001 diff --git a/data/player.bmp b/data/player.bmp deleted file mode 100644 index c572e75189ff600bda912f22a283e6ce139ed865..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4150 zcmZ?rH4|U}12YB&1`P%V1_dZ)1hW_z7z7v?gt;LYtZQ+;@P~nc;TZ!1Ll*-BgCVho z5}^*1jFK4`7;Z2yF#O`><^3-yDf!>X$Ow)>e2_TQEg(1jWnf^q%)r1fmw|!7hk=1X zje&uIjR?Dtm4MV+FfcG2Wnf_V0y3M2hv$E4YU=-)GiUxs28$Oj{@>i({NLKz8tf)C z_uOG%U|7b$z+g#&8$fnPGB7aQV_;wah3$V;Rn`Afrc6P$7AG6zK9D;>?ghCUiqA7J zFa#0d2AJJXK>DPlr2fap$N#^3_byKRa7nCMwd%jKv-5wD86dM57#KiqAe1&d85kH| zg4C<1sQjNhckchspFiWWf}r@>vuFRex3?p^VJ);sLXK+~8ba34#-c?a02CNP+mm0{{zVWXV0FIY$v(~P#QrO z1M!QCi(z3f8{KjS1_rSGAa%rGQ1~h;DuTnBP`tp*1NjZ)M+OFl*I4Wam6b511ZhzC zMny&a=j7xhs1{iP)c(&{?B4~FLspB-UcP+!e-K6%1BF3cTpY3xK{m(^P+f+_{yLBx zD2%WfA}=ow&g+E28e|5p_+PtrEiC>)^*6c`tU!9PrT-HrPJs1+${K8LLly&-Lm-SS z24m;v=Y!2*U|_%&{-E~D&Ghv2|DZAxrUyiW!kLMQi75Yr${%KCW{@@v4636+euUOV z=>7-syFhsqTNq#%Mxp?yE(4VfQ2SSbEW?7;85kIDgWT}+=~EJIz^@#sP4JF^fgv4> z-5?3j$e#7lYhT1JVa_gN%&K|H{hB|HqCUBf?gQl6&{={SONZ1Gf{P zb|(^PH_Tx|3=9k<3=9m9L2lsV85kHU85kJOFfcHDf|lW+^bEp3p?xAy k+jR#toVBjq9 zh%9Dc;1&j9Muu5)Bp4VN*h@TpUD@xk$%!-bJeacL9RmZ4oTrOpNW|f{)BQbU%0-Ub zFWxPknzm%>C4=rOOV(UF>?Ex|A>ib#D{)mHCOJ7M=6Of%ow8)YH-#6G8JT*#M*^5y zIk=NPPLNw-K5^Cs1JA^bw@goEtzNysMDzE0;i!22nVhTpUcYmDvGo4s{JQtwXTSgc z{oZ@qd;I^BHB8@Ba#}F%VclX?oPFTD16M`S6(*(zz7ht(2h0m(GZ_Ayo3;Fay@OZ< z#~Ft2jjHMIGS@OOHN2b<#}voQ!t`R7UvaVVu62u7X(=_`f3H6OeDZCx=;-JtpMSoM z(KBbPVUKv~BGZ!g!1#f=Yv7WVD?R<@*=SzO2sw8AcxqyzV~kDRpC3Ofs;i^d#qL%U z*N+nk4L$nNV}0?Au7!-s4H{iay1KeXHa0q+KYtF=3=0qUcFkdsxBR|b>63rVr*GfN zb{0NvyVCUZX=)SD)rR?5xk2&pgRT?R)N?^7r!?9)14FSGskP#v+Zb&t16nYt0+`iVq9ctafdQ(0P{G?V|K&^TuWi+m0v4`(!7(C~Z8wZO4um^Xj+*VuRv48%iH+y?Hb8>8Gcs zO-xMQ1f@rcEz8`rZ=auq%&~2`=jPj=zjR3`J3BjK8f(M-_v$iy!hG%X-|LESojH4U z=lt)Dd#1DNF;<3#rlzF0aJ3$4{P_0WJF(Evr$0VEe)RdL%Vm>55m%nWAMQ-{TDoNW z_Um5{h_lCD;#=i1do@A)YPd{r>;7wuCBgx`SRsc{wNl7 zaozr4mvGfnGBZ1S^6TsC!(D1VKRdgZx5K;c;A+FrQyni@_A%XK3Gu!B;`QstUtV73 z;p4N5w=gtx)S8-DCs3$IYH#Z9t9Vap{Ffe$!`njxgN@xNAq8cj5 literal 0 HcmV?d00001 diff --git a/data/rock.bmp b/data/rock.bmp deleted file mode 100644 index 8b24019c8cbd62c486850b33012ecdaf4e0cf7ea..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4150 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 Nd^KZdu)jfe0sst6uZaKv diff --git a/data/rock.png b/data/rock.png new file mode 100644 index 0000000000000000000000000000000000000000..4a8fb790704f76b183b7bc4561b77152654a8545 GIT binary patch literal 2658 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 literal 0 HcmV?d00001 diff --git a/data/soldier.bmp b/data/soldier.bmp deleted file mode 100644 index 85c151989a3900c5aa09d3ee31c39466b3b592c2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6200 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 diff --git a/data/soldier.png b/data/soldier.png new file mode 100644 index 0000000000000000000000000000000000000000..1081e8ce3422ac7c2a01a4bda64dc4e57cfa5039 GIT binary patch literal 3323 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 diff --git a/data/spider_left.png b/data/spider_left.png new file mode 100644 index 0000000000000000000000000000000000000000..b4ef4e7af0545fc26524fdbd2445847bff42fcef GIT binary patch literal 1294 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}jKx9jP7LeL$-HD>U|>t~ zc6VX;4}uH!E}zW6z`$AH5n0T@z%2~Ij105pNH8!ku$OrHy0YJ6lM`psj%n37!oa}N z=jq}Y5^?zLG~b+%P?6*H&-Zx;@!^q97F3DV&{bSnxUkwR zFDB!T;IvoMT00Hh%uY4+3p5G2C>nP8ssse*h-`e>o@_nEY`yW^%K6t@jh6@nD5&jt zVPAQ2r~dPKpY5MNoAL2qTem(B{K;*+c<{!OGzxI1%Y~j7V&Hi+X(QFqL zj>8`$A3U=CBWf`1^wV?43*T7v6(9cocjfORddySX6&Lf%SQO+H6nt2c8u@*V-b4=> z#z(ogx9Rfp^P6wF`Q}7z(%&1u{)w*2{qpte#w}Yyq9P)0*cli&q^CcBxO?tm4XFYd z_jU36=e>IMYSZuEzqfDK$`$^@azWZW@69Hi)pPuon=Xj{|DH2*d-nNxw)dsm5_|jl zPW8!JFM9XxUF+lH{rioqt#@zox_kTf=_gNATAdp2?k;~Fyxi~ag~@*W{pZfqY~Qyy z`S9+OOLFt>o?0Kh?L&ys$$J|O=j|@>yuYV1IPA&p&CE-KG^d_^>T}p&$;FIl{1!kE)80EGiOugs)`}q3G>rStZzqkE--J<>Tug~&b z7rXn|(wUO0q|FNQGCaP$zrWtqMZEiHd6c<&SyEE+=B?Ye zqx0uJ6-{87!QHgrw25!c{q(dnH?CHv<3D~_obT)Xxbt<F9nI&PBV$*F@G-u>f3Z=cEAB&W{IloJ3uC8O?d^NL%gD}do}l2QlPQ|B&+b!E zdc9afiO2bo#j(=ZE!QTUO|wk8&2x9h!AqBf;=2|!JKU-}F2!4CT{|m8OEqIILtVV* zf}B}tnmo==E9LqgFW7plG&bh?(Lx!W(?a*Z&u7^s)Y-y!SYWBhRIgUI#g2CKmoF0O zPV9L9dyawcszi^)7Z=2>FJ{{z<*K8vzq#zJ)KtIa(r@2sCm2lia!r(AdQd5seSMv4 zcJKS&SF%iBeYIj(8Pe6-%DPd9`>?@`xpPzV^7_u5^UKRT>nd1tKi!byhge7Ld=FQs>pmF8% z&zdDuxEh4LRvzwqyhl?h*lVTb(kpv9e73lKWj~-NIMc-Uvb>bks^>*JZy5A&J&AJx zoQ6V_;UVP*l}oQ|3|g6TJ< ztoyZG(1lZLkIYXqni+U|TfbQM(JRe)X1CoW+Ae#oJlWaV`LkW+gJ3~vQqrOviDTEJ zvgJACN;WgFH;PBUj_ucYo$I*k&x-d=%?Hd^^B)Se;rqinMek#T{e_lh1_lNOPgg&e IbxsLQ04F$S5C8xG literal 0 HcmV?d00001 diff --git a/data/spider_right.bmp b/data/spider_right.bmp deleted file mode 100644 index 355dedc35254abc18fccea5a0c3d0c7113a4866e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4150 zcmZ?rH4|U}12YB&1`P%V1_dZ)1hW_z7z7v?gt;LYtZHt<&)?FMN95)yk82*!@ zS3yC6lbxM?B@YkJB?SeAg;4z@g@J;Cf-o~P^G_Zgo-a`S=uTin7l82<6ckt$6ckE9 z`ZP2&o+&CS9)N}e6HE;uT2N51kd>A7x1^-xS5{WmA4uv!_OdfDFz_)jFz_=lFmQk{ z3kwT~wqjslXklPru#l0Fu@Vpvc%!PS`pwYL@I4a~(+dU$25YD}%upIcf!H83L2MY- z)qxw&70{Km-0_?m%%;VuIM!y^!ziHYee zCnx7GW@hF;3=9k)`Z+&8|35!JzppGTEWa2T86Pn)FgP+WFmy98Fmy69GCp8pVtUKO z#Po`hk?}D%H+K#b6Vnt128Q)aOiUoZ|CN`Q|0*jh`{)1v|EvrQ3{4yy9LHH%)&FyF znEdDDYm1 z@ju9IoSd9LI5;@Ib8&I~1F2(SVfoL<$oLQBCy<$Pa&n;b_Fq9k;lGuY)n5YxgTElZ zGcYhPGBPsW;o|cA&%t5!pM!(rKLdjv$V@P1Vq*Kxz#t4}v$3)LXJiceFDMxF-_z6c zznPgC*i2Sd*8d<3vXhI83+zrNCMK{P$bOI;g@uK|YC!gTczFCXFfjOxR0gncadBM} z5t01Q%gg(pfg$8SJG&^@EfDwk|L5Qk{?Eh1^PhoX;(sBbl>ertrvH6>eEy4zi~on& zB`PWk4iAw3LFRzegWL>~2e|>n2ifoAz1)&Bla?&ilr7tEmP5=j6QoA7ocpSlB;1J3Fx1pl|}YkAZ>V3IhYfOa=yq^PsS|v9b9q zCnxt06doWwR#sO3!@|OTtEs7V!7YX|6ciN7KyC~S4E&drbpC&G^6CFEF){yLU0wg% z*}eWB8M)wpQc}`?6O+|oKbxDIzm1HH{09nSkpDqp$H2hwih+S)1~hDqJUu<%hlGS& z2IU!0ICyz^{SOWf{;RLA56ibu+fk_hA|fLHe0(1KFE5|+KR-YJznj~X|I*SE{tF9B z{9s~YdMGPvAT2B`d^|BR@gFE$Kz@a#ab%Ok#l_7sGc#ZN`}_Zql$8AM?(Y82#l__( z)P2ZGQP^y3Z1X{8g3>c6ZA(ZY>dP(A^bNicaZ zEg~W^#oOEazm1K}!>FjJSBi>?pzs6B5lMjR84$)$&dbYtDkLQ2yRNP-C_RJXViATS z1_lO@AAEg%H>9Vh?*{n`n;JY~IO`c+US4ZZoyO1452_chF)%RTst@WpI5?K`^YdR| sXJ=oI$1ZZDK;e0b2#uW#3=EryP)AE8(X=#t)a=m^7!85Z5Fj=L0QQ=BzyJUM diff --git a/data/spider_right.png b/data/spider_right.png new file mode 100644 index 0000000000000000000000000000000000000000..d9a6d1883c153ad4e75a56c1998e44676259668c GIT binary patch literal 1277 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}jKx9jP7LeL$-HD>U|>t~ zc6VX;4}uH!E}zW6z`$AH5n0T@z%2~Ij105pNH8!ku$OrHy0YJ6lM`oBI351ghk=2m z*3-o?B;xSfX}%dUsS?NQ-`Bi5cdl&qjJqZ#%Y=nhgR*Y9F41rcII(cXwQF92{Bky5 z-Z=J8yQedcg;ifE%&|%{$m#Ej3nEbh7cYg(V)Nxm*?rS2`%a0yk+rq)`_~73JGW}) zI@-*z=lT3;-}&eD^D5_wn{8<1&3RDYas40fVy+!E{6)tbg0s!HRF_PMf3Gmt&pvt9 zvzb0>#bPsdb)Qx4bXlZ7`Q(?I+x{N?oAx94_s(Djdl{RG3->oBALmlgJ#AH|Zh6_{ z>Wv#WrnmFU+g(n3^NuHC+E>m6GRFg#Wj@=Ub8`}FNcDd)V`XLK-J5Q%u{AcH?6WjT zsqgW{+qtEsrL_iDR$fbkZicSD+V=bR@BF!vuWK*+&Nf>qU;aL==66|Lu36=mS6ADW zW1rtm`+W7N*VCWs+wy96ZP@fFQE&QX|M_;hHTRdVU*G@p=g)Ur+ji~VJ>RO}!GVRX zt*sShW!vr+P`WISQ~aq&`?&cK6BWpMT7s7XAEn{cw{%U4k!ITQ<1-C;maJ1=>e9OKM-)faR;lW4*S_6)nb%!4Raafr3i4W{q12b$ zB4ByFG@j$|hlvUtGv>`JTdc9@V#b0gNtv0QF?#BcEb7X1ncE&))Ez6_^6M1W3iKVS!k$bDWG`7q4DD z`sk68dET7^CcY)H%Y#;Sq!@Y195<2TT{7jvbY?4S>y=@v8C(KgjAr&U8uD6X-7fpN z-C)U8v3c9pOcPMb%Wht_@U@i_$G#x1TJhs+4R{_G?Of9$;Gvm(*nsJ~7Ah?s%!UF>f>tK)d(VIN{Q3N= zCU1`_aBNB1cw$SgC=M5g*%UY$zpiK`22s?GjaKV s|2e;HKgQqfI>+R0rq?db@IyE)`R@FgKW08e+E;A=M1q7 zPZ`P?3P?7Ohv6B60mFX=aVR!sc)(E3;6SuF5Vijq${GGM#54S7ux9wrAjAl@i!r=r;9__HH4C?s${Erb z#2Eg9{eY|=!hQ}l1HU_z7&c>dgC)av1_g%oxGhJL;bVA(=7#%Vx0k~bG?H3u%yI@* ysQP~l4b*3_oOZ${BbV92xQ%m>Iq^urS<4mLie;fq{V`i$pziQ4Rq0%Tc8O diff --git a/data/spike_left.png b/data/spike_left.png new file mode 100644 index 0000000000000000000000000000000000000000..5bbada26fe52d9ef94ea2ee139e5efe7d883c20c GIT binary patch literal 364 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s77>k44ofy`glX=O&z`&N| z?e44JIZ=_19~Nj48{X4eF4NQ-`QwBz-g ze@&7qP3s;J|4EkIR-5eEFN!bAyjjgZLB3#7GQaQiTV_Gh^(FQ9 zs}^Z(R54t)c!k-Wn_TbCc#BkTe6UR2N<_*-XV>k44ofy`glX=O&z`&N| z?e4qMBrQ#2GWdiwz63-c?%Kp!yf?1N=i(OLe7$x{kJ2?aea zt+^pA!z*;+>%)v=lU*(*&gb62cwejRYAo+PM$7r%O7E~l3?M!$!z~7m$nOl?Y+upbgyxRr^$ZNl|1-ogfN%qv zByrqW1~&!T*DgO(dHFfY8%z_j=u1LstT zUXU9w6%rN^XIRZ3WcZ(fbJ~9fJ%;}bAU?=F3`_qrh-?05&|-LrVhAXF6c~;%uz3Gt zU{LtazzK3Y*#G-c)Dg=8*$1+hZPtGVnG#4Cfb3_R{hvWz`agpr!%?_VrVOPF0t~;v z?&P-n&mimnpFxP>KZ6*{9`=3En@;n2B;sOQ+27GyVA-UAoD>OpZy?t7*=C|zWXpft(p{GUOH<3EEa!*>Rd|FGB$5%PG>zz_`a7bqXOg3A~P zA7(zXe?j&$g7e`|cv=OCLCW1fU@?$;B*gzSFfaJe0CI~U!(Rq#h8~E0Xe5)=Zw3ZX z`dkiC&nonrK@cS!LdsN_TVQq}y9p#G1$DPO!wqm9Aqp**L3t2lK9dZ{PssH-%pw25 zbtYKd^8XBMEI$~yq4tC9P_p~a016Y39iY4ovY(IPKLazv2L>&M7hwN_N;_|G8P_@9Bz9g?O&-mg8nnGx&38elK#iQ)cBu))f3bn`o$o~@Q;C=7g86-G8i#% zF+6AB%Yyg; zen{Q0d_Gt$xUO*i4^B6+3|p@cC7|>MDx)CwgZz)pOo;zM=?0?iBQ`~Z#cbX) zFz|xfIS{3wa0HcS49@= diff --git a/data/spikedbush.png b/data/spikedbush.png new file mode 100644 index 0000000000000000000000000000000000000000..b3c8b26fbc03aa435ea93b2c6f01a50de9f2aa83 GIT binary patch literal 1486 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}jKx9jP7LeL$-HD>U|>t~ zc6VX;4}uH!E}zW6z`$AH5n0T@z%2~Ij105pNH8!ku$OrHy0YJ6lM`oR`5q!Tmw|!R z&(p;*B;xSf>+w0)(nZ-nod3P=@BV)a*It-*FzVENCP~(nvvz72-Mmmz7`GwT;B#Ar zphWxadsXuubH}{_VB$ z`gQyFO}R8}-MdSZ|9q;R_u2Y+<-YTl&n=(-39_^NnqXRI&3{v1|NXhX3OgAXN_QCX z@7xygPItc2)`xR{*v`M)Ud>q>#GT`M*rst`8~?xSm+#qSM$MgiZ~KiEzu#wG+n|2G zLCf*hJ=VAXRDYd5;lsEgdg_MW2aemHG3{&K(7YgW!o1tOn|CE}F4g?B!7|NuRln=R zu+A;JB1690RWAR`{+xLMZ?0_4+m1hPyf$W+W~?a@xb{8D>~QXm%f7C0H^U?%-{yNJ z^-li0^}x03KRC-AmwCJm>iHh6o*R7FeVVz#>=P&B4;mXz@T_|Ekn?B3W`pC_7WxeS z8(s=Y-~OrWqtfEK(cy8Xz3l7I%R(QOcRl#sbtU3u@ugQfTVod zC1&sF?*v*XV*m6;+`>) zjX!Uv`$pw*2sSt^J=r2+W4>_F1ZVN~7O^iO0S1ac->+$Tb%Qnh>00dxI}D}dANuY# zUG?LWLi=pXXyN>i)1pfJkDZ)nwcbqkQ=rV^^9xj&3|^(Fl^ye{(M`O1U`7bPmsqjM zX=lxE=98wUp7!nBWi;jS6vyN!+XWTrvy`O^B@atn>-OGIw)R`|-ntF1mYGidT9xJ% zvM~A7PH%pJZ-TRg zoRUxdh;`gylDWrPu78;Ze-KxZ=ZTG5Ed+i0b9#PC`mDIHNUgl*v&7->*e&pg;jfE1hlG5q zbXR(wtbfcSf9-?Q(l<}_t3r1#o~%_lxjEKm`()=2haMYl){5IwHO<2BM3qXq`oAXk z09n>A-9P{Qw7S1CK_%PekiP8qKUY+PCO0dWth|(PLv5>Ju|#uI)Wx^^WtufR=lgl` z`$p#ap6Op(_|7DD>Y<8>^}AlJQjDL!TkOlvZNb6Mqzg~Iy|Z11jdAYI-F4=FO z9iRA-d-~dmTNh5)92)3uY7wdTPS0)Wzk>Gn(W!s)0@r2=Dtt*O&lB-zX3awhk@M4c`-pj=n^OZj?mz|qq?fZI9eNLY zM7+x7|8-WzHM4J>neLiuovNB+6Hc0~4m~iT=)Bg~jZ+dzzr3w}>g2q7&6hj12llQ! zw%(L`y*S5t{nJ}-Jbcc2=swN3x!t{Vbov=5^aI=BHA5PWZE5 zc22=-7o7b0QcE_+Zo;Lz^QQcbEL^ku!a9jqEngYQV{FPVj2_viclDIqH+aHb<{y6J zB>Qf)H78D2t<16rH;s>~kP-RSZgltZABjKn?OcE9GnO3OpHZ)`!oa}5;OXk;vd$@? F2>=CA(>wqG literal 0 HcmV?d00001 diff --git a/data/wizard_left.bmp b/data/wizard_left.bmp deleted file mode 100644 index b56f7334beeb6294e255b31b465f5c78ffe9c47c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8246 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 DfGQzc literal 0 HcmV?d00001 diff --git a/data/wizard_right.bmp b/data/wizard_right.bmp deleted file mode 100644 index 06b729722232fd2be3a07ba52b7da2a475269e06..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8246 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 diff --git a/data/wizard_right.png b/data/wizard_right.png new file mode 100644 index 0000000000000000000000000000000000000000..1f1c89bb0cf4e3675886246a8ad2d8d6033621cf GIT binary patch literal 3807 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 BB(?wm literal 0 HcmV?d00001 diff --git a/main.c b/main.c index 883120b..b68e9d6 100644 --- a/main.c +++ b/main.c @@ -69,7 +69,7 @@ int main(int argc,char *argv[]){ font=Draw_DefaultFont(255,255,255,255); font_shad=Draw_DefaultFont(0,0,0,127); - img_background=Draw_LoadImage("data/heaven.bmp"); + img_background=Draw_LoadImage("data/heaven.png"); Draw_SetOffset(img_background,0,0); GameEnts_Init();