Skip to content

Instantly share code, notes, and snippets.

@ntrrgc
Last active August 29, 2015 14:27
Show Gist options
  • Save ntrrgc/09ba29c0af27983c1d96 to your computer and use it in GitHub Desktop.
Save ntrrgc/09ba29c0af27983c1d96 to your computer and use it in GitHub Desktop.
Find images susceptible of being used as wallpaper. The hard way, in C.
#define _BSD_SOURCE
#define _POSIX_C_SOURCE 200809L
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <dirent.h>
#include <endian.h>
#include <stdint.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <fcntl.h>
#define GEOMETRY "1366x768"
#define MAX_ENTRIES 9999
#define MIN_RATIO 4.0/3.0
#define MAX_RATIO 20.0/9.0
#define MIN_HEIGHT 720
int read_size_jpg(int * dst_height, float *dst_ratio, int fd,
const char * file_name)
{
uint8_t buf[4];
// Find the SOFx (start of frame marker, FF C0)
// This function accepts SOF0 and SOF2 markers.
off_t current_marker = 2;
while (1) {
if (pread(fd, buf, 4, current_marker) != 4 || buf[0] != 0xFF) {
fprintf(stderr, "Corrupted file: %s\n", file_name);
return -1;
}
if (buf[1] == 0xC0 || buf[1] == 0xC2) {
// Found!
break;
} else {
int sectionLength = be16toh(*((uint16_t*) (buf+2)));
current_marker += 2 + sectionLength;
}
}
// Read width and height from SOFx
// Structure: FF Cx ll ll dd hh hh ww ww
// l = length of section
// d = depth (always 8 bit)
// w = width
// h = height
if (pread(fd, buf, 4, current_marker + 5) != 4) {
fprintf(stderr, "Corrupted file: %s\n", file_name);
return -1;
}
uint16_t width, height;
width = be16toh(*(((uint16_t*) buf) + 1));
height = be16toh(*(((uint16_t*) buf) + 0));
*dst_height = height;
*dst_ratio = (float)width / height;
return 0;
}
int read_size_png(int * dst_height, float *dst_ratio, int fd,
const char * file_name)
{
char buf[8];
if (pread(fd, buf, 8, 0x10) != 8) { // width
fprintf(stderr, "Corrupted file: %s\n", file_name);
return -1;
}
uint32_t width, height;
width = be32toh(*((uint32_t*) buf));
height = be32toh(*((uint32_t*) buf+1));
*dst_height = height;
*dst_ratio = (float)width / height;
return 0;
}
int read_size(int * dst_height, float *dst_ratio, const char * file_name) {
int fd = open(file_name, O_RDONLY);
if (!fd) {
perror(file_name);
return -1;
}
const char * extension = strrchr(file_name, '.');
if (!extension) {
goto skip;
}
int ret;
if (!strcmp(extension, ".png")) {
ret = read_size_png(dst_height, dst_ratio, fd, file_name);
} else if (!strcmp(extension, ".jpg") || !strcmp(extension, ".jpeg")) {
ret = read_size_jpg(dst_height, dst_ratio, fd, file_name);
} else {
skip:
fprintf(stderr, "Skiping %s\n", file_name);
ret = -1;
}
close(fd);
return ret;
}
int image_qualifies(int height, float ratio) {
return ratio >= MIN_RATIO && ratio <= MAX_RATIO && height >= MIN_HEIGHT;
}
int main(int argc, char** argv) {
DIR *directory = opendir(".");
if (!directory) {
perror("opendir");
exit(1);
}
char found_entries[MAX_ENTRIES][255];
int found_entries_count = 0;
struct dirent * dir_entry;
while ((dir_entry = readdir(directory)) != NULL) {
int height;
float ratio;
if (read_size(&height, &ratio, dir_entry->d_name) != -1
&& image_qualifies(height, ratio)) {
printf("%s\n", dir_entry->d_name);
if (found_entries_count > MAX_ENTRIES) {
printf("Too many entries.\n");
break;
}
strcpy(found_entries[found_entries_count++], dir_entry->d_name);
}
}
closedir(directory);
// Open image viewer
int pid = fork();
if (pid == 0) {
char * args[MAX_ENTRIES+6] = {
"feh", "--geometry", GEOMETRY, "--image-bg", "black"
};
int i_arg, i_entry;
for (i_arg = 5, i_entry = 0;
i_entry < found_entries_count;
i_entry++, i_arg++)
{
args[i_arg] = found_entries[i_entry];
}
args[i_arg] = NULL;
if (execvp("feh", args) == -1) {
perror("feh");
exit(1);
}
} else if (pid > 0) {
while (wait(NULL) != pid)
;
} else {
perror("fork");
exit(1);
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment