summaryrefslogtreecommitdiffstats
path: root/mpng.c
blob: 95125c302ea311b352b9c053535a0eada2750b9a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
#include <stdlib.h>

#include "config.h"
#include "bswap.h"
#include "postproc/rgb2rgb.h"
#include "libvo/fastmemcpy.h"
#include "mp_msg.h"
#include "png.h"

static int    pngPointer;

static void pngReadFN( png_structp pngstr,png_bytep buffer,png_size_t size )
{
 char * p = pngstr->io_ptr;
 memcpy( buffer,(char *)&p[pngPointer],size );
 pngPointer+=size;
}

void decode_mpng(
  unsigned char *encoded,
  int encoded_size,
  unsigned char *decoded,
  int width,
  int height,
  int bytes_per_pixel)
{
 png_structp     png;
 png_infop       info;
 png_infop       endinfo;
 png_bytep       data;
 png_bytep     * row_p;
 png_uint_32     png_width,png_height;
 char	       * palette = NULL;
 int             depth,color;
 png_uint_32     i;

 /* currently supporting only 24 and 32bpp */
 if ((bytes_per_pixel != 3) && (bytes_per_pixel != 4))
 {
    /* is this memset really needed? */
    memset(decoded, 0, width*height*bytes_per_pixel);
    return;
 }

 png=png_create_read_struct( PNG_LIBPNG_VER_STRING,NULL,NULL,NULL );
 info=png_create_info_struct( png );
 endinfo=png_create_info_struct( png );

 pngPointer=8;
 png_set_read_fn( png,encoded,pngReadFN );
 png_set_sig_bytes( png,8 );
 png_read_info( png,info );
 png_get_IHDR( png,info,&png_width,&png_height,&depth,&color,NULL,NULL,NULL );

 png_set_bgr( png );

#if 0
 switch( info->color_type )
  {
   case PNG_COLOR_TYPE_GRAY_ALPHA: printf( "[png] used GrayA -> stripping alpha channel\n" ); break;
   case PNG_COLOR_TYPE_GRAY:       printf( "[png] used Gray -> rgb\n" ); break;
   case PNG_COLOR_TYPE_PALETTE:    printf( "[png] used palette -> rgb\n" ); break;
   case PNG_COLOR_TYPE_RGB_ALPHA:  printf( "[png] used RGBA -> stripping alpha channel\n" ); break;
   case PNG_COLOR_TYPE_RGB:        printf( "[png] read rgb datas.\n" ); break;
  }
#endif

 if ( info->color_type == PNG_COLOR_TYPE_RGB ) data=decoded;
  else data=(png_bytep)malloc( png_get_rowbytes( png,info ) * height );

 row_p=(png_bytep*)malloc( sizeof( png_bytep ) * png_height );
 for ( i=0; i < png_height; i++ ) row_p[i]=&data[png_get_rowbytes( png,info ) * i];
 png_read_image( png,row_p );
 free( row_p );
						     
 switch( info->color_type )
  {
   case PNG_COLOR_TYPE_GRAY_ALPHA:
          mp_msg( MSGT_DECVIDEO,MSGL_INFO,"Sorry gray scaled png with alpha channel not supported at moment.\n" );
          free( data );
	  break;
   case PNG_COLOR_TYPE_GRAY:
	  /* constant 256 colors */
          palette=malloc( 1024 );
          for ( i=0;i < 256;i++ ) palette[(i*4)]=palette[(i*4)+1]=palette[(i*4)+2]=(char)i;
	  if (bytes_per_pixel == 4)
	    palette8torgb32( data,decoded,png_width * png_height,palette );
	  else
	    palette8torgb24( data,decoded,png_width * png_height,palette );
          free( data );
	  break;
   case PNG_COLOR_TYPE_PALETTE:
          { 
           int    cols;
	   unsigned char * pal;
           png_get_PLTE( png,info,(png_colorp*)&pal,&cols ); 
           palette=calloc( 1,cols*4 );
	   mp_dbg(MSGT_DECVIDEO, MSGL_DBG2, "[mPNG] palette. used colors: %d\n", cols);
	   for ( i=0;i < cols;i++ )
	    {
	     palette[(i*4)  ]=pal[(i*3)+2];
	     palette[(i*4)+1]=pal[(i*3)+1];
	     palette[(i*4)+2]=pal[(i*3)  ];
	    }
	  }
	  if (bytes_per_pixel == 4)
	    palette8torgb32( data,decoded,png_width * png_height,palette );
	  else
	    palette8torgb24( data,decoded,png_width * png_height,palette );
          free( data );
	  break;
   case PNG_COLOR_TYPE_RGB_ALPHA:
	  if (bytes_per_pixel == 4)
	    memcpy(decoded, data, png_width * png_height * 4);
	  else
            rgb32to24( data,decoded,png_width * png_height * 4 );
          free( data );
	  break;
  }

 if ( palette ) free( palette );

 png_read_end( png,endinfo );
 png_destroy_read_struct( &png,&info,&endinfo );
}