Browse code

Add jpeg support

Dario Rodriguez authored on 16/01/2022 19:30:36
Showing 2 changed files
... ...
@@ -1,6 +1,6 @@
1 1
 CC=gcc
2 2
 CFLAGS=-g -Wall
3
-LDFLAGS=-lm -lpng
3
+LDFLAGS=-lm -lpng -ljpeg
4 4
 
5 5
 all: luttool
6 6
 
... ...
@@ -13,18 +13,26 @@
13 13
 #include <stdlib.h>
14 14
 #include <unistd.h>
15 15
 #include <string.h>
16
+#include <setjmp.h>
17
+#include <sys/types.h>
18
+#include <sys/stat.h>
19
+#include <fcntl.h>
16 20
 #include <math.h>
17 21
 #include <png.h>
22
+#include <jpeglib.h>
18 23
 
19 24
 #define DEFAULT_IDENTITYSIZE 12 /* Same as RawTherapee's HaldCLUTs, 1728x1728 AKA (12*12)*12x12*(12*12), equivalent to a cube with 144px wide sides*/
20 25
 #define DEFAULT_QUALITY 85
21
-/* #define JPEG_SUPPORTED */
22 26
 
23 27
 int luttool_applylut(char *lutfilenamelist,char *infilename, char *outfilename,int quality,int identitysize,int flaginterpolatelut);
24 28
 
29
+int util_imgload(char *filename, char **bufimg, int *sizebufimg, int *width, int *height);
30
+int util_imgsave(char *filename, char *bufimg, int width, int height,int quality);
25 31
 int util_pnginfo(char *filename, int *width, int *height);
26 32
 int util_pngload(char *filename, char **bufimg, int *sizebufimg, int *width, int *height);
27 33
 int util_pngsave(char *filename, char *bufimg, int width, int height);
34
+int util_jpgload(char *filename, char **bufimg, int *sizebufimg, int *width, int *height);
35
+int util_jpgsave(char *filename, char *bufimg, int width, int height,int quality);
28 36
 int util_identitygen(char **bufimg, int *sizebufimg, int identitysize, int *width, int *height);
29 37
 int luttool_rgba2lut4096(char *rgba, int width, int height, char **lut4096, int *sizelut4096);
30 38
 int luttool_rgba2lut4096_interpolated(char *rgba, int width, int height, char **lut4096, int *sizelut4096);
... ...
@@ -44,20 +52,12 @@ main(int argc, char *argv[])
44 52
         char bufoutfilename[1024];
45 53
         char *currentoutfilename;
46 54
         if(argc<2 || strcmp(argv[argc-1],"--help")==0) {
47
-#ifdef JPEG_SUPPORTED
48 55
                 printf("Syntax: %s [-i] [-q jpegquality] [-n identitylevel] {identity | lutfile[,lutfile[,...]]} { identity | infile1 } [infile2 [...]] -o outfile\n",argv[0]);
49 56
                 printf("Example: %s haldclut.png sprite.png -o result.png\n",argv[0]);
50 57
                 printf("Example: %s -i haldclut.png sprite.png -o result.png\n",argv[0]);
51 58
                 printf("Example: %s -n 16 identity identity -o identity.png\n",argv[0]);
52 59
                 printf("Example: %s -q 85 haldclut.png infile.png -o outfile.jpg\n",argv[0]);
53 60
                 printf("NOTE: -i makes the program interpolate the LUTs.\n");
54
-#else
55
-                printf("Syntax: %s [-n identitylevel] {identity | lutfile[,lutfile[,...]]} { identity | infile1 } [infile2 [...]] -o outfile\n",argv[0]);
56
-                printf("Example: %s haldclut.png sprite.png -o result.png\n",argv[0]);
57
-                printf("Example: -i %s haldclut.png sprite.png -o result.png\n",argv[0]);
58
-                printf("Example: %s -n 16 identity identity -o identity.png\n",argv[0]);
59
-                printf("NOTE: -i makes the program interpolate the LUTs.\n");
60
-#endif
61 61
                 return(1);
62 62
         }
63 63
         /* parse arguments */
... ...
@@ -153,7 +153,7 @@ luttool_applylut(char *lutlist,char *infilename, char *outfilename,int quality,i
153 153
                  if(util_identitygen(&imgbuf,&sizeimgbuf,identitysize,&imgwidth,&imgheight)==-1)
154 154
                          in_error=1;
155 155
         } else {
156
-                if(util_pngload(infilename,&imgbuf,&sizeimgbuf,&imgwidth,&imgheight)!=0)
156
+                if(util_imgload(infilename,&imgbuf,&sizeimgbuf,&imgwidth,&imgheight)!=0)
157 157
                         in_error=1;
158 158
         }
159 159
         /* apply all luts */
... ...
@@ -170,7 +170,7 @@ luttool_applylut(char *lutlist,char *infilename, char *outfilename,int quality,i
170 170
                                 break; /* couldn't generate identity lut */
171 171
                         }
172 172
                 } else {
173
-                        if(util_pngload(filename,&lutbuf,&sizelutbuf,&lutwidth,&lutheight)==-1) {
173
+                        if(util_imgload(filename,&lutbuf,&sizelutbuf,&lutwidth,&lutheight)==-1) {
174 174
                                 in_error=1;
175 175
                                 break; /* couldn't load lut */
176 176
                         }
... ...
@@ -191,7 +191,7 @@ luttool_applylut(char *lutlist,char *infilename, char *outfilename,int quality,i
191 191
         }
192 192
         /* save the result */
193 193
         if(in_error==0) {
194
-                if(util_pngsave(outfilename,imgbuf,imgwidth,imgheight)!=0)
194
+                if(util_imgsave(outfilename,imgbuf,imgwidth,imgheight,quality)!=0)
195 195
                         in_error=1; /* couldn't write */
196 196
         }
197 197
         /* cleanup and exit */
... ...
@@ -204,7 +204,52 @@ luttool_applylut(char *lutlist,char *infilename, char *outfilename,int quality,i
204 204
         return((in_error!=0)?-1:0);
205 205
 }
206 206
 
207
+int
208
+util_imgload(char *filename, char **bufimg, int *sizebufimg, int *width, int *height)
209
+{
210
+        int fd;
211
+        char buf[8];
212
+        if((fd=open(filename,O_RDONLY))==-1
213
+          || read(fd,buf,sizeof(buf))<sizeof(buf)) {
214
+                if(fd!=-1)
215
+                        close(fd),fd=-1;
216
+                return(-1); /* couldn't open file for reading */
217
+        }
218
+        close(fd),fd=-1;
219
+        if(memcmp(buf,"\x89\x50\x4e\x47\x0d\x0a\x1a\x0a",8)==0) { /* PNG magic */
220
+                return(util_pngload(filename,bufimg,sizebufimg,width,height));
221
+        } else if(memcmp(buf,"\xff\xd8",2)==0) { /* EXIF magic */
222
+                return(util_jpgload(filename,bufimg,sizebufimg,width,height));
223
+        }
224
+        return(-1); /* file type not recognized */
225
+}
207 226
 
227
+int
228
+util_imgsave(char *filename, char *bufimg, int width, int height,int quality)
229
+{
230
+        int l;
231
+        int flagjpeg;
232
+        if(filename==NULL || bufimg==NULL || width<=0 || height<=0)
233
+                return(-1); /* sanity check error */
234
+        l=strlen(filename);
235
+        if((l>=4
236
+          && filename[l-4]=='.'
237
+          && (filename[l-3]=='J' || filename[l-3]=='j')
238
+          && (filename[l-2]=='P' || filename[l-2]=='p')
239
+          && (filename[l-1]=='G' || filename[l-1]=='g'))
240
+          || (l>=5
241
+          && filename[l-5]=='.'
242
+          && (filename[l-4]=='J' || filename[l-4]=='j')
243
+          && (filename[l-3]=='P' || filename[l-3]=='p')
244
+          && (filename[l-2]=='e' || filename[l-2]=='e')
245
+          && (filename[l-1]=='G' || filename[l-1]=='g'))) {
246
+                flagjpeg=1;
247
+        }
248
+        /* use png as default format; only use jpg if file extension says so */
249
+        if(flagjpeg)
250
+                return(util_jpgsave(filename,bufimg,width,height,quality));
251
+        return(util_pngsave(filename,bufimg,width,height));
252
+}
208 253
 
209 254
 int
210 255
 util_pnginfo(char *filename, int *width, int *height)
... ...
@@ -322,6 +367,147 @@ util_pngsave(char *filename, char *bufimg, int width, int height)
322 367
         return(0);
323 368
 }
324 369
 
370
+typedef struct jpegerrmgr_t {
371
+        struct jpeg_error_mgr pub;
372
+        jmp_buf setjmpbuf;
373
+} jpegerrmgr_t;
374
+
375
+static void
376
+util_jpgerrhandler(j_common_ptr cinfo)
377
+{
378
+        jpegerrmgr_t *errmgr;
379
+        errmgr=(jpegerrmgr_t *)cinfo->err;
380
+        longjmp(errmgr->setjmpbuf,1);
381
+}
382
+
383
+int
384
+util_jpgload(char *filename, char **bufimg, int *sizebufimg, int *width, int *height)
385
+{
386
+        FILE *f;
387
+        struct jpeg_decompress_struct cinfo;
388
+        jpegerrmgr_t errmgr;
389
+        int reqsize;
390
+        JSAMPROW rowptrs[1];
391
+        unsigned char *ptr,*orig,*dest;
392
+        if(filename==NULL || (bufimg==NULL && sizebufimg!=NULL) || (bufimg!=NULL && sizebufimg==NULL) || width==NULL || height==NULL)
393
+                return(-1); /* sanity check failed */
394
+        if((f=fopen(filename,"rb"))==NULL)
395
+                return(-1); /* couldn't open file */
396
+        memset(&cinfo,0,sizeof(cinfo));
397
+        cinfo.err=jpeg_std_error(&errmgr.pub);
398
+        errmgr.pub.error_exit=util_jpgerrhandler;
399
+        if(setjmp(errmgr.setjmpbuf)) {
400
+                jpeg_destroy_decompress(&cinfo);
401
+                if(f!=NULL)
402
+                        fclose(f),f=NULL;
403
+                return(-1); /* libjpeg couldn't decompress stream */
404
+        }
405
+        jpeg_create_decompress(&cinfo);
406
+        jpeg_stdio_src(&cinfo,f);
407
+        jpeg_read_header(&cinfo,TRUE);
408
+        jpeg_start_decompress(&cinfo);
409
+        *width=cinfo.output_width;
410
+        *height=cinfo.output_height;
411
+        /* special case: if bufimg==NULL, we only want the width/height */
412
+        if(bufimg==NULL) {
413
+                jpeg_destroy_decompress(&cinfo);
414
+                return(0); /* all done */
415
+        }
416
+        /* make sure is in a supported format */
417
+        if(cinfo.output_components!=3 && cinfo.output_components!=4) {
418
+                jpeg_destroy_decompress(&cinfo);
419
+                return(-1); /* we only support 8-bit RGB jpeg */
420
+        }
421
+        /* make sure we have enough space for the new image in 8-bit RGBA */
422
+        reqsize=(*width)*(*height)*4;
423
+        if(*sizebufimg<reqsize) {
424
+                char *newbufimg;
425
+                if((newbufimg=realloc(*bufimg,reqsize))==NULL) {
426
+                      jpeg_destroy_decompress(&cinfo);
427
+                      fclose(f),f=NULL;
428
+                      return(-1); /* insuf. mem. for resulting image */
429
+                }
430
+                *bufimg=newbufimg;
431
+                *sizebufimg=reqsize;
432
+        }
433
+        while(cinfo.output_scanline<cinfo.output_height) {
434
+                ptr=(unsigned char *)((*bufimg)+cinfo.output_scanline*((*width)*4));
435
+                rowptrs[0]=ptr;
436
+                jpeg_read_scanlines(&cinfo,rowptrs,1);
437
+                if(cinfo.output_components==3) {
438
+                        orig=ptr+((*width)-1)*3;
439
+                        dest=ptr+((*width)-1)*4;
440
+                        for(;orig>=ptr;orig-=3,dest-=4) {
441
+                                dest[0]=orig[0];
442
+                                dest[1]=orig[1];
443
+                                dest[2]=orig[2];
444
+                                dest[3]=0xff;
445
+                        }
446
+                }
447
+        }
448
+        jpeg_finish_decompress(&cinfo);
449
+        jpeg_destroy_decompress(&cinfo);
450
+        fclose(f),f=NULL;
451
+        return(0);
452
+}
453
+
454
+int
455
+util_jpgsave(char *filename, char *bufimg, int width, int height,int quality)
456
+{
457
+        FILE *f;
458
+        struct jpeg_compress_struct cinfo;
459
+        jpegerrmgr_t errmgr;
460
+        char *rowdata;
461
+        JSAMPROW rowptrs[1];
462
+        int i;
463
+        unsigned char *ptr,*orig,*dest;
464
+        if(filename==NULL || bufimg==NULL || width<=0 || height<=0 || quality<1 || quality>100)
465
+                return(-1); /* sanity check failed */
466
+        if((rowdata=malloc(width*3))==NULL)
467
+                return(-1);
468
+        if((f=fopen(filename,"wb"))==NULL) {
469
+                if(rowdata!=NULL)
470
+                        free(rowdata),rowdata=NULL;
471
+                return(-1); /* couldn't open file for writing */
472
+        }
473
+        memset(&cinfo,0,sizeof(cinfo));
474
+        cinfo.err=jpeg_std_error(&errmgr.pub);
475
+        errmgr.pub.error_exit=util_jpgerrhandler;
476
+        if(setjmp(errmgr.setjmpbuf)) {
477
+                if(f!=NULL)
478
+                        fclose(f),f=NULL;
479
+                if(rowdata!=NULL)
480
+                        free(rowdata),rowdata=NULL;
481
+                jpeg_destroy_compress(&cinfo);
482
+                return(-1); /* libjpeg couldn't compress stream */
483
+        }
484
+        jpeg_create_compress(&cinfo);
485
+        jpeg_stdio_dest(&cinfo,f);
486
+        cinfo.image_width=width;
487
+        cinfo.image_height=height;
488
+        cinfo.input_components=3;
489
+        cinfo.in_color_space=JCS_RGB;
490
+        jpeg_set_defaults(&cinfo);
491
+        jpeg_set_quality(&cinfo,quality,TRUE);
492
+        jpeg_start_compress(&cinfo,TRUE);
493
+        while(cinfo.next_scanline<cinfo.image_height) {
494
+                ptr=(unsigned char *)(bufimg+cinfo.next_scanline*(width*4));
495
+                for(orig=ptr,dest=rowdata,i=0;i<width;i++,orig+=4,dest+=3) {
496
+                        dest[0]=orig[0];
497
+                        dest[1]=orig[1];
498
+                        dest[2]=orig[2];
499
+                }
500
+                rowptrs[0]=rowdata;
501
+                jpeg_write_scanlines(&cinfo,rowptrs,1);
502
+        }
503
+        jpeg_finish_compress(&cinfo);
504
+        jpeg_destroy_compress(&cinfo);
505
+        fclose(f),f=NULL;
506
+        free(rowdata),rowdata=NULL;
507
+        return(0);
508
+}
509
+
510
+
325 511
 int
326 512
 util_identitygen(char **bufimg, int *sizebufimg, int identitysize, int *width, int *height)
327 513
 {