Tools/Directories.py: Get rid of "fallback" in resolveFilename
[openblackhole/openblackhole-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                 fclose(fpin);
48                 return 1;
49         }
50         png_structp png_ptr = png_create_read_struct
51                 (PNG_LIBPNG_VER_STRING, 0, 0, 0);
52         assert(png_ptr);
53
54         png_infop info_ptr = png_create_info_struct(png_ptr);
55         assert(info_ptr);
56
57         png_infop end_info = png_create_info_struct(png_ptr);
58         assert (end_info);
59
60         if (setjmp(png_jmpbuf(png_ptr)))
61         {
62                 png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
63                 fclose(fpin);
64                 fprintf(stderr, "failed.\n");
65                 return 1;
66         }
67
68         png_init_io(png_ptr, fpin);
69         png_set_sig_bytes(png_ptr, 8);
70         png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, 0);
71         png_bytep * row_pointers = png_get_rows(png_ptr, info_ptr);
72
73         png_uint_32 width, height;
74         int bit_depth, color_type;
75         png_get_IHDR(png_ptr, info_ptr, &width, &height, 
76                 &bit_depth, &color_type, 0, 0, 0);
77
78         if (color_type != PNG_COLOR_TYPE_RGB_ALPHA)
79         {
80                 fprintf(stderr, "input PNG must be RGB+Alpha\n");
81                 fclose(fpin);
82                 return 1;
83         }
84         if (bit_depth != 8)
85         {
86                 fprintf(stderr, "input bit depth must be 8bit!\n");
87                 fclose(fpin);
88                 return 1;
89         }
90         printf("png is %ldx%ld\n", width, height);
91         int channels = png_get_channels(png_ptr, info_ptr);
92         if (channels != 4)
93         {
94                 fprintf(stderr, "channels must be 4.\n");
95                 fclose(fpin);
96                 return 1;
97         }
98
99         fclose(fpin);
100
101         /* now write jpeg */
102         struct jpeg_compress_struct cinfo;
103         struct jpeg_error_mgr jerr;
104         JSAMPROW jrow_pointer[1];
105         FILE *outfp;
106
107         char filename[strlen(outfile) + 10];
108         strcpy(filename, outfile);
109         strcat(filename, ".rgb.jpg");
110
111         outfp = fopen(filename, "wb");
112         if (!outfp)
113         {
114                 perror(filename);
115                 return 1;
116         }
117
118         cinfo.err = jpeg_std_error(&jerr);
119         jpeg_create_compress(&cinfo);
120         jpeg_stdio_dest(&cinfo, outfp);
121
122         cinfo.image_width = width;
123         cinfo.image_height = height;
124         cinfo.input_components = 3;
125         cinfo.in_color_space = JCS_RGB;
126         jpeg_set_defaults(&cinfo);
127         jpeg_set_quality(&cinfo, jpeg_quality, 1);
128         jpeg_start_compress(&cinfo, 1);
129
130         unsigned char *row = malloc(width * 3);
131         while (cinfo.next_scanline < cinfo.image_height)
132         {
133                 int x;
134                 jrow_pointer[0] = row;
135                 unsigned char *source = row_pointers[cinfo.next_scanline];
136                 for (x = 0; x < width; ++x)
137                 {
138                         row[x * 3 + 0] = source[0];
139                         row[x * 3 + 1] = source[1];
140                         row[x * 3 + 2] = source[2];
141                         source += 4;
142                 }
143                 jpeg_write_scanlines(&cinfo, jrow_pointer, 1);
144         }
145
146         jpeg_finish_compress(&cinfo);
147         fclose(outfp);
148         jpeg_destroy_compress(&cinfo);
149
150         /* and write png */
151         strcpy(filename, outfile);
152         strcat(filename, ".a.png");
153
154         outfp = fopen(filename, "wb");
155         if (!outfp)
156         {
157                 perror(filename);
158                 return 1;
159         }
160
161         png_structp png_ptr_w = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
162         png_infop info_ptr_w = png_create_info_struct(png_ptr_w);
163         if (setjmp(png_jmpbuf(png_ptr_w)))
164         {
165                 png_destroy_write_struct(&png_ptr_w, &info_ptr_w);
166                 fclose(outfp);
167                 return 1;
168         }
169         png_init_io(png_ptr_w, outfp);
170         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);
171
172                 /* turn RGBA into A, in-place */
173         int x, y;
174         for (y=0; y < height; ++y)
175         {
176                 unsigned char *source = row_pointers[y];
177                 unsigned char *dst = source;
178                 for (x=0; x < width; ++x)
179                 {
180                         *dst++ = source[3];
181                         source += 4;
182                 }
183         }
184         png_set_rows(png_ptr_w, info_ptr_w, row_pointers);
185         png_write_png(png_ptr_w, info_ptr_w, PNG_TRANSFORM_IDENTITY, 0);
186         png_write_end(png_ptr_w, info_ptr_w);
187         png_destroy_write_struct(&png_ptr_w, &info_ptr_w);
188         fclose(outfp);
189         return 0;
190 }