i3lock-color

The world's most popular non-default computer lockscreen.
Index Commits Files Refs README LICENSE
jpg.c (3553B)
   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 }