aboutsummaryrefslogtreecommitdiff
path: root/src/png-file.c
blob: 09925a75e227f1a22ebb130fb6e5222c7e0204eb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
/*
 * png-file.c
 *
 * PNG output
 *
 * (c) 2006-2007 Thomas White <taw27@cam.ac.uk>
 *
 *  synth2d - Two-Dimensional Crystallographic Fourier Synthesis
 *
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <stdio.h>
#include <png.h>
#include <math.h>
#include <stdlib.h>
#include <fftw3.h>

#include "data.h"
#include "colwheel.h"
#include "renderer.h"

int png_write_real(const char *filename, fftw_complex *out, double brightness, double gamma_angle, int width, int height, int nx, int ny) {

	FILE *fh;
	png_structp png_ptr;
	png_infop info_ptr;
	png_bytep *row_pointers;
	int xn, yn;
	int width_n, height_n;
	ComplexArray cxar;
	
	fh = fopen(filename, "wb");
	if (!fh) {
		fprintf(stderr, "Couldn't open output file.\n");
		return 1;
	}
	png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
	if ( !png_ptr ) {
		fprintf(stderr, "Couldn't create PNG write structure.\n");
		fclose(fh);
		return 1;
	}	
	info_ptr = png_create_info_struct(png_ptr);
	if ( !info_ptr ) {
		png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
		fprintf(stderr, "Couldn't create PNG info structure.\n");
		fclose(fh);
		return 1;
	}	
	if ( setjmp(png_jmpbuf(png_ptr)) ) {
		png_destroy_write_struct(&png_ptr, &info_ptr);
		fclose(fh);
		fprintf(stderr, "PNG write failed.\n");
		return 1;
	}	
	png_init_io(png_ptr, fh);
	
	width_n = (int)renderer_width(width, height, gamma_angle, nx, ny);
	height_n = (int)renderer_height(width, height, gamma_angle, nx, ny);
	cxar = renderer_draw(out, width, height, gamma_angle, nx, ny);

	png_set_IHDR(png_ptr, info_ptr, width_n, height_n, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
		PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
	
	/* Write the image data */
	row_pointers = malloc(height_n*sizeof(png_bytep *));

	for ( yn=0; yn<height_n; yn++ ) {
	
		row_pointers[yn] = malloc(width_n*3);
		for ( xn=0; xn<width_n; xn++ ) {
			row_pointers[yn][3*xn] = 0;
			row_pointers[yn][3*xn+1] = 0;
			row_pointers[yn][3*xn+2] = 0;
		}
		
	}

	for ( yn=0; yn<height_n; yn++ ) {
		for ( xn=0; xn<width_n; xn++ ) {
		
			double re, im, am, ph;
			
			re = cxar.re[xn+width_n*yn];
			im = cxar.im[xn+width_n*yn];
			am = sqrt(re*re + im*im) / brightness;
			ph = atan2(im, re);
			if ( am > 1 ) am = 1;
			
			row_pointers[yn][3*xn] = (png_byte)255*colwheel_red(am, ph);
			row_pointers[yn][3*xn+1] = (png_byte)255*colwheel_green(am, ph);
			row_pointers[yn][3*xn+2] = (png_byte)255*colwheel_blue(am, ph);
			
		}
	}
	
	for ( yn=0; yn<height_n/2+1; yn++ ) {
		png_bytep scratch;
		scratch = row_pointers[yn];
		row_pointers[yn] = row_pointers[height_n-yn-1];
		row_pointers[height_n-yn-1] = scratch;
	}
	
	png_set_rows(png_ptr, info_ptr, row_pointers);
	png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);
	
	png_destroy_write_struct(&png_ptr, &info_ptr);
	for ( yn=0; yn<height_n; yn++ ) {
		free(row_pointers[yn]);
	}
	free(row_pointers);
	fclose(fh);
	
	return 0;

}

int png_write(const char *filename, fftw_complex *out, double norm, int nx, int ny) {
	return png_write_real(filename, out, norm, data_gamma(), data_width(), data_height(), nx, ny);
}