add support for JPEG images
This commit is contained in:
parent
4318dbe051
commit
8678e0ad67
10
Makefile.am
10
Makefile.am
|
@ -22,7 +22,8 @@ i3lock_CFLAGS = \
|
|||
$(XKBCOMMON_CFLAGS) \
|
||||
$(CAIRO_CFLAGS) \
|
||||
$(CODE_COVERAGE_CFLAGS) \
|
||||
$(X11_CFLAGS)
|
||||
$(X11_CFLAGS) \
|
||||
$(JPEG_CFLAGS)
|
||||
|
||||
i3lock_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
|
@ -35,7 +36,8 @@ i3lock_LDADD = \
|
|||
$(XKBCOMMON_LIBS) \
|
||||
$(CAIRO_LIBS) \
|
||||
$(CODE_COVERAGE_LDFLAGS) \
|
||||
$(X11_LIBS)
|
||||
$(X11_LIBS) \
|
||||
$(JPEG_LIBS)
|
||||
|
||||
i3lock_SOURCES = \
|
||||
cursors.h \
|
||||
|
@ -51,7 +53,9 @@ i3lock_SOURCES = \
|
|||
tinyexpr.h \
|
||||
blur_simd.c \
|
||||
blur.c \
|
||||
blur.h
|
||||
blur.h \
|
||||
jpg.c \
|
||||
jpg.h
|
||||
|
||||
|
||||
EXTRA_DIST = \
|
||||
|
|
|
@ -90,6 +90,7 @@ i3lock now uses GNU autotools for building; you'll need to do something like `au
|
|||
- libx11-xcb-dev
|
||||
- libxkbcommon >= 0.5.0
|
||||
- libxkbcommon-x11 >= 0.5.0
|
||||
- libjpeg-turbo >= 1.4.90
|
||||
|
||||
(On centos/RHEL/etc, the packages tend to look like `cairo-devel` instead of `libcairo-dev`. Use `yum provides \*/<header.h>` to figure out what packages you need.)
|
||||
|
||||
|
@ -97,6 +98,8 @@ i3lock now uses GNU autotools for building; you'll need to do something like `au
|
|||
|
||||
sudo apt-get install pkg-config libxcb1 libpam-dev libcairo-dev libxcb-composite0 libxcb-composite0-dev libxcb-xinerama0-dev libev-dev libx11-dev libx11-xcb-dev libxkbcommon0 libxkbcommon-x11-0 libxcb-dpms0-dev libxcb-image0-dev libxcb-util0-dev libxcb-xkb-dev libxkbcommon-x11-dev libxkbcommon-dev
|
||||
|
||||
For JPEG lock image support, you'll also need `libjpeg-turbo8` version 1.4.90 or newer (Ubuntu 17.04 or later)
|
||||
|
||||
##### Aur Package
|
||||
[Stable](https://aur.archlinux.org/packages/i3lock-color/)
|
||||
|
||||
|
|
|
@ -88,6 +88,7 @@ PKG_CHECK_MODULES([XCB_UTIL], [xcb-event xcb-util xcb-atom])
|
|||
PKG_CHECK_MODULES([XKBCOMMON], [xkbcommon xkbcommon-x11])
|
||||
PKG_CHECK_MODULES([CAIRO], [cairo])
|
||||
PKG_CHECK_MODULES([X11], [x11])
|
||||
PKG_CHECK_MODULES([JPEG], [libjpeg])
|
||||
|
||||
|
||||
# Checks for programs.
|
||||
|
|
18
i3lock.c
18
i3lock.c
|
@ -20,6 +20,7 @@
|
|||
#include <xcb/xcb.h>
|
||||
#include <xcb/xkb.h>
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#ifdef __OpenBSD__
|
||||
#include <bsd_auth.h>
|
||||
|
@ -50,6 +51,7 @@
|
|||
#include "unlock_indicator.h"
|
||||
#include "randr.h"
|
||||
#include "blur.h"
|
||||
#include "jpg.h"
|
||||
|
||||
#define TSTAMP_N_SECS(n) (n * 1.0)
|
||||
#define TSTAMP_N_MINS(n) (60 * TSTAMP_N_SECS(n))
|
||||
|
@ -988,6 +990,7 @@ int main(int argc, char *argv[]) {
|
|||
struct passwd *pw;
|
||||
char *username;
|
||||
char *image_path = NULL;
|
||||
JPEG_INFO jpg_info;
|
||||
#ifndef __OpenBSD__
|
||||
int ret;
|
||||
struct pam_conv conv = {conv_callback, NULL};
|
||||
|
@ -1604,7 +1607,20 @@ int main(int argc, char *argv[]) {
|
|||
|
||||
if (image_path) {
|
||||
/* Create a pixmap to render on, fill it with the background color */
|
||||
img = cairo_image_surface_create_from_png(image_path);
|
||||
if (file_is_jpg(image_path)) {
|
||||
if (debug_mode) {
|
||||
fprintf(stderr, "Image looks like a jpeg, decoding\n");
|
||||
}
|
||||
|
||||
unsigned char* jpg_data = read_JPEG_file(image_path, &jpg_info);
|
||||
if (jpg_data != NULL) {
|
||||
img = cairo_image_surface_create_for_data(jpg_data,
|
||||
CAIRO_FORMAT_ARGB32, jpg_info.width, jpg_info.height,
|
||||
jpg_info.stride);
|
||||
}
|
||||
} else {
|
||||
img = cairo_image_surface_create_from_png(image_path);
|
||||
}
|
||||
/* In case loading failed, we just pretend no -i was specified. */
|
||||
if (cairo_surface_status(img) != CAIRO_STATUS_SUCCESS) {
|
||||
fprintf(stderr, "Could not load image \"%s\": %s\n",
|
||||
|
|
|
@ -0,0 +1,117 @@
|
|||
#include <stdlib.h>
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <cairo.h>
|
||||
#include <jpeglib.h>
|
||||
|
||||
#include "jpg.h"
|
||||
|
||||
/*
|
||||
* Checks if the file is a JPEG by looking for a valid JPEG header.
|
||||
*/
|
||||
bool file_is_jpg(char* file_path) {
|
||||
FILE* image_file;
|
||||
uint16_t file_header;
|
||||
size_t read_count;
|
||||
// TODO: Consider endianess on non-x86 platforms
|
||||
uint16_t jpg_magick = 0xd8ff;
|
||||
|
||||
image_file = fopen(file_path, "rb");
|
||||
if (image_file == NULL) {
|
||||
int img_err = errno;
|
||||
fprintf(stderr, "Could not open image file %s: %s\n",
|
||||
file_path, strerror(img_err));
|
||||
return false;
|
||||
}
|
||||
|
||||
read_count = fread(&file_header, sizeof(file_header), 1, image_file);
|
||||
fclose(image_file);
|
||||
|
||||
if (read_count < 1) {
|
||||
fprintf(stderr, "Error searching for JPEG header in %s\n", file_path);
|
||||
return false;
|
||||
}
|
||||
|
||||
return file_header == jpg_magick;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reads a JPEG from a file into memory, in a format that Cairo can create a
|
||||
* surface from.
|
||||
*/
|
||||
void* read_JPEG_file(char *file_path, JPEG_INFO *jpg_info) {
|
||||
int img_err;
|
||||
struct jpeg_decompress_struct cinfo;
|
||||
struct jpeg_error_mgr jerr;
|
||||
FILE *infile; /* source file */
|
||||
void *img; /* decompressed image data pointer */
|
||||
|
||||
if ((infile = fopen(file_path, "rb")) == NULL) {
|
||||
img_err = errno;
|
||||
fprintf(stderr, "Could not open image file %s: %s\n",
|
||||
file_path, strerror(img_err));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cinfo.err = jpeg_std_error(&jerr);
|
||||
jpeg_create_decompress(&cinfo);
|
||||
|
||||
jpeg_stdio_src(&cinfo, infile);
|
||||
|
||||
(void) jpeg_read_header(&cinfo, TRUE);
|
||||
|
||||
// BGRA + endianness change = RGBA?
|
||||
// TODO: Test this code on non-x86_64 platforms
|
||||
cinfo.out_color_space = JCS_EXT_BGRA;
|
||||
|
||||
(void) jpeg_start_decompress(&cinfo);
|
||||
|
||||
jpg_info->height = cinfo.output_height;
|
||||
jpg_info->width = cinfo.output_width;
|
||||
|
||||
/* Get the *cairo* stride rather than the stride from the image. This is
|
||||
* the space needed in memory for each row for optimized Cairo rendering. */
|
||||
int cairo_stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32,
|
||||
cinfo.output_width);
|
||||
jpg_info->stride = cairo_stride;
|
||||
if (cairo_stride < jpg_info->width) {
|
||||
/* This should never happen, but if it does then the following code
|
||||
* will potentially write into unallocated memory */
|
||||
fprintf(
|
||||
stderr,
|
||||
"WARNING: Cairo stride shorter than JPEG width. Aborting JPEG read."
|
||||
);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Allocate storage for the final, decompressed image.
|
||||
img = calloc(cairo_stride, cinfo.output_height);
|
||||
if (img == NULL) {
|
||||
fprintf(stderr, "Could not allocate memory for JPEG decode\n");
|
||||
|
||||
(void) jpeg_finish_decompress(&cinfo);
|
||||
jpeg_destroy_decompress(&cinfo);
|
||||
fclose(infile);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
while (cinfo.output_scanline < cinfo.output_height) {
|
||||
/* Normally, you would allocate a buffer using libJPEG's memory
|
||||
* management and write into it, but since we're reading one row at a
|
||||
* time, we just write it directly into the image memory space */
|
||||
unsigned char* pos = img + (cairo_stride * (cinfo.output_scanline));
|
||||
(void) jpeg_read_scanlines(&cinfo, &pos, 1);
|
||||
}
|
||||
|
||||
(void) jpeg_finish_decompress(&cinfo);
|
||||
|
||||
jpeg_destroy_decompress(&cinfo);
|
||||
fclose(infile);
|
||||
|
||||
return img;
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
#ifndef _JPG_H
|
||||
#define _JPG_H
|
||||
|
||||
typedef struct {
|
||||
uint height;
|
||||
uint width;
|
||||
uint stride; // The width of each row in memory, in bytes
|
||||
} JPEG_INFO;
|
||||
|
||||
/*
|
||||
* Checks if the file is a JPEG by looking for a valid JPEG header.
|
||||
*/
|
||||
bool file_is_jpg(char* file_path);
|
||||
|
||||
/*
|
||||
* Reads a JPEG from a file into memory, in a format that Cairo can create a
|
||||
* surface from.
|
||||
*/
|
||||
void* read_JPEG_file(char *filename, JPEG_INFO *jpg_info);
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue