Last active
August 29, 2015 14:27
-
-
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #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