add a format converter, i.e. to convert from lamedb to sat.xml files
[enigma2.git] / tools / convert_argb_png.c
1 /*
2      convert_argb_png.c
3      
4    compile with:
5      
6      gcc convert_argb_png.c -o convert_argb_png -lpng -ljpeg
7     
8    this tool takes a 32bit RGB+A PNG file, for example produced by photoshop,
9    and splits the data into RGB and A. The RGB data is then lossy compressed with JPEG,
10    the alpha channel is lossless compressed as PNG.
11
12    enigma2 can then pickup those two files, and combine them on load. This gives
13    the possibilty to use truecolor RGB pictures without storing them lossless
14    (which would be inefficient). 
15  */
16
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <png.h>
20 #include <assert.h>
21 #include <jpeglib.h>
22
23 int main(int argc, char **argv)
24 {
25         if (argc != 4)
26         {
27                 fprintf(stderr, "usage: %s <input.png> <output_basename> <jpeg-quality>\n", *argv);
28                 return 1;
29         }
30
31         const char *infile = argv[1];
32         const char *outfile = argv[2];
33         int jpeg_quality = atoi(argv[3]);
34
35         FILE *fpin = fopen(infile, "rb");
36         if (!fpin)
37         {
38                 perror(infile);
39                 return 1;
40         }
41
42         unsigned char header[8];
43         fread(header, 1, 8, fpin);
44         if (png_sig_cmp(header, 0, 8))
45         {
46                 fprintf(stderr, "this is not a PNG file\n");
47                 return 1;
48         }
49         png_structp png_ptr = png_create_read_struct
50                 (PNG_LIBPNG_VER_STRING, 0, 0, 0);
51         assert(png_ptr);
52
53         png_infop info_ptr = png_create_info_struct(png_ptr);
54         assert(info_ptr);
55
56         png_infop end_info = png_create_info_struct(png_ptr);
57         assert (end_info);
58
59         if (setjmp(png_jmpbuf(png_ptr)))
60         {
61                 png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
62                 fclose(fpin);
63                 fprintf(stderr, "failed.\n");
64                 return 1;
65         }
66
67         png_init_io(png_ptr, fpin);
68         png_set_sig_bytes(png_ptr, 8);
69         png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, 0);
70         png_bytep * row_pointers = png_get_rows(png_ptr, info_ptr);
71
72         png_uint_32 width, height;
73         int bit_depth, color_type;
74         png_get_IHDR(png_ptr, info_ptr, &width, &height, 
75                 &bit_depth, &color_type, 0, 0, 0);
76
77         if (color_type != PNG_COLOR_TYPE_RGB_ALPHA)
78         {
79                 fprintf(stderr, "input PNG must be RGB+Alpha\n");
80                 return 1;
81         }
82         if (bit_depth != 8)
83         {
84                 fprintf(stderr, "input bit depth must be 8bit!\n");
85                 return 1;
86         }
87         printf("png is %ldx%ld\n", width, height);
88         int channels = png_get_channels(png_ptr, info_ptr);
89         if (channels != 4)
90         {
91                 fprintf(stderr, "channels must be 4.\n");
92                 return 1;
93         }
94
95                 /* now write jpeg */
96         struct jpeg_compress_struct cinfo;
97         struct jpeg_error_mgr jerr;
98         JSAMPROW jrow_pointer[1];
99         FILE *outfp;
100
101         char filename[strlen(outfile) + 10];
102         strcpy(filename, outfile);
103         strcat(filename, ".rgb.jpg");
104
105         outfp = fopen(filename, "wb");
106         if (!outfp)
107         {
108                 perror(filename);
109                 return 1;
110         }
111
112         cinfo.err = jpeg_std_error(&jerr);
113         jpeg_create_compress(&cinfo);
114         jpeg_stdio_dest(&cinfo, outfp);
115
116         cinfo.image_width = width;
117         cinfo.image_height = height;
118         cinfo.input_components = 3;
119         cinfo.in_color_space = JCS_RGB;
120         jpeg_set_defaults(&cinfo);
121         jpeg_set_quality(&cinfo, jpeg_quality, 1);
122         jpeg_start_compress(&cinfo, 1);
123
124         unsigned char *row = malloc(width * 3);
125         while (cinfo.next_scanline < cinfo.image_height)
126         {
127                 int x;
128                 jrow_pointer[0] = row;
129                 unsigned char *source = row_pointers[cinfo.next_scanline];
130                 for (x = 0; x < width; ++x)
131                 {
132                         row[x * 3 + 0] = source[0];
133                         row[x * 3 + 1] = source[1];
134                         row[x * 3 + 2] = source[2];
135                         source += 4;
136                 }
137                 jpeg_write_scanlines(&cinfo, jrow_pointer, 1);
138         }
139
140         jpeg_finish_compress(&cinfo);
141         fclose(outfp);
142         jpeg_destroy_compress(&cinfo);
143
144                 /* and write png */
145         strcpy(filename, outfile);
146         strcat(filename, ".a.png");
147
148         outfp = fopen(filename, "wb");
149         if (!outfp)
150         {
151                 perror(filename);
152                 return 1;
153         }
154
155         png_structp png_ptr_w = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
156         png_infop info_ptr_w = png_create_info_struct(png_ptr_w);
157         if (setjmp(png_jmpbuf(png_ptr_w)))
158         {
159                 png_destroy_write_struct(&png_ptr_w, &info_ptr_w);
160                 fclose(outfp);
161                 return 1;
162         }
163         png_init_io(png_ptr_w, outfp);
164         png_set_IHDR(png_ptr_w, info_ptr_w, width, height, 8, PNG_COLOR_TYPE_GRAY, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
165
166                 /* turn RGBA into A, in-place */
167         int x, y;
168         for (y=0; y < height; ++y)
169         {
170                 unsigned char *source = row_pointers[y];
171                 unsigned char *dst = source;
172                 for (x=0; x < width; ++x)
173                 {
174                         *dst++ = source[3];
175                         source += 4;
176                 }
177         }
178         png_set_rows(png_ptr_w, info_ptr_w, row_pointers);
179         png_write_png(png_ptr_w, info_ptr_w, PNG_TRANSFORM_IDENTITY, 0);
180         png_write_end(png_ptr_w, info_ptr_w);
181         png_destroy_write_struct(&png_ptr_w, &info_ptr_w);
182         return 0;
183 }