├── resize.h ├── rotate.h ├── fourier_filter.h ├── edge_detection.h ├── histogram_equalization.h ├── contrast_enhancement.h ├── bilinear_interpolation.h ├── histograms.h ├── manipulate_hsi.h ├── median_filter.h ├── kernel_filter.h ├── gradient_filter.h ├── README.md ├── bilinear_interpolation.c ├── array_utility.h ├── Makefile ├── rotate.c ├── resize.c ├── histograms.c ├── edge_detection.c ├── contrast_enhancement.c ├── kernel_filter.c ├── histogram_equalization.c ├── median_filter.c ├── manipulate_hsi.c ├── fourier_filter.c ├── array_utility.c ├── process.c ├── gradient_filter.c └── lodepng.h /resize.h: -------------------------------------------------------------------------------- 1 | #ifndef RESIZE_H 2 | #define RESIZE_H 3 | 4 | float*** resize (float*** input, int M_in, int N_in, int* output_height, 5 | int* output_width); 6 | 7 | #endif 8 | -------------------------------------------------------------------------------- /rotate.h: -------------------------------------------------------------------------------- 1 | #ifndef ROTATE_H 2 | #define ROTATE_H 3 | 4 | #define Pi 3.141592653589 5 | 6 | #include "bilinear_interpolation.h" 7 | 8 | float*** rotate (float*** input, int M_in, int N_in); 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /fourier_filter.h: -------------------------------------------------------------------------------- 1 | #ifndef FOURIER_FILTER_H 2 | #define FOURIER_FILTER_H 3 | 4 | void discrete_fourier_transform(float xr[], float xi[], int N, int inverse); 5 | float*** fourier_filter(float*** input, int M_in, int N_in); 6 | 7 | #endif -------------------------------------------------------------------------------- /edge_detection.h: -------------------------------------------------------------------------------- 1 | #ifndef EDGE_DETECTION_H 2 | #define EDGE_DETECTION_H 3 | 4 | float*** apply_Laplacian_of_Gaussian(float*** input, int M_in, int N_in, 5 | float threshold, int square_size); 6 | float*** detect_edges(float*** input, int M_in, int N_in); 7 | 8 | #endif -------------------------------------------------------------------------------- /histogram_equalization.h: -------------------------------------------------------------------------------- 1 | #ifndef HISTOGRAM_EQUALIZATION_H 2 | #define HISTOGRAM_EQUALIZATION_H 3 | 4 | float*** equalize (float*** input, int M_in, int N_in); 5 | float*** apply_concave_equalization (float*** input, int M_in, int N_in); 6 | float*** apply_convex_equalization (float*** input, int M_in, int N_in); 7 | 8 | #endif -------------------------------------------------------------------------------- /contrast_enhancement.h: -------------------------------------------------------------------------------- 1 | #ifndef CONTRAST_ENHANCEMENT_H 2 | #define CONTRAST_ENHANCEMENT_H 3 | 4 | float*** enhance_contrast (float*** input, int M_in, int N_in); 5 | 6 | float*** linear_stretch (float*** input, int M_in, int N_in); 7 | 8 | float*** min_max_stretch (float*** input, int M_in, int N_in, double cutoff); 9 | 10 | #endif -------------------------------------------------------------------------------- /bilinear_interpolation.h: -------------------------------------------------------------------------------- 1 | #ifndef BILINEAR_INTERPOLATION_H 2 | #define BILINEAR_INTERPOLATION_H 3 | 4 | // Function that performs bilinear interpolation to determine the pixel 5 | // value of a new pixel. 6 | float bilinearly_interpolate (int top, int bottom, int left, int right, 7 | float horizontal_position, float vertical_position, float** input); 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /histograms.h: -------------------------------------------------------------------------------- 1 | #ifndef HISTOGRAMS_H 2 | #define HISTOGRAMS_H 3 | 4 | // Helper function that returns the maximum value in an array of integers. 5 | int max_value (int* array, int num_elements); 6 | 7 | float** generate_density_histogram (float** input, int size, int M_in, 8 | int N_in); 9 | 10 | float** generate_cumulative_histogram (float** img, int size, int M_in, 11 | int N_in); 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /manipulate_hsi.h: -------------------------------------------------------------------------------- 1 | #ifndef MANIPULATE_HSI_H 2 | #define MANIPULATE_HSI_H 3 | 4 | void rgb_to_hsi (float R, float G, float B, float* H, float* S, float* I); 5 | void hsi_to_rgb (float H, float S, float I, float* R, float* G, float* B); 6 | 7 | float*** rotate_hue (float*** input, int M_in, int N_in); 8 | float*** increase_saturation (float*** input, int M_in, int N_in); 9 | float*** increase_intensity (float*** input, int M_in, int N_in); 10 | 11 | #endif -------------------------------------------------------------------------------- /median_filter.h: -------------------------------------------------------------------------------- 1 | #ifndef MEDIAN_FILTER_H 2 | #define MEDIAN_FILTER_H 3 | 4 | float* find_cross_array (float** input, int M_in, int N_in, int row, int col, 5 | int width, int height, int* array_size); 6 | float* find_pixel_array (float** input, int M_in, int N_in, 7 | int row, int col, int size, int* array_size); 8 | float*** median_filter (float*** input, int M_in, int N_in); 9 | float*** square_median_filter (float*** input, int M_in, int N_in); 10 | float*** cross_median_filter (float*** input, int M_in, int N_in); 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /kernel_filter.h: -------------------------------------------------------------------------------- 1 | #ifndef KERNEL_FILTER_H 2 | #define KERNEL_FILTER_H 3 | 4 | float** add (float** arrayOne, float** arrayTwo, int row, int col); 5 | float** subtract (float** arrayOne, float** arrayTwo, int row, int col); 6 | float** find_pixel_matrix (float** input, int M_in, int N_in, 7 | int row, int col, int size); 8 | float convolve_matrices (float** array_one, float** array_two, int size); 9 | float*** convolve (float*** input, int M_in, int N_in, float** kernel, int dim); 10 | 11 | float*** lowpass_filter(float*** input, int M_in, int N_in); 12 | float*** highpass_filter(float*** input, int M_in, int N_in); 13 | float** lowpass_filter_3by3kernel(); 14 | float** highpass_filter_3by3kernel(); 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /gradient_filter.h: -------------------------------------------------------------------------------- 1 | #ifndef GRADIENT_FILTER_H 2 | #define GRADIENT_FILTER_H 3 | 4 | float*** gradient_filter(float*** input, int M_in, int N_in); 5 | float*** roberts_operator(float*** input, int M_in, int N_in); 6 | float*** sobel_operator(float*** input, int M_in, int N_in); 7 | float*** prewitt_operator_3by3kernel(float*** input, int M_in, int N_in); 8 | float*** prewitt_operator_5by5kernel(float*** input, int M_in, int N_in); 9 | float*** vertical_operator(float*** input, int M_in, int N_in); 10 | float*** horizontal_operator(float*** input, int M_in, int N_in); 11 | float*** diagonal_compass_nw_operator(float*** input, int M_in, int N_in); 12 | float*** diagonal_compass_ne_operator(float*** input, int M_in, int N_in); 13 | 14 | #endif -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | image-manipulation-in-c 2 | ======================= 3 | 4 | A C program that allows the user to input a PNG image through command line and select how they want to manipulate that image. 5 | 6 | Using the provided Makefile, the user can compile using gcc/ clang and run the resulting "process" executable. 7 | Running "./process" on the command line will allow the user to: 8 | - Generate a density histogram for the image. 9 | - Generate a cumulative histogram for the image. 10 | - Improve the image's contrast. 11 | - Resize an image's width and height by certain factors. 12 | - Rotate an image by some angle (in degrees). 13 | - Perform histogram equalization on the image. 14 | - Rotate the image's hue. 15 | - Increase the image's color saturation. 16 | - Increase the image's intensity. 17 | - Perform low-pass filtering on an image using a kernel. 18 | - Perform high-pass filtering on an image using a kernel. 19 | - Perform low-pass or high-pass filtering using a Fourier transform. 20 | - Create a gradient image that accentuates changes in color based on the given image. 21 | - Clean up an image using a median filter. 22 | - Detect edges in an image. 23 | -------------------------------------------------------------------------------- /bilinear_interpolation.c: -------------------------------------------------------------------------------- 1 | #include "bilinear_interpolation.h" 2 | 3 | // Function that performs bilinear interpolation to determine the pixel 4 | // value of a new pixel. 5 | float bilinearly_interpolate (int top, int bottom, int left, int right, 6 | float horizontal_position, float vertical_position, float** input) 7 | { 8 | // Determine the values of the corners. 9 | float top_left = input[top][left]; 10 | float top_right = input[top][right]; 11 | float bottom_left = input[bottom][left]; 12 | float bottom_right = input[bottom][right]; 13 | 14 | // Figure out "how far" the output pixel being considered is 15 | // between *_left and *_right. 16 | float horizontal_progress = horizontal_position - 17 | (float) left; 18 | float vertical_progress = vertical_position - 19 | (float) top; 20 | 21 | // Combine top_left and top_right into one large, horizontal 22 | // block. 23 | float top_block = top_left + horizontal_progress 24 | * (top_right - top_left); 25 | 26 | // Combine bottom_left and bottom_right into one large, horizontal 27 | // block. 28 | float bottom_block = bottom_left + 29 | horizontal_progress 30 | * (bottom_right - bottom_left); 31 | 32 | // Combine the top_block and bottom_block using vertical 33 | // interpolation and return as the resulting pixel. 34 | return top_block + vertical_progress * (bottom_block - top_block); 35 | } -------------------------------------------------------------------------------- /array_utility.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | This header file provides utility operations that allow for easy manipulation 4 | of image arrays. 5 | 6 | This header file is a rewritten file based off of a version given by Prof. Ruye 7 | Wang of Harvey Mudd's Department of Engineering (2013). 8 | 9 | */ 10 | 11 | #ifndef ARRAY_UTILITY_H 12 | #define ARRAY_UTILITY_H 13 | 14 | #include 15 | 16 | char fname[50]; 17 | FILE* fp; 18 | 19 | double* alloc1dd (int n); 20 | double** alloc2dd (int m, int n); 21 | 22 | float* alloc1df (int n); 23 | float** alloc2df (int m, int n); 24 | float*** alloc3df (int l, int m, int n); 25 | float**** alloc4df (int k, int l, int m, int n); 26 | 27 | void dealloc2df (float** array, int m, int n); 28 | void dealloc3df (float*** array, int l, int m, int n); 29 | void dealloc4df (float**** array, int k, int l, int m, int n); 30 | 31 | int* alloc1di (int n); 32 | int** alloc2di (int m, int n); 33 | int*** alloc3di (int l, int m, int n); 34 | 35 | void dealloc2di (int** array, int m, int n); 36 | void dealloc3di (int*** array, int l, int m, int n); 37 | 38 | // This function prints an end of file error message and exits. 39 | void eof_err (); 40 | 41 | int getword (FILE* fp, char *word); 42 | 43 | float*** read_color_image (char *fname, int *m, int *n); 44 | float** read_bw_image (char *fname, int *m, int *n); 45 | 46 | void write_color_image (char filename[], float*** image, int m, int n, int s); 47 | void write_bw_image (char* filename, float** image, int m, int n, int s); 48 | 49 | #endif 50 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Constants 2 | OBJECTS = array_utility.o bilinear_interpolation.o contrast_enhancement.o \ 3 | edge_detection.o fourier_filter.o gradient_filter.o \ 4 | histogram_equalization.o histograms.o kernel_filter.o \ 5 | manipulate_hsi.o median_filter.o process.o resize.o rotate.o lodepng.o 6 | 7 | all: process 8 | 9 | clean: 10 | rm -rf *.0 *.dSYM process 11 | 12 | process: $(OBJECTS) 13 | gcc -lm -g -o process $(OBJECTS) 14 | 15 | 16 | array_utility.o: array_utility.c array_utility.h 17 | bilinear_interpolation.o: bilinear_interpolation.c \ 18 | bilinear_interpolation.h 19 | contrast_enhancement.o: contrast_enhancement.c contrast_enhancement.h \ 20 | histograms.h array_utility.h 21 | edge_detection.o: edge_detection.c edge_detection.h array_utility.h \ 22 | kernel_filter.h contrast_enhancement.h median_filter.h 23 | fourier_filter.o: fourier_filter.c fourier_filter.h array_utility.h 24 | gradient_filter.o: gradient_filter.c gradient_filter.h array_utility.h \ 25 | kernel_filter.h 26 | histogram_equalization.o: histogram_equalization.c \ 27 | histogram_equalization.h array_utility.h 28 | histograms.o: histograms.c histograms.h array_utility.h 29 | kernel_filter.o: kernel_filter.c kernel_filter.h array_utility.h 30 | lodepng.o: lodepng.c lodepng.h 31 | manipulate_hsi.o: manipulate_hsi.c manipulate_hsi.h array_utility.h 32 | median_filter.o: median_filter.c median_filter.h array_utility.h \ 33 | kernel_filter.h 34 | process.o: process.c array_utility.h rotate.h bilinear_interpolation.h \ 35 | resize.h histograms.h contrast_enhancement.h manipulate_hsi.h \ 36 | histogram_equalization.h kernel_filter.h median_filter.h \ 37 | gradient_filter.h fourier_filter.h edge_detection.h lodepng.h 38 | resize.o: resize.c resize.h bilinear_interpolation.h array_utility.h 39 | rotate.o: rotate.c rotate.h bilinear_interpolation.h array_utility.h 40 | 41 | -------------------------------------------------------------------------------- /rotate.c: -------------------------------------------------------------------------------- 1 | #include "rotate.h" 2 | #include "array_utility.h" 3 | #include "bilinear_interpolation.h" 4 | 5 | #include 6 | #include 7 | 8 | float*** rotate (float*** input, int M_in, int N_in) 9 | { 10 | // Prompt the user. 11 | float rotation_factor; 12 | printf("By how many degrees CCW do you want to rotate your image?\n"); 13 | scanf("%f", &rotation_factor); 14 | printf("Rotating the input file...\n"); 15 | 16 | // Prepare the output files. 17 | float*** output = alloc3df(3, M_in, N_in); 18 | 19 | // Define the center of the image. 20 | int vertical_center = floor(M_in / 2); 21 | int horizontal_center = floor(N_in / 2); 22 | 23 | // Loop through each pixel of the new image, select the new vertical 24 | // and horizontal positions, and interpolate the image to make the change. 25 | int i, j, k; 26 | for (i = 0; i < M_in; ++i) { 27 | for (j = 0; j < N_in; ++j) { 28 | // // Figure out how rotated we want the image. 29 | double angle = rotation_factor * (double) Pi / 180; 30 | float vertical_position = (float) cos(angle) * 31 | (i - vertical_center) + sin(angle) * (j - horizontal_center) 32 | + vertical_center; 33 | float horizontal_position = (float) -sin(angle) * 34 | (i - vertical_center) + cos(angle) * (j - horizontal_center) 35 | + horizontal_center; 36 | 37 | // Figure out the four locations (and then, four pixels) 38 | // that we must interpolate from the original image. 39 | int top = floor(vertical_position); 40 | int bottom = top + 1; 41 | int left = floor(horizontal_position); 42 | int right = left + 1; 43 | 44 | // Check if any of the four locations are invalid. If they are, 45 | // skip interpolating this pixel. Otherwise, interpolate the 46 | // pixel according to the dimensions set above and set the 47 | // resulting pixel. 48 | if (top >= 0 && bottom < M_in && left >= 0 && right < N_in ) { 49 | for (k = 0; k < 3; k++) { 50 | float interpolated = bilinearly_interpolate(top, bottom, 51 | left, right, horizontal_position, vertical_position, 52 | input[k]); 53 | output[k][i][j] = interpolated; 54 | } 55 | } 56 | } 57 | } 58 | 59 | return output; 60 | } -------------------------------------------------------------------------------- /resize.c: -------------------------------------------------------------------------------- 1 | #include "resize.h" 2 | #include "bilinear_interpolation.h" 3 | #include "array_utility.h" 4 | 5 | #include 6 | 7 | float*** resize (float*** input, int M_in, int N_in, int* output_height, 8 | int* output_width) 9 | { 10 | // Prompt the user. 11 | float verti_resize_factor, horiz_resize_factor; 12 | printf("By what factor do you want to scale your image horizontally?\n"); 13 | scanf("%f", &horiz_resize_factor); 14 | printf("By what factor do you want to scale your image vertically?\n"); 15 | scanf("%f", &verti_resize_factor); 16 | 17 | printf("Resizing...\n"); 18 | 19 | // Figure out the dimensions of the new, resized image and define the 20 | // new array. 21 | int M_out_resized = *output_height = M_in * verti_resize_factor; 22 | int N_out_resized = *output_width = N_in * horiz_resize_factor; 23 | float*** output = alloc3df(3, M_out_resized, N_out_resized); 24 | 25 | // Loop through each pixel of the new image and interpolate the pixels 26 | // based on what's in the input image. 27 | int i, j, k; 28 | for (i = 0; i < M_out_resized; ++i) { 29 | for (j = 0; j < N_out_resized; ++j) { 30 | // Figure out how far down or across (in percentage) we are with 31 | // respect to the original image. 32 | float vertical_position = i * ( (float) M_in / M_out_resized); 33 | float horizontal_position = j * ( (float) N_in / N_out_resized); 34 | 35 | // Figure out the four locations (and then, four pixels) 36 | // that we must interpolate from the original image. 37 | int top = floor(vertical_position); 38 | int bottom = top + 1; 39 | int left = floor(horizontal_position); 40 | int right = left + 1; 41 | 42 | // Check if any of the four locations are invalid. If they are, 43 | // simply access the valid adjacent pixel. 44 | if (bottom >= M_in) { 45 | bottom = top; 46 | } 47 | if (right >= N_in) { 48 | right = left; 49 | } 50 | 51 | // Interpolate the pixel according to the dimensions 52 | // set above and set the resulting pixel. Do so for each color. 53 | for (k = 0; k < 3; k++) { 54 | float interpolated = bilinearly_interpolate(top, bottom, left, 55 | right, horizontal_position, vertical_position, input[k]); 56 | output[k][i][j] = interpolated; 57 | } 58 | 59 | } 60 | } 61 | 62 | return output; 63 | } -------------------------------------------------------------------------------- /histograms.c: -------------------------------------------------------------------------------- 1 | #include "histograms.h" 2 | #include "array_utility.h" 3 | 4 | #include 5 | #include 6 | 7 | // Helper function that returns the maximum value in an array of integers. 8 | int max_value (int* array, int num_elements) 9 | { 10 | int i, max = -32000; 11 | for (i = 0; i < num_elements; i++) { 12 | if (array[i] > max) { 13 | max = array[i]; 14 | } 15 | } 16 | 17 | return max; 18 | } 19 | 20 | float** generate_density_histogram (float** input, int size, int M_in, 21 | int N_in) 22 | { 23 | // Instantiate counting variables used in for loops and the return 24 | // variable. 25 | int i, j; 26 | float** output = alloc2df(size, size); 27 | 28 | // Count the grayscale color present in each pixel. 29 | int* count = alloc1di(size); 30 | 31 | for (i = 0; i < M_in; i++) { 32 | for (j = 0; j < N_in; j++) { 33 | count[(int) input[i][j]]++; 34 | } 35 | } 36 | 37 | // Scale the images by making a ratio of (the count / the largest 38 | // count) and multiply by the total size of our histogram. 39 | double max = (double) max_value(count, size); 40 | 41 | for (i = 0; i < size; i++) { 42 | count[i] = (count[i] / max) * size; 43 | } 44 | 45 | // Create the density histogram. 46 | for (i = 0; i < size; i++) { 47 | for (j = 0; j < size; j++) { 48 | float value; 49 | 50 | if (255 - i < count[j]) { 51 | value = 255.0; 52 | } else { 53 | value = 0.0; 54 | } 55 | output[i][j] = value; 56 | } 57 | } 58 | 59 | // Deallocate memory. 60 | free(count); 61 | 62 | return output; 63 | } 64 | 65 | float** generate_cumulative_histogram (float** img, int size, int M_in, 66 | int N_in) 67 | { 68 | // Instantiate counting variables used in for loops and the return 69 | // variable. 70 | int i, j; 71 | float** output = alloc2df(size, size); 72 | 73 | // Create the cumulative histogram count. 74 | double* count = alloc1dd(size); 75 | float density = 1 / (float) (M_in * N_in); 76 | 77 | for (i = 0; i < M_in; i++) { 78 | for (j = 0; j < N_in; j++) { 79 | count[(int) img[i][j]] += density; 80 | } 81 | } 82 | 83 | // Enable cumulation. 84 | double total = 0.0; 85 | for (i = 0; i < size; i++) { 86 | total += count[i]; 87 | count[i] = total * size; 88 | } 89 | 90 | // Create the cumulative histogram. 91 | for (i = 0; i < size; i++) { 92 | for (j = 0; j < size; j++) { 93 | float value; 94 | 95 | if (255 - i < count[j]) { 96 | 97 | value = 255.0; 98 | } else { 99 | value = 0.0; 100 | } 101 | output[i][j] = value; 102 | } 103 | } 104 | 105 | // Deallocate memory. 106 | free(count); 107 | 108 | return output; 109 | } 110 | 111 | -------------------------------------------------------------------------------- /edge_detection.c: -------------------------------------------------------------------------------- 1 | #include "edge_detection.h" 2 | #include "array_utility.h" 3 | #include "kernel_filter.h" 4 | #include "contrast_enhancement.h" 5 | #include "median_filter.h" 6 | 7 | float*** apply_Laplacian_of_Gaussian (float*** input, int M_in, int N_in, 8 | float threshold, int square_size) 9 | { 10 | // Declare output. 11 | float** intermediate = alloc2df(M_in, N_in); 12 | float*** output = alloc3df(3, M_in, N_in); 13 | 14 | // Define the Laplacian of Gaussian kernel. 15 | float** kernel = alloc2df(5, 5); 16 | kernel[0][0] = 0; kernel[0][1] = 0; kernel[0][2] = 1; kernel[0][3] = 0; 17 | kernel[0][4] = 0; 18 | kernel[1][0] = 0; kernel[1][1] = 1; kernel[1][2] = 2; kernel[1][3] = 1; 19 | kernel[1][4] = 0; 20 | kernel[2][0] = 1; kernel[2][1] = 2; kernel[2][2] = -16; kernel[2][3] = 2; 21 | kernel[2][4] = 1; 22 | kernel[3][0] = 0; kernel[3][1] = 1; kernel[3][2] = 2; kernel[3][3] = 1; 23 | kernel[3][4] = 0; 24 | kernel[4][0] = 0; kernel[4][1] = 0; kernel[4][2] = 1; kernel[4][3] = 0; 25 | kernel[4][4] = 0; 26 | 27 | int i, j, k, l, m; 28 | for (k = 0; k < 3; k++) { 29 | // Find the pixel matrix for each pixel, multiply that matrix with the one 30 | // above, and set the array combination of the two equal to the currently 31 | // processed pixel. 32 | for (i = 0; i < M_in; i++) { 33 | for (j = 0; j < N_in; j++) { 34 | float** pixelMatrix = find_pixel_matrix(input[k], M_in, N_in, 35 | i, j, 5); 36 | float newValue = convolve_matrices(pixelMatrix, kernel, 5); 37 | intermediate[i][j] = newValue; 38 | } 39 | } 40 | 41 | // Find zerocrossings and eliminate noise (given pseudocode). 42 | for (i = 0; i < M_in - square_size; i++) { 43 | for (j = 0; j < N_in - square_size; j++) { 44 | float min = 9e9; 45 | float max = -min; 46 | 47 | for (m = 0; m < square_size; m++) { 48 | for (l = 0; l < square_size; l++) { 49 | float w = intermediate[i+m][j+l]; 50 | if (w < min) { 51 | min = w; 52 | } 53 | 54 | if (w > max) { 55 | max = w; 56 | } 57 | } 58 | } 59 | 60 | if (min < -threshold && max > threshold) { 61 | output[k][i][j] = 254; 62 | } else { 63 | output[k][i][j] = 0; 64 | } 65 | } 66 | } 67 | } 68 | 69 | return output; 70 | } 71 | 72 | float*** detect_edges (float*** input, int M_in, int N_in) 73 | { 74 | printf("Applying a series of steps to detect edges in this image...\n"); 75 | float*** lowpass_filtered = lowpass_filter(input, M_in, N_in); 76 | float*** linearly_stretched = min_max_stretch(lowpass_filtered, M_in, N_in, 0.50); 77 | float*** square_median_filtered = square_median_filter(linearly_stretched, M_in, N_in); 78 | float*** laplacian_of_gaussian = 79 | apply_Laplacian_of_Gaussian(square_median_filtered, M_in, N_in, 1, 3); 80 | 81 | dealloc3df(lowpass_filtered, 3, M_in, N_in); 82 | dealloc3df(linearly_stretched, 3, M_in, N_in); 83 | dealloc3df(square_median_filtered, 3, M_in, N_in); 84 | 85 | return laplacian_of_gaussian; 86 | } 87 | -------------------------------------------------------------------------------- /contrast_enhancement.c: -------------------------------------------------------------------------------- 1 | #include "contrast_enhancement.h" 2 | #include "histograms.h" 3 | #include "array_utility.h" 4 | 5 | #include 6 | 7 | float*** enhance_contrast (float*** input, int M_in, int N_in) 8 | { 9 | int option; 10 | 11 | // Prompt the user. 12 | printf("Which histogram stretch would you like to perform? (1) for"); 13 | printf(" a linear stretch, (2) for a 3%% min-max linear stretch.\n"); 14 | scanf("%d", &option); 15 | 16 | switch (option) { 17 | case 2: 18 | printf("Performing a 3%% min-max linear stretch..."); 19 | return min_max_stretch(input, M_in, N_in, 0.03); 20 | default: 21 | printf("Performing a linear histogram stretch..."); 22 | return linear_stretch(input, M_in, N_in); 23 | } 24 | } 25 | 26 | float*** linear_stretch (float*** input, int M_in, int N_in) 27 | { 28 | // Define output. 29 | float*** output = alloc3df(3, M_in, N_in); 30 | float** densityHistogram; 31 | 32 | int minColor, maxColor; 33 | int i, j, k; 34 | 35 | // Linearly stretch for all colors. 36 | for (k = 0; k < 3; k++) { 37 | // Reset necessary variables. 38 | minColor = 0; 39 | maxColor = 255; 40 | 41 | // Create a histogram of the input. 42 | densityHistogram = generate_density_histogram(input[k], 256, 43 | M_in, N_in); 44 | 45 | // Find the minimum and maximum pixel using the original histogram by 46 | // looping through the columns and checking for the first row that 47 | // has a value greater than 0. 48 | for (i = 0; i < 256; i++) { 49 | if (densityHistogram[255][i] > 0.0) { 50 | minColor = i + 1; 51 | break; 52 | } 53 | } 54 | for (i = 256 - 1; i > 0; i--) { 55 | if (densityHistogram[255][i] > 0.0) { 56 | maxColor = i + 1; 57 | break; 58 | } 59 | } 60 | 61 | // Create the new image with this information. 62 | for (i = 0; i < M_in; i++) { 63 | for (j = 0; j < N_in; j++) { 64 | // Set any pixel that has < minimum equal to zero, and set 65 | // any pixel that has > maximum equal to zero. 66 | if (input[k][i][j] < minColor) { 67 | output[k][i][j] = 0; 68 | } else if (input[k][i][j] > maxColor) { 69 | output[k][i][j] = 255; 70 | } else { 71 | // Create the resulting pixel based on a linear scaling factor 72 | // that takes into account the min and max. 73 | output[k][i][j] = ((input[k][i][j] - minColor) / 74 | (maxColor - minColor)) * 255; 75 | } 76 | } 77 | } 78 | 79 | free(densityHistogram); 80 | } 81 | 82 | return output; 83 | } 84 | 85 | float*** min_max_stretch (float*** input, int M_in, int N_in, double cutoff) 86 | { 87 | // Define output. 88 | float*** output = alloc3df(3, M_in, N_in); 89 | float* density; 90 | float* cumulative; 91 | 92 | int minColor, maxColor; 93 | int i, j, k; 94 | // Linearly stretch for all three colors. 95 | for (k = 0; k < 3; k++) { 96 | minColor = 0; 97 | maxColor = 255; 98 | 99 | // Define the density and cumulative distribution functions. 100 | density = alloc1df(256); 101 | cumulative = alloc1df(256); 102 | 103 | // Define the weight of each pixel. 104 | float weight = (float) 1.0 / M_in / N_in; 105 | 106 | for (i = 0; i < M_in; i++) { 107 | for (j = 0; j < N_in; j++) { 108 | density[(int) input[k][i][j]] += weight; 109 | } 110 | } 111 | 112 | // Populate the cumulative distribution function. 113 | cumulative[0] = density[0]; 114 | for (i = 1; i < 256; i++) { 115 | cumulative[i] += cumulative[i - 1] + density[i]; 116 | } 117 | 118 | float w = 0; 119 | while (w < cutoff) { 120 | w += density[minColor++]; 121 | } 122 | 123 | w = 0; 124 | while (w < cutoff) { 125 | w += density[maxColor--]; 126 | } 127 | 128 | // Create the new image with this information. 129 | for (i = 0; i < M_in; i++) { 130 | for (j = 0; j < N_in; j++) { 131 | // Set any pixel that has < minimum equal to zero, and set 132 | // any pixel that has > maximum equal to zero. 133 | if (input[k][i][j] < minColor) { 134 | output[k][i][j] = 0; 135 | } else if (input[k][i][j] > maxColor) { 136 | output[k][i][j] = 255; 137 | } else { 138 | // Create the resulting pixel based on a linear scaling factor 139 | // that takes into account the min and max. 140 | output[k][i][j] = ((input[k][i][j] - minColor) / 141 | (maxColor - minColor)) * 255; 142 | } 143 | } 144 | } 145 | 146 | // Free memory. 147 | free(density); 148 | free(cumulative); 149 | } 150 | 151 | return output; 152 | } 153 | -------------------------------------------------------------------------------- /kernel_filter.c: -------------------------------------------------------------------------------- 1 | #include "kernel_filter.h" 2 | #include "array_utility.h" 3 | 4 | #include 5 | #include 6 | 7 | // Array addition. 8 | float** add (float** arrayOne, float** arrayTwo, int row, int col) 9 | { 10 | int i, j; 11 | float** final = alloc2df(row, col); 12 | for (i = 0; i < row; i++) { 13 | for (j = 0; j < col; j++) { 14 | final[i][j] = arrayOne[i][j] + arrayTwo[i][j]; 15 | } 16 | } 17 | 18 | return final; 19 | } 20 | 21 | // Array subtraction. 22 | float** subtract (float** arrayOne, float** arrayTwo, int row, int col) 23 | { 24 | int i, j; 25 | float** final = alloc2df(row, col); 26 | for (i = 0; i < row; i++) { 27 | for (j = 0; j < col; j++) { 28 | final[i][j] = arrayOne[i][j] - arrayTwo[i][j]; 29 | } 30 | } 31 | 32 | return final; 33 | } 34 | 35 | // Finds the surrounding pixel matrix in a given image. 36 | float** find_pixel_matrix (float** input, int M_in, int N_in, 37 | int row, int col, int size) 38 | { 39 | // Declare the pixel matrix. 40 | float** pixelMatrix = alloc2df(size, size); 41 | 42 | // Find the coordinates of the center pixel in the pixel matrix. 43 | int center = (int) floor((double) size / 2); 44 | 45 | // Fill in the surrounding edges relative to the center pixel. 46 | int i, j; 47 | for (i = 0; i < size; i++) { 48 | for (j = 0; j < size; j++) { 49 | int pixelRow = row + (i - center); 50 | int pixelCol = col + (j - center); 51 | 52 | if (pixelRow < 0) { 53 | pixelRow = 0; 54 | } 55 | 56 | if (pixelRow > (M_in - 1)) { 57 | pixelRow = M_in - 1; 58 | } 59 | 60 | if (pixelCol < 0) { 61 | pixelCol = 0; 62 | } 63 | 64 | if (pixelCol > (N_in - 1)) { 65 | pixelCol = N_in - 1; 66 | } 67 | 68 | pixelMatrix[i][j] = input[pixelRow][pixelCol]; 69 | } 70 | } 71 | 72 | return pixelMatrix; 73 | } 74 | 75 | // Convolution operation between two matrices. 76 | float convolve_matrices (float** array_one, float** array_two, int size) 77 | { 78 | int i, j; 79 | float sum = 0; 80 | for (i = 0; i < size; i++) { 81 | for (j = 0; j < size; j++) { 82 | sum += array_one[i][j] * array_two[i][j]; 83 | } 84 | } 85 | 86 | return sum; 87 | } 88 | 89 | // Convolution matrix filtering. 90 | float*** convolve (float*** input, int M_in, int N_in, float** kernel, int dim) 91 | { 92 | // Declare output. 93 | float*** output = alloc3df(3, M_in, N_in); 94 | int i, j, k; 95 | 96 | // For each channel... 97 | for (k = 0; k < 3; k++) { 98 | // Find the pixel matrix for each pixel, convolve that matrix with the 99 | // given kernel, and use that result to determine the new value. 100 | for (i = 0; i < M_in; i++) { 101 | for (j = 0; j < N_in; j++) { 102 | float** pixel_matrix = find_pixel_matrix(input[k], M_in, 103 | N_in, i, j, dim); 104 | float new_value = convolve_matrices(pixel_matrix, kernel, dim); 105 | output[k][i][j] = new_value; 106 | } 107 | } 108 | } 109 | 110 | return output; 111 | } 112 | 113 | float*** lowpass_filter(float*** input, int M_in, int N_in) 114 | { 115 | // Inform the user. 116 | printf("Performing a low-pass filter...\n"); 117 | 118 | return convolve(input, M_in, N_in, lowpass_filter_3by3kernel(), 3); 119 | } 120 | 121 | float*** highpass_filter(float*** input, int M_in, int N_in) 122 | { 123 | // Inform the user. 124 | printf("Performing a high-pass filter...\n"); 125 | 126 | return convolve(input, M_in, N_in, highpass_filter_3by3kernel(), 3); 127 | } 128 | 129 | float** lowpass_filter_3by3kernel() 130 | { 131 | float** kernel = alloc2df(3, 3); 132 | 133 | // Low-pass filter using 3x3 kernel. 134 | kernel[0][0] = (float) 1 * 1/16; kernel[0][1] = (float) 2 * 1/16; 135 | kernel[0][2] = (float) 1 * 1/16; 136 | kernel[1][0] = (float) 2 * 1/16; kernel[1][1] = (float) 4 * 1/16; 137 | kernel[1][2] = (float) 2 * 1/16; 138 | kernel[2][0] = (float) 1 * 1/16; kernel[2][1] = (float) 2 * 1/16; 139 | kernel[2][2] = (float) 1 * 1/16; 140 | 141 | return kernel; 142 | } 143 | 144 | float** highpass_filter_3by3kernel() 145 | { 146 | // Define our 3 by 3 kernel. 147 | float** lpKernel = alloc2df(3, 3); 148 | lpKernel[0][0] = (float) 1 * 1/16; lpKernel[0][1] = (float) 2 * 1/16; 149 | lpKernel[0][2] = (float) 1 * 1/16; 150 | lpKernel[1][0] = (float) 2 * 1/16; lpKernel[1][1] = (float) 4 * 1/16; 151 | lpKernel[1][2] = (float) 2 * 1/16; 152 | lpKernel[2][0] = (float) 1 * 1/16; lpKernel[2][1] = (float) 2 * 1/16; 153 | lpKernel[2][2] = (float) 1 * 1/16; 154 | 155 | // Define our delta function kernel. 156 | float** deltaKernel = alloc2df(3, 3); 157 | deltaKernel[0][0] = (float) 0; deltaKernel[0][1] = (float) 0; 158 | deltaKernel[0][2] = (float) 0; 159 | deltaKernel[1][0] = (float) 0; deltaKernel[1][1] = (float) 1; 160 | deltaKernel[1][2] = (float) 0; 161 | deltaKernel[2][0] = (float) 0; deltaKernel[2][1] = (float) 0; 162 | deltaKernel[2][2] = (float) 0; 163 | 164 | // Subtract the latter from the former. 165 | return subtract(deltaKernel, lpKernel, 3, 3); 166 | } 167 | -------------------------------------------------------------------------------- /histogram_equalization.c: -------------------------------------------------------------------------------- 1 | #include "histogram_equalization.h" 2 | #include "array_utility.h" 3 | 4 | #include 5 | 6 | float*** equalize (float*** input, int M_in, int N_in) 7 | { 8 | int option; 9 | 10 | // Prompt the user. 11 | printf("Which histgram specification would you like to apply? (1) for"); 12 | printf(" a histogram that increases linearly in the lower half, but"); 13 | printf(" decreases linearly in the upper half, (2) for a histogram that"); 14 | printf(" decreases linearly in the lower half, but increases linearly"); 15 | printf(" in the upper half.\n"); 16 | scanf("%d", &option); 17 | 18 | switch (option) { 19 | case 1: 20 | return apply_convex_equalization(input, M_in, N_in); 21 | default: 22 | return apply_concave_equalization(input, M_in, N_in); 23 | } 24 | } 25 | 26 | float*** apply_concave_equalization (float*** input, int M_in, int N_in) 27 | { 28 | // Declare output. 29 | float*** output = alloc3df(3, M_in, N_in); 30 | 31 | // Create the desired density histogram. 32 | int i, j, k; 33 | int* desired_histogram = alloc1di(256); 34 | double* desired_histogram_count = alloc1dd(256); 35 | int total_pixels = 0; 36 | for (i = 0; i < 256; i++) { 37 | if (i < 129) { 38 | desired_histogram[i] = i; 39 | } else { 40 | desired_histogram[i] = 128 - i; 41 | } 42 | 43 | total_pixels += desired_histogram[i]; 44 | } 45 | 46 | // Create the desired cumulative distribution for the above histogram. 47 | double fraction = 0.0; 48 | for (i = 0; i < 256; i++) { 49 | fraction += (double) desired_histogram[i] * (1 / (double) 50 | total_pixels); 51 | desired_histogram_count[i] = fraction; 52 | } 53 | 54 | // Prepare to calculate the cumulative histogram. 55 | double* pixel_count; 56 | int* new_histogram; 57 | float pixel_density = 1 / (float) (M_in * N_in); 58 | 59 | // Equalize the histogram on all three channels. 60 | for (k = 0; k < 3; k++) { 61 | pixel_count = alloc1dd(256); 62 | new_histogram = alloc1di(256); 63 | 64 | // Construct the current cumulative histogram. 65 | for (i = 0; i < M_in; i++) { 66 | for (j = 0; j < N_in; j++) { 67 | pixel_count[(int) input[k][i][j]] += pixel_density; 68 | } 69 | } 70 | 71 | // Create the lookup table for the new values of each grayscale color. 72 | j = 0; 73 | for (i = 0; i < 256; i++) { 74 | if (pixel_count[i] <= desired_histogram_count[j]) { 75 | new_histogram[i] = j; 76 | } else { 77 | while (pixel_count[i] > desired_histogram_count[j]) { 78 | j++; 79 | } 80 | if (desired_histogram_count[j] - pixel_count[i] > 81 | pixel_count[i] - desired_histogram_count[j - 1]) { 82 | new_histogram[i] = j - 1; 83 | } else { 84 | new_histogram[i] = j; 85 | } 86 | } 87 | } 88 | 89 | // Create the new image. 90 | for (i = 0; i < M_in; i++) { 91 | for (j = 0; j < N_in; j++) { 92 | output[k][i][j] = new_histogram[(int) input[k][i][j]]; 93 | } 94 | } 95 | free(pixel_count); 96 | free(new_histogram); 97 | } 98 | 99 | free(desired_histogram); 100 | return output; 101 | } 102 | 103 | float*** apply_convex_equalization (float*** input, int M_in, int N_in) 104 | { 105 | // Declare output. 106 | float*** output = alloc3df(3, M_in, N_in); 107 | 108 | // Create the desired density histogram. 109 | int i, j, k; 110 | int* desired_histogram = alloc1di(256); 111 | double* desired_histogram_count = alloc1dd(256); 112 | int total_pixels = 0; 113 | for (i = 0; i < 256; i++) { 114 | if (i < 129) { 115 | desired_histogram[i] = 128 - i; 116 | } else { 117 | desired_histogram[i] = i - 128; 118 | } 119 | 120 | total_pixels += desired_histogram[i]; 121 | } 122 | 123 | // Create the desired cumulative distribution for the above histogram. 124 | double fraction = 0.0; 125 | for (i = 0; i < 256; i++) { 126 | fraction += (double) desired_histogram[i] * (1 / (double) 127 | total_pixels); 128 | desired_histogram_count[i] = fraction; 129 | } 130 | 131 | // Prepare to calculate the cumulative histogram. 132 | double* pixel_count; 133 | int* new_histogram; 134 | float pixel_density = 1 / (float) (M_in * N_in); 135 | 136 | // Equalize the histogram on all three channels. 137 | for (k = 0; k < 3; k++) { 138 | pixel_count = alloc1dd(256); 139 | new_histogram = alloc1di(256); 140 | 141 | // Construct the current cumulative histogram. 142 | for (i = 0; i < M_in; i++) { 143 | for (j = 0; j < N_in; j++) { 144 | pixel_count[(int) input[k][i][j]] += pixel_density; 145 | } 146 | } 147 | 148 | // Create the lookup table for the new values of each grayscale color. 149 | j = 0; 150 | for (i = 0; i < 256; i++) { 151 | if (pixel_count[i] <= desired_histogram_count[j]) { 152 | new_histogram[i] = j; 153 | } else { 154 | while (pixel_count[i] > desired_histogram_count[j]) { 155 | j++; 156 | } 157 | if (desired_histogram_count[j] - pixel_count[i] > 158 | pixel_count[i] - desired_histogram_count[j - 1]) { 159 | new_histogram[i] = j - 1; 160 | } else { 161 | new_histogram[i] = j; 162 | } 163 | } 164 | } 165 | 166 | // Create the new image. 167 | for (i = 0; i < M_in; i++) { 168 | for (j = 0; j < N_in; j++) { 169 | output[k][i][j] = new_histogram[(int) input[k][i][j]]; 170 | } 171 | } 172 | free(pixel_count); 173 | free(new_histogram); 174 | } 175 | 176 | free(desired_histogram); 177 | return output; 178 | } 179 | -------------------------------------------------------------------------------- /median_filter.c: -------------------------------------------------------------------------------- 1 | #include "median_filter.h" 2 | #include "array_utility.h" 3 | #include "kernel_filter.h" 4 | 5 | #include 6 | 7 | // Helper function to find the pixel array for a particular input image. 8 | float* find_pixel_array (float** input, int M_in, int N_in, 9 | int row, int col, int size, int* array_size) 10 | { 11 | // Declare array size. 12 | *array_size = size * size; 13 | 14 | // Declare the pixel array. 15 | float* array = alloc1df(*array_size); 16 | int index = 0; 17 | 18 | // Find the coordinates of the center pixel in the pixel matrix. 19 | int center = (int) floor((double) size / 2); 20 | 21 | // Fill in the surrounding edges relative to the center pixel. 22 | int i, j; 23 | for (i = 0; i < size; i++) { 24 | for (j = 0; j < size; j++) { 25 | int pixel_row = row + (i - center); 26 | int pixel_col = col + (j - center); 27 | 28 | if (pixel_row < 0) { 29 | pixel_row = 0; 30 | } 31 | 32 | if (pixel_row > (M_in - 1)) { 33 | pixel_row = M_in - 1; 34 | } 35 | 36 | if (pixel_col < 0) { 37 | pixel_col = 0; 38 | } 39 | 40 | if (pixel_col > (N_in - 1)) { 41 | pixel_col = N_in - 1; 42 | } 43 | 44 | array[index++] = input[pixel_row][pixel_col]; 45 | } 46 | } 47 | 48 | return array; 49 | } 50 | 51 | // Helper function to find the cross array for a particular input image. 52 | float* find_cross_array (float** input, int M_in, int N_in, 53 | int row, int col, int width, int height, int* array_size) 54 | { 55 | // Declare the pixel matrix and the index on which we're currently iterating. 56 | *array_size = width * 2 + height * 2; 57 | float* cross_array = alloc1df(*array_size); 58 | int current_index = 0; 59 | 60 | // Find the horizontal elements of the cross. 61 | int i, j; 62 | for (i = 0; i < width * 2; i++) { 63 | int pixel_row = row + (i - width); 64 | int pixel_col = col; 65 | 66 | if (pixel_row < 0) { 67 | pixel_row = 0; 68 | } 69 | 70 | if (pixel_row > (M_in - 1)) { 71 | pixel_row = M_in - 1; 72 | } 73 | 74 | cross_array[current_index++] = input[pixel_row][pixel_col]; 75 | } 76 | 77 | // Find the vertical elements of the cross. 78 | for (j = 0; j < height * 2; j++) { 79 | int pixel_row = row; 80 | int pixel_col = col + (j - height); 81 | 82 | if (pixel_col < 0) { 83 | pixel_col = 0; 84 | } 85 | 86 | if (pixel_col > (N_in - 1)) { 87 | pixel_col = N_in - 1; 88 | } 89 | 90 | cross_array[current_index++] = input[pixel_row][pixel_col]; 91 | } 92 | 93 | return cross_array; 94 | } 95 | 96 | float*** median_filter (float*** input, int M_in, int N_in) 97 | { 98 | // Prompt the user. 99 | printf("What shape would you like to use for the median filter's window?"); 100 | printf(" (1) for cross, (2) for square.\n"); 101 | int option; 102 | scanf("%d", &option); 103 | 104 | float*** output; 105 | switch (option) { 106 | case 2: 107 | printf("Performing a square-shaped median filter...\n"); 108 | output = square_median_filter(input, M_in, N_in); 109 | break; 110 | default: 111 | printf("Performing a cross-shaped median filter...\n"); 112 | output = cross_median_filter(input, M_in, N_in); 113 | break; 114 | } 115 | 116 | return output; 117 | } 118 | 119 | float*** square_median_filter (float*** input, int M_in, int N_in) 120 | { 121 | // Declare output. 122 | float*** output = alloc3df(3, M_in, N_in); 123 | 124 | // Decide the window of a 2D median filter to be an 3 by 3 pixel array. 125 | int size = 3; 126 | 127 | int i, j, k, l, m; 128 | for (k = 0; k < 3; k++) { 129 | for (i = 0; i < M_in; i++) { 130 | for (j = 0; j < N_in; j++) { 131 | int array_size; 132 | float* square = find_pixel_array(input[k], M_in, N_in, i, 133 | j, size, &array_size); 134 | 135 | // Sort the resulting set of pixels. 136 | for (m = 0; m < array_size - 1; m++) { 137 | for (l = m + 1; l < array_size; l++) { 138 | if (square[m] > square[l]) { 139 | float swap = square[m]; 140 | square[m] = square[l]; 141 | square[l] = swap; 142 | } 143 | } 144 | } 145 | 146 | // Replace the pixel that we're evaluating with the median 147 | // pixel. 148 | int center = (int) floor((double) array_size / 2); 149 | output[k][i][j] = square[center]; 150 | } 151 | } 152 | } 153 | 154 | return output; 155 | } 156 | 157 | float*** cross_median_filter (float*** input, int M_in, int N_in) 158 | { 159 | // Declare output. 160 | float*** output = alloc3df(3, M_in, N_in); 161 | 162 | // Decide the window of a 2D median filter to be a cross that extends 163 | // 4 pixels W and E and 4 pixels N and S. 164 | int width = 4; 165 | int height = 4; 166 | 167 | int i, j, k, l, m; 168 | for (k = 0; k < 3; k++) { 169 | for (i = 0; i < M_in; i++) { 170 | for (j = 0; j < N_in; j++) { 171 | int array_size; 172 | float* cross = find_cross_array(input[k], M_in, N_in, i, j, 173 | width, height, &array_size); 174 | 175 | // Sort the resulting set of pixels. 176 | for (m = 0; m < array_size - 1; m++) { 177 | for (l = m + 1; l < array_size; l++) { 178 | if (cross[m] > cross[l]) { 179 | float swap = cross[m]; 180 | cross[m] = cross[l]; 181 | cross[l] = swap; 182 | } 183 | } 184 | } 185 | 186 | // Replace the pixel that we're evaluating with the median 187 | // pixel. 188 | int center = (int) floor((double) array_size / 2); 189 | output[k][i][j] = cross[center]; 190 | } 191 | } 192 | } 193 | 194 | return output; 195 | } 196 | -------------------------------------------------------------------------------- /manipulate_hsi.c: -------------------------------------------------------------------------------- 1 | #include "manipulate_hsi.h" 2 | #include "array_utility.h" 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | // This function is a rewritten version based off one given by Prof. Ruye 9 | // Wang of Harvey Mudd's Department of Engineering (2013). 10 | void rgb_to_hsi (float R, float G, float B, float* H, float* S, float* I) 11 | { 12 | float r, g, b, w, i, min=1.e-6; 13 | *I = (i = R + G + B)/3.0; 14 | r = R / i; 15 | g = G / i; 16 | b = B / i; 17 | 18 | if (R==G && G==B) { 19 | *S = 0; 20 | *H = 0; 21 | } else { 22 | w = 0.5 * (R - G + R - B) / sqrt((R - G)*(R - G) + (R - B)*(G - B)); 23 | 24 | if (w > 1) { 25 | w = 1; 26 | } else if(w < -1) { 27 | w = -1; 28 | } 29 | 30 | *H = acos(w); 31 | 32 | if (*H < 0) { 33 | printf("Error while converting to HSI (H < 0)."); 34 | exit(1); 35 | } 36 | 37 | if (B > G) { 38 | *H = 2 * 3.14159 - *H; 39 | } 40 | 41 | if (r <= g && r <= b) { 42 | *S = 1 - 3 * r; 43 | } 44 | 45 | if (g <= r && g <= b) { 46 | *S = 1 - 3 * g; 47 | } 48 | 49 | if (b <= r && b <= g) { 50 | *S = 1 - 3 * b; 51 | } 52 | } 53 | } 54 | 55 | // This function is a rewritten version based off one given by Prof. Ruye 56 | // Wang of Harvey Mudd's Department of Engineering (2013). 57 | void hsi_to_rgb (float H, float S, float I, float* R, float* G, float* B) 58 | { 59 | float r, g, b; 60 | 61 | if (S > 1) { 62 | S = 1; 63 | } 64 | 65 | if (I > 1) { 66 | I = 1; 67 | } 68 | 69 | if (S == 0) { 70 | *R = *G = *B = I; 71 | } else { 72 | if ((H >= 0) && (H <2*3.14159/3)) { 73 | b = (1 - S) / 3; 74 | r = (1 + S*cos(H) / cos(3.14159/3 - H)) / 3; 75 | g = 1 - r - b; 76 | } else if ((H >= 2*3.14159/3) && (H < 4*3.14159/3)) { 77 | H = H - 2*3.14159/3; 78 | r = (1 - S)/3; 79 | g = (1 + S*cos(H) / cos(3.14159/3-H)) / 3; 80 | b = 1 - r - g; 81 | } else if ((H >= 4*3.14159/3) && (H < 2*3.14159)) { 82 | H = H - 4*3.14159/3; 83 | g = (1 - S)/3; 84 | b = (1 + S*cos(H) / cos(3.14159/3 - H)) / 3; 85 | r = 1 - b - g; 86 | } else { 87 | printf("\nError: H is out of range at %f deg.\n", H*180 / 3.14159); 88 | exit(1); 89 | } 90 | 91 | if (r < 0 || g < 0 || b < 0) { 92 | printf("Error: Given invalid R, G, B values (%f, %f, %f).", r , g, 93 | b); 94 | exit(1); 95 | } 96 | 97 | if (r < 0) { 98 | r = 0; 99 | } 100 | if (g < 0) { 101 | g = 0; 102 | } 103 | if (b < 0) { 104 | b = 0; 105 | } 106 | 107 | *R = 3 * I * r; 108 | *G = 3 *I * g; 109 | *B = 3 * I * b; 110 | 111 | if (*R > 1) { 112 | *R=1; 113 | } 114 | if (*G > 1) { 115 | *G=1; 116 | } 117 | if (*B > 1) { 118 | *B=1; 119 | } 120 | } 121 | } 122 | 123 | float*** rotate_hue (float*** input, int M_in, int N_in) 124 | { 125 | // Prompt the user. 126 | float degrees; 127 | printf("By how many degrees do you want to rotate the hue (a number less"); 128 | printf(" than 360 degrees)?\n"); 129 | scanf("%f", °rees); 130 | 131 | // Declare output. 132 | float*** output = alloc3df(3, M_in, N_in); 133 | 134 | // Loop through all of the pixels and modify them in one fell swoop. 135 | int i, j; 136 | for (i = 0; i < M_in; i++) { 137 | for (j = 0; j < N_in; j++) { 138 | // Convert the incoming color image into HSI coordinates. 139 | float h, s, k, r, g, b; 140 | rgb_to_hsi(input[0][i][j] / 255, 141 | input[1][i][j] / 255, 142 | input[2][i][j] / 255, 143 | &h, &s, &k); 144 | 145 | // Rotate the hue by however many degrees (convert to radians). 146 | h += degrees * (3.14159/180); 147 | 148 | // Ensure that our hue is below 2pi. 149 | if (h > 6.28) { 150 | h -= 6.28; 151 | } 152 | 153 | // Convert the HSI coordinates back into a color image. 154 | hsi_to_rgb(h, s, k, &r, &g, &b); 155 | 156 | output[0][i][j] = r * 255; 157 | output[1][i][j] = g * 255; 158 | output[2][i][j] = b * 255; 159 | } 160 | } 161 | 162 | return output; 163 | } 164 | 165 | float*** increase_saturation (float*** input, int M_in, int N_in) 166 | { 167 | // Prompt the user. 168 | float saturation; 169 | printf("By what factor do you want to increase the saturation?\n"); 170 | scanf("%f", &saturation); 171 | 172 | // Declare output. 173 | float*** output = alloc3df(3, M_in, N_in); 174 | 175 | // Loop through all of the pixels and modify them in one fell swoop. 176 | int i, j; 177 | for (i = 0; i < M_in; i++) { 178 | for (j = 0; j < N_in; j++) { 179 | // Convert the incoming color image into HSI coordinates. 180 | float h, s, k, r, g, b; 181 | rgb_to_hsi(input[0][i][j] / 255, 182 | input[1][i][j] / 255, 183 | input[2][i][j] / 255, 184 | &h, &s, &k); 185 | 186 | // Rotate the hue by 90 degrees, as required. 187 | s *= saturation; 188 | 189 | // Ensure that saturation is below 1. 190 | if (s > 1.0) { 191 | s = 1.0; 192 | } 193 | 194 | // Convert the HSI coordinates back into a color image. 195 | hsi_to_rgb(h, s, k, &r, &g, &b); 196 | 197 | output[0][i][j] = r * 255; 198 | output[1][i][j] = g * 255; 199 | output[2][i][j] = b * 255; 200 | } 201 | } 202 | 203 | return output; 204 | } 205 | 206 | float*** increase_intensity (float*** input, int M_in, int N_in) 207 | { 208 | // Declare necessary variables. 209 | int i, j; 210 | float*** output = alloc3df(3, M_in, N_in); 211 | float* intensity_distribution = alloc1df(100); 212 | float intensity_density = (float) 1.0 / M_in / N_in; 213 | 214 | // Loop through all of the pixels in the image and find the lowest 215 | // and highest values for saturation when converted. 216 | float min_intensity = 1, max_intensity = 0; 217 | for (i = 0; i < M_in; i++) { 218 | for (j = 0; j < N_in; j++) { 219 | // Convert the incoming color image into HSI coordinates. 220 | float h, s, k; 221 | rgb_to_hsi(input[0][i][j] / 255, 222 | input[1][i][j] / 255, 223 | input[2][i][j] / 255, 224 | &h, &s, &k); 225 | 226 | // Weird bug that happens when you passed in an image already 227 | // converted from RGB -> HSI -> RGB where the H is greater 228 | // than 6.28. Add this check to make sure that doesn't happen. 229 | if (h > 6.28) { 230 | h = 6.28; 231 | } 232 | 233 | output[0][i][j] = h; 234 | output[1][i][j] = s; 235 | output[2][i][j] = k; 236 | 237 | intensity_distribution[(int) (k + 0.5) * 100] += intensity_density; 238 | 239 | // Find the minimum and maximum intensity 240 | if (k < min_intensity) { 241 | min_intensity = floorf(k * 100) / 100; 242 | } else if (k > max_intensity) { 243 | max_intensity = floorf(k * 100) / 100; 244 | } 245 | } 246 | } 247 | 248 | // Find the cutoff point. 249 | float w = 0; 250 | while (w < 0.03) { 251 | w += intensity_distribution[(int) (min_intensity + 0.5) * 100]; 252 | min_intensity += 0.1; 253 | } 254 | 255 | w = 0; 256 | while (w < 0.03) { 257 | w += intensity_distribution[(int) (max_intensity + 0.5) * 100]; 258 | max_intensity -= 0.1; 259 | } 260 | 261 | // Loop through the image pixels again and linearly stretch the intensity. 262 | for (i = 0; i < M_in; i++) { 263 | for (j = 0; j < N_in; j++) { 264 | float r, g, b; 265 | // Linearly stretech the altered image. 266 | if (output[2][i][j] < min_intensity) { 267 | output[2][i][j] = 0.0; 268 | } else if (output[2][i][j] > max_intensity) { 269 | output[2][i][j] = 1.0; 270 | } else { 271 | // Create the resulting saturation based on a linear scaling 272 | // factor that takes into account the min and max. 273 | output[2][i][j] = ((output[2][i][j] - min_intensity) / 274 | (max_intensity - min_intensity)); 275 | } 276 | 277 | // Convert the HSI coordinates back into a color image. 278 | hsi_to_rgb(output[0][i][j], 279 | output[1][i][j], 280 | output[2][i][j], &r, &g, &b); 281 | 282 | output[0][i][j] = r * 255; 283 | output[1][i][j] = g * 255; 284 | output[2][i][j] = b * 255; 285 | } 286 | } 287 | 288 | return output; 289 | } 290 | -------------------------------------------------------------------------------- /fourier_filter.c: -------------------------------------------------------------------------------- 1 | #include "fourier_filter.h" 2 | #include "array_utility.h" 3 | 4 | #include 5 | #include 6 | #define _USE_MATH_DEFINES 7 | #include 8 | 9 | #define SWAP(a,b) tempr=(a); (a)=(b); (b)=tempr 10 | 11 | // Discrete Fourier transform function. Courtesy of Prof. Ruye Wang of Harvey 12 | // Mudd College (2013). 13 | // Note that N _must_ be a power of 2. 14 | void discrete_fourier_transform(float xr[], float xi[], int N, int inverse) 15 | { 16 | int mmax, step, i, j, k, j1, m, n; 17 | float arg, s, c, w, tempr, tempi; 18 | 19 | m = log((float) N) / log(2.0); 20 | 21 | // Perform bit reversal. 22 | for (i = 0; i < N; ++i) { 23 | j = 0; 24 | 25 | for (k=0; k> k)); 27 | } 28 | 29 | if (j < i) { 30 | SWAP(xr[i],xr[j]); 31 | SWAP(xi[i],xi[j]); 32 | } 33 | } 34 | 35 | // For log N stages. 36 | for (i = 0; i < m; i++) { 37 | n = w = pow(2.0,(float) i); 38 | w = M_PI / n; 39 | 40 | if (inverse) { 41 | w=-w; 42 | } 43 | 44 | k = 0; 45 | 46 | // For N components. 47 | while (k < N - 1) { 48 | // For each section. 49 | for (j=0; j 0.00000001) { 208 | if (high == 0) { 209 | real = input_fourier_series[k][i][j][0]; 210 | im = input_fourier_series[k][i][j][1]; 211 | } 212 | } else { 213 | if (high == 1) { 214 | real = input_fourier_series[k][i][j][0]; 215 | im = input_fourier_series[k][i][j][1]; 216 | } 217 | } 218 | 219 | desired_image_spectrum[k][i][j][0] = real; 220 | desired_image_spectrum[k][i][j][1] = im; 221 | } 222 | } 223 | } 224 | 225 | // Inform the user. 226 | printf("Carrying out the inverse 2D Fourier transform of the image...\n"); 227 | 228 | // Store the imaginary values returned in the following intermediate 229 | // step. 230 | float*** imaginary_y = alloc3df(3, M_in_new, N_in_new); 231 | 232 | // Perform first for each row in the y-direction. 233 | // Note that this involves the extra step of making sure that row 234 | // has its pixels in a sequential row before taking the DFT. 235 | for (k = 0; k < 3; k++) { 236 | for (j = 0; j < N_in_new; j++) { 237 | float* real = alloc1df(M_in_new); 238 | float* imaginary = alloc1df(M_in_new); 239 | 240 | for (i = 0; i < M_in_new; i++) { 241 | real[i] = desired_image_spectrum[k][i][j][0]; 242 | imaginary[i] = desired_image_spectrum[k][i][j][1]; 243 | } 244 | 245 | // Inverse transform. 246 | discrete_fourier_transform(real, imaginary, M_in_new, 1); 247 | 248 | for (i = 0; i < M_in_new; i++) { 249 | output[k][i][j] = real[i]; 250 | imaginary_y[k][i][j] = imaginary[i]; 251 | } 252 | 253 | // Release "real" and "imaginary" memory. 254 | free(real); 255 | free(imaginary); 256 | } 257 | } 258 | 259 | // Perform then for each column in the x-direction. 260 | for (k = 0; k < 3; k++) { 261 | for (i = 0; i < M_in_new; i++) { 262 | discrete_fourier_transform(output[k][i], imaginary_y[k][i], N_in_new, 1); 263 | } 264 | } 265 | 266 | return output; 267 | } 268 | -------------------------------------------------------------------------------- /array_utility.c: -------------------------------------------------------------------------------- 1 | #include "array_utility.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | char fname[50]; 9 | FILE* fp; 10 | 11 | double* alloc1dd (int n) 12 | { 13 | int i; 14 | double* array; 15 | if ((array = (double*) malloc(n * sizeof(double))) == NULL) { 16 | printf("Unable to allocate memory for 1D double array...\n"); 17 | exit(0); 18 | } 19 | for (i = 0; i < n; i++) { 20 | array[i] = 0.0; 21 | } 22 | 23 | return array; 24 | } 25 | 26 | double** alloc2dd (int m, int n) 27 | { 28 | int i, j; 29 | double** array; 30 | if ((array = (double **) malloc(m * sizeof(double*))) == NULL) { 31 | printf("Unable to allocate memory for 2D float array...\n"); 32 | exit(0); 33 | } 34 | 35 | for (i = 0; i < m; i++) { 36 | array[i] = alloc1dd(n); 37 | } 38 | 39 | return array; 40 | } 41 | 42 | float* alloc1df (int n) 43 | { 44 | int i; 45 | float* array; 46 | if ((array = (float*) malloc(n * sizeof(float))) == NULL) { 47 | printf("Unable to allocate memory for 1D float array...\n"); 48 | exit(0); 49 | } 50 | 51 | for (i = 0; i < n; i++) { 52 | array[i] = 0.0; 53 | } 54 | 55 | return array; 56 | } 57 | 58 | float** alloc2df (int m, int n) 59 | { 60 | int i,j; 61 | float** array; 62 | if ((array = (float **) malloc(m * sizeof(float*))) == NULL) { 63 | printf("Unable to allocate memory for 2D float array...\n"); 64 | exit(0); 65 | } 66 | 67 | for (i = 0; i < m; i++) { 68 | array[i] = alloc1df(n); 69 | } 70 | 71 | return array; 72 | } 73 | 74 | float*** alloc3df (int l, int m, int n) 75 | { 76 | int i; 77 | float*** array; 78 | 79 | if ((array = (float ***) malloc(l * sizeof(float**))) == NULL) { 80 | printf("Unable to allocate memory for 3D float array...\n"); 81 | exit(0); 82 | } 83 | 84 | for (i = 0; i < l; i++) { 85 | array[i] = alloc2df(m,n); 86 | } 87 | 88 | return array; 89 | } 90 | 91 | float**** alloc4df (int k, int l, int m, int n) 92 | { 93 | int i; 94 | float**** array; 95 | 96 | if ((array = (float ****) malloc(k * sizeof(float***))) == NULL) { 97 | printf("Unable to allocate memory for 4D float array...\n"); 98 | exit(0); 99 | } 100 | 101 | for (i = 0; i < k; i++) { 102 | array[i] = alloc3df(l,m,n); 103 | } 104 | 105 | return array; 106 | } 107 | 108 | void dealloc2df (float** array, int m, int n) 109 | { 110 | int i; 111 | for (i = 0; i < m; i++) { 112 | free(array[i]); 113 | } 114 | 115 | free(array); 116 | } 117 | 118 | void dealloc3df (float*** array, int l, int m, int n) 119 | { 120 | int i; 121 | for (i = 0; i < l; i++) { 122 | dealloc2df(array[i], m, n); 123 | } 124 | 125 | free(array); 126 | } 127 | 128 | void dealloc4df (float**** array, int k, int l, int m, int n) 129 | { 130 | int i; 131 | for (i = 0; i < k; i++) { 132 | dealloc3df(array[i], l, m, n); 133 | } 134 | 135 | free(array); 136 | } 137 | 138 | int* alloc1di (int n) 139 | { 140 | int i, *array; 141 | if ((array = (int*) malloc(n * sizeof(int))) == NULL) { 142 | printf("Unable to allocate memory for 1D int array...\n"); 143 | exit(0); 144 | } 145 | 146 | for (i = 0; i < n; i++) { 147 | array[i] = 0.0; 148 | } 149 | 150 | return array; 151 | } 152 | 153 | int** alloc2di (int m, int n) 154 | { 155 | int i; 156 | int** array; 157 | if ((array = (int**) malloc(m * sizeof(int*))) == NULL) { 158 | printf("Unable to allocate memory for 2D int array...\n"); 159 | exit(0); 160 | } 161 | 162 | for (i = 0; i < m; i++) { 163 | array[i] = alloc1di(n); 164 | } 165 | 166 | return array; 167 | } 168 | 169 | 170 | int*** alloc3di (int l, int m, int n) 171 | { 172 | int i; 173 | int*** array; 174 | if ( (array = (int ***) malloc(l * sizeof(int**)) )==NULL) { 175 | printf("Unable to allocate memory for 3D int array...\n"); 176 | exit(0); 177 | } 178 | 179 | for (i = 0; i < l; i++) { 180 | array[i] = alloc2di(m, n); 181 | } 182 | 183 | return array; 184 | } 185 | 186 | void dealloc2di (int** array, int m, int n) 187 | { 188 | int i; 189 | for (i = 0; i < m; i++) { 190 | free(array[i]); 191 | } 192 | 193 | free(array); 194 | } 195 | 196 | void dealloc3di (int*** array, int l, int m, int n) 197 | { 198 | int i; 199 | for (i = 0; i < l; i++) { 200 | dealloc2di(array[i], m, n); 201 | } 202 | 203 | free(array); 204 | } 205 | 206 | // This function prints an end of file error message and exits. 207 | void eof_err () 208 | { 209 | printf("Unexpected end of file, exiting. \n"); 210 | exit(0); 211 | } 212 | 213 | int getword (FILE* fp, char *word) 214 | { 215 | int i = 0, cha = ' '; 216 | short end = 0; 217 | 218 | do { // Eliminate White Space and comments (from # to end of line) 219 | cha = fgetc(fp); 220 | if (cha=='#') { 221 | do cha = fgetc(fp); 222 | while (!(cha == '\n')); 223 | } 224 | } 225 | while (isspace(cha) && (cha != EOF)); 226 | 227 | if (cha == EOF) { 228 | return -1; 229 | } else { // get chars until a whitespace or End of File 230 | do { 231 | word[i++] = cha; 232 | cha = fgetc(fp); 233 | } // Get Single Word 234 | while (!(isspace(cha)) && (cha != EOF)); 235 | } 236 | 237 | if (cha == EOF) { 238 | end = 1; // if end of the file then we are done reading chars 239 | } 240 | 241 | word[i] = '\0'; 242 | return end; 243 | } 244 | 245 | 246 | float*** read_color_image (char *fname, int *m, int *n) 247 | { 248 | int c, i, j, k, Max; 249 | float*** img; 250 | char word[10]; 251 | FILE* fp; 252 | char magic[4]; 253 | 254 | if ((fp = fopen(fname, "r")) == NULL) { 255 | printf("Unable to open file: %s for reading, exiting.\n", fname); 256 | exit(0); 257 | } 258 | 259 | if (getword(fp,word) != 0) { 260 | eof_err(); 261 | } 262 | 263 | strcpy(magic,word); 264 | 265 | if ((strcmp(magic,"P5") != 0) && (strcmp(magic,"P6") != 0)) { 266 | printf("\nBad file type, use raw grayscale (pgm) or raw color (ppm)"); 267 | printf("file.\n"); 268 | exit(0); 269 | } 270 | 271 | if (getword(fp,word) != 0) { 272 | eof_err(); 273 | } 274 | *n = atoi(word); 275 | 276 | if (getword(fp,word) != 0) { 277 | eof_err(); 278 | } 279 | *m = atoi(word); 280 | 281 | if (getword(fp,word) != 0) { 282 | eof_err(); 283 | } 284 | Max = atoi(word); 285 | 286 | img = alloc3df(3,*m,*n); 287 | 288 | for (i=0; i<*m; i++) { 289 | for (j=0; j<*n; j++) { 290 | for (k=0; k<3; k++) { 291 | c = fgetc(fp); 292 | if (c==EOF) { 293 | eof_err(); 294 | } 295 | img[k][i][j]=c; 296 | } 297 | } 298 | } 299 | 300 | fclose(fp); 301 | 302 | return img; 303 | } 304 | 305 | float** read_bw_image (char *fname, int *m, int *n) 306 | { 307 | int c, i, j, Max; 308 | float** img; 309 | char word[10]; 310 | FILE* fp; 311 | char magic[4]; 312 | 313 | if ((fp = fopen(fname, "r")) == NULL) { 314 | printf("Unable to open file: %s for reading, exiting.\n", fname); 315 | exit(0); 316 | } 317 | 318 | if (getword(fp,word) != 0) { 319 | eof_err(); 320 | } 321 | 322 | strcpy(magic,word); 323 | 324 | if ((strcmp(magic, "P5") != 0) && (strcmp(magic, "P6") != 0)) { 325 | printf("\nBad file type, use raw grayscale (pgm) or raw color (ppm)"); 326 | printf("file.\n"); 327 | exit(0); 328 | } 329 | 330 | if (getword(fp, word) != 0) { 331 | eof_err(); 332 | } 333 | *n = atoi(word); 334 | 335 | if (getword(fp, word) != 0) { 336 | eof_err(); 337 | } 338 | *m = atoi(word); 339 | 340 | if (getword(fp, word) != 0) { 341 | eof_err(); 342 | } 343 | Max = atoi(word); 344 | 345 | img = alloc2df(*m, *n); 346 | 347 | for (i = 0; i < *m; i++) { 348 | for (j = 0; j < *n; j++) { 349 | c = fgetc(fp); 350 | if (c == EOF) { 351 | eof_err(); 352 | } 353 | img[i][j] = c; 354 | } 355 | } 356 | 357 | fclose(fp); 358 | 359 | return img; 360 | } 361 | 362 | void write_color_image (char filename[], float*** image, int m, int n, int s) 363 | { 364 | int i, j, k, l; 365 | float v, min, max, ***Image; 366 | unsigned char w; 367 | FILE* fp; 368 | min = 9e9; 369 | max = -min; 370 | 371 | for (k = 0; k < 3; k++){ 372 | for (i = 0; i < m; i++) { 373 | for (j = 0; j < n; j++) { 374 | v = image[k][i][j]; 375 | if (min > v) { 376 | min = v; 377 | } 378 | 379 | if (max < v) { 380 | max = v; 381 | } 382 | } 383 | } 384 | } 385 | 386 | v = 254.99 / (max - min); 387 | 388 | for (k=0; k<3; k++) { 389 | for (i=0; iv) { 437 | min=v; 438 | } 439 | if (max 2 | #include 3 | #include 4 | 5 | #include "array_utility.h" 6 | #include "rotate.h" 7 | #include "resize.h" 8 | #include "histograms.h" 9 | #include "contrast_enhancement.h" 10 | #include "manipulate_hsi.h" 11 | #include "histogram_equalization.h" 12 | #include "kernel_filter.h" 13 | #include "median_filter.h" 14 | #include "gradient_filter.h" 15 | #include "fourier_filter.h" 16 | #include "edge_detection.h" 17 | #include "lodepng.h" 18 | 19 | float*** png_to_ppm (unsigned char* image, unsigned width, unsigned height) 20 | { 21 | float*** img = alloc3df(3, height, width); 22 | 23 | int i, j; 24 | for (i = 0; i < height; i++) { 25 | for (j = 0; j < width; j++) { 26 | img[0][i][j] = image[3 * i * width + 3 * j + 0]; // Red. 27 | img[1][i][j] = image[3 * i * width + 3 * j + 1]; // Green. 28 | img[2][i][j] = image[3 * i * width + 3 * j + 2]; // Blue. 29 | } 30 | } 31 | 32 | return img; 33 | } 34 | unsigned char* ppm_to_png (float*** image, unsigned width, unsigned height) 35 | { 36 | unsigned char* img = (unsigned char*) malloc(3 * width * height * 37 | sizeof(unsigned char)); 38 | 39 | // Perform linear stretch before converting to PNG. 40 | int i, j, k; 41 | 42 | for (k = 0; k < 3; k++) { 43 | float min = 9e9; 44 | float max = -min; 45 | 46 | for (i = 0; i < height; i++) { 47 | for (j = 0; j < width; j++) { 48 | float v = image[k][i][j]; 49 | if (min > v) { 50 | min = v; 51 | } 52 | if (max < v) { 53 | max = v; 54 | } 55 | } 56 | } 57 | 58 | float v = 254.99 / (max - min); 59 | 60 | for (i = 0; i < height; i++) { 61 | for (j = 0; j < width; j++) { 62 | img[3 * i * width + 3 * j + k] = (image[k][i][j] - min) * v; 63 | } 64 | } 65 | } 66 | 67 | return img; 68 | } 69 | 70 | int main () 71 | { 72 | int action = 1; 73 | 74 | char filename[256]; 75 | char saved_filename[256]; 76 | 77 | printf("Type in the name of the PNG file you would like to process.\n"); 78 | scanf("%s", filename); 79 | 80 | setbuf(stdout, NULL); 81 | 82 | // Load the PNG using LodePNG library. 83 | printf("Loading the file into memory...\n\n\n"); 84 | unsigned error; 85 | unsigned char* image; 86 | unsigned width, height; 87 | 88 | error = lodepng_decode24_file(&image, &width, &height, filename); 89 | if (error) { 90 | printf("Error (%u) loading file: %s\n", error, 91 | lodepng_error_text(error)); 92 | exit(1); 93 | } 94 | 95 | // Then use array to load into a three-dimensional array of R, G, 96 | // and B values. 97 | float*** input = png_to_ppm(image, width, height); 98 | free(image); 99 | 100 | int i, j; 101 | int output_height, output_width; 102 | 103 | // Begin coding the user prompt menu. 104 | while (action > 0) { 105 | float*** output = (float ***) malloc(3 * sizeof(float**)); 106 | 107 | printf("Select how you would like to process %s: \n", filename); 108 | printf("1) Generate a density histogram for the image.\n"); 109 | printf("2) Generate a cumulative histogram for the image.\n"); 110 | printf("3) Improve the image's contrast.\n"); 111 | printf("4) Resize an image's width and height by certain factors.\n"); 112 | printf("5) Rotate an image by some angle (in degrees).\n"); 113 | printf("6) Perform histogram equalization on the image.\n"); 114 | printf("7) Rotate the image's hue.\n"); 115 | printf("8) Increase the image's color saturation.\n"); 116 | printf("9) Increase the image's intensity.\n"); 117 | printf("10) Perform low-pass filtering on an image using a kernel.\n"); 118 | printf("11) Perform high-pass filtering on an image using a kernel."); 119 | printf("\n"); 120 | printf("12) Perform low-pass or high-pass filtering using a Fourier"); 121 | printf(" transform.\n"); 122 | printf("13) Create a gradient image that accentuates changes in"); 123 | printf(" color based on the given image.\n"); 124 | printf("14) Clean up an image using a median filter.\n"); 125 | printf("15) Detect edges in an image.\n"); 126 | 127 | 128 | printf("Type in the number of the action you're interested in "); 129 | printf("(-1 to exit): "); 130 | scanf("%d", &action); 131 | printf("----------------------------------------------------\n\n\n"); 132 | 133 | // Act according to what the user selected. 134 | switch (action) { 135 | case 1: 136 | output_height = output_width = 256; 137 | for (i = 0; i < 3; i++) { 138 | output[i] = generate_density_histogram(input[i], 139 | output_height, height, width); 140 | } 141 | 142 | strncpy(saved_filename, filename, 256); 143 | saved_filename[strlen(saved_filename) - 4] = 0; 144 | strcat(saved_filename, "_density_histogram.png"); 145 | break; 146 | case 2: 147 | output_height = output_width = 256; 148 | for (i = 0; i < 3; i++) { 149 | output[i] = generate_cumulative_histogram(input[i], 150 | output_height, height, width); 151 | } 152 | 153 | strncpy(saved_filename, filename, 256); 154 | saved_filename[strlen(saved_filename) - 4] = 0; 155 | strcat(saved_filename, "_cumu_histogram.png"); 156 | break; 157 | case 3: 158 | output_height = height; 159 | output_width = width; 160 | output = enhance_contrast(input, height, width); 161 | 162 | strncpy(saved_filename, filename, 256); 163 | saved_filename[strlen(saved_filename) - 4] = 0; 164 | strcat(saved_filename, "_with_contrast.png"); 165 | break; 166 | case 4: 167 | output = resize(input, height, width, &output_height, 168 | &output_width); 169 | 170 | strncpy(saved_filename, filename, 256); 171 | saved_filename[strlen(saved_filename) - 4] = 0; 172 | strcat(saved_filename, "_resized.png"); 173 | break; 174 | case 5: 175 | output_height = height; 176 | output_width = width; 177 | output = rotate(input, height, width); 178 | 179 | strncpy(saved_filename, filename, 256); 180 | saved_filename[strlen(saved_filename) - 4] = 0; 181 | strcat(saved_filename, "_rotated.png"); 182 | break; 183 | case 6: 184 | output_height = height; 185 | output_width = width; 186 | output = equalize(input, height, width); 187 | 188 | strncpy(saved_filename, filename, 256); 189 | saved_filename[strlen(saved_filename) - 4] = 0; 190 | strcat(saved_filename, "_equalized.png"); 191 | break; 192 | case 7: 193 | output_height = height; 194 | output_width = width; 195 | output = rotate_hue(input, height, width); 196 | 197 | strncpy(saved_filename, filename, 256); 198 | saved_filename[strlen(saved_filename) - 4] = 0; 199 | strcat(saved_filename, "_rotated_hue.png"); 200 | break; 201 | case 8: 202 | output_height = height; 203 | output_width = width; 204 | output = increase_saturation(input, height, width); 205 | 206 | strncpy(saved_filename, filename, 256); 207 | saved_filename[strlen(saved_filename) - 4] = 0; 208 | strcat(saved_filename, "_increased_saturation.png"); 209 | break; 210 | case 9: 211 | output_height = height; 212 | output_width = width; 213 | output = increase_intensity(input, height, width); 214 | 215 | strncpy(saved_filename, filename, 256); 216 | saved_filename[strlen(saved_filename) - 4] = 0; 217 | strcat(saved_filename, "_increased_intensity.png"); 218 | break; 219 | case 10: 220 | output_height = height; 221 | output_width = width; 222 | output = lowpass_filter(input, height, width); 223 | 224 | strncpy(saved_filename, filename, 256); 225 | saved_filename[strlen(saved_filename) - 4] = 0; 226 | strcat(saved_filename, "_lowpass_filter.png"); 227 | break; 228 | case 11: 229 | output_height = height; 230 | output_width = width; 231 | output = highpass_filter(input, height, width); 232 | 233 | strncpy(saved_filename, filename, 256); 234 | saved_filename[strlen(saved_filename) - 4] = 0; 235 | strcat(saved_filename, "_highpass_filter.png"); 236 | break; 237 | case 12: 238 | output_height = height; 239 | output_width = width; 240 | output = fourier_filter(input, height, width); 241 | 242 | strncpy(saved_filename, filename, 256); 243 | saved_filename[strlen(saved_filename) - 4] = 0; 244 | strcat(saved_filename, "_fourier_filter.png"); 245 | break; 246 | case 13: 247 | output_height = height; 248 | output_width = width; 249 | output = gradient_filter(input, height, width); 250 | 251 | strncpy(saved_filename, filename, 256); 252 | saved_filename[strlen(saved_filename) - 4] = 0; 253 | strcat(saved_filename, "_gradient_image.png"); 254 | break; 255 | case 14: 256 | output_height = height; 257 | output_width = width; 258 | output = median_filter(input, height, width); 259 | 260 | strncpy(saved_filename, filename, 256); 261 | saved_filename[strlen(saved_filename) - 4] = 0; 262 | strcat(saved_filename, "_median_filter.png"); 263 | break; 264 | case 15: 265 | output_height = height; 266 | output_width = width; 267 | output = detect_edges(input, height, width); 268 | 269 | strncpy(saved_filename, filename, 256); 270 | saved_filename[strlen(saved_filename) - 4] = 0; 271 | strcat(saved_filename, "_detected_edges.png"); 272 | break; 273 | default: 274 | break; 275 | } 276 | 277 | if (action > 0) { 278 | // Save the file and indicate what the file was saved as. 279 | unsigned char* output_png = ppm_to_png(output, output_width, 280 | output_height); 281 | dealloc3df(output, 3, output_height, output_width); 282 | error = lodepng_encode24_file(saved_filename, output_png, 283 | output_width, output_height); 284 | if (error) { 285 | printf("Error (%u) saving file: %s\n\n\n", error, 286 | lodepng_error_text(error)); 287 | } else { 288 | printf("The file was successfully saved as %s.\n\n\n", 289 | saved_filename); 290 | } 291 | } 292 | } 293 | 294 | dealloc3df(input, 3, height, width); 295 | } 296 | -------------------------------------------------------------------------------- /gradient_filter.c: -------------------------------------------------------------------------------- 1 | #include "gradient_filter.h" 2 | #include "array_utility.h" 3 | #include "kernel_filter.h" 4 | 5 | #include 6 | 7 | float*** gradient_filter(float*** input, int M_in, int N_in) 8 | { 9 | printf("Which gradient filter would you like to apply?\n"); 10 | printf("1) Roberts operator.\n"); 11 | printf("2) Sobel operator.\n"); 12 | printf("3) Prewitt operator--3-by-3 kernel.\n"); 13 | printf("4) Prewitt operator--5-by-5 kernel.\n"); 14 | printf("5) Vertical operator.\n"); 15 | printf("6) Horizontal operator.\n"); 16 | printf("7) Diagonal operator (changes from Northwest direction).\n"); 17 | printf("8) Diagonal operator (changes from Northeast direction).\n\n"); 18 | int action; 19 | scanf("%d", &action); 20 | 21 | float*** output; 22 | switch (action) { 23 | case 2: 24 | printf("Applying the Sobel operator...\n"); 25 | output = sobel_operator(input, M_in, N_in); 26 | break; 27 | case 3: 28 | printf("Applying the Prewitt operator with a 3-by-3 kernel...\n"); 29 | output = prewitt_operator_3by3kernel(input, M_in, N_in); 30 | break; 31 | case 4: 32 | printf("Applying the Prewitt operator with a 5-by-5 kernel...\n"); 33 | output = prewitt_operator_5by5kernel(input, M_in, N_in); 34 | break; 35 | case 5: 36 | printf("Applying the Vertical operator...\n"); 37 | output = vertical_operator(input, M_in, N_in); 38 | break; 39 | case 6: 40 | printf("Applying the Horizontal operator...\n"); 41 | output = horizontal_operator(input, M_in, N_in); 42 | break; 43 | case 7: 44 | printf("Applying the Diagonal operator (changes from Northwest direction)...\n"); 45 | output = diagonal_compass_nw_operator(input, M_in, N_in); 46 | break; 47 | case 8: 48 | printf("Applying Diagonal operator (changes from Northeast direction)...\n"); 49 | output = diagonal_compass_ne_operator(input, M_in, N_in); 50 | break; 51 | default: 52 | printf("Applying the Roberts operator...\n"); 53 | output = roberts_operator(input, M_in, N_in); 54 | break; 55 | } 56 | 57 | return output; 58 | } 59 | 60 | float*** roberts_operator(float*** input, int M_in, int N_in) 61 | { 62 | // Declare output. 63 | float*** output = alloc3df(3, M_in, N_in); 64 | 65 | // Define our first kernel. 66 | float** kernel1 = alloc2df(3, 3); 67 | kernel1[0][0] = -1; kernel1[0][1] = 1; kernel1[0][2] = 0; 68 | kernel1[1][0] = 0; kernel1[1][1] = 0; kernel1[1][2] = 0; 69 | kernel1[2][0] = 0; kernel1[2][1] = 0; kernel1[2][2] = 0; 70 | 71 | // Define our second kernel. 72 | float** kernel2 = alloc2df(3, 3); 73 | kernel2[0][0] = -1; kernel2[0][1] = 0; kernel2[0][2] = 0; 74 | kernel2[1][0] = 1; kernel2[1][1] = 0; kernel2[1][2] = 0; 75 | kernel2[2][0] = 0; kernel2[2][1] = 0; kernel2[2][2] = 0; 76 | 77 | // Find the pixel matrix for each pixel, determine our g_m and g_n, find 78 | // the magnitude, and set the new pixel equal to that value. 79 | int i, j, k; 80 | for (k = 0; k < 3; k++) { 81 | for (i = 0; i < M_in; i++) { 82 | for (j = 0; j < N_in; j++) { 83 | float** pixel_matrix = find_pixel_matrix(input[k], M_in, 84 | N_in, i, j, 3); 85 | float g_m = convolve_matrices(pixel_matrix, kernel1, 3); 86 | float g_n = convolve_matrices(pixel_matrix, kernel2, 3); 87 | 88 | float new_value = sqrt(pow(g_m, 2) + pow(g_n, 2)); 89 | output[k][i][j] = new_value; 90 | } 91 | } 92 | } 93 | 94 | return output; 95 | } 96 | 97 | float*** sobel_operator(float*** input, int M_in, int N_in) 98 | { 99 | // Declare output. 100 | float*** output = alloc3df(3, M_in, N_in); 101 | 102 | // Define our first kernel. 103 | float** kernel1 = alloc2df(3, 3); 104 | kernel1[0][0] = -1; kernel1[0][1] = 0; kernel1[0][2] = 1; 105 | kernel1[1][0] = -2; kernel1[1][1] = 0; kernel1[1][2] = 2; 106 | kernel1[2][0] = -1; kernel1[2][1] = 0; kernel1[2][2] = 1; 107 | 108 | // Define our second kernel. 109 | float** kernel2 = alloc2df(3, 3); 110 | kernel2[0][0] = -1; kernel2[0][1] = -2; kernel2[0][2] = -2; 111 | kernel2[1][0] = 0; kernel2[1][1] = 0; kernel2[1][2] = 0; 112 | kernel2[2][0] = 1; kernel2[2][1] = 2; kernel2[2][2] = 1; 113 | 114 | // Find the pixel matrix for each pixel, determine our g_m and g_n, find 115 | // the magnitude, and set the new pixel equal to that value. 116 | int i, j, k; 117 | for (k = 0; k < 3; k++) { 118 | for (i = 0; i < M_in; i++) { 119 | for (j = 0; j < N_in; j++) { 120 | float** pixel_matrix = find_pixel_matrix(input[k], M_in, 121 | N_in, i, j, 3); 122 | float g_m = convolve_matrices(pixel_matrix, kernel1, 3); 123 | float g_n = convolve_matrices(pixel_matrix, kernel2, 3); 124 | 125 | float new_value = sqrt(pow(g_m, 2) + pow(g_n, 2)); 126 | output[k][i][j] = new_value; 127 | } 128 | } 129 | } 130 | 131 | return output; 132 | } 133 | 134 | float*** prewitt_operator_3by3kernel(float*** input, int M_in, int N_in) 135 | { 136 | // Declare output. 137 | float*** output = alloc3df(3, M_in, N_in); 138 | 139 | // Define our first kernel. 140 | float** kernel1 = alloc2df(3, 3); 141 | kernel1[0][0] = -1; kernel1[0][1] = 0; kernel1[0][2] = 1; 142 | kernel1[1][0] = -1; kernel1[1][1] = 0; kernel1[1][2] = 1; 143 | kernel1[2][0] = -1; kernel1[2][1] = 0; kernel1[2][2] = 1; 144 | 145 | // Define our second kernel. 146 | float** kernel2 = alloc2df(3, 3); 147 | kernel2[0][0] = -1; kernel2[0][1] = -1; kernel2[0][2] = -1; 148 | kernel2[1][0] = 0; kernel2[1][1] = 0; kernel2[1][2] = 0; 149 | kernel2[2][0] = 1; kernel2[2][1] = 1; kernel2[2][2] = 1; 150 | 151 | // Find the pixel matrix for each pixel, determine our g_m and g_n, find 152 | // the magnitude, and set the new pixel equal to that value. 153 | int i, j, k; 154 | for (k = 0; k < 3; k++) { 155 | for (i = 0; i < M_in; i++) { 156 | for (j = 0; j < N_in; j++) { 157 | float** pixel_matrix = find_pixel_matrix(input[k], M_in, 158 | N_in, i, j, 3); 159 | float g_m = convolve_matrices(pixel_matrix, kernel1, 3); 160 | float g_n = convolve_matrices(pixel_matrix, kernel2, 3); 161 | 162 | float new_value = sqrt(pow(g_m, 2) + pow(g_n, 2)); 163 | output[k][i][j] = new_value; 164 | } 165 | } 166 | } 167 | 168 | return output; 169 | } 170 | 171 | float*** prewitt_operator_5by5kernel(float*** input, int M_in, int N_in) 172 | { 173 | // Declare output. 174 | float*** output = alloc3df(3, M_in, N_in); 175 | 176 | // Define our first kernel. 177 | float** kernel1 = alloc2df(5, 5); 178 | kernel1[0][0] = -3; kernel1[0][1] = -1; kernel1[0][2] = 1; 179 | kernel1[0][3] = 3; kernel1[0][4] = 0; 180 | kernel1[1][0] = -3; kernel1[1][1] = -1; kernel1[1][2] = 1; 181 | kernel1[1][3] = 3; kernel1[1][4] = 0; 182 | kernel1[2][0] = -3; kernel1[2][1] = -1; kernel1[2][2] = 1; 183 | kernel1[2][3] = 3; kernel1[2][4] = 0; 184 | kernel1[3][0] = -3; kernel1[3][1] = -1; kernel1[3][2] = 1; 185 | kernel1[3][3] = 3; kernel1[3][4] = 0; 186 | kernel1[4][0] = 0; kernel1[4][1] = 0; kernel1[4][2] = 0; 187 | kernel1[4][3] = 0; kernel1[4][4] = 0; 188 | 189 | // Define our second kernel. 190 | float** kernel2 = alloc2df(5, 5); 191 | kernel2[0][0] = -3; kernel2[0][1] = -3; kernel2[0][2] = -3; 192 | kernel2[0][3] = 3; kernel2[0][4] = 0; 193 | kernel2[1][0] = -1; kernel2[1][1] = -1; kernel2[1][2] = -1; 194 | kernel2[1][3] = -1; kernel2[1][4] = 0; 195 | kernel2[2][0] = 1; kernel2[2][1] = 1; kernel2[2][2] = 1; 196 | kernel2[2][3] = 1; kernel2[2][4] = 0; 197 | kernel2[3][0] = 3; kernel2[3][1] = 3; kernel2[3][2] = 3; 198 | kernel2[3][3] = 3; kernel2[3][4] = 0; 199 | kernel2[4][0] = 0; kernel2[4][1] = 0; kernel2[4][2] = 0; 200 | kernel2[4][3] = 0; kernel2[4][4] = 0; 201 | 202 | // Find the pixel matrix for each pixel, determine our g_m and g_n, find 203 | // the magnitude, and set the new pixel equal to that value. 204 | int i, j, k; 205 | for (k = 0; k < 3; k++) { 206 | for (i = 0; i < M_in; i++) { 207 | for (j = 0; j < N_in; j++) { 208 | float** pixel_matrix = find_pixel_matrix(input[k], M_in, 209 | N_in, i, j, 5); 210 | float g_m = convolve_matrices(pixel_matrix, kernel1, 5); 211 | float g_n = convolve_matrices(pixel_matrix, kernel2, 5); 212 | 213 | float new_value = sqrt(pow(g_m, 2) + pow(g_n, 2)); 214 | output[k][i][j] = new_value; 215 | } 216 | } 217 | } 218 | 219 | return output; 220 | } 221 | 222 | float*** vertical_operator(float*** input, int M_in, int N_in) 223 | { 224 | // Declare output. 225 | float*** output = alloc3df(3, M_in, N_in); 226 | 227 | // Define our first kernel. 228 | float** kernel1 = alloc2df(3, 3); 229 | kernel1[0][0] = -1; kernel1[0][1] = 0; kernel1[0][2] = 1; 230 | kernel1[1][0] = -1; kernel1[1][1] = 0; kernel1[1][2] = 1; 231 | kernel1[2][0] = -1; kernel1[2][1] = 0; kernel1[2][2] = 1; 232 | 233 | // Define our second kernel. 234 | float** kernel2 = alloc2df(3, 3); 235 | kernel2[0][0] = 1; kernel2[0][1] = 0; kernel2[0][2] = -1; 236 | kernel2[1][0] = 1; kernel2[1][1] = 0; kernel2[1][2] = -1; 237 | kernel2[2][0] = 1; kernel2[2][1] = 0; kernel2[2][2] = -1; 238 | 239 | // Find the pixel matrix for each pixel, determine our g_m and g_n, find 240 | // the magnitude, and set the new pixel equal to that value. 241 | int i, j, k; 242 | for (k = 0; k < 3; k++) { 243 | for (i = 0; i < M_in; i++) { 244 | for (j = 0; j < N_in; j++) { 245 | float** pixel_matrix = find_pixel_matrix(input[k], M_in, 246 | N_in, i, j, 3); 247 | float g_m = convolve_matrices(pixel_matrix, kernel1, 3); 248 | float g_n = convolve_matrices(pixel_matrix, kernel2, 3); 249 | 250 | float new_value = sqrt(pow(g_m, 2) + pow(g_n, 2)); 251 | output[k][i][j] = new_value; 252 | } 253 | } 254 | } 255 | 256 | return output; 257 | } 258 | 259 | float*** horizontal_operator(float*** input, int M_in, int N_in) 260 | { 261 | // Declare output. 262 | float*** output = alloc3df(3, M_in, N_in); 263 | 264 | // Define our first kernel. 265 | float** kernel1 = alloc2df(3, 3); 266 | kernel1[0][0] = 1; kernel1[0][1] = 1; kernel1[0][2] = 1; 267 | kernel1[1][0] = 0; kernel1[1][1] = 0; kernel1[1][2] = 0; 268 | kernel1[2][0] = -1; kernel1[2][1] = -1; kernel1[2][2] = -1; 269 | 270 | // Define our second kernel. 271 | float** kernel2 = alloc2df(3, 3); 272 | kernel2[0][0] = -1; kernel2[0][1] = -1; kernel2[0][2] = -1; 273 | kernel2[1][0] = 0; kernel2[1][1] = 0; kernel2[1][2] = 0; 274 | kernel2[2][0] = 1; kernel2[2][1] = 1; kernel2[2][2] = 1; 275 | 276 | // Find the pixel matrix for each pixel, determine our g_m and g_n, find 277 | // the magnitude, and set the new pixel equal to that value. 278 | int i, j, k; 279 | for (k = 0; k < 3; k++) { 280 | for (i = 0; i < M_in; i++) { 281 | for (j = 0; j < N_in; j++) { 282 | float** pixel_matrix = find_pixel_matrix(input[k], M_in, 283 | N_in, i, j, 3); 284 | float g_m = convolve_matrices(pixel_matrix, kernel1, 3); 285 | float g_n = convolve_matrices(pixel_matrix, kernel2, 3); 286 | 287 | float new_value = sqrt(pow(g_m, 2) + pow(g_n, 2)); 288 | output[k][i][j] = new_value; 289 | } 290 | } 291 | } 292 | 293 | return output; 294 | } 295 | 296 | float*** diagonal_compass_nw_operator(float*** input, int M_in, int N_in) 297 | { 298 | // Declare output. 299 | float*** output = alloc3df(3, M_in, N_in); 300 | 301 | // Define our first kernel. 302 | float** kernel1 = alloc2df(3, 3); 303 | kernel1[0][0] = 0; kernel1[0][1] = 1; kernel1[0][2] = 1; 304 | kernel1[1][0] = -1; kernel1[1][1] = 0; kernel1[1][2] = 1; 305 | kernel1[2][0] = -1; kernel1[2][1] = -1; kernel1[2][2] = 0; 306 | 307 | // Define our second kernel. 308 | float** kernel2 = alloc2df(3, 3); 309 | kernel2[0][0] = 0; kernel2[0][1] = -1; kernel2[0][2] = -1; 310 | kernel2[1][0] = 1; kernel2[1][1] = 0; kernel2[1][2] = -1; 311 | kernel2[2][0] = 1; kernel2[2][1] = 1; kernel2[2][2] = 0; 312 | 313 | // Find the pixel matrix for each pixel, determine our g_m and g_n, find 314 | // the magnitude, and set the new pixel equal to that value. 315 | int i, j, k; 316 | for (k = 0; k < 3; k++) { 317 | for (i = 0; i < M_in; i++) { 318 | for (j = 0; j < N_in; j++) { 319 | float** pixel_matrix = find_pixel_matrix(input[k], M_in, 320 | N_in, i, j, 3); 321 | float g_m = convolve_matrices(pixel_matrix, kernel1, 3); 322 | float g_n = convolve_matrices(pixel_matrix, kernel2, 3); 323 | 324 | float new_value = sqrt(pow(g_m, 2) + pow(g_n, 2)); 325 | output[k][i][j] = new_value; 326 | } 327 | } 328 | } 329 | 330 | return output; 331 | } 332 | 333 | 334 | float*** diagonal_compass_ne_operator(float*** input, int M_in, int N_in) 335 | { 336 | // Declare output. 337 | float*** output = alloc3df(3, M_in, N_in); 338 | 339 | // Define our first kernel. 340 | float** kernel1 = alloc2df(3, 3); 341 | kernel1[0][0] = 1; kernel1[0][1] = 1; kernel1[0][2] = 0; 342 | kernel1[1][0] = 1; kernel1[1][1] = 0; kernel1[1][2] = -1; 343 | kernel1[2][0] = 0; kernel1[2][1] = -1; kernel1[2][2] = -1; 344 | 345 | // Define our second kernel. 346 | float** kernel2 = alloc2df(3, 3); 347 | kernel2[0][0] = -1; kernel2[0][1] = -1; kernel2[0][2] = 0; 348 | kernel2[1][0] = -1; kernel2[1][1] = 0; kernel2[1][2] = 1; 349 | kernel2[2][0] = 0; kernel2[2][1] = 1; kernel2[2][2] = 1; 350 | 351 | // Find the pixel matrix for each pixel, determine our g_m and g_n, find 352 | // the magnitude, and set the new pixel equal to that value. 353 | int i, j, k; 354 | for (k = 0; k < 3; k++) { 355 | for (i = 0; i < M_in; i++) { 356 | for (j = 0; j < N_in; j++) { 357 | float** pixel_matrix = find_pixel_matrix(input[k], M_in, 358 | N_in, i, j, 3); 359 | float g_m = convolve_matrices(pixel_matrix, kernel1, 3); 360 | float g_n = convolve_matrices(pixel_matrix, kernel2, 3); 361 | 362 | float new_value = sqrt(pow(g_m, 2) + pow(g_n, 2)); 363 | output[k][i][j] = new_value; 364 | } 365 | } 366 | } 367 | 368 | return output; 369 | } 370 | -------------------------------------------------------------------------------- /lodepng.h: -------------------------------------------------------------------------------- 1 | /* 2 | LodePNG version 20131222 3 | 4 | Copyright (c) 2005-2013 Lode Vandevenne 5 | 6 | This software is provided 'as-is', without any express or implied 7 | warranty. In no event will the authors be held liable for any damages 8 | arising from the use of this software. 9 | 10 | Permission is granted to anyone to use this software for any purpose, 11 | including commercial applications, and to alter it and redistribute it 12 | freely, subject to the following restrictions: 13 | 14 | 1. The origin of this software must not be misrepresented; you must not 15 | claim that you wrote the original software. If you use this software 16 | in a product, an acknowledgment in the product documentation would be 17 | appreciated but is not required. 18 | 19 | 2. Altered source versions must be plainly marked as such, and must not be 20 | misrepresented as being the original software. 21 | 22 | 3. This notice may not be removed or altered from any source 23 | distribution. 24 | */ 25 | 26 | #ifndef LODEPNG_H 27 | #define LODEPNG_H 28 | 29 | #include /*for size_t*/ 30 | 31 | #ifdef __cplusplus 32 | #include 33 | #include 34 | #endif /*__cplusplus*/ 35 | 36 | /* 37 | The following #defines are used to create code sections. They can be disabled 38 | to disable code sections, which can give faster compile time and smaller binary. 39 | The "NO_COMPILE" defines are designed to be used to pass as defines to the 40 | compiler command to disable them without modifying this header, e.g. 41 | -DLODEPNG_NO_COMPILE_ZLIB for gcc. 42 | */ 43 | /*deflate & zlib. If disabled, you must specify alternative zlib functions in 44 | the custom_zlib field of the compress and decompress settings*/ 45 | #ifndef LODEPNG_NO_COMPILE_ZLIB 46 | #define LODEPNG_COMPILE_ZLIB 47 | #endif 48 | /*png encoder and png decoder*/ 49 | #ifndef LODEPNG_NO_COMPILE_PNG 50 | #define LODEPNG_COMPILE_PNG 51 | #endif 52 | /*deflate&zlib decoder and png decoder*/ 53 | #ifndef LODEPNG_NO_COMPILE_DECODER 54 | #define LODEPNG_COMPILE_DECODER 55 | #endif 56 | /*deflate&zlib encoder and png encoder*/ 57 | #ifndef LODEPNG_NO_COMPILE_ENCODER 58 | #define LODEPNG_COMPILE_ENCODER 59 | #endif 60 | /*the optional built in harddisk file loading and saving functions*/ 61 | #ifndef LODEPNG_NO_COMPILE_DISK 62 | #define LODEPNG_COMPILE_DISK 63 | #endif 64 | /*support for chunks other than IHDR, IDAT, PLTE, tRNS, IEND: ancillary and unknown chunks*/ 65 | #ifndef LODEPNG_NO_COMPILE_ANCILLARY_CHUNKS 66 | #define LODEPNG_COMPILE_ANCILLARY_CHUNKS 67 | #endif 68 | /*ability to convert error numerical codes to English text string*/ 69 | #ifndef LODEPNG_NO_COMPILE_ERROR_TEXT 70 | #define LODEPNG_COMPILE_ERROR_TEXT 71 | #endif 72 | /*Compile the default allocators (C's free, malloc and realloc). If you disable this, 73 | you can define the functions lodepng_free, lodepng_malloc and lodepng_realloc in your 74 | source files with custom allocators.*/ 75 | #ifndef LODEPNG_NO_COMPILE_ALLOCATORS 76 | #define LODEPNG_COMPILE_ALLOCATORS 77 | #endif 78 | /*compile the C++ version (you can disable the C++ wrapper here even when compiling for C++)*/ 79 | #ifdef __cplusplus 80 | #ifndef LODEPNG_NO_COMPILE_CPP 81 | #define LODEPNG_COMPILE_CPP 82 | #endif 83 | #endif 84 | 85 | #ifdef LODEPNG_COMPILE_PNG 86 | /*The PNG color types (also used for raw).*/ 87 | typedef enum LodePNGColorType 88 | { 89 | LCT_GREY = 0, /*greyscale: 1,2,4,8,16 bit*/ 90 | LCT_RGB = 2, /*RGB: 8,16 bit*/ 91 | LCT_PALETTE = 3, /*palette: 1,2,4,8 bit*/ 92 | LCT_GREY_ALPHA = 4, /*greyscale with alpha: 8,16 bit*/ 93 | LCT_RGBA = 6 /*RGB with alpha: 8,16 bit*/ 94 | } LodePNGColorType; 95 | 96 | #ifdef LODEPNG_COMPILE_DECODER 97 | /* 98 | Converts PNG data in memory to raw pixel data. 99 | out: Output parameter. Pointer to buffer that will contain the raw pixel data. 100 | After decoding, its size is w * h * (bytes per pixel) bytes larger than 101 | initially. Bytes per pixel depends on colortype and bitdepth. 102 | Must be freed after usage with free(*out). 103 | Note: for 16-bit per channel colors, uses big endian format like PNG does. 104 | w: Output parameter. Pointer to width of pixel data. 105 | h: Output parameter. Pointer to height of pixel data. 106 | in: Memory buffer with the PNG file. 107 | insize: size of the in buffer. 108 | colortype: the desired color type for the raw output image. See explanation on PNG color types. 109 | bitdepth: the desired bit depth for the raw output image. See explanation on PNG color types. 110 | Return value: LodePNG error code (0 means no error). 111 | */ 112 | unsigned lodepng_decode_memory(unsigned char** out, unsigned* w, unsigned* h, 113 | const unsigned char* in, size_t insize, 114 | LodePNGColorType colortype, unsigned bitdepth); 115 | 116 | /*Same as lodepng_decode_memory, but always decodes to 32-bit RGBA raw image*/ 117 | unsigned lodepng_decode32(unsigned char** out, unsigned* w, unsigned* h, 118 | const unsigned char* in, size_t insize); 119 | 120 | /*Same as lodepng_decode_memory, but always decodes to 24-bit RGB raw image*/ 121 | unsigned lodepng_decode24(unsigned char** out, unsigned* w, unsigned* h, 122 | const unsigned char* in, size_t insize); 123 | 124 | #ifdef LODEPNG_COMPILE_DISK 125 | /* 126 | Load PNG from disk, from file with given name. 127 | Same as the other decode functions, but instead takes a filename as input. 128 | */ 129 | unsigned lodepng_decode_file(unsigned char** out, unsigned* w, unsigned* h, 130 | const char* filename, 131 | LodePNGColorType colortype, unsigned bitdepth); 132 | 133 | /*Same as lodepng_decode_file, but always decodes to 32-bit RGBA raw image.*/ 134 | unsigned lodepng_decode32_file(unsigned char** out, unsigned* w, unsigned* h, 135 | const char* filename); 136 | 137 | /*Same as lodepng_decode_file, but always decodes to 24-bit RGB raw image.*/ 138 | unsigned lodepng_decode24_file(unsigned char** out, unsigned* w, unsigned* h, 139 | const char* filename); 140 | #endif /*LODEPNG_COMPILE_DISK*/ 141 | #endif /*LODEPNG_COMPILE_DECODER*/ 142 | 143 | 144 | #ifdef LODEPNG_COMPILE_ENCODER 145 | /* 146 | Converts raw pixel data into a PNG image in memory. The colortype and bitdepth 147 | of the output PNG image cannot be chosen, they are automatically determined 148 | by the colortype, bitdepth and content of the input pixel data. 149 | Note: for 16-bit per channel colors, needs big endian format like PNG does. 150 | out: Output parameter. Pointer to buffer that will contain the PNG image data. 151 | Must be freed after usage with free(*out). 152 | outsize: Output parameter. Pointer to the size in bytes of the out buffer. 153 | image: The raw pixel data to encode. The size of this buffer should be 154 | w * h * (bytes per pixel), bytes per pixel depends on colortype and bitdepth. 155 | w: width of the raw pixel data in pixels. 156 | h: height of the raw pixel data in pixels. 157 | colortype: the color type of the raw input image. See explanation on PNG color types. 158 | bitdepth: the bit depth of the raw input image. See explanation on PNG color types. 159 | Return value: LodePNG error code (0 means no error). 160 | */ 161 | unsigned lodepng_encode_memory(unsigned char** out, size_t* outsize, 162 | const unsigned char* image, unsigned w, unsigned h, 163 | LodePNGColorType colortype, unsigned bitdepth); 164 | 165 | /*Same as lodepng_encode_memory, but always encodes from 32-bit RGBA raw image.*/ 166 | unsigned lodepng_encode32(unsigned char** out, size_t* outsize, 167 | const unsigned char* image, unsigned w, unsigned h); 168 | 169 | /*Same as lodepng_encode_memory, but always encodes from 24-bit RGB raw image.*/ 170 | unsigned lodepng_encode24(unsigned char** out, size_t* outsize, 171 | const unsigned char* image, unsigned w, unsigned h); 172 | 173 | #ifdef LODEPNG_COMPILE_DISK 174 | /* 175 | Converts raw pixel data into a PNG file on disk. 176 | Same as the other encode functions, but instead takes a filename as output. 177 | NOTE: This overwrites existing files without warning! 178 | */ 179 | unsigned lodepng_encode_file(const char* filename, 180 | const unsigned char* image, unsigned w, unsigned h, 181 | LodePNGColorType colortype, unsigned bitdepth); 182 | 183 | /*Same as lodepng_encode_file, but always encodes from 32-bit RGBA raw image.*/ 184 | unsigned lodepng_encode32_file(const char* filename, 185 | const unsigned char* image, unsigned w, unsigned h); 186 | 187 | /*Same as lodepng_encode_file, but always encodes from 24-bit RGB raw image.*/ 188 | unsigned lodepng_encode24_file(const char* filename, 189 | const unsigned char* image, unsigned w, unsigned h); 190 | #endif /*LODEPNG_COMPILE_DISK*/ 191 | #endif /*LODEPNG_COMPILE_ENCODER*/ 192 | 193 | 194 | #ifdef LODEPNG_COMPILE_CPP 195 | namespace lodepng 196 | { 197 | #ifdef LODEPNG_COMPILE_DECODER 198 | /*Same as lodepng_decode_memory, but decodes to an std::vector.*/ 199 | unsigned decode(std::vector& out, unsigned& w, unsigned& h, 200 | const unsigned char* in, size_t insize, 201 | LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); 202 | unsigned decode(std::vector& out, unsigned& w, unsigned& h, 203 | const std::vector& in, 204 | LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); 205 | #ifdef LODEPNG_COMPILE_DISK 206 | /* 207 | Converts PNG file from disk to raw pixel data in memory. 208 | Same as the other decode functions, but instead takes a filename as input. 209 | */ 210 | unsigned decode(std::vector& out, unsigned& w, unsigned& h, 211 | const std::string& filename, 212 | LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); 213 | #endif //LODEPNG_COMPILE_DISK 214 | #endif //LODEPNG_COMPILE_DECODER 215 | 216 | #ifdef LODEPNG_COMPILE_ENCODER 217 | /*Same as lodepng_encode_memory, but encodes to an std::vector.*/ 218 | unsigned encode(std::vector& out, 219 | const unsigned char* in, unsigned w, unsigned h, 220 | LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); 221 | unsigned encode(std::vector& out, 222 | const std::vector& in, unsigned w, unsigned h, 223 | LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); 224 | #ifdef LODEPNG_COMPILE_DISK 225 | /* 226 | Converts 32-bit RGBA raw pixel data into a PNG file on disk. 227 | Same as the other encode functions, but instead takes a filename as output. 228 | NOTE: This overwrites existing files without warning! 229 | */ 230 | unsigned encode(const std::string& filename, 231 | const unsigned char* in, unsigned w, unsigned h, 232 | LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); 233 | unsigned encode(const std::string& filename, 234 | const std::vector& in, unsigned w, unsigned h, 235 | LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); 236 | #endif //LODEPNG_COMPILE_DISK 237 | #endif //LODEPNG_COMPILE_ENCODER 238 | } //namespace lodepng 239 | #endif /*LODEPNG_COMPILE_CPP*/ 240 | #endif /*LODEPNG_COMPILE_PNG*/ 241 | 242 | #ifdef LODEPNG_COMPILE_ERROR_TEXT 243 | /*Returns an English description of the numerical error code.*/ 244 | const char* lodepng_error_text(unsigned code); 245 | #endif /*LODEPNG_COMPILE_ERROR_TEXT*/ 246 | 247 | #ifdef LODEPNG_COMPILE_DECODER 248 | /*Settings for zlib decompression*/ 249 | typedef struct LodePNGDecompressSettings LodePNGDecompressSettings; 250 | struct LodePNGDecompressSettings 251 | { 252 | unsigned ignore_adler32; /*if 1, continue and don't give an error message if the Adler32 checksum is corrupted*/ 253 | 254 | /*use custom zlib decoder instead of built in one (default: null)*/ 255 | unsigned (*custom_zlib)(unsigned char**, size_t*, 256 | const unsigned char*, size_t, 257 | const LodePNGDecompressSettings*); 258 | /*use custom deflate decoder instead of built in one (default: null) 259 | if custom_zlib is used, custom_deflate is ignored since only the built in 260 | zlib function will call custom_deflate*/ 261 | unsigned (*custom_inflate)(unsigned char**, size_t*, 262 | const unsigned char*, size_t, 263 | const LodePNGDecompressSettings*); 264 | 265 | const void* custom_context; /*optional custom settings for custom functions*/ 266 | }; 267 | 268 | extern const LodePNGDecompressSettings lodepng_default_decompress_settings; 269 | void lodepng_decompress_settings_init(LodePNGDecompressSettings* settings); 270 | #endif /*LODEPNG_COMPILE_DECODER*/ 271 | 272 | #ifdef LODEPNG_COMPILE_ENCODER 273 | /* 274 | Settings for zlib compression. Tweaking these settings tweaks the balance 275 | between speed and compression ratio. 276 | */ 277 | typedef struct LodePNGCompressSettings LodePNGCompressSettings; 278 | struct LodePNGCompressSettings /*deflate = compress*/ 279 | { 280 | /*LZ77 related settings*/ 281 | unsigned btype; /*the block type for LZ (0, 1, 2 or 3, see zlib standard). Should be 2 for proper compression.*/ 282 | unsigned use_lz77; /*whether or not to use LZ77. Should be 1 for proper compression.*/ 283 | unsigned windowsize; /*must be a power of two <= 32768. higher compresses more but is slower. Typical value: 2048.*/ 284 | unsigned minmatch; /*mininum lz77 length. 3 is normally best, 6 can be better for some PNGs. Default: 0*/ 285 | unsigned nicematch; /*stop searching if >= this length found. Set to 258 for best compression. Default: 128*/ 286 | unsigned lazymatching; /*use lazy matching: better compression but a bit slower. Default: true*/ 287 | 288 | /*use custom zlib encoder instead of built in one (default: null)*/ 289 | unsigned (*custom_zlib)(unsigned char**, size_t*, 290 | const unsigned char*, size_t, 291 | const LodePNGCompressSettings*); 292 | /*use custom deflate encoder instead of built in one (default: null) 293 | if custom_zlib is used, custom_deflate is ignored since only the built in 294 | zlib function will call custom_deflate*/ 295 | unsigned (*custom_deflate)(unsigned char**, size_t*, 296 | const unsigned char*, size_t, 297 | const LodePNGCompressSettings*); 298 | 299 | const void* custom_context; /*optional custom settings for custom functions*/ 300 | }; 301 | 302 | extern const LodePNGCompressSettings lodepng_default_compress_settings; 303 | void lodepng_compress_settings_init(LodePNGCompressSettings* settings); 304 | #endif /*LODEPNG_COMPILE_ENCODER*/ 305 | 306 | #ifdef LODEPNG_COMPILE_PNG 307 | /* 308 | Color mode of an image. Contains all information required to decode the pixel 309 | bits to RGBA colors. This information is the same as used in the PNG file 310 | format, and is used both for PNG and raw image data in LodePNG. 311 | */ 312 | typedef struct LodePNGColorMode 313 | { 314 | /*header (IHDR)*/ 315 | LodePNGColorType colortype; /*color type, see PNG standard or documentation further in this header file*/ 316 | unsigned bitdepth; /*bits per sample, see PNG standard or documentation further in this header file*/ 317 | 318 | /* 319 | palette (PLTE and tRNS) 320 | 321 | Dynamically allocated with the colors of the palette, including alpha. 322 | When encoding a PNG, to store your colors in the palette of the LodePNGColorMode, first use 323 | lodepng_palette_clear, then for each color use lodepng_palette_add. 324 | If you encode an image without alpha with palette, don't forget to put value 255 in each A byte of the palette. 325 | 326 | When decoding, by default you can ignore this palette, since LodePNG already 327 | fills the palette colors in the pixels of the raw RGBA output. 328 | 329 | The palette is only supported for color type 3. 330 | */ 331 | unsigned char* palette; /*palette in RGBARGBA... order. When allocated, must be either 0, or have size 1024*/ 332 | size_t palettesize; /*palette size in number of colors (amount of bytes is 4 * palettesize)*/ 333 | 334 | /* 335 | transparent color key (tRNS) 336 | 337 | This color uses the same bit depth as the bitdepth value in this struct, which can be 1-bit to 16-bit. 338 | For greyscale PNGs, r, g and b will all 3 be set to the same. 339 | 340 | When decoding, by default you can ignore this information, since LodePNG sets 341 | pixels with this key to transparent already in the raw RGBA output. 342 | 343 | The color key is only supported for color types 0 and 2. 344 | */ 345 | unsigned key_defined; /*is a transparent color key given? 0 = false, 1 = true*/ 346 | unsigned key_r; /*red/greyscale component of color key*/ 347 | unsigned key_g; /*green component of color key*/ 348 | unsigned key_b; /*blue component of color key*/ 349 | } LodePNGColorMode; 350 | 351 | /*init, cleanup and copy functions to use with this struct*/ 352 | void lodepng_color_mode_init(LodePNGColorMode* info); 353 | void lodepng_color_mode_cleanup(LodePNGColorMode* info); 354 | /*return value is error code (0 means no error)*/ 355 | unsigned lodepng_color_mode_copy(LodePNGColorMode* dest, const LodePNGColorMode* source); 356 | 357 | void lodepng_palette_clear(LodePNGColorMode* info); 358 | /*add 1 color to the palette*/ 359 | unsigned lodepng_palette_add(LodePNGColorMode* info, 360 | unsigned char r, unsigned char g, unsigned char b, unsigned char a); 361 | 362 | /*get the total amount of bits per pixel, based on colortype and bitdepth in the struct*/ 363 | unsigned lodepng_get_bpp(const LodePNGColorMode* info); 364 | /*get the amount of color channels used, based on colortype in the struct. 365 | If a palette is used, it counts as 1 channel.*/ 366 | unsigned lodepng_get_channels(const LodePNGColorMode* info); 367 | /*is it a greyscale type? (only colortype 0 or 4)*/ 368 | unsigned lodepng_is_greyscale_type(const LodePNGColorMode* info); 369 | /*has it got an alpha channel? (only colortype 2 or 6)*/ 370 | unsigned lodepng_is_alpha_type(const LodePNGColorMode* info); 371 | /*has it got a palette? (only colortype 3)*/ 372 | unsigned lodepng_is_palette_type(const LodePNGColorMode* info); 373 | /*only returns true if there is a palette and there is a value in the palette with alpha < 255. 374 | Loops through the palette to check this.*/ 375 | unsigned lodepng_has_palette_alpha(const LodePNGColorMode* info); 376 | /* 377 | Check if the given color info indicates the possibility of having non-opaque pixels in the PNG image. 378 | Returns true if the image can have translucent or invisible pixels (it still be opaque if it doesn't use such pixels). 379 | Returns false if the image can only have opaque pixels. 380 | In detail, it returns true only if it's a color type with alpha, or has a palette with non-opaque values, 381 | or if "key_defined" is true. 382 | */ 383 | unsigned lodepng_can_have_alpha(const LodePNGColorMode* info); 384 | /*Returns the byte size of a raw image buffer with given width, height and color mode*/ 385 | size_t lodepng_get_raw_size(unsigned w, unsigned h, const LodePNGColorMode* color); 386 | 387 | #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS 388 | /*The information of a Time chunk in PNG.*/ 389 | typedef struct LodePNGTime 390 | { 391 | unsigned year; /*2 bytes used (0-65535)*/ 392 | unsigned month; /*1-12*/ 393 | unsigned day; /*1-31*/ 394 | unsigned hour; /*0-23*/ 395 | unsigned minute; /*0-59*/ 396 | unsigned second; /*0-60 (to allow for leap seconds)*/ 397 | } LodePNGTime; 398 | #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ 399 | 400 | /*Information about the PNG image, except pixels, width and height.*/ 401 | typedef struct LodePNGInfo 402 | { 403 | /*header (IHDR), palette (PLTE) and transparency (tRNS) chunks*/ 404 | unsigned compression_method;/*compression method of the original file. Always 0.*/ 405 | unsigned filter_method; /*filter method of the original file*/ 406 | unsigned interlace_method; /*interlace method of the original file*/ 407 | LodePNGColorMode color; /*color type and bits, palette and transparency of the PNG file*/ 408 | 409 | #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS 410 | /* 411 | suggested background color chunk (bKGD) 412 | This color uses the same color mode as the PNG (except alpha channel), which can be 1-bit to 16-bit. 413 | 414 | For greyscale PNGs, r, g and b will all 3 be set to the same. When encoding 415 | the encoder writes the red one. For palette PNGs: When decoding, the RGB value 416 | will be stored, not a palette index. But when encoding, specify the index of 417 | the palette in background_r, the other two are then ignored. 418 | 419 | The decoder does not use this background color to edit the color of pixels. 420 | */ 421 | unsigned background_defined; /*is a suggested background color given?*/ 422 | unsigned background_r; /*red component of suggested background color*/ 423 | unsigned background_g; /*green component of suggested background color*/ 424 | unsigned background_b; /*blue component of suggested background color*/ 425 | 426 | /* 427 | non-international text chunks (tEXt and zTXt) 428 | 429 | The char** arrays each contain num strings. The actual messages are in 430 | text_strings, while text_keys are keywords that give a short description what 431 | the actual text represents, e.g. Title, Author, Description, or anything else. 432 | 433 | A keyword is minimum 1 character and maximum 79 characters long. It's 434 | discouraged to use a single line length longer than 79 characters for texts. 435 | 436 | Don't allocate these text buffers yourself. Use the init/cleanup functions 437 | correctly and use lodepng_add_text and lodepng_clear_text. 438 | */ 439 | size_t text_num; /*the amount of texts in these char** buffers (there may be more texts in itext)*/ 440 | char** text_keys; /*the keyword of a text chunk (e.g. "Comment")*/ 441 | char** text_strings; /*the actual text*/ 442 | 443 | /* 444 | international text chunks (iTXt) 445 | Similar to the non-international text chunks, but with additional strings 446 | "langtags" and "transkeys". 447 | */ 448 | size_t itext_num; /*the amount of international texts in this PNG*/ 449 | char** itext_keys; /*the English keyword of the text chunk (e.g. "Comment")*/ 450 | char** itext_langtags; /*language tag for this text's language, ISO/IEC 646 string, e.g. ISO 639 language tag*/ 451 | char** itext_transkeys; /*keyword translated to the international language - UTF-8 string*/ 452 | char** itext_strings; /*the actual international text - UTF-8 string*/ 453 | 454 | /*time chunk (tIME)*/ 455 | unsigned time_defined; /*set to 1 to make the encoder generate a tIME chunk*/ 456 | LodePNGTime time; 457 | 458 | /*phys chunk (pHYs)*/ 459 | unsigned phys_defined; /*if 0, there is no pHYs chunk and the values below are undefined, if 1 else there is one*/ 460 | unsigned phys_x; /*pixels per unit in x direction*/ 461 | unsigned phys_y; /*pixels per unit in y direction*/ 462 | unsigned phys_unit; /*may be 0 (unknown unit) or 1 (metre)*/ 463 | 464 | /* 465 | unknown chunks 466 | There are 3 buffers, one for each position in the PNG where unknown chunks can appear 467 | each buffer contains all unknown chunks for that position consecutively 468 | The 3 buffers are the unknown chunks between certain critical chunks: 469 | 0: IHDR-PLTE, 1: PLTE-IDAT, 2: IDAT-IEND 470 | Do not allocate or traverse this data yourself. Use the chunk traversing functions declared 471 | later, such as lodepng_chunk_next and lodepng_chunk_append, to read/write this struct. 472 | */ 473 | unsigned char* unknown_chunks_data[3]; 474 | size_t unknown_chunks_size[3]; /*size in bytes of the unknown chunks, given for protection*/ 475 | #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ 476 | } LodePNGInfo; 477 | 478 | /*init, cleanup and copy functions to use with this struct*/ 479 | void lodepng_info_init(LodePNGInfo* info); 480 | void lodepng_info_cleanup(LodePNGInfo* info); 481 | /*return value is error code (0 means no error)*/ 482 | unsigned lodepng_info_copy(LodePNGInfo* dest, const LodePNGInfo* source); 483 | 484 | #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS 485 | void lodepng_clear_text(LodePNGInfo* info); /*use this to clear the texts again after you filled them in*/ 486 | unsigned lodepng_add_text(LodePNGInfo* info, const char* key, const char* str); /*push back both texts at once*/ 487 | 488 | void lodepng_clear_itext(LodePNGInfo* info); /*use this to clear the itexts again after you filled them in*/ 489 | unsigned lodepng_add_itext(LodePNGInfo* info, const char* key, const char* langtag, 490 | const char* transkey, const char* str); /*push back the 4 texts of 1 chunk at once*/ 491 | #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ 492 | 493 | /* 494 | Converts raw buffer from one color type to another color type, based on 495 | LodePNGColorMode structs to describe the input and output color type. 496 | See the reference manual at the end of this header file to see which color conversions are supported. 497 | return value = LodePNG error code (0 if all went ok, an error if the conversion isn't supported) 498 | The out buffer must have size (w * h * bpp + 7) / 8, where bpp is the bits per pixel 499 | of the output color type (lodepng_get_bpp) 500 | The fix_png value works as described in struct LodePNGDecoderSettings. 501 | Note: for 16-bit per channel colors, uses big endian format like PNG does. 502 | */ 503 | unsigned lodepng_convert(unsigned char* out, const unsigned char* in, 504 | LodePNGColorMode* mode_out, const LodePNGColorMode* mode_in, 505 | unsigned w, unsigned h, unsigned fix_png); 506 | 507 | #ifdef LODEPNG_COMPILE_DECODER 508 | /* 509 | Settings for the decoder. This contains settings for the PNG and the Zlib 510 | decoder, but not the Info settings from the Info structs. 511 | */ 512 | typedef struct LodePNGDecoderSettings 513 | { 514 | LodePNGDecompressSettings zlibsettings; /*in here is the setting to ignore Adler32 checksums*/ 515 | 516 | unsigned ignore_crc; /*ignore CRC checksums*/ 517 | /* 518 | The fix_png setting, if 1, makes the decoder tolerant towards some PNG images 519 | that do not correctly follow the PNG specification. This only supports errors 520 | that are fixable, were found in images that are actually used on the web, and 521 | are silently tolerated by other decoders as well. Currently only one such fix 522 | is implemented: if a palette index is out of bounds given the palette size, 523 | interpret it as opaque black. 524 | By default this value is 0, which makes it stop with an error on such images. 525 | */ 526 | unsigned fix_png; 527 | unsigned color_convert; /*whether to convert the PNG to the color type you want. Default: yes*/ 528 | 529 | #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS 530 | unsigned read_text_chunks; /*if false but remember_unknown_chunks is true, they're stored in the unknown chunks*/ 531 | /*store all bytes from unknown chunks in the LodePNGInfo (off by default, useful for a png editor)*/ 532 | unsigned remember_unknown_chunks; 533 | #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ 534 | } LodePNGDecoderSettings; 535 | 536 | void lodepng_decoder_settings_init(LodePNGDecoderSettings* settings); 537 | #endif /*LODEPNG_COMPILE_DECODER*/ 538 | 539 | #ifdef LODEPNG_COMPILE_ENCODER 540 | /*automatically use color type with less bits per pixel if losslessly possible. Default: AUTO*/ 541 | typedef enum LodePNGFilterStrategy 542 | { 543 | /*every filter at zero*/ 544 | LFS_ZERO, 545 | /*Use filter that gives minumum sum, as described in the official PNG filter heuristic.*/ 546 | LFS_MINSUM, 547 | /*Use the filter type that gives smallest Shannon entropy for this scanline. Depending 548 | on the image, this is better or worse than minsum.*/ 549 | LFS_ENTROPY, 550 | /* 551 | Brute-force-search PNG filters by compressing each filter for each scanline. 552 | Experimental, very slow, and only rarely gives better compression than MINSUM. 553 | */ 554 | LFS_BRUTE_FORCE, 555 | /*use predefined_filters buffer: you specify the filter type for each scanline*/ 556 | LFS_PREDEFINED 557 | } LodePNGFilterStrategy; 558 | 559 | /*automatically use color type with less bits per pixel if losslessly possible. Default: LAC_AUTO*/ 560 | typedef enum LodePNGAutoConvert 561 | { 562 | LAC_NO, /*use color type user requested*/ 563 | LAC_ALPHA, /*use color type user requested, but if only opaque pixels and RGBA or grey+alpha, use RGB or grey*/ 564 | LAC_AUTO, /*use PNG color type that can losslessly represent the uncompressed image the smallest possible*/ 565 | /* 566 | like AUTO, but do not choose 1, 2 or 4 bit per pixel types. 567 | sometimes a PNG image compresses worse if less than 8 bits per pixels. 568 | */ 569 | LAC_AUTO_NO_NIBBLES, 570 | /* 571 | like AUTO, but never choose palette color type. For small images, encoding 572 | the palette may take more bytes than what is gained. Note that AUTO also 573 | already prevents encoding the palette for extremely small images, but that may 574 | not be sufficient because due to the compression it cannot predict when to 575 | switch. 576 | */ 577 | LAC_AUTO_NO_PALETTE, 578 | LAC_AUTO_NO_NIBBLES_NO_PALETTE 579 | } LodePNGAutoConvert; 580 | 581 | 582 | /* 583 | Automatically chooses color type that gives smallest amount of bits in the 584 | output image, e.g. grey if there are only greyscale pixels, palette if there 585 | are less than 256 colors, ... 586 | The auto_convert parameter allows limiting it to not use palette, ... 587 | */ 588 | unsigned lodepng_auto_choose_color(LodePNGColorMode* mode_out, 589 | const unsigned char* image, unsigned w, unsigned h, 590 | const LodePNGColorMode* mode_in, 591 | LodePNGAutoConvert auto_convert); 592 | 593 | /*Settings for the encoder.*/ 594 | typedef struct LodePNGEncoderSettings 595 | { 596 | LodePNGCompressSettings zlibsettings; /*settings for the zlib encoder, such as window size, ...*/ 597 | 598 | LodePNGAutoConvert auto_convert; /*how to automatically choose output PNG color type, if at all*/ 599 | 600 | /*If true, follows the official PNG heuristic: if the PNG uses a palette or lower than 601 | 8 bit depth, set all filters to zero. Otherwise use the filter_strategy. Note that to 602 | completely follow the official PNG heuristic, filter_palette_zero must be true and 603 | filter_strategy must be LFS_MINSUM*/ 604 | unsigned filter_palette_zero; 605 | /*Which filter strategy to use when not using zeroes due to filter_palette_zero. 606 | Set filter_palette_zero to 0 to ensure always using your chosen strategy. Default: LFS_MINSUM*/ 607 | LodePNGFilterStrategy filter_strategy; 608 | /*used if filter_strategy is LFS_PREDEFINED. In that case, this must point to a buffer with 609 | the same length as the amount of scanlines in the image, and each value must <= 5. You 610 | have to cleanup this buffer, LodePNG will never free it. Don't forget that filter_palette_zero 611 | must be set to 0 to ensure this is also used on palette or low bitdepth images.*/ 612 | const unsigned char* predefined_filters; 613 | 614 | /*force creating a PLTE chunk if colortype is 2 or 6 (= a suggested palette). 615 | If colortype is 3, PLTE is _always_ created.*/ 616 | unsigned force_palette; 617 | #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS 618 | /*add LodePNG identifier and version as a text chunk, for debugging*/ 619 | unsigned add_id; 620 | /*encode text chunks as zTXt chunks instead of tEXt chunks, and use compression in iTXt chunks*/ 621 | unsigned text_compression; 622 | #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ 623 | } LodePNGEncoderSettings; 624 | 625 | void lodepng_encoder_settings_init(LodePNGEncoderSettings* settings); 626 | #endif /*LODEPNG_COMPILE_ENCODER*/ 627 | 628 | 629 | #if defined(LODEPNG_COMPILE_DECODER) || defined(LODEPNG_COMPILE_ENCODER) 630 | /*The settings, state and information for extended encoding and decoding.*/ 631 | typedef struct LodePNGState 632 | { 633 | #ifdef LODEPNG_COMPILE_DECODER 634 | LodePNGDecoderSettings decoder; /*the decoding settings*/ 635 | #endif /*LODEPNG_COMPILE_DECODER*/ 636 | #ifdef LODEPNG_COMPILE_ENCODER 637 | LodePNGEncoderSettings encoder; /*the encoding settings*/ 638 | #endif /*LODEPNG_COMPILE_ENCODER*/ 639 | LodePNGColorMode info_raw; /*specifies the format in which you would like to get the raw pixel buffer*/ 640 | LodePNGInfo info_png; /*info of the PNG image obtained after decoding*/ 641 | unsigned error; 642 | #ifdef LODEPNG_COMPILE_CPP 643 | //For the lodepng::State subclass. 644 | virtual ~LodePNGState(){} 645 | #endif 646 | } LodePNGState; 647 | 648 | /*init, cleanup and copy functions to use with this struct*/ 649 | void lodepng_state_init(LodePNGState* state); 650 | void lodepng_state_cleanup(LodePNGState* state); 651 | void lodepng_state_copy(LodePNGState* dest, const LodePNGState* source); 652 | #endif /* defined(LODEPNG_COMPILE_DECODER) || defined(LODEPNG_COMPILE_ENCODER) */ 653 | 654 | #ifdef LODEPNG_COMPILE_DECODER 655 | /* 656 | Same as lodepng_decode_memory, but uses a LodePNGState to allow custom settings and 657 | getting much more information about the PNG image and color mode. 658 | */ 659 | unsigned lodepng_decode(unsigned char** out, unsigned* w, unsigned* h, 660 | LodePNGState* state, 661 | const unsigned char* in, size_t insize); 662 | 663 | /* 664 | Read the PNG header, but not the actual data. This returns only the information 665 | that is in the header chunk of the PNG, such as width, height and color type. The 666 | information is placed in the info_png field of the LodePNGState. 667 | */ 668 | unsigned lodepng_inspect(unsigned* w, unsigned* h, 669 | LodePNGState* state, 670 | const unsigned char* in, size_t insize); 671 | #endif /*LODEPNG_COMPILE_DECODER*/ 672 | 673 | 674 | #ifdef LODEPNG_COMPILE_ENCODER 675 | /*This function allocates the out buffer with standard malloc and stores the size in *outsize.*/ 676 | unsigned lodepng_encode(unsigned char** out, size_t* outsize, 677 | const unsigned char* image, unsigned w, unsigned h, 678 | LodePNGState* state); 679 | #endif /*LODEPNG_COMPILE_ENCODER*/ 680 | 681 | /* 682 | The lodepng_chunk functions are normally not needed, except to traverse the 683 | unknown chunks stored in the LodePNGInfo struct, or add new ones to it. 684 | It also allows traversing the chunks of an encoded PNG file yourself. 685 | 686 | PNG standard chunk naming conventions: 687 | First byte: uppercase = critical, lowercase = ancillary 688 | Second byte: uppercase = public, lowercase = private 689 | Third byte: must be uppercase 690 | Fourth byte: uppercase = unsafe to copy, lowercase = safe to copy 691 | */ 692 | 693 | /*get the length of the data of the chunk. Total chunk length has 12 bytes more.*/ 694 | unsigned lodepng_chunk_length(const unsigned char* chunk); 695 | 696 | /*puts the 4-byte type in null terminated string*/ 697 | void lodepng_chunk_type(char type[5], const unsigned char* chunk); 698 | 699 | /*check if the type is the given type*/ 700 | unsigned char lodepng_chunk_type_equals(const unsigned char* chunk, const char* type); 701 | 702 | /*0: it's one of the critical chunk types, 1: it's an ancillary chunk (see PNG standard)*/ 703 | unsigned char lodepng_chunk_ancillary(const unsigned char* chunk); 704 | 705 | /*0: public, 1: private (see PNG standard)*/ 706 | unsigned char lodepng_chunk_private(const unsigned char* chunk); 707 | 708 | /*0: the chunk is unsafe to copy, 1: the chunk is safe to copy (see PNG standard)*/ 709 | unsigned char lodepng_chunk_safetocopy(const unsigned char* chunk); 710 | 711 | /*get pointer to the data of the chunk, where the input points to the header of the chunk*/ 712 | unsigned char* lodepng_chunk_data(unsigned char* chunk); 713 | const unsigned char* lodepng_chunk_data_const(const unsigned char* chunk); 714 | 715 | /*returns 0 if the crc is correct, 1 if it's incorrect (0 for OK as usual!)*/ 716 | unsigned lodepng_chunk_check_crc(const unsigned char* chunk); 717 | 718 | /*generates the correct CRC from the data and puts it in the last 4 bytes of the chunk*/ 719 | void lodepng_chunk_generate_crc(unsigned char* chunk); 720 | 721 | /*iterate to next chunks. don't use on IEND chunk, as there is no next chunk then*/ 722 | unsigned char* lodepng_chunk_next(unsigned char* chunk); 723 | const unsigned char* lodepng_chunk_next_const(const unsigned char* chunk); 724 | 725 | /* 726 | Appends chunk to the data in out. The given chunk should already have its chunk header. 727 | The out variable and outlength are updated to reflect the new reallocated buffer. 728 | Returns error code (0 if it went ok) 729 | */ 730 | unsigned lodepng_chunk_append(unsigned char** out, size_t* outlength, const unsigned char* chunk); 731 | 732 | /* 733 | Appends new chunk to out. The chunk to append is given by giving its length, type 734 | and data separately. The type is a 4-letter string. 735 | The out variable and outlength are updated to reflect the new reallocated buffer. 736 | Returne error code (0 if it went ok) 737 | */ 738 | unsigned lodepng_chunk_create(unsigned char** out, size_t* outlength, unsigned length, 739 | const char* type, const unsigned char* data); 740 | 741 | 742 | /*Calculate CRC32 of buffer*/ 743 | unsigned lodepng_crc32(const unsigned char* buf, size_t len); 744 | #endif /*LODEPNG_COMPILE_PNG*/ 745 | 746 | 747 | #ifdef LODEPNG_COMPILE_ZLIB 748 | /* 749 | This zlib part can be used independently to zlib compress and decompress a 750 | buffer. It cannot be used to create gzip files however, and it only supports the 751 | part of zlib that is required for PNG, it does not support dictionaries. 752 | */ 753 | 754 | #ifdef LODEPNG_COMPILE_DECODER 755 | /*Inflate a buffer. Inflate is the decompression step of deflate. Out buffer must be freed after use.*/ 756 | unsigned lodepng_inflate(unsigned char** out, size_t* outsize, 757 | const unsigned char* in, size_t insize, 758 | const LodePNGDecompressSettings* settings); 759 | 760 | /* 761 | Decompresses Zlib data. Reallocates the out buffer and appends the data. The 762 | data must be according to the zlib specification. 763 | Either, *out must be NULL and *outsize must be 0, or, *out must be a valid 764 | buffer and *outsize its size in bytes. out must be freed by user after usage. 765 | */ 766 | unsigned lodepng_zlib_decompress(unsigned char** out, size_t* outsize, 767 | const unsigned char* in, size_t insize, 768 | const LodePNGDecompressSettings* settings); 769 | #endif /*LODEPNG_COMPILE_DECODER*/ 770 | 771 | #ifdef LODEPNG_COMPILE_ENCODER 772 | /* 773 | Compresses data with Zlib. Reallocates the out buffer and appends the data. 774 | Zlib adds a small header and trailer around the deflate data. 775 | The data is output in the format of the zlib specification. 776 | Either, *out must be NULL and *outsize must be 0, or, *out must be a valid 777 | buffer and *outsize its size in bytes. out must be freed by user after usage. 778 | */ 779 | unsigned lodepng_zlib_compress(unsigned char** out, size_t* outsize, 780 | const unsigned char* in, size_t insize, 781 | const LodePNGCompressSettings* settings); 782 | 783 | /* 784 | Find length-limited Huffman code for given frequencies. This function is in the 785 | public interface only for tests, it's used internally by lodepng_deflate. 786 | */ 787 | unsigned lodepng_huffman_code_lengths(unsigned* lengths, const unsigned* frequencies, 788 | size_t numcodes, unsigned maxbitlen); 789 | 790 | /*Compress a buffer with deflate. See RFC 1951. Out buffer must be freed after use.*/ 791 | unsigned lodepng_deflate(unsigned char** out, size_t* outsize, 792 | const unsigned char* in, size_t insize, 793 | const LodePNGCompressSettings* settings); 794 | 795 | #endif /*LODEPNG_COMPILE_ENCODER*/ 796 | #endif /*LODEPNG_COMPILE_ZLIB*/ 797 | 798 | #ifdef LODEPNG_COMPILE_DISK 799 | /* 800 | Load a file from disk into buffer. The function allocates the out buffer, and 801 | after usage you should free it. 802 | out: output parameter, contains pointer to loaded buffer. 803 | outsize: output parameter, size of the allocated out buffer 804 | filename: the path to the file to load 805 | return value: error code (0 means ok) 806 | */ 807 | unsigned lodepng_load_file(unsigned char** out, size_t* outsize, const char* filename); 808 | 809 | /* 810 | Save a file from buffer to disk. Warning, if it exists, this function overwrites 811 | the file without warning! 812 | buffer: the buffer to write 813 | buffersize: size of the buffer to write 814 | filename: the path to the file to save to 815 | return value: error code (0 means ok) 816 | */ 817 | unsigned lodepng_save_file(const unsigned char* buffer, size_t buffersize, const char* filename); 818 | #endif /*LODEPNG_COMPILE_DISK*/ 819 | 820 | #ifdef LODEPNG_COMPILE_CPP 821 | //The LodePNG C++ wrapper uses std::vectors instead of manually allocated memory buffers. 822 | namespace lodepng 823 | { 824 | #ifdef LODEPNG_COMPILE_PNG 825 | class State : public LodePNGState 826 | { 827 | public: 828 | State(); 829 | State(const State& other); 830 | virtual ~State(); 831 | State& operator=(const State& other); 832 | }; 833 | 834 | #ifdef LODEPNG_COMPILE_DECODER 835 | //Same as other lodepng::decode, but using a State for more settings and information. 836 | unsigned decode(std::vector& out, unsigned& w, unsigned& h, 837 | State& state, 838 | const unsigned char* in, size_t insize); 839 | unsigned decode(std::vector& out, unsigned& w, unsigned& h, 840 | State& state, 841 | const std::vector& in); 842 | #endif /*LODEPNG_COMPILE_DECODER*/ 843 | 844 | #ifdef LODEPNG_COMPILE_ENCODER 845 | //Same as other lodepng::encode, but using a State for more settings and information. 846 | unsigned encode(std::vector& out, 847 | const unsigned char* in, unsigned w, unsigned h, 848 | State& state); 849 | unsigned encode(std::vector& out, 850 | const std::vector& in, unsigned w, unsigned h, 851 | State& state); 852 | #endif /*LODEPNG_COMPILE_ENCODER*/ 853 | 854 | #ifdef LODEPNG_COMPILE_DISK 855 | /* 856 | Load a file from disk into an std::vector. If the vector is empty, then either 857 | the file doesn't exist or is an empty file. 858 | */ 859 | void load_file(std::vector& buffer, const std::string& filename); 860 | 861 | /* 862 | Save the binary data in an std::vector to a file on disk. The file is overwritten 863 | without warning. 864 | */ 865 | void save_file(const std::vector& buffer, const std::string& filename); 866 | #endif //LODEPNG_COMPILE_DISK 867 | #endif //LODEPNG_COMPILE_PNG 868 | 869 | #ifdef LODEPNG_COMPILE_ZLIB 870 | #ifdef LODEPNG_COMPILE_DECODER 871 | //Zlib-decompress an unsigned char buffer 872 | unsigned decompress(std::vector& out, const unsigned char* in, size_t insize, 873 | const LodePNGDecompressSettings& settings = lodepng_default_decompress_settings); 874 | 875 | //Zlib-decompress an std::vector 876 | unsigned decompress(std::vector& out, const std::vector& in, 877 | const LodePNGDecompressSettings& settings = lodepng_default_decompress_settings); 878 | #endif //LODEPNG_COMPILE_DECODER 879 | 880 | #ifdef LODEPNG_COMPILE_ENCODER 881 | //Zlib-compress an unsigned char buffer 882 | unsigned compress(std::vector& out, const unsigned char* in, size_t insize, 883 | const LodePNGCompressSettings& settings = lodepng_default_compress_settings); 884 | 885 | //Zlib-compress an std::vector 886 | unsigned compress(std::vector& out, const std::vector& in, 887 | const LodePNGCompressSettings& settings = lodepng_default_compress_settings); 888 | #endif //LODEPNG_COMPILE_ENCODER 889 | #endif //LODEPNG_COMPILE_ZLIB 890 | } //namespace lodepng 891 | #endif /*LODEPNG_COMPILE_CPP*/ 892 | 893 | /* 894 | TODO: 895 | [.] test if there are no memory leaks or security exploits - done a lot but needs to be checked often 896 | [.] check compatibility with vareous compilers - done but needs to be redone for every newer version 897 | [X] converting color to 16-bit per channel types 898 | [ ] read all public PNG chunk types (but never let the color profile and gamma ones touch RGB values) 899 | [ ] make sure encoder generates no chunks with size > (2^31)-1 900 | [ ] partial decoding (stream processing) 901 | [X] let the "isFullyOpaque" function check color keys and transparent palettes too 902 | [X] better name for the variables "codes", "codesD", "codelengthcodes", "clcl" and "lldl" 903 | [ ] don't stop decoding on errors like 69, 57, 58 (make warnings) 904 | [ ] make option to choose if the raw image with non multiple of 8 bits per scanline should have padding bits or not 905 | [ ] let the C++ wrapper catch exceptions coming from the standard library and return LodePNG error codes 906 | */ 907 | 908 | #endif /*LODEPNG_H inclusion guard*/ 909 | 910 | /* 911 | LodePNG Documentation 912 | --------------------- 913 | 914 | 0. table of contents 915 | -------------------- 916 | 917 | 1. about 918 | 1.1. supported features 919 | 1.2. features not supported 920 | 2. C and C++ version 921 | 3. security 922 | 4. decoding 923 | 5. encoding 924 | 6. color conversions 925 | 6.1. PNG color types 926 | 6.2. color conversions 927 | 6.3. padding bits 928 | 6.4. A note about 16-bits per channel and endianness 929 | 7. error values 930 | 8. chunks and PNG editing 931 | 9. compiler support 932 | 10. examples 933 | 10.1. decoder C++ example 934 | 10.2. decoder C example 935 | 11. changes 936 | 12. contact information 937 | 938 | 939 | 1. about 940 | -------- 941 | 942 | PNG is a file format to store raster images losslessly with good compression, 943 | supporting different color types and alpha channel. 944 | 945 | LodePNG is a PNG codec according to the Portable Network Graphics (PNG) 946 | Specification (Second Edition) - W3C Recommendation 10 November 2003. 947 | 948 | The specifications used are: 949 | 950 | *) Portable Network Graphics (PNG) Specification (Second Edition): 951 | http://www.w3.org/TR/2003/REC-PNG-20031110 952 | *) RFC 1950 ZLIB Compressed Data Format version 3.3: 953 | http://www.gzip.org/zlib/rfc-zlib.html 954 | *) RFC 1951 DEFLATE Compressed Data Format Specification ver 1.3: 955 | http://www.gzip.org/zlib/rfc-deflate.html 956 | 957 | The most recent version of LodePNG can currently be found at 958 | http://lodev.org/lodepng/ 959 | 960 | LodePNG works both in C (ISO C90) and C++, with a C++ wrapper that adds 961 | extra functionality. 962 | 963 | LodePNG exists out of two files: 964 | -lodepng.h: the header file for both C and C++ 965 | -lodepng.c(pp): give it the name lodepng.c or lodepng.cpp (or .cc) depending on your usage 966 | 967 | If you want to start using LodePNG right away without reading this doc, get the 968 | examples from the LodePNG website to see how to use it in code, or check the 969 | smaller examples in chapter 13 here. 970 | 971 | LodePNG is simple but only supports the basic requirements. To achieve 972 | simplicity, the following design choices were made: There are no dependencies 973 | on any external library. There are functions to decode and encode a PNG with 974 | a single function call, and extended versions of these functions taking a 975 | LodePNGState struct allowing to specify or get more information. By default 976 | the colors of the raw image are always RGB or RGBA, no matter what color type 977 | the PNG file uses. To read and write files, there are simple functions to 978 | convert the files to/from buffers in memory. 979 | 980 | This all makes LodePNG suitable for loading textures in games, demos and small 981 | programs, ... It's less suitable for full fledged image editors, loading PNGs 982 | over network (it requires all the image data to be available before decoding can 983 | begin), life-critical systems, ... 984 | 985 | 1.1. supported features 986 | ----------------------- 987 | 988 | The following features are supported by the decoder: 989 | 990 | *) decoding of PNGs with any color type, bit depth and interlace mode, to a 24- or 32-bit color raw image, 991 | or the same color type as the PNG 992 | *) encoding of PNGs, from any raw image to 24- or 32-bit color, or the same color type as the raw image 993 | *) Adam7 interlace and deinterlace for any color type 994 | *) loading the image from harddisk or decoding it from a buffer from other sources than harddisk 995 | *) support for alpha channels, including RGBA color model, translucent palettes and color keying 996 | *) zlib decompression (inflate) 997 | *) zlib compression (deflate) 998 | *) CRC32 and ADLER32 checksums 999 | *) handling of unknown chunks, allowing making a PNG editor that stores custom and unknown chunks. 1000 | *) the following chunks are supported (generated/interpreted) by both encoder and decoder: 1001 | IHDR: header information 1002 | PLTE: color palette 1003 | IDAT: pixel data 1004 | IEND: the final chunk 1005 | tRNS: transparency for palettized images 1006 | tEXt: textual information 1007 | zTXt: compressed textual information 1008 | iTXt: international textual information 1009 | bKGD: suggested background color 1010 | pHYs: physical dimensions 1011 | tIME: modification time 1012 | 1013 | 1.2. features not supported 1014 | --------------------------- 1015 | 1016 | The following features are _not_ supported: 1017 | 1018 | *) some features needed to make a conformant PNG-Editor might be still missing. 1019 | *) partial loading/stream processing. All data must be available and is processed in one call. 1020 | *) The following public chunks are not supported but treated as unknown chunks by LodePNG 1021 | cHRM, gAMA, iCCP, sRGB, sBIT, hIST, sPLT 1022 | Some of these are not supported on purpose: LodePNG wants to provide the RGB values 1023 | stored in the pixels, not values modified by system dependent gamma or color models. 1024 | 1025 | 1026 | 2. C and C++ version 1027 | -------------------- 1028 | 1029 | The C version uses buffers allocated with alloc that you need to free() 1030 | yourself. You need to use init and cleanup functions for each struct whenever 1031 | using a struct from the C version to avoid exploits and memory leaks. 1032 | 1033 | The C++ version has extra functions with std::vectors in the interface and the 1034 | lodepng::State class which is a LodePNGState with constructor and destructor. 1035 | 1036 | These files work without modification for both C and C++ compilers because all 1037 | the additional C++ code is in "#ifdef __cplusplus" blocks that make C-compilers 1038 | ignore it, and the C code is made to compile both with strict ISO C90 and C++. 1039 | 1040 | To use the C++ version, you need to rename the source file to lodepng.cpp 1041 | (instead of lodepng.c), and compile it with a C++ compiler. 1042 | 1043 | To use the C version, you need to rename the source file to lodepng.c (instead 1044 | of lodepng.cpp), and compile it with a C compiler. 1045 | 1046 | 1047 | 3. Security 1048 | ----------- 1049 | 1050 | Even if carefully designed, it's always possible that LodePNG contains possible 1051 | exploits. If you discover one, please let me know, and it will be fixed. 1052 | 1053 | When using LodePNG, care has to be taken with the C version of LodePNG, as well 1054 | as the C-style structs when working with C++. The following conventions are used 1055 | for all C-style structs: 1056 | 1057 | -if a struct has a corresponding init function, always call the init function when making a new one 1058 | -if a struct has a corresponding cleanup function, call it before the struct disappears to avoid memory leaks 1059 | -if a struct has a corresponding copy function, use the copy function instead of "=". 1060 | The destination must also be inited already. 1061 | 1062 | 1063 | 4. Decoding 1064 | ----------- 1065 | 1066 | Decoding converts a PNG compressed image to a raw pixel buffer. 1067 | 1068 | Most documentation on using the decoder is at its declarations in the header 1069 | above. For C, simple decoding can be done with functions such as 1070 | lodepng_decode32, and more advanced decoding can be done with the struct 1071 | LodePNGState and lodepng_decode. For C++, all decoding can be done with the 1072 | various lodepng::decode functions, and lodepng::State can be used for advanced 1073 | features. 1074 | 1075 | When using the LodePNGState, it uses the following fields for decoding: 1076 | *) LodePNGInfo info_png: it stores extra information about the PNG (the input) in here 1077 | *) LodePNGColorMode info_raw: here you can say what color mode of the raw image (the output) you want to get 1078 | *) LodePNGDecoderSettings decoder: you can specify a few extra settings for the decoder to use 1079 | 1080 | LodePNGInfo info_png 1081 | -------------------- 1082 | 1083 | After decoding, this contains extra information of the PNG image, except the actual 1084 | pixels, width and height because these are already gotten directly from the decoder 1085 | functions. 1086 | 1087 | It contains for example the original color type of the PNG image, text comments, 1088 | suggested background color, etc... More details about the LodePNGInfo struct are 1089 | at its declaration documentation. 1090 | 1091 | LodePNGColorMode info_raw 1092 | ------------------------- 1093 | 1094 | When decoding, here you can specify which color type you want 1095 | the resulting raw image to be. If this is different from the colortype of the 1096 | PNG, then the decoder will automatically convert the result. This conversion 1097 | always works, except if you want it to convert a color PNG to greyscale or to 1098 | a palette with missing colors. 1099 | 1100 | By default, 32-bit color is used for the result. 1101 | 1102 | LodePNGDecoderSettings decoder 1103 | ------------------------------ 1104 | 1105 | The settings can be used to ignore the errors created by invalid CRC and Adler32 1106 | chunks, and to disable the decoding of tEXt chunks. 1107 | 1108 | There's also a setting color_convert, true by default. If false, no conversion 1109 | is done, the resulting data will be as it was in the PNG (after decompression) 1110 | and you'll have to puzzle the colors of the pixels together yourself using the 1111 | color type information in the LodePNGInfo. 1112 | 1113 | 1114 | 5. Encoding 1115 | ----------- 1116 | 1117 | Encoding converts a raw pixel buffer to a PNG compressed image. 1118 | 1119 | Most documentation on using the encoder is at its declarations in the header 1120 | above. For C, simple encoding can be done with functions such as 1121 | lodepng_encode32, and more advanced decoding can be done with the struct 1122 | LodePNGState and lodepng_encode. For C++, all encoding can be done with the 1123 | various lodepng::encode functions, and lodepng::State can be used for advanced 1124 | features. 1125 | 1126 | Like the decoder, the encoder can also give errors. However it gives less errors 1127 | since the encoder input is trusted, the decoder input (a PNG image that could 1128 | be forged by anyone) is not trusted. 1129 | 1130 | When using the LodePNGState, it uses the following fields for encoding: 1131 | *) LodePNGInfo info_png: here you specify how you want the PNG (the output) to be. 1132 | *) LodePNGColorMode info_raw: here you say what color type of the raw image (the input) has 1133 | *) LodePNGEncoderSettings encoder: you can specify a few settings for the encoder to use 1134 | 1135 | LodePNGInfo info_png 1136 | -------------------- 1137 | 1138 | When encoding, you use this the opposite way as when decoding: for encoding, 1139 | you fill in the values you want the PNG to have before encoding. By default it's 1140 | not needed to specify a color type for the PNG since it's automatically chosen, 1141 | but it's possible to choose it yourself given the right settings. 1142 | 1143 | The encoder will not always exactly match the LodePNGInfo struct you give, 1144 | it tries as close as possible. Some things are ignored by the encoder. The 1145 | encoder uses, for example, the following settings from it when applicable: 1146 | colortype and bitdepth, text chunks, time chunk, the color key, the palette, the 1147 | background color, the interlace method, unknown chunks, ... 1148 | 1149 | When encoding to a PNG with colortype 3, the encoder will generate a PLTE chunk. 1150 | If the palette contains any colors for which the alpha channel is not 255 (so 1151 | there are translucent colors in the palette), it'll add a tRNS chunk. 1152 | 1153 | LodePNGColorMode info_raw 1154 | ------------------------- 1155 | 1156 | You specify the color type of the raw image that you give to the input here, 1157 | including a possible transparent color key and palette you happen to be using in 1158 | your raw image data. 1159 | 1160 | By default, 32-bit color is assumed, meaning your input has to be in RGBA 1161 | format with 4 bytes (unsigned chars) per pixel. 1162 | 1163 | LodePNGEncoderSettings encoder 1164 | ------------------------------ 1165 | 1166 | The following settings are supported (some are in sub-structs): 1167 | *) auto_convert: when this option is enabled, the encoder will 1168 | automatically choose the smallest possible color mode (including color key) that 1169 | can encode the colors of all pixels without information loss. 1170 | *) btype: the block type for LZ77. 0 = uncompressed, 1 = fixed huffman tree, 1171 | 2 = dynamic huffman tree (best compression). Should be 2 for proper 1172 | compression. 1173 | *) use_lz77: whether or not to use LZ77 for compressed block types. Should be 1174 | true for proper compression. 1175 | *) windowsize: the window size used by the LZ77 encoder (1 - 32768). Has value 1176 | 2048 by default, but can be set to 32768 for better, but slow, compression. 1177 | *) force_palette: if colortype is 2 or 6, you can make the encoder write a PLTE 1178 | chunk if force_palette is true. This can used as suggested palette to convert 1179 | to by viewers that don't support more than 256 colors (if those still exist) 1180 | *) add_id: add text chunk "Encoder: LodePNG " to the image. 1181 | *) text_compression: default 1. If 1, it'll store texts as zTXt instead of tEXt chunks. 1182 | zTXt chunks use zlib compression on the text. This gives a smaller result on 1183 | large texts but a larger result on small texts (such as a single program name). 1184 | It's all tEXt or all zTXt though, there's no separate setting per text yet. 1185 | 1186 | 1187 | 6. color conversions 1188 | -------------------- 1189 | 1190 | An important thing to note about LodePNG, is that the color type of the PNG, and 1191 | the color type of the raw image, are completely independent. By default, when 1192 | you decode a PNG, you get the result as a raw image in the color type you want, 1193 | no matter whether the PNG was encoded with a palette, greyscale or RGBA color. 1194 | And if you encode an image, by default LodePNG will automatically choose the PNG 1195 | color type that gives good compression based on the values of colors and amount 1196 | of colors in the image. It can be configured to let you control it instead as 1197 | well, though. 1198 | 1199 | To be able to do this, LodePNG does conversions from one color mode to another. 1200 | It can convert from almost any color type to any other color type, except the 1201 | following conversions: RGB to greyscale is not supported, and converting to a 1202 | palette when the palette doesn't have a required color is not supported. This is 1203 | not supported on purpose: this is information loss which requires a color 1204 | reduction algorithm that is beyong the scope of a PNG encoder (yes, RGB to grey 1205 | is easy, but there are multiple ways if you want to give some channels more 1206 | weight). 1207 | 1208 | By default, when decoding, you get the raw image in 32-bit RGBA or 24-bit RGB 1209 | color, no matter what color type the PNG has. And by default when encoding, 1210 | LodePNG automatically picks the best color model for the output PNG, and expects 1211 | the input image to be 32-bit RGBA or 24-bit RGB. So, unless you want to control 1212 | the color format of the images yourself, you can skip this chapter. 1213 | 1214 | 6.1. PNG color types 1215 | -------------------- 1216 | 1217 | A PNG image can have many color types, ranging from 1-bit color to 64-bit color, 1218 | as well as palettized color modes. After the zlib decompression and unfiltering 1219 | in the PNG image is done, the raw pixel data will have that color type and thus 1220 | a certain amount of bits per pixel. If you want the output raw image after 1221 | decoding to have another color type, a conversion is done by LodePNG. 1222 | 1223 | The PNG specification gives the following color types: 1224 | 1225 | 0: greyscale, bit depths 1, 2, 4, 8, 16 1226 | 2: RGB, bit depths 8 and 16 1227 | 3: palette, bit depths 1, 2, 4 and 8 1228 | 4: greyscale with alpha, bit depths 8 and 16 1229 | 6: RGBA, bit depths 8 and 16 1230 | 1231 | Bit depth is the amount of bits per pixel per color channel. So the total amount 1232 | of bits per pixel is: amount of channels * bitdepth. 1233 | 1234 | 6.2. color conversions 1235 | ---------------------- 1236 | 1237 | As explained in the sections about the encoder and decoder, you can specify 1238 | color types and bit depths in info_png and info_raw to change the default 1239 | behaviour. 1240 | 1241 | If, when decoding, you want the raw image to be something else than the default, 1242 | you need to set the color type and bit depth you want in the LodePNGColorMode, 1243 | or the parameters of the simple function of LodePNG you're using. 1244 | 1245 | If, when encoding, you use another color type than the default in the input 1246 | image, you need to specify its color type and bit depth in the LodePNGColorMode 1247 | of the raw image, or use the parameters of the simplefunction of LodePNG you're 1248 | using. 1249 | 1250 | If, when encoding, you don't want LodePNG to choose the output PNG color type 1251 | but control it yourself, you need to set auto_convert in the encoder settings 1252 | to LAC_NONE, and specify the color type you want in the LodePNGInfo of the 1253 | encoder. 1254 | 1255 | If you do any of the above, LodePNG may need to do a color conversion, which 1256 | follows the rules below, and may sometimes not be allowed. 1257 | 1258 | To avoid some confusion: 1259 | -the decoder converts from PNG to raw image 1260 | -the encoder converts from raw image to PNG 1261 | -the colortype and bitdepth in LodePNGColorMode info_raw, are those of the raw image 1262 | -the colortype and bitdepth in the color field of LodePNGInfo info_png, are those of the PNG 1263 | -when encoding, the color type in LodePNGInfo is ignored if auto_convert 1264 | is enabled, it is automatically generated instead 1265 | -when decoding, the color type in LodePNGInfo is set by the decoder to that of the original 1266 | PNG image, but it can be ignored since the raw image has the color type you requested instead 1267 | -if the color type of the LodePNGColorMode and PNG image aren't the same, a conversion 1268 | between the color types is done if the color types are supported. If it is not 1269 | supported, an error is returned. If the types are the same, no conversion is done. 1270 | -even though some conversions aren't supported, LodePNG supports loading PNGs from any 1271 | colortype and saving PNGs to any colortype, sometimes it just requires preparing 1272 | the raw image correctly before encoding. 1273 | -both encoder and decoder use the same color converter. 1274 | 1275 | Non supported color conversions: 1276 | -color to greyscale: no error is thrown, but the result will look ugly because 1277 | only the red channel is taken 1278 | -anything, to palette when that palette does not have that color in it: in this 1279 | case an error is thrown 1280 | 1281 | Supported color conversions: 1282 | -anything to 8-bit RGB, 8-bit RGBA, 16-bit RGB, 16-bit RGBA 1283 | -any grey or grey+alpha, to grey or grey+alpha 1284 | -anything to a palette, as long as the palette has the requested colors in it 1285 | -removing alpha channel 1286 | -higher to smaller bitdepth, and vice versa 1287 | 1288 | If you want no color conversion to be done: 1289 | -In the encoder, you can make it save a PNG with any color type by giving the 1290 | raw color mode and LodePNGInfo the same color mode, and setting auto_convert to 1291 | LAC_NO. 1292 | -In the decoder, you can make it store the pixel data in the same color type 1293 | as the PNG has, by setting the color_convert setting to false. Settings in 1294 | info_raw are then ignored. 1295 | 1296 | The function lodepng_convert does the color conversion. It is available in the 1297 | interface but normally isn't needed since the encoder and decoder already call 1298 | it. 1299 | 1300 | 6.3. padding bits 1301 | ----------------- 1302 | 1303 | In the PNG file format, if a less than 8-bit per pixel color type is used and the scanlines 1304 | have a bit amount that isn't a multiple of 8, then padding bits are used so that each 1305 | scanline starts at a fresh byte. But that is NOT true for the LodePNG raw input and output. 1306 | The raw input image you give to the encoder, and the raw output image you get from the decoder 1307 | will NOT have these padding bits, e.g. in the case of a 1-bit image with a width 1308 | of 7 pixels, the first pixel of the second scanline will the the 8th bit of the first byte, 1309 | not the first bit of a new byte. 1310 | 1311 | 6.4. A note about 16-bits per channel and endianness 1312 | ---------------------------------------------------- 1313 | 1314 | LodePNG uses unsigned char arrays for 16-bit per channel colors too, just like 1315 | for any other color format. The 16-bit values are stored in big endian (most 1316 | significant byte first) in these arrays. This is the opposite order of the 1317 | little endian used by x86 CPU's. 1318 | 1319 | LodePNG always uses big endian because the PNG file format does so internally. 1320 | Conversions to other formats than PNG uses internally are not supported by 1321 | LodePNG on purpose, there are myriads of formats, including endianness of 16-bit 1322 | colors, the order in which you store R, G, B and A, and so on. Supporting and 1323 | converting to/from all that is outside the scope of LodePNG. 1324 | 1325 | This may mean that, depending on your use case, you may want to convert the big 1326 | endian output of LodePNG to little endian with a for loop. This is certainly not 1327 | always needed, many applications and libraries support big endian 16-bit colors 1328 | anyway, but it means you cannot simply cast the unsigned char* buffer to an 1329 | unsigned short* buffer on x86 CPUs. 1330 | 1331 | 1332 | 7. error values 1333 | --------------- 1334 | 1335 | All functions in LodePNG that return an error code, return 0 if everything went 1336 | OK, or a non-zero code if there was an error. 1337 | 1338 | The meaning of the LodePNG error values can be retrieved with the function 1339 | lodepng_error_text: given the numerical error code, it returns a description 1340 | of the error in English as a string. 1341 | 1342 | Check the implementation of lodepng_error_text to see the meaning of each code. 1343 | 1344 | 1345 | 8. chunks and PNG editing 1346 | ------------------------- 1347 | 1348 | If you want to add extra chunks to a PNG you encode, or use LodePNG for a PNG 1349 | editor that should follow the rules about handling of unknown chunks, or if your 1350 | program is able to read other types of chunks than the ones handled by LodePNG, 1351 | then that's possible with the chunk functions of LodePNG. 1352 | 1353 | A PNG chunk has the following layout: 1354 | 1355 | 4 bytes length 1356 | 4 bytes type name 1357 | length bytes data 1358 | 4 bytes CRC 1359 | 1360 | 8.1. iterating through chunks 1361 | ----------------------------- 1362 | 1363 | If you have a buffer containing the PNG image data, then the first chunk (the 1364 | IHDR chunk) starts at byte number 8 of that buffer. The first 8 bytes are the 1365 | signature of the PNG and are not part of a chunk. But if you start at byte 8 1366 | then you have a chunk, and can check the following things of it. 1367 | 1368 | NOTE: none of these functions check for memory buffer boundaries. To avoid 1369 | exploits, always make sure the buffer contains all the data of the chunks. 1370 | When using lodepng_chunk_next, make sure the returned value is within the 1371 | allocated memory. 1372 | 1373 | unsigned lodepng_chunk_length(const unsigned char* chunk): 1374 | 1375 | Get the length of the chunk's data. The total chunk length is this length + 12. 1376 | 1377 | void lodepng_chunk_type(char type[5], const unsigned char* chunk): 1378 | unsigned char lodepng_chunk_type_equals(const unsigned char* chunk, const char* type): 1379 | 1380 | Get the type of the chunk or compare if it's a certain type 1381 | 1382 | unsigned char lodepng_chunk_critical(const unsigned char* chunk): 1383 | unsigned char lodepng_chunk_private(const unsigned char* chunk): 1384 | unsigned char lodepng_chunk_safetocopy(const unsigned char* chunk): 1385 | 1386 | Check if the chunk is critical in the PNG standard (only IHDR, PLTE, IDAT and IEND are). 1387 | Check if the chunk is private (public chunks are part of the standard, private ones not). 1388 | Check if the chunk is safe to copy. If it's not, then, when modifying data in a critical 1389 | chunk, unsafe to copy chunks of the old image may NOT be saved in the new one if your 1390 | program doesn't handle that type of unknown chunk. 1391 | 1392 | unsigned char* lodepng_chunk_data(unsigned char* chunk): 1393 | const unsigned char* lodepng_chunk_data_const(const unsigned char* chunk): 1394 | 1395 | Get a pointer to the start of the data of the chunk. 1396 | 1397 | unsigned lodepng_chunk_check_crc(const unsigned char* chunk): 1398 | void lodepng_chunk_generate_crc(unsigned char* chunk): 1399 | 1400 | Check if the crc is correct or generate a correct one. 1401 | 1402 | unsigned char* lodepng_chunk_next(unsigned char* chunk): 1403 | const unsigned char* lodepng_chunk_next_const(const unsigned char* chunk): 1404 | 1405 | Iterate to the next chunk. This works if you have a buffer with consecutive chunks. Note that these 1406 | functions do no boundary checking of the allocated data whatsoever, so make sure there is enough 1407 | data available in the buffer to be able to go to the next chunk. 1408 | 1409 | unsigned lodepng_chunk_append(unsigned char** out, size_t* outlength, const unsigned char* chunk): 1410 | unsigned lodepng_chunk_create(unsigned char** out, size_t* outlength, unsigned length, 1411 | const char* type, const unsigned char* data): 1412 | 1413 | These functions are used to create new chunks that are appended to the data in *out that has 1414 | length *outlength. The append function appends an existing chunk to the new data. The create 1415 | function creates a new chunk with the given parameters and appends it. Type is the 4-letter 1416 | name of the chunk. 1417 | 1418 | 8.2. chunks in info_png 1419 | ----------------------- 1420 | 1421 | The LodePNGInfo struct contains fields with the unknown chunk in it. It has 3 1422 | buffers (each with size) to contain 3 types of unknown chunks: 1423 | the ones that come before the PLTE chunk, the ones that come between the PLTE 1424 | and the IDAT chunks, and the ones that come after the IDAT chunks. 1425 | It's necessary to make the distionction between these 3 cases because the PNG 1426 | standard forces to keep the ordering of unknown chunks compared to the critical 1427 | chunks, but does not force any other ordering rules. 1428 | 1429 | info_png.unknown_chunks_data[0] is the chunks before PLTE 1430 | info_png.unknown_chunks_data[1] is the chunks after PLTE, before IDAT 1431 | info_png.unknown_chunks_data[2] is the chunks after IDAT 1432 | 1433 | The chunks in these 3 buffers can be iterated through and read by using the same 1434 | way described in the previous subchapter. 1435 | 1436 | When using the decoder to decode a PNG, you can make it store all unknown chunks 1437 | if you set the option settings.remember_unknown_chunks to 1. By default, this 1438 | option is off (0). 1439 | 1440 | The encoder will always encode unknown chunks that are stored in the info_png. 1441 | If you need it to add a particular chunk that isn't known by LodePNG, you can 1442 | use lodepng_chunk_append or lodepng_chunk_create to the chunk data in 1443 | info_png.unknown_chunks_data[x]. 1444 | 1445 | Chunks that are known by LodePNG should not be added in that way. E.g. to make 1446 | LodePNG add a bKGD chunk, set background_defined to true and add the correct 1447 | parameters there instead. 1448 | 1449 | 1450 | 9. compiler support 1451 | ------------------- 1452 | 1453 | No libraries other than the current standard C library are needed to compile 1454 | LodePNG. For the C++ version, only the standard C++ library is needed on top. 1455 | Add the files lodepng.c(pp) and lodepng.h to your project, include 1456 | lodepng.h where needed, and your program can read/write PNG files. 1457 | 1458 | If performance is important, use optimization when compiling! For both the 1459 | encoder and decoder, this makes a large difference. 1460 | 1461 | Make sure that LodePNG is compiled with the same compiler of the same version 1462 | and with the same settings as the rest of the program, or the interfaces with 1463 | std::vectors and std::strings in C++ can be incompatible. 1464 | 1465 | CHAR_BITS must be 8 or higher, because LodePNG uses unsigned chars for octets. 1466 | 1467 | *) gcc and g++ 1468 | 1469 | LodePNG is developed in gcc so this compiler is natively supported. It gives no 1470 | warnings with compiler options "-Wall -Wextra -pedantic -ansi", with gcc and g++ 1471 | version 4.7.1 on Linux, 32-bit and 64-bit. 1472 | 1473 | *) Mingw 1474 | 1475 | The Mingw compiler (a port of gcc) for Windows is fully supported by LodePNG. 1476 | 1477 | *) Visual Studio 2005 and up, Visual C++ Express Edition 2005 and up 1478 | 1479 | Visual Studio may give warnings about 'fopen' being deprecated. A multiplatform library 1480 | can't support the proposed Visual Studio alternative however, so LodePNG keeps using 1481 | fopen. If you don't want to see the deprecated warnings, put this on top of lodepng.h 1482 | before the inclusions: 1483 | #define _CRT_SECURE_NO_DEPRECATE 1484 | 1485 | Other than the above warnings, LodePNG should be warning-free with warning 1486 | level 3 (W3). Warning level 4 (W4) will give warnings about integer conversions. 1487 | I'm not planning to resolve these warnings. To get rid of them, let Visual 1488 | Studio use warning level W3 for lodepng.cpp only: right click lodepng.cpp, 1489 | Properties, C/C++, General, Warning Level: Level 3 (/W3). 1490 | 1491 | Visual Studio may want "stdafx.h" files to be included in each source file and 1492 | give an error "unexpected end of file while looking for precompiled header". 1493 | That is not standard C++ and will not be added to the stock LodePNG. You can 1494 | disable it for lodepng.cpp only by right clicking it, Properties, C/C++, 1495 | Precompiled Headers, and set it to Not Using Precompiled Headers there. 1496 | 1497 | *) Visual Studio 6.0 1498 | 1499 | LodePNG support for Visual Studio 6.0 is not guaranteed because VS6 doesn't 1500 | follow the C++ standard correctly. 1501 | 1502 | *) Comeau C/C++ 1503 | 1504 | Vesion 20070107 compiles without problems on the Comeau C/C++ Online Test Drive 1505 | at http://www.comeaucomputing.com/tryitout in both C90 and C++ mode. 1506 | 1507 | *) Compilers on Macintosh 1508 | 1509 | LodePNG has been reported to work both with the gcc and LLVM for Macintosh, both 1510 | for C and C++. 1511 | 1512 | *) Other Compilers 1513 | 1514 | If you encounter problems on other compilers, feel free to let me know and I may 1515 | try to fix it if the compiler is modern standards complient. 1516 | 1517 | 1518 | 10. examples 1519 | ------------ 1520 | 1521 | This decoder example shows the most basic usage of LodePNG. More complex 1522 | examples can be found on the LodePNG website. 1523 | 1524 | 10.1. decoder C++ example 1525 | ------------------------- 1526 | 1527 | #include "lodepng.h" 1528 | #include 1529 | 1530 | int main(int argc, char *argv[]) 1531 | { 1532 | const char* filename = argc > 1 ? argv[1] : "test.png"; 1533 | 1534 | //load and decode 1535 | std::vector image; 1536 | unsigned width, height; 1537 | unsigned error = lodepng::decode(image, width, height, filename); 1538 | 1539 | //if there's an error, display it 1540 | if(error) std::cout << "decoder error " << error << ": " << lodepng_error_text(error) << std::endl; 1541 | 1542 | //the pixels are now in the vector "image", 4 bytes per pixel, ordered RGBARGBA..., use it as texture, draw it, ... 1543 | } 1544 | 1545 | 10.2. decoder C example 1546 | ----------------------- 1547 | 1548 | #include "lodepng.h" 1549 | 1550 | int main(int argc, char *argv[]) 1551 | { 1552 | unsigned error; 1553 | unsigned char* image; 1554 | size_t width, height; 1555 | const char* filename = argc > 1 ? argv[1] : "test.png"; 1556 | 1557 | error = lodepng_decode32_file(&image, &width, &height, filename); 1558 | 1559 | if(error) printf("decoder error %u: %s\n", error, lodepng_error_text(error)); 1560 | 1561 | / * use image here * / 1562 | 1563 | free(image); 1564 | return 0; 1565 | } 1566 | 1567 | 1568 | 11. changes 1569 | ----------- 1570 | 1571 | The version number of LodePNG is the date of the change given in the format 1572 | yyyymmdd. 1573 | 1574 | Some changes aren't backwards compatible. Those are indicated with a (!) 1575 | symbol. 1576 | 1577 | *) 22 dec 2013: Power of two windowsize required for optimization. 1578 | *) 15 apr 2013: Fixed bug with LAC_ALPHA and color key. 1579 | *) 25 mar 2013: Added an optional feature to ignore some PNG errors (fix_png). 1580 | *) 11 mar 2013 (!): Bugfix with custom free. Changed from "my" to "lodepng_" 1581 | prefix for the custom allocators and made it possible with a new #define to 1582 | use custom ones in your project without needing to change lodepng's code. 1583 | *) 28 jan 2013: Bugfix with color key. 1584 | *) 27 okt 2012: Tweaks in text chunk keyword length error handling. 1585 | *) 8 okt 2012 (!): Added new filter strategy (entropy) and new auto color mode. 1586 | (no palette). Better deflate tree encoding. New compression tweak settings. 1587 | Faster color conversions while decoding. Some internal cleanups. 1588 | *) 23 sep 2012: Reduced warnings in Visual Studio a little bit. 1589 | *) 1 sep 2012 (!): Removed #define's for giving custom (de)compression functions 1590 | and made it work with function pointers instead. 1591 | *) 23 jun 2012: Added more filter strategies. Made it easier to use custom alloc 1592 | and free functions and toggle #defines from compiler flags. Small fixes. 1593 | *) 6 may 2012 (!): Made plugging in custom zlib/deflate functions more flexible. 1594 | *) 22 apr 2012 (!): Made interface more consistent, renaming a lot. Removed 1595 | redundant C++ codec classes. Reduced amount of structs. Everything changed, 1596 | but it is cleaner now imho and functionality remains the same. Also fixed 1597 | several bugs and shrinked the implementation code. Made new samples. 1598 | *) 6 nov 2011 (!): By default, the encoder now automatically chooses the best 1599 | PNG color model and bit depth, based on the amount and type of colors of the 1600 | raw image. For this, autoLeaveOutAlphaChannel replaced by auto_choose_color. 1601 | *) 9 okt 2011: simpler hash chain implementation for the encoder. 1602 | *) 8 sep 2011: lz77 encoder lazy matching instead of greedy matching. 1603 | *) 23 aug 2011: tweaked the zlib compression parameters after benchmarking. 1604 | A bug with the PNG filtertype heuristic was fixed, so that it chooses much 1605 | better ones (it's quite significant). A setting to do an experimental, slow, 1606 | brute force search for PNG filter types is added. 1607 | *) 17 aug 2011 (!): changed some C zlib related function names. 1608 | *) 16 aug 2011: made the code less wide (max 120 characters per line). 1609 | *) 17 apr 2011: code cleanup. Bugfixes. Convert low to 16-bit per sample colors. 1610 | *) 21 feb 2011: fixed compiling for C90. Fixed compiling with sections disabled. 1611 | *) 11 dec 2010: encoding is made faster, based on suggestion by Peter Eastman 1612 | to optimize long sequences of zeros. 1613 | *) 13 nov 2010: added LodePNG_InfoColor_hasPaletteAlpha and 1614 | LodePNG_InfoColor_canHaveAlpha functions for convenience. 1615 | *) 7 nov 2010: added LodePNG_error_text function to get error code description. 1616 | *) 30 okt 2010: made decoding slightly faster 1617 | *) 26 okt 2010: (!) changed some C function and struct names (more consistent). 1618 | Reorganized the documentation and the declaration order in the header. 1619 | *) 08 aug 2010: only changed some comments and external samples. 1620 | *) 05 jul 2010: fixed bug thanks to warnings in the new gcc version. 1621 | *) 14 mar 2010: fixed bug where too much memory was allocated for char buffers. 1622 | *) 02 sep 2008: fixed bug where it could create empty tree that linux apps could 1623 | read by ignoring the problem but windows apps couldn't. 1624 | *) 06 jun 2008: added more error checks for out of memory cases. 1625 | *) 26 apr 2008: added a few more checks here and there to ensure more safety. 1626 | *) 06 mar 2008: crash with encoding of strings fixed 1627 | *) 02 feb 2008: support for international text chunks added (iTXt) 1628 | *) 23 jan 2008: small cleanups, and #defines to divide code in sections 1629 | *) 20 jan 2008: support for unknown chunks allowing using LodePNG for an editor. 1630 | *) 18 jan 2008: support for tIME and pHYs chunks added to encoder and decoder. 1631 | *) 17 jan 2008: ability to encode and decode compressed zTXt chunks added 1632 | Also vareous fixes, such as in the deflate and the padding bits code. 1633 | *) 13 jan 2008: Added ability to encode Adam7-interlaced images. Improved 1634 | filtering code of encoder. 1635 | *) 07 jan 2008: (!) changed LodePNG to use ISO C90 instead of C++. A 1636 | C++ wrapper around this provides an interface almost identical to before. 1637 | Having LodePNG be pure ISO C90 makes it more portable. The C and C++ code 1638 | are together in these files but it works both for C and C++ compilers. 1639 | *) 29 dec 2007: (!) changed most integer types to unsigned int + other tweaks 1640 | *) 30 aug 2007: bug fixed which makes this Borland C++ compatible 1641 | *) 09 aug 2007: some VS2005 warnings removed again 1642 | *) 21 jul 2007: deflate code placed in new namespace separate from zlib code 1643 | *) 08 jun 2007: fixed bug with 2- and 4-bit color, and small interlaced images 1644 | *) 04 jun 2007: improved support for Visual Studio 2005: crash with accessing 1645 | invalid std::vector element [0] fixed, and level 3 and 4 warnings removed 1646 | *) 02 jun 2007: made the encoder add a tag with version by default 1647 | *) 27 may 2007: zlib and png code separated (but still in the same file), 1648 | simple encoder/decoder functions added for more simple usage cases 1649 | *) 19 may 2007: minor fixes, some code cleaning, new error added (error 69), 1650 | moved some examples from here to lodepng_examples.cpp 1651 | *) 12 may 2007: palette decoding bug fixed 1652 | *) 24 apr 2007: changed the license from BSD to the zlib license 1653 | *) 11 mar 2007: very simple addition: ability to encode bKGD chunks. 1654 | *) 04 mar 2007: (!) tEXt chunk related fixes, and support for encoding 1655 | palettized PNG images. Plus little interface change with palette and texts. 1656 | *) 03 mar 2007: Made it encode dynamic Huffman shorter with repeat codes. 1657 | Fixed a bug where the end code of a block had length 0 in the Huffman tree. 1658 | *) 26 feb 2007: Huffman compression with dynamic trees (BTYPE 2) now implemented 1659 | and supported by the encoder, resulting in smaller PNGs at the output. 1660 | *) 27 jan 2007: Made the Adler-32 test faster so that a timewaste is gone. 1661 | *) 24 jan 2007: gave encoder an error interface. Added color conversion from any 1662 | greyscale type to 8-bit greyscale with or without alpha. 1663 | *) 21 jan 2007: (!) Totally changed the interface. It allows more color types 1664 | to convert to and is more uniform. See the manual for how it works now. 1665 | *) 07 jan 2007: Some cleanup & fixes, and a few changes over the last days: 1666 | encode/decode custom tEXt chunks, separate classes for zlib & deflate, and 1667 | at last made the decoder give errors for incorrect Adler32 or Crc. 1668 | *) 01 jan 2007: Fixed bug with encoding PNGs with less than 8 bits per channel. 1669 | *) 29 dec 2006: Added support for encoding images without alpha channel, and 1670 | cleaned out code as well as making certain parts faster. 1671 | *) 28 dec 2006: Added "Settings" to the encoder. 1672 | *) 26 dec 2006: The encoder now does LZ77 encoding and produces much smaller files now. 1673 | Removed some code duplication in the decoder. Fixed little bug in an example. 1674 | *) 09 dec 2006: (!) Placed output parameters of public functions as first parameter. 1675 | Fixed a bug of the decoder with 16-bit per color. 1676 | *) 15 okt 2006: Changed documentation structure 1677 | *) 09 okt 2006: Encoder class added. It encodes a valid PNG image from the 1678 | given image buffer, however for now it's not compressed. 1679 | *) 08 sep 2006: (!) Changed to interface with a Decoder class 1680 | *) 30 jul 2006: (!) LodePNG_InfoPng , width and height are now retrieved in different 1681 | way. Renamed decodePNG to decodePNGGeneric. 1682 | *) 29 jul 2006: (!) Changed the interface: image info is now returned as a 1683 | struct of type LodePNG::LodePNG_Info, instead of a vector, which was a bit clumsy. 1684 | *) 28 jul 2006: Cleaned the code and added new error checks. 1685 | Corrected terminology "deflate" into "inflate". 1686 | *) 23 jun 2006: Added SDL example in the documentation in the header, this 1687 | example allows easy debugging by displaying the PNG and its transparency. 1688 | *) 22 jun 2006: (!) Changed way to obtain error value. Added 1689 | loadFile function for convenience. Made decodePNG32 faster. 1690 | *) 21 jun 2006: (!) Changed type of info vector to unsigned. 1691 | Changed position of palette in info vector. Fixed an important bug that 1692 | happened on PNGs with an uncompressed block. 1693 | *) 16 jun 2006: Internally changed unsigned into unsigned where 1694 | needed, and performed some optimizations. 1695 | *) 07 jun 2006: (!) Renamed functions to decodePNG and placed them 1696 | in LodePNG namespace. Changed the order of the parameters. Rewrote the 1697 | documentation in the header. Renamed files to lodepng.cpp and lodepng.h 1698 | *) 22 apr 2006: Optimized and improved some code 1699 | *) 07 sep 2005: (!) Changed to std::vector interface 1700 | *) 12 aug 2005: Initial release (C++, decoder only) 1701 | 1702 | 1703 | 12. contact information 1704 | ----------------------- 1705 | 1706 | Feel free to contact me with suggestions, problems, comments, ... concerning 1707 | LodePNG. If you encounter a PNG image that doesn't work properly with this 1708 | decoder, feel free to send it and I'll use it to find and fix the problem. 1709 | 1710 | My email address is (puzzle the account and domain together with an @ symbol): 1711 | Domain: gmail dot com. 1712 | Account: lode dot vandevenne. 1713 | 1714 | 1715 | Copyright (c) 2005-2013 Lode Vandevenne 1716 | */ 1717 | --------------------------------------------------------------------------------