1 #include <stdlib.h> 2 #include <inttypes.h> 3 #include <string.h> 4 #include <stdbool.h> 5 #include <stdio.h> 6 #include <err.h> 7 #include <errno.h> 8 #include <cairo.h> 9 #include <jpeglib.h> 10 11 #include "jpg.h" 12 13 /* 14 * Checks if the file is a JPEG by looking for a valid JPEG header. 15 */ 16 bool file_is_jpg(char* file_path) { 17 if (!file_path) return false; 18 FILE* image_file; 19 uint16_t file_header; 20 size_t read_count; 21 // TODO: Consider endianess on non-x86 platforms 22 uint16_t jpg_magick = 0xd8ff; 23 24 image_file = fopen(file_path, "rb"); 25 if (image_file == NULL) { 26 int img_err = errno; 27 fprintf(stderr, "Could not open image file %s: %s\n", 28 file_path, strerror(img_err)); 29 return false; 30 } 31 32 read_count = fread(&file_header, sizeof(file_header), 1, image_file); 33 fclose(image_file); 34 35 if (read_count < 1) { 36 fprintf(stderr, "Error searching for JPEG header in %s\n", file_path); 37 return false; 38 } 39 40 return file_header == jpg_magick; 41 } 42 43 /* 44 * Reads a JPEG from a file into memory, in a format that Cairo can create a 45 * surface from. 46 */ 47 void* read_JPEG_file(char *file_path, JPEG_INFO *jpg_info) { 48 int img_err; 49 struct jpeg_decompress_struct cinfo; 50 struct jpeg_error_mgr jerr; 51 FILE *infile; /* source file */ 52 void *img; /* decompressed image data pointer */ 53 54 if ((infile = fopen(file_path, "rb")) == NULL) { 55 img_err = errno; 56 fprintf(stderr, "Could not open image file %s: %s\n", 57 file_path, strerror(img_err)); 58 return NULL; 59 } 60 61 cinfo.err = jpeg_std_error(&jerr); 62 jpeg_create_decompress(&cinfo); 63 64 jpeg_stdio_src(&cinfo, infile); 65 66 (void) jpeg_read_header(&cinfo, TRUE); 67 68 // BGRA + endianness change = RGBA? 69 // TODO: Test this code on non-x86_64 platforms 70 cinfo.out_color_space = JCS_EXT_BGRA; 71 72 (void) jpeg_start_decompress(&cinfo); 73 74 jpg_info->height = cinfo.output_height; 75 jpg_info->width = cinfo.output_width; 76 77 /* Get the *cairo* stride rather than the stride from the image. This is 78 * the space needed in memory for each row for optimized Cairo rendering. */ 79 int cairo_stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, 80 cinfo.output_width); 81 jpg_info->stride = cairo_stride; 82 if (cairo_stride < jpg_info->width) { 83 /* This should never happen, but if it does then the following code 84 * will potentially write into unallocated memory */ 85 fprintf( 86 stderr, 87 "WARNING: Cairo stride shorter than JPEG width. Aborting JPEG read." 88 ); 89 return NULL; 90 } 91 92 // Allocate storage for the final, decompressed image. 93 img = calloc(cairo_stride, cinfo.output_height); 94 if (img == NULL) { 95 fprintf(stderr, "Could not allocate memory for JPEG decode\n"); 96 97 (void) jpeg_finish_decompress(&cinfo); 98 jpeg_destroy_decompress(&cinfo); 99 fclose(infile); 100 101 return NULL; 102 } 103 104 while (cinfo.output_scanline < cinfo.output_height) { 105 /* Normally, you would allocate a buffer using libJPEG's memory 106 * management and write into it, but since we're reading one row at a 107 * time, we just write it directly into the image memory space */ 108 unsigned char* pos = img + (cairo_stride * (cinfo.output_scanline)); 109 (void) jpeg_read_scanlines(&cinfo, &pos, 1); 110 } 111 112 (void) jpeg_finish_decompress(&cinfo); 113 114 jpeg_destroy_decompress(&cinfo); 115 fclose(infile); 116 117 return img; 118 }
