add tool to convert 32bit argb into jpg+png. we still need enigma support to load...
[enigma2.git] / tools / convert_argb_png.c
diff --git a/tools/convert_argb_png.c b/tools/convert_argb_png.c
new file mode 100644 (file)
index 0000000..d278ca9
--- /dev/null
@@ -0,0 +1,183 @@
+/*
+     convert_argb_png.c
+     
+   compile with:
+     
+     gcc convert_argb_png.c -o convert_argb_png -lpng -ljpeg
+    
+   this tool takes a 32bit RGB+A PNG file, for example produced by photoshop,
+   and splits the data into RGB and A. The RGB data is then lossy compressed with JPEG,
+   the alpha channel is lossless compressed as PNG.
+
+   enigma2 can then pickup those two files, and combine them on load. This gives
+   the possibilty to use truecolor RGB pictures without storing them lossless
+   (which would be inefficient). 
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <png.h>
+#include <assert.h>
+#include <jpeglib.h>
+
+int main(int argc, char **argv)
+{
+       if (argc != 4)
+       {
+               fprintf(stderr, "usage: %s <input.png> <output_basename> <jpeg-quality>\n", *argv);
+               return 1;
+       }
+
+       const char *infile = argv[1];
+       const char *outfile = argv[2];
+       int jpeg_quality = atoi(argv[3]);
+
+       FILE *fpin = fopen(infile, "rb");
+       if (!fpin)
+       {
+               perror(infile);
+               return 1;
+       }
+
+       unsigned char header[8];
+       fread(header, 1, 8, fpin);
+       if (png_sig_cmp(header, 0, 8))
+       {
+               fprintf(stderr, "this is not a PNG file\n");
+               return 1;
+       }
+       png_structp png_ptr = png_create_read_struct
+               (PNG_LIBPNG_VER_STRING, 0, 0, 0);
+       assert(png_ptr);
+
+       png_infop info_ptr = png_create_info_struct(png_ptr);
+       assert(info_ptr);
+
+       png_infop end_info = png_create_info_struct(png_ptr);
+       assert (end_info);
+
+       if (setjmp(png_jmpbuf(png_ptr)))
+       {
+               png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
+               fclose(fpin);
+               fprintf(stderr, "failed.\n");
+               return 1;
+       }
+
+       png_init_io(png_ptr, fpin);
+       png_set_sig_bytes(png_ptr, 8);
+       png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, 0);
+       png_bytep * row_pointers = png_get_rows(png_ptr, info_ptr);
+
+       png_uint_32 width, height;
+       int bit_depth, color_type;
+       png_get_IHDR(png_ptr, info_ptr, &width, &height, 
+               &bit_depth, &color_type, 0, 0, 0);
+
+       if (color_type != PNG_COLOR_TYPE_RGB_ALPHA)
+       {
+               fprintf(stderr, "input PNG must be RGB+Alpha\n");
+               return 1;
+       }
+       if (bit_depth != 8)
+       {
+               fprintf(stderr, "input bit depth must be 8bit!\n");
+               return 1;
+       }
+       printf("png is %ldx%ld\n", width, height);
+       int channels = png_get_channels(png_ptr, info_ptr);
+       if (channels != 4)
+       {
+               fprintf(stderr, "channels must be 4.\n");
+               return 1;
+       }
+
+               /* now write jpeg */
+       struct jpeg_compress_struct cinfo;
+       struct jpeg_error_mgr jerr;
+       JSAMPROW jrow_pointer[1];
+       FILE *outfp;
+
+       char filename[strlen(outfile) + 10];
+       strcpy(filename, outfile);
+       strcat(filename, ".rgb.jpg");
+
+       outfp = fopen(filename, "wb");
+       if (!outfp)
+       {
+               perror(filename);
+               return 1;
+       }
+
+       cinfo.err = jpeg_std_error(&jerr);
+       jpeg_create_compress(&cinfo);
+       jpeg_stdio_dest(&cinfo, outfp);
+
+       cinfo.image_width = width;
+       cinfo.image_height = height;
+       cinfo.input_components = 3;
+       cinfo.in_color_space = JCS_RGB;
+       jpeg_set_defaults(&cinfo);
+       jpeg_set_quality(&cinfo, jpeg_quality, 1);
+       jpeg_start_compress(&cinfo, 1);
+
+       unsigned char *row = malloc(width * 3);
+       while (cinfo.next_scanline < cinfo.image_height)
+       {
+               int x;
+               jrow_pointer[0] = row;
+               unsigned char *source = row_pointers[cinfo.next_scanline];
+               for (x = 0; x < width; ++x)
+               {
+                       row[x * 3 + 0] = source[0];
+                       row[x * 3 + 1] = source[1];
+                       row[x * 3 + 2] = source[2];
+                       source += 4;
+               }
+               jpeg_write_scanlines(&cinfo, jrow_pointer, 1);
+       }
+
+       jpeg_finish_compress(&cinfo);
+       fclose(outfp);
+       jpeg_destroy_compress(&cinfo);
+
+               /* and write png */
+       strcpy(filename, outfile);
+       strcat(filename, ".a.png");
+
+       outfp = fopen(filename, "wb");
+       if (!outfp)
+       {
+               perror(filename);
+               return 1;
+       }
+
+       png_structp png_ptr_w = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
+       png_infop info_ptr_w = png_create_info_struct(png_ptr_w);
+       if (setjmp(png_jmpbuf(png_ptr_w)))
+       {
+               png_destroy_write_struct(&png_ptr_w, &info_ptr_w);
+               fclose(outfp);
+               return 1;
+       }
+       png_init_io(png_ptr_w, outfp);
+       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);
+
+               /* turn RGBA into A, in-place */
+       int x, y;
+       for (y=0; y < height; ++y)
+       {
+               unsigned char *source = row_pointers[y];
+               unsigned char *dst = source;
+               for (x=0; x < width; ++x)
+               {
+                       *dst++ = source[3];
+                       source += 4;
+               }
+       }
+       png_set_rows(png_ptr_w, info_ptr_w, row_pointers);
+       png_write_png(png_ptr_w, info_ptr_w, PNG_TRANSFORM_IDENTITY, 0);
+       png_write_end(png_ptr_w, info_ptr_w);
+       png_destroy_write_struct(&png_ptr_w, &info_ptr_w);
+       return 0;
+}