1 |
/* |
2 |
* render_image - make .png or .ppm image from a segment image file in a series. |
3 |
*/ |
4 |
|
5 |
/** |
6 |
@defgroup render_image render_image Make .png or .ppm image from a segment image file in a series. |
7 |
@ingroup su_util |
8 |
|
9 |
@brief Make .png or .ppm image from a segment image file in a series. |
10 |
|
11 |
@par Synopsis: |
12 |
@code |
13 |
render_image --help |
14 |
render_iamge in=<RecordSet> out=<target> | {outname=<ident_for_filename>} {scaling=<scaletype>} |
15 |
{palette=<color_table>} {type=<image_protocol>} {outid=<filename_code>} |
16 |
{tkey=<time_keyword>} {min=<scale_min>} {max=<scale_max>} |
17 |
{scale=<image_size_ratio>} {-c} {-u} {-w} {-x} |
18 |
@endcode |
19 |
|
20 |
@code |
21 |
in=Input data series. |
22 |
n=limit limit number of records to n from beginning or -n from end of 'in' |
23 |
out=Output data series or full path of directory or pipe via ppm program. |
24 |
outname=Output quantity name for filenames. |
25 |
scaling=Color table type, minmax, minmax99, minmaxgiven, histeq, ...,, default=MINMAX |
26 |
palette=Color table, GREY or filename, default=GREY (bad spelling as pallette still allowed) |
27 |
type=Image protocol, png, ppm, ..., default=png |
28 |
tkey=keyword name for time, default T_REC |
29 |
outid=output identifier, #=record counter, time=time as yyyymmdd_hhmmss, default=# |
30 |
min=Min value for scaling, default nan |
31 |
max=Max value for scaling, default nan |
32 |
scale"Reduction factor list, default 1. |
33 |
-c Crop flag, causes crop to RSUN_OBS |
34 |
-u use unchanged for rotation and centering |
35 |
-w use white for missing pixels, instead of black |
36 |
-x High-quality flag, sets bytespercolor to 2 instead of 1, |
37 |
@endcode |
38 |
|
39 |
@par |
40 |
Render_image can make one or many images per record in the input recordset. It will make one image for each value |
41 |
of scale where the values are given as a comma delimited list of divisors for the dimensions of the input image array. |
42 |
The image file will be written to a filename created from outid_outname_type where outid is either "time" or "#", |
43 |
outname is any literal string, and type is "png" or "ppm" or if out specifies a pipe, then type may be any file type |
44 |
that is supported as the output of a pipeline which accepts a PPM file. |
45 |
@par |
46 |
The file location is spcified with the out parameter. The target may be a seriesname in which case the image will |
47 |
be written into a record directory of that series. If the target seriesname is the same as the series specified in in, then |
48 |
each input record will be cloned. The image will be written into a segment named "image". |
49 |
@par |
50 |
If the target location begins with a "/" or "./" then the $target will be used as the path for a directory into which |
51 |
the image file will be written. If the target location beginw with a "|" character, then the target string will be used |
52 |
as a pipe into which a .ppm file will be written. The pipe string will have " > <filename>" appended to it. |
53 |
In the case of a pipe, the string given in the 'out' parameter will be scanned |
54 |
for replacement tokens delimited by '{...}'. Inside the '{}' pair the following |
55 |
replacement instructions are available: |
56 |
@code |
57 |
The word 'ID' is replaced by the filename ID as built from outid. |
58 |
The word '%' is replaced by that percent of the height of the image rounded |
59 |
to the nearest pixel. If the floating point number after the '%' is itself |
60 |
followed by a ':' and an integer, then that integer will be used as the |
61 |
smallest number for the replacement token. So, for instance '{%1.2:5}' |
62 |
with the image height of 256 pixels will be processed as: 1.2% of 256 is 3.072 |
63 |
which rounds to 3 which is smaller than 5 so the result will be 5. |
64 |
@endcode |
65 |
@par |
66 |
The image filename is generated from the outid, outname, and type parameters. If outid is the string "time" then |
67 |
the time of the image as specified by the tkey (defaults to T_REC) will be used with the "." and ":" and "_<zone>" componenets deleted. I.e. |
68 |
the time will be in the form "yyyymmdd_hhmmss". The outid = time can have a suffix specifying the number of time characters to |
69 |
include. the format of the suffix is ":nn" where nn is from 1 to 15. If outid is a literal "#" then the "%04d" layout will be used to generate |
70 |
the image sequence number within the run of the program (i.e. the record number within the current recordset). the |
71 |
type parameter must be "png" or "ppm" unless the out parameter specifies a ppm pipeline in which case type should |
72 |
be the suffix for the file type geenrated by the pipe. |
73 |
@par |
74 |
The scaling of image values to color table indices is controlled by the scaling parameter. scaling must be one of |
75 |
MINMAX, MAXMIN, MINMAXGIVEN, MINMAX99, MAXMIN99, HISTEQ, MAG at present. The default is MINMAX. If the scaling is |
76 |
MINMAX and both min and max parameters are given, then the MINMAXGIVEN scaling will be used. MINMAX99 and |
77 |
MAXMIN99 mean to eliminate the top and bottom 0.5% of the histogram of the values before computing a linear scaling. |
78 |
MAXMIN and MAXMIN99 result in a reversed scaling with the max value mapped to the first color in the table and the |
79 |
min value mapped to the max color in the table. String case is ignored for the scaling parameter. |
80 |
@par |
81 |
The MAG scaling uses a scaling of 400*M/pow((abs(M)+bias),0.75) bias=30, from user provided min and max (defaulting to +-1500). |
82 |
This scaling emphasizes low absolute field strength but still shows detail up to a max of 3000 gauss. The default |
83 |
of 1500 clips umbral fields with the tradeoff of more contrast for plage and network fields. |
84 |
@par |
85 |
The color table is specified by the palette parameter. The table may be a built in table, at persent the only |
86 |
build-in is "grey". ("grey", "gray", "GREY", "GRAY" are all allowed). If not a build-in table name the palette |
87 |
parameter is expected to be a file path to a table of .sao or .lut types. These table formats are described in the |
88 |
ds9(1) documentation. |
89 |
@par |
90 |
The image will be centered to the nearest pixel, and will be rotated 180 degrees if CROTA2 is near 180. |
91 |
|
92 |
@par Flags: |
93 |
@c -c: Crop image. This flag will casue the image to be cropped at pixel radius RSUN_OBS/CDELT1 about CRPIX1,CRPIX2 center. |
94 |
|
95 |
@c -w: White background, the -w flag will cause missing values to be white. Else black. |
96 |
|
97 |
@c -x: the -x flag is used to indicate extra resolution in the color table, i.e. 16-bits per color. |
98 |
|
99 |
@par Example to generate a directory full of simple grey scaled png images, perhaps for a movie |
100 |
@code |
101 |
render_image in='hmi.M_45s_nrt[2010.06.01_TAI/5d@30m]' out=./movie scaling=minmax99 outid=# outname=M |
102 |
@endcode |
103 |
|
104 |
@par Example to generate a set of 4096x4096 and 1024x1024, and 256x256 pixel images of magnetograms in the current directory |
105 |
using a color table the adds dynamic range to small absolute values. The times will omit the seconds field in this example. |
106 |
@code |
107 |
render_image in='hmi.M_45s_nrt'$QRY \ |
108 |
outname=M \ |
109 |
palette=/home/phil/apps/mag.lut \ |
110 |
outid=time:13 \ |
111 |
-c \ |
112 |
min=-500 \ |
113 |
max=500 \ |
114 |
type=jpg \ |
115 |
-w \ |
116 |
scale=1,4,16 \ |
117 |
out='| ppmlabel -color black -size {%0.75:5} -x 15 -y {%98} -text "SDO/HMI Quick-Look Magnetogram: {ID}" | pnmtojpeg -quality=95' |
118 |
@endcode |
119 |
|
120 |
@bug |
121 |
Using the MAG scaling with a list of scale sizes, any instance of scale=1 must appear last in the list. This is because the values of the |
122 |
image data are replaced in the original array in the scale=1 case. This will affect any scaling type that modifies the values of the data. |
123 |
|
124 |
@bug |
125 |
Does not make 16-bit colors correctly, or I can not get ppm tools with correct flags... |
126 |
|
127 |
*/ |
128 |
|
129 |
#include "mypng.h" |
130 |
#include "jsoc_main.h" |
131 |
|
132 |
#define PNGDIE(msg) {fprintf(stderr,"%s\n",msg); \ |
133 |
if (png_ptr) png_destroy_write_struct(&png_ptr, &info_ptr); \ |
134 |
if (row_pointers) free(row_pointers); \ |
135 |
if (fp) fclose(fp); \ |
136 |
return(1);} |
137 |
|
138 |
#define DIE(msg) {fflush(stdout);fprintf(stderr,"%s, status=%d\n",msg,status); return(status);} |
139 |
|
140 |
#define MINMAX 1 |
141 |
#define MAXMIN 2 |
142 |
#define HISTEQ 3 |
143 |
#define MINMAX99 4 |
144 |
#define MAXMIN99 5 |
145 |
#define MINMAXGIVEN 6 |
146 |
#define MAG 7 |
147 |
#define MAGMINMAXGIVEN 8 |
148 |
#define LOG 9 |
149 |
#define SQRT 10 |
150 |
|
151 |
char *module_name = "render_image"; |
152 |
|
153 |
ModuleArgs_t module_args[] = |
154 |
{ |
155 |
{ARG_STRING, "in", "NOT SPECIFIED", "Input data series."}, |
156 |
{ARG_INT, "n", "0", "Limit of number of records, 0 for no limin; >0 count from start; <0 count from end"}, |
157 |
{ARG_STRING, "out", "NOT SPECIFIED", "Output data series or full path of directory or pipe via ppm program."}, |
158 |
{ARG_STRING, "outname", "NOT SPECIFIED", "Output quantity name for filenames"}, |
159 |
{ARG_STRING, "scaling", "MINMAX", "Color table type, minmax, minmax99, minmaxgiven, histeq, ..."}, |
160 |
{ARG_STRING, "pallette", "none", "Color table, GREY or filename"}, |
161 |
{ARG_STRING, "palette", "GREY", "Color table, GREY or filename"}, |
162 |
{ARG_STRING, "type", "png", "Image protocol, png, ppm, ..."}, |
163 |
{ARG_STRING, "outid", "#", "output identifier, #=record counter, time=time as yyyymmdd_hhmmss"}, |
164 |
{ARG_STRING, "tkey", "T_REC", "Time keyword name used if outid==time, defaults to T_REC"}, |
165 |
{ARG_FLOAT, "min", "DRMS_MISSING_FLOAT", "Min value for scaling"}, |
166 |
{ARG_FLOAT, "max", "DRMS_MISSING_FLOAT", "Max value for scaling"}, |
167 |
{ARG_FLOAT, "bias", "30.0", "Max value for mag scaling"}, |
168 |
{ARG_INTS, "scale", "1", "Reduction factors"}, |
169 |
{ARG_FLAG, "c", "0", "Crop flag, causes crop to RSUN_OBS"}, |
170 |
{ARG_FLAG, "u", "0", "use unchanged, is-is for rotation and centering"}, |
171 |
{ARG_FLAG, "w", "0", "use white for missing pixels, instead of black"}, |
172 |
{ARG_FLAG, "x", "0", "High-quality flag, sets bytespercolor to 2 instead of 1"}, |
173 |
{ARG_END} |
174 |
}; |
175 |
|
176 |
#define Deg2Rad (M_PI/180.0) |
177 |
#define Rad2arcsec (3600.0/Deg2Rad) |
178 |
#define arcsec2Rad (Deg2Rad/3600.0) |
179 |
#define Rad2Deg (180.0/M_PI) |
180 |
|
181 |
struct ObsInfo_struct |
182 |
{ |
183 |
// from observation info |
184 |
TIME t_obs; |
185 |
double rsun_obs, obs_vr, obs_vw, obs_vn; |
186 |
double crpix1, crpix2, cdelt1, cdelt2, crota2; |
187 |
double crval1, crval2; |
188 |
double cosa, sina; |
189 |
double obs_b0; |
190 |
// observed point |
191 |
int i,j; |
192 |
// parameters for observed point |
193 |
double x,y,r; |
194 |
double rho; |
195 |
double lon; |
196 |
double lat; |
197 |
double sinlat, coslat; |
198 |
double sig; |
199 |
double mu; |
200 |
double chi; |
201 |
double obs_v; |
202 |
}; |
203 |
|
204 |
typedef struct ObsInfo_struct ObsInfo_t; |
205 |
|
206 |
void rebinArraySF(DRMS_Array_t *out, DRMS_Array_t *in); |
207 |
|
208 |
int add_png(char *imgPath, DRMS_Array_t *imgArray, int scaletype, int usewhite, char *palette, int colors, int bytespercolor, double *minp, double *maxp); |
209 |
|
210 |
int add_ppm(char *imgPath, DRMS_Array_t *imgArray, int scaletype, int usewhite, char *palette, int colors, int bytespercolor, double *minp, double *maxp); |
211 |
|
212 |
int make_png(char *imgPath, unsigned char *data, int height, int width, char *palette, int bytepercolor, int colors); |
213 |
|
214 |
char *set_scaling(DRMS_Array_t *in, double *minp, double *maxp, int *nmissp, char *palette, int colors, int bytepercolor, int scaling, int usewhite); |
215 |
|
216 |
int upNcenter(DRMS_Array_t *arr, ObsInfo_t *ObsLoc); |
217 |
int crop_image(DRMS_Array_t *arr, ObsInfo_t *ObsLoc); |
218 |
|
219 |
ObsInfo_t *GetObsInfo(DRMS_Segment_t *seg, ObsInfo_t *pObsLoc, int *rstatus); |
220 |
|
221 |
#define PNG 1 |
222 |
#define PPM 2 |
223 |
#define PPMPIPE 3 |
224 |
|
225 |
int DoIt(void) |
226 |
{ |
227 |
int status = DRMS_SUCCESS; |
228 |
DRMS_RecordSet_t *inRS, *outRS = NULL; |
229 |
DRMS_Record_t *inRec, *outRec; |
230 |
int irec, nrecs; |
231 |
int fileonly=0; |
232 |
int imgtype; |
233 |
int quality; |
234 |
|
235 |
char *inQuery = (char *)params_get_str(&cmdparams, "in"); |
236 |
char *outQuery = (char *)params_get_str(&cmdparams, "out"); |
237 |
char *outName = (char *)params_get_str(&cmdparams, "outname"); |
238 |
char *outid = (char *)params_get_str(&cmdparams, "outid"); |
239 |
char *tkey = (char *)params_get_str(&cmdparams, "tkey"); |
240 |
char *palette = (char *)params_get_str(&cmdparams, "palette"); |
241 |
if (strcmp((char *)params_get_str(&cmdparams, "pallette"), "none")) |
242 |
palette = (char *)params_get_str(&cmdparams, "pallette"); |
243 |
int limit = params_get_int(&cmdparams, "n"); |
244 |
int bytespercolor = (params_isflagset(&cmdparams, "x") ? 2 : 1); |
245 |
int missingwhite = params_isflagset(&cmdparams, "w"); |
246 |
int crop = params_isflagset(&cmdparams, "c"); |
247 |
int asis = params_isflagset(&cmdparams, "u"); |
248 |
char *type = (char *)params_get_str(&cmdparams, "type"); |
249 |
char *scaling = (char *)params_get_str(&cmdparams, "scaling"); |
250 |
double called_min = params_get_double(&cmdparams, "min"); |
251 |
double called_max = params_get_double(&cmdparams, "max"); |
252 |
double min, max; |
253 |
int *scales = NULL; |
254 |
int iscale, nscales; |
255 |
int colors; |
256 |
int scaletype; |
257 |
int srcNx = 0, srcNy = 0; |
258 |
|
259 |
if (strcasecmp(palette, "grey") == 0 || strcasecmp(palette, "gray") == 0) |
260 |
{ |
261 |
palette = "GREY"; |
262 |
colors = 1; |
263 |
} |
264 |
else |
265 |
colors = 3; |
266 |
|
267 |
if (strcasecmp(type, "png")==0) imgtype = PNG; |
268 |
else if (strcasecmp(type, "ppm")==0) imgtype = PPM; |
269 |
else imgtype = PPMPIPE; |
270 |
|
271 |
nscales = cmdparams_get_intarr(&cmdparams, "scale", &scales, &status); |
272 |
if (status) |
273 |
DIE("scale parameter not found"); |
274 |
|
275 |
// for (iscale=0; iscale<nscales; iscale++) |
276 |
// fprintf(stderr,"Scale #%d=%d ", iscale, scales[iscale]); |
277 |
// fprintf(stderr," using min=%f, max=%f\n", min, max); |
278 |
|
279 |
if (strcasecmp(scaling, "minmax") == 0) scaletype = MINMAX; |
280 |
else if (strcasecmp(scaling, "maxmin") == 0) scaletype = MAXMIN; |
281 |
else if (strcasecmp(scaling, "minmax") == 0) scaletype = MINMAX99; |
282 |
else if (strcasecmp(scaling, "maxmin99") == 0) scaletype = MAXMIN99; |
283 |
else if (strcasecmp(scaling, "histeq") == 0) scaletype = HISTEQ; |
284 |
else if (strcasecmp(scaling, "minmaxgiven") == 0) scaletype = MINMAXGIVEN; |
285 |
else if (strncasecmp(scaling, "mag", 3) == 0) scaletype = MAG; |
286 |
else if (strncasecmp(scaling, "log", 3) == 0) scaletype = LOG; |
287 |
else if (strncasecmp(scaling, "sqrt", 4) == 0) scaletype = SQRT; |
288 |
|
289 |
else scaletype = 0; |
290 |
fprintf(stdout, " using scaling %d\n", scaletype); |
291 |
if (isnan(called_min) || isnan(called_max)) |
292 |
{ |
293 |
if (scaletype == MINMAXGIVEN) |
294 |
DIE("min and max must be specified for type MINMAXGIVEN\n"); |
295 |
} |
296 |
else |
297 |
{ |
298 |
if (scaletype == MINMAX) |
299 |
scaletype = MINMAXGIVEN; |
300 |
else if (scaletype == MAG) |
301 |
scaletype = MAGMINMAXGIVEN; |
302 |
} |
303 |
|
304 |
if (limit == 0) |
305 |
inRS = drms_open_records(drms_env, inQuery, &status); |
306 |
else |
307 |
inRS = drms_open_nrecords(drms_env, inQuery, limit, &status); |
308 |
if (status || inRS->n == 0) |
309 |
DIE("No input data found"); |
310 |
drms_stage_records(inRS, 1, 1); |
311 |
nrecs = inRS->n; |
312 |
fprintf(stderr,"nrecs=%d\n",nrecs); |
313 |
|
314 |
if (!outQuery[0]) |
315 |
DIE("No valid output place specified"); |
316 |
if (outQuery[0] == '/' || (outQuery[0] == '.' && outQuery[1] && outQuery[1] == '/') || outQuery[0] == '|') |
317 |
{ |
318 |
// Output to a directory |
319 |
fileonly = 1; |
320 |
} |
321 |
else |
322 |
{ |
323 |
// output to a record segment |
324 |
fileonly = 0; |
325 |
if (strcmp(inRS->records[0]->seriesinfo->seriesname, outQuery) == 0) |
326 |
outRS = drms_clone_records(inRS, DRMS_PERMANENT, DRMS_SHARE_SEGMENTS, &status); |
327 |
else |
328 |
outRS = drms_create_records(drms_env, nrecs, outQuery, DRMS_PERMANENT, &status); |
329 |
if (status) |
330 |
DIE("Output recordset not created"); |
331 |
} |
332 |
|
333 |
for (irec=0; irec<nrecs; irec++) |
334 |
{ |
335 |
int status; |
336 |
DRMS_Array_t *srcArray; |
337 |
DRMS_Segment_t *srcSeg; |
338 |
ObsInfo_t *ObsLoc; |
339 |
|
340 |
char imageID[100]; |
341 |
inRec = inRS->records[irec]; |
342 |
quality = drms_getkey_int(inRec, "QUALITY", &status); |
343 |
if (!status && quality < 0) |
344 |
{ |
345 |
fprintf(stderr,"Quality bad for rec %d\n", irec); |
346 |
continue; |
347 |
} |
348 |
else |
349 |
{ |
350 |
srcSeg = drms_segment_lookupnum(inRec, 0); |
351 |
srcArray = drms_segment_read(srcSeg, DRMS_TYPE_FLOAT, &status); |
352 |
if (!srcArray || status) |
353 |
{ |
354 |
fprintf(stderr," No data file found rec %d, status=%d\n", irec,status); |
355 |
if (srcArray) |
356 |
{ |
357 |
drms_free_array(srcArray); |
358 |
srcArray = NULL; |
359 |
} |
360 |
continue; |
361 |
} |
362 |
ObsLoc = GetObsInfo(srcSeg, NULL, &status); |
363 |
if (!asis) upNcenter(srcArray, ObsLoc); |
364 |
if (crop) crop_image(srcArray, ObsLoc); |
365 |
srcNx = srcArray->axis[0]; |
366 |
srcNy = srcArray->axis[1]; |
367 |
} |
368 |
if (strcmp(outid,"#") == 0) |
369 |
sprintf(imageID, "%04d", irec); |
370 |
else if (strncasecmp(outid,"time",4) == 0) |
371 |
{ |
372 |
int timestatus; |
373 |
char timebuf[100]; |
374 |
static int t[] = {0,1,2,3,5,6,8,9,10,11,12,14,15,17,18}; |
375 |
int i; |
376 |
int maxtplace = 15; |
377 |
char *tplace = index(outid,':'); |
378 |
TIME now = drms_getkey_time(inRec, tkey, ×tatus); |
379 |
if (timestatus) |
380 |
{ |
381 |
fprintf(stderr,"Time key given in 'tkey' param, %s, is not found in the input series.\n",tkey); |
382 |
return(timestatus); |
383 |
} |
384 |
sprint_time(timebuf, now, "TAI", 0); |
385 |
if (tplace) |
386 |
sscanf(tplace+1,"%d",&maxtplace); |
387 |
for (i=0; i<maxtplace; i++) |
388 |
imageID[i] = timebuf[t[i]]; |
389 |
imageID[i] = '\0'; |
390 |
} |
391 |
else |
392 |
{ |
393 |
fprintf(stderr, "Invalid outid param: |%s|\n", outid); |
394 |
return(1); |
395 |
} |
396 |
for (iscale=0; iscale<nscales; iscale++) |
397 |
{ |
398 |
int dimxy; |
399 |
char dimxytxt[50]; |
400 |
DRMS_Array_t *imageArray = NULL; |
401 |
char imgPath[DRMS_MAXPATHLEN]; |
402 |
int scale = scales[iscale]; |
403 |
int imageDims[2]; |
404 |
int tmparray = 0; |
405 |
char imageFileName[DRMS_MAXSEGFILENAME]; |
406 |
min = called_min; |
407 |
max = called_max; |
408 |
imageDims[0] = srcNx/scale; |
409 |
imageDims[1] = srcNy/scale; |
410 |
dimxy = imageDims[0]; |
411 |
sprintf(dimxytxt,"%d",dimxy); |
412 |
// fprintf(stderr,"scale=%d, imageNy=%d, imageNx=%d\n", scale, imageDims[1], imageDims[0]); |
413 |
|
414 |
if (scale != 1) |
415 |
{ |
416 |
imageArray = drms_array_create(DRMS_TYPE_FLOAT, 2, imageDims, NULL, &status); |
417 |
rebinArraySF(imageArray, srcArray); |
418 |
tmparray = 1; |
419 |
} |
420 |
else |
421 |
{ |
422 |
imageArray = srcArray; |
423 |
tmparray = 0; |
424 |
} |
425 |
|
426 |
sprintf(imageFileName, "%s%s%s_%s.%s", imageID, (strcmp(outid,"#")==0 ? "." : "_"), outName, |
427 |
(dimxy == 4096 ? "4k" : |
428 |
(dimxy == 2048 ? "2k" : |
429 |
(dimxy == 1024 ? "1k" : |
430 |
(dimxy == 512 ? "512" : |
431 |
(dimxy == 256 ? "256" : |
432 |
(dimxy == 128 ? "128" : dimxytxt)))))), type); |
433 |
|
434 |
if (fileonly) |
435 |
{ |
436 |
if (outQuery[0] == '|') |
437 |
{ // process outQuery for '{...}' replacement tokens |
438 |
char buf[4096]; |
439 |
char *pbuf = buf, *c = outQuery; |
440 |
while (*c && (pbuf-buf) < sizeof(buf)) |
441 |
{ |
442 |
if (*c == '{') |
443 |
{ |
444 |
c++; |
445 |
if (*c == '%') |
446 |
{ |
447 |
float x; |
448 |
int ix, minx; |
449 |
c++; |
450 |
x = strtof(c, &c); |
451 |
ix = round(0.01*x*imageDims[1]); |
452 |
if (*c == ':') |
453 |
{ |
454 |
c++; |
455 |
minx = (int)strtol(c, &c, 10); |
456 |
} |
457 |
else minx = 0; |
458 |
pbuf += sprintf(pbuf,"%d",(ix < minx ? minx : ix)); |
459 |
} |
460 |
else if (strncmp(c, "ID", 2) == 0) |
461 |
{ |
462 |
pbuf += sprintf(pbuf, "%s", imageID); |
463 |
c += 2; |
464 |
} |
465 |
if (*c++ != '}') |
466 |
DIE("Unrecognized token in pipe string"); |
467 |
} |
468 |
else |
469 |
*pbuf++ = *c++; |
470 |
} |
471 |
*pbuf = '\0'; |
472 |
sprintf(imgPath, "%s > %s", buf, imageFileName); |
473 |
} |
474 |
else |
475 |
sprintf(imgPath, "%s/%s", outQuery, imageFileName); |
476 |
} |
477 |
else |
478 |
{ |
479 |
DRMS_Segment_t *imageSeg; |
480 |
char recdir[DRMS_MAXPATHLEN]; |
481 |
outRec = outRS->records[irec]; |
482 |
drms_copykeys(outRec, inRec, 0, kDRMS_KeyClass_Explicit); |
483 |
drms_record_directory(outRec, recdir, 0); |
484 |
imageSeg = drms_segment_lookup(outRec, "image"); |
485 |
strcpy(imageSeg->filename, imageFileName); |
486 |
drms_keyword_setdate(outRec); |
487 |
sprintf(imgPath, "%s/%s", recdir, imageFileName); |
488 |
} |
489 |
|
490 |
if (imgtype == PNG) |
491 |
add_png(imgPath, imageArray, scaletype, missingwhite, palette, colors, bytespercolor, &min, &max); |
492 |
else if (imgtype == PPM || imgtype == PPMPIPE) |
493 |
add_ppm(imgPath, imageArray, scaletype, missingwhite, palette, colors, bytespercolor, &min, &max); |
494 |
|
495 |
if (tmparray) |
496 |
drms_free_array(imageArray); |
497 |
} |
498 |
drms_free_array(srcArray); |
499 |
} |
500 |
fprintf(stderr,"render_image done, irec=%d\n",irec); |
501 |
drms_close_records(inRS, DRMS_FREE_RECORD); |
502 |
fprintf(stderr,"render_image close in records done\n"); |
503 |
if (!fileonly && outRS) |
504 |
drms_close_records(outRS, DRMS_INSERT_RECORD); |
505 |
fprintf(stderr,"leaving module\n"); |
506 |
return (DRMS_SUCCESS); |
507 |
} // end of DoIt |
508 |
|
509 |
/* ---------------------------------------------------------------------- |
510 |
functions |
511 |
------------------------------------------------------------ |
512 |
*/ |
513 |
|
514 |
int add_ppm(char *imgPath, DRMS_Array_t *imageArray, int scaletype, int usewhite, char *palette, int colors, int bytespercolor, double *minp, double *maxp) |
515 |
{ |
516 |
int i, Nx, Ny; |
517 |
unsigned char *imgData = NULL; |
518 |
int nmissing; |
519 |
int maxpixval = (bytespercolor == 1 ? 255 : 65535); |
520 |
FILE *out; |
521 |
char *ppmcode; |
522 |
|
523 |
imgData = (unsigned char*)set_scaling(imageArray, minp, maxp, &nmissing, palette, colors, bytespercolor, scaletype, usewhite); |
524 |
if (!imgData) |
525 |
{ |
526 |
fprintf(stderr,"scaling failed\n"); |
527 |
return(1); |
528 |
} |
529 |
|
530 |
ppmcode = (colors == 1 ? "P5" : "P6"); |
531 |
|
532 |
Nx = imageArray->axis[0]; |
533 |
Ny = imageArray->axis[1]; |
534 |
|
535 |
if (imgPath[0] == '|') |
536 |
out = popen(imgPath+1, "w"); |
537 |
else |
538 |
out = fopen(imgPath, "w"); |
539 |
|
540 |
fprintf(out, "%s\n%d %d %d\n", ppmcode, Nx, Ny, maxpixval); |
541 |
for (i=Ny-1; i >=0; i--) |
542 |
fwrite(imgData + i*Nx*bytespercolor*colors, bytespercolor, colors*Nx, out); |
543 |
if (imgPath[0] == '|') |
544 |
pclose(out); |
545 |
else |
546 |
fclose(out); |
547 |
|
548 |
free(imgData); |
549 |
return(0); |
550 |
} |
551 |
|
552 |
int add_png(char *imgPath, DRMS_Array_t *imageArray, int scaletype, int usewhite, char *palette, int colors, int bytespercolor, double *minp, double *maxp) |
553 |
{ |
554 |
int srcNx, srcNy; |
555 |
int status=0; |
556 |
unsigned char *imgData = NULL; |
557 |
int nmissing; |
558 |
|
559 |
imgData = (unsigned char*)set_scaling(imageArray, minp, maxp, &nmissing, palette, colors, bytespercolor, scaletype, usewhite); |
560 |
|
561 |
if (!imgData) |
562 |
{ |
563 |
fprintf(stderr,"scaling failed, status=%d\n",status); |
564 |
return(status); |
565 |
} |
566 |
|
567 |
// should add text info to .png file with min, max, nmissing, etc. |
568 |
|
569 |
if (make_png(imgPath, imgData, imageArray->axis[0], imageArray->axis[1], palette, bytespercolor, colors) != 0) |
570 |
{ |
571 |
fprintf(stderr,"png failed, status=%d\n",status); |
572 |
free(imgData); |
573 |
return(status); |
574 |
} |
575 |
free(imgData); |
576 |
return(0); |
577 |
} |
578 |
// ---------------------------------------------------------------------- |
579 |
|
580 |
void rebinArraySF(DRMS_Array_t *out, DRMS_Array_t *in) |
581 |
{ |
582 |
float *inData = in->data; |
583 |
float *outData = out->data; |
584 |
float *inp, *outp; |
585 |
int inNx=in->axis[0], inNy=in->axis[1]; |
586 |
int outNx=out->axis[0], outNy=out->axis[1]; |
587 |
int inI, inJ, outI, outJ, i; |
588 |
int binsize = inNx/outNx; |
589 |
double inRow[inNx], outRow[outNx]; |
590 |
int inRowN[inNx], outRowN[outNx]; |
591 |
|
592 |
for (outJ=0; outJ < outNy; outJ++) |
593 |
{ |
594 |
int inRow0 = outJ * binsize; |
595 |
for (outI=0; outI<outNx; outI++) |
596 |
{ |
597 |
outRowN[outI] = 0; |
598 |
outRow[outI] = 0.0; |
599 |
} |
600 |
for (inJ = inRow0; inJ < inRow0+binsize; inJ++) |
601 |
{ |
602 |
inp = inData + inJ*inNx; |
603 |
for (outI=0; outI<outNx; outI++) |
604 |
for (i=0; i<binsize; i++, inp++) |
605 |
if (*inp != DRMS_MISSING_FLOAT) |
606 |
{ |
607 |
outRow[outI] += *inp; |
608 |
outRowN[outI]++; |
609 |
} |
610 |
} |
611 |
for (outI=0; outI < outNx; outI++) |
612 |
outData[outJ*outNx + outI] = (outRowN[outI] ? |
613 |
(outRow[outI]/outRowN[outI]) : DRMS_MISSING_FLOAT); |
614 |
} // end outJ |
615 |
} |
616 |
|
617 |
// --------------------------------------------------------------------- |
618 |
|
619 |
unsigned short *init_color_table(char * palette, int colors, int bytepercolor) |
620 |
{ |
621 |
int c, i; |
622 |
int tablesize = (bytepercolor == 1 ? 256 : 65536); |
623 |
int maxcolor = tablesize - 2; // i.e. for 8-bit, max=254, leave top for missing |
624 |
int lastcolor = tablesize - 1; |
625 |
int mincolor = 1; |
626 |
unsigned short *table = (unsigned short *)malloc(colors*tablesize*sizeof(unsigned short)); |
627 |
|
628 |
if (!table) return NULL; |
629 |
if (strcmp(palette,"GREY") == 0) |
630 |
for (i=0; i<tablesize; i++) |
631 |
for (c = 0; c<colors; c++) |
632 |
table[i*colors + c] = i; |
633 |
|
634 |
else if (colors == 3 && access(palette, R_OK) == 0) |
635 |
{ |
636 |
FILE *ct = fopen(palette,"r"); |
637 |
void proc_color(FILE *ct, unsigned short *t, int max); |
638 |
char buf[256]; |
639 |
char *dot = rindex(palette, '.'); |
640 |
if (dot && strcmp(dot, ".lut")==0) |
641 |
{ |
642 |
float fr, fg, fb; |
643 |
table[0] = table[1] = table[2] = 0; |
644 |
table[colors*lastcolor] = table[colors*lastcolor+1] = table[colors*lastcolor+2] = lastcolor; |
645 |
for (i=1; i<lastcolor; i++) |
646 |
{ |
647 |
fscanf(ct, "%f%f%f", &fr, &fg, &fb); |
648 |
c = 0; |
649 |
table[i*colors + c++] = maxcolor*fr; |
650 |
table[i*colors + c++] = maxcolor*fg; |
651 |
table[i*colors + c++] = maxcolor*fb; |
652 |
} |
653 |
} |
654 |
else |
655 |
{ |
656 |
// assume .sao type color table |
657 |
unsigned short r[tablesize], g[tablesize], b[tablesize]; |
658 |
for (i=0; i<=tablesize; i++) |
659 |
r[i] = g[i] = b[i] = 0; |
660 |
while (fgets(buf,256,ct)) |
661 |
{ |
662 |
if (strncmp(buf,"RED:",4)==0) |
663 |
proc_color(ct,r,maxcolor); |
664 |
if (strncmp(buf,"GREEN:",6)==0) |
665 |
proc_color(ct,g,maxcolor); |
666 |
if (strncmp(buf,"BLUE:",5)==0) |
667 |
proc_color(ct,b,maxcolor); |
668 |
} |
669 |
table[0] = table[1] = table[2] = 0; |
670 |
table[colors*lastcolor] = table[colors*lastcolor+1] = table[colors*lastcolor+2] = lastcolor; |
671 |
for (i=1; i<lastcolor; i++) |
672 |
{ |
673 |
c = 0; |
674 |
table[i*colors + c++] = r[i]; |
675 |
table[i*colors + c++] = g[i]; |
676 |
table[i*colors + c++] = b[i]; |
677 |
} |
678 |
} |
679 |
fclose(ct); |
680 |
} |
681 |
return(table); |
682 |
} |
683 |
|
684 |
void proc_color(FILE *ct, unsigned short *t, int max) |
685 |
{ |
686 |
float cut, val; |
687 |
int pos = -1; |
688 |
double prev = 0.0; |
689 |
int prevloc = 0; |
690 |
double slope; |
691 |
pos = -1; |
692 |
prev = 0.0; |
693 |
prevloc = 0; |
694 |
while (fscanf(ct,"(%f,%f)", &cut, &val) == 2) |
695 |
{ |
696 |
int loc = max*cut + 0.5; |
697 |
val *= max; |
698 |
// fprintf(stderr," got loc=%d, cut=%f %f\n",loc,cut,val); |
699 |
if (pos < 0) |
700 |
{ |
701 |
pos = 0; |
702 |
prev = val; |
703 |
prevloc = 0; |
704 |
} |
705 |
if (loc == prevloc) |
706 |
slope = 0.0; |
707 |
else |
708 |
slope = (val - prev)/(loc - prevloc); |
709 |
while (pos <= loc) |
710 |
{ |
711 |
t[pos] = slope * (pos-prevloc) + prev; |
712 |
pos++; |
713 |
} |
714 |
prev = t[loc]; |
715 |
prevloc = loc; |
716 |
} |
717 |
while (pos <= max) |
718 |
t[pos++] = prev; |
719 |
} |
720 |
|
721 |
|
722 |
char *set_scaling(DRMS_Array_t *in, double *minp, double *maxp, |
723 |
int *nmissp, char *palette, int colors, int bytepercolor, int scaling, int usewhite) |
724 |
{ |
725 |
int idata, ndata, nmiss = 0; |
726 |
float *inData = in->data; |
727 |
ndata = in->axis[0] * in->axis[1]; |
728 |
int tablesize = (bytepercolor == 1 ? 256 : 65536); |
729 |
int color; |
730 |
int grey = strcmp(palette, "GREY") == 0; |
731 |
static unsigned short *table = NULL; |
732 |
static unsigned short *greytable = NULL; |
733 |
static unsigned short *colortable = NULL; |
734 |
char *out; |
735 |
out = (char *)malloc(ndata * colors * bytepercolor * sizeof(char)); |
736 |
int maxcolor = (bytepercolor == 1 ? 254 : 65534); |
737 |
int missingcolor = (usewhite ? maxcolor + 1 : 0); |
738 |
|
739 |
fprintf(stderr,"set_scaling called, scaling=%d, palette=%s, min=%f, max=%f",scaling,palette,*minp,*maxp); |
740 |
fprintf(stderr,"\n missingcolor %d maxcolor %d \n", missingcolor, maxcolor); |
741 |
if (!out) |
742 |
return(NULL); |
743 |
|
744 |
// get color table unless palette is GREY and scaling is MINMAX, do grey inline for that case only |
745 |
// since that combination is used to call set_scaling recursively for histogram generation |
746 |
if (grey && scaling == MINMAX && colors == 1) |
747 |
{ |
748 |
if (!greytable) |
749 |
{ |
750 |
int i; |
751 |
greytable = (unsigned short *)malloc(65536 * sizeof(unsigned short)); |
752 |
for (i=0; i<65536; i++) |
753 |
greytable[i] = i; |
754 |
colortable = greytable; |
755 |
} |
756 |
} |
757 |
else |
758 |
{ |
759 |
if (!table) |
760 |
table = init_color_table(palette, colors, bytepercolor); |
761 |
colortable = table; |
762 |
} |
763 |
|
764 |
switch(scaling) |
765 |
{ |
766 |
case MAG: |
767 |
case MAGMINMAXGIVEN: |
768 |
{ |
769 |
float bias = params_get_double(&cmdparams, "bias"); |
770 |
for (idata=0; idata<ndata; idata++) |
771 |
{ |
772 |
float val = inData[idata]; |
773 |
if (!isnan(val)) |
774 |
// inData[idata] = val/sqrt(fabs(val)+bias); |
775 |
inData[idata] = 400.0*val/pow((fabs(val)+bias), 0.75); |
776 |
} |
777 |
if (isnan(*minp)) *minp = -1500.0; |
778 |
if (isnan(*maxp)) *maxp = -*minp; |
779 |
// no break; |
780 |
} |
781 |
case MINMAX: |
782 |
case MAXMIN: |
783 |
case MINMAXGIVEN: |
784 |
case LOG: |
785 |
case SQRT: |
786 |
{ |
787 |
double min; |
788 |
double max; |
789 |
if (bytepercolor != 1 && bytepercolor != 2) |
790 |
{fprintf(stderr,"wrong bytes per color\n"); return(NULL);} |
791 |
if (scaling == MINMAXGIVEN || scaling == MAG || scaling == MAGMINMAXGIVEN) |
792 |
{ |
793 |
min = *minp; |
794 |
max = *maxp; |
795 |
/* fprintf(stderr,"debug pt 1: min=%f max=%f\n scaling=%d",min,max,scaling ); */ |
796 |
} |
797 |
else |
798 |
{ |
799 |
if (isnan(*minp) || isnan(*maxp)) |
800 |
{ |
801 |
int n=0; |
802 |
min = 1.0e20; |
803 |
max = -min; |
804 |
/* fprintf(stderr,"debug pt 2: min=%f max=%f\n",min,max); */ |
805 |
for (idata=0; idata<ndata; idata++) |
806 |
{ |
807 |
float val = inData[idata]; |
808 |
if (!isnan(val)) |
809 |
{ |
810 |
n++; |
811 |
if (val > max) max = val; |
812 |
if (val < min) min = val; |
813 |
} |
814 |
} |
815 |
if (n==0) |
816 |
{ |
817 |
fprintf(stderr,"set_scaling, min or max is missing and no data values found.\n"); |
818 |
return(NULL); |
819 |
} |
820 |
} |
821 |
if (isnan(*minp)) *minp = min; |
822 |
if (isnan(*maxp)) *maxp = max; |
823 |
min = *minp; |
824 |
max = *maxp; |
825 |
} |
826 |
double use_min, use_max; |
827 |
if (scaling == LOG) |
828 |
{ |
829 |
if (min <= 0) |
830 |
min = 1.0e-10; |
831 |
if (max <= 0) |
832 |
max = 1.0e-10; |
833 |
use_min = log10(min); |
834 |
use_max = log10(max); |
835 |
} |
836 |
else if (scaling == SQRT) |
837 |
{ |
838 |
if (min < 0) |
839 |
min = 0; |
840 |
if (max < 0) |
841 |
max = 0; |
842 |
use_min = sqrt(min); |
843 |
use_max = sqrt(max); |
844 |
} |
845 |
for (idata=0; idata<ndata; idata++) |
846 |
{ |
847 |
/* fprintf(stderr,"debug pt 4: min=%f max=%f\n",min,max); */ |
848 |
float val = inData[idata]; |
849 |
int newval; |
850 |
if (!isnan(val)) |
851 |
{ |
852 |
if (val <= min) val = min; |
853 |
if (val >= max) val = max; |
854 |
if (scaling == LOG) |
855 |
newval = (maxcolor-1)*((log10(val)-use_min)/(use_max-use_min)) + 0.5; |
856 |
else if (scaling == SQRT ) |
857 |
newval = (maxcolor-1)*((sqrt(val)-use_min)/(use_max-use_min)) + 0.5; |
858 |
else |
859 |
{ |
860 |
newval = (maxcolor-1)*(val-min)/(max-min) + 0.5; |
861 |
if (scaling == MAXMIN) |
862 |
newval = maxcolor - newval; |
863 |
} |
864 |
if (newval >= maxcolor) newval = maxcolor; |
865 |
if (newval < 1) newval = 1; |
866 |
} |
867 |
else |
868 |
{ |
869 |
newval = missingcolor; |
870 |
nmiss += 1; |
871 |
} |
872 |
for (color=0; color<colors; color++) |
873 |
{ |
874 |
if (bytepercolor == 1) |
875 |
*((unsigned char *)out + colors*idata + color) = colortable[newval*colors + color]; |
876 |
else |
877 |
*((unsigned short *)out + colors*idata + color) = colortable[newval*colors + color]; |
878 |
} |
879 |
} |
880 |
*maxp = max; |
881 |
*minp = min; |
882 |
*nmissp = nmiss; |
883 |
fprintf(stderr," min %f max %f nmissp %d ndata %d\n", *minp, *maxp, nmiss, ndata); |
884 |
break; |
885 |
} |
886 |
|
887 |
case HISTEQ: |
888 |
{ |
889 |
int ihist, nhist=65536; |
890 |
int *hist = (int *)malloc(nhist * sizeof(int)); |
891 |
int icolor, ncolor = (bytepercolor == 1 ? 255 : 65535); |
892 |
int total, want; |
893 |
unsigned int newval; |
894 |
double valspercolor; |
895 |
char *outa; |
896 |
outa = set_scaling(in, minp, maxp, nmissp, "GREY", 1, 2, MINMAX, 0); |
897 |
valspercolor = (ndata - *nmissp)/(double)ncolor; |
898 |
for (ihist = 0; ihist < nhist; ihist++) |
899 |
hist[ihist] = 0; |
900 |
for (idata=0; idata<ndata; idata++) |
901 |
hist[*((unsigned short *)outa+idata)] += 1; |
902 |
for (icolor=0, total=0, ihist=0; icolor<=ncolor; icolor++) |
903 |
{ |
904 |
want = icolor * valspercolor; |
905 |
for ( ; ihist<nhist; ihist++) |
906 |
{ |
907 |
if (total >= want) |
908 |
break; |
909 |
total += hist[ihist]; |
910 |
hist[ihist] = icolor; |
911 |
} |
912 |
} |
913 |
for ( ; ihist<nhist; ihist++) |
914 |
hist[ihist] = ncolor; |
915 |
for (idata=0; idata<ndata; idata++) |
916 |
{ |
917 |
if (!isnan(inData[idata])) |
918 |
{ |
919 |
newval = hist[*((unsigned short *)outa+idata)]; |
920 |
if (newval > maxcolor) newval = maxcolor; |
921 |
if (newval < 1) newval = 1; |
922 |
} |
923 |
else |
924 |
newval = missingcolor; |
925 |
for (color=0; color<colors; color++) |
926 |
{ |
927 |
if (bytepercolor == 1) |
928 |
*((unsigned char *)out + colors*idata + color) = colortable[newval*colors + color]; |
929 |
else |
930 |
*((unsigned short *)out + colors*idata + color) = colortable[newval*colors + color]; |
931 |
} |
932 |
} |
933 |
// fprintf(stderr," HISTEQ scaling %d \n", scaling); |
934 |
free(outa); |
935 |
free(hist); |
936 |
break; |
937 |
} |
938 |
|
939 |
case MINMAX99: |
940 |
case MAXMIN99: |
941 |
{ |
942 |
fprintf(stderr,"DOING set_scaling case MAXMIN99 \n"); |
943 |
int ihist, nhist=65536; |
944 |
int *hist = (int *)malloc(nhist * sizeof(int)); |
945 |
int icolor, ncolor = (bytepercolor == 1 ? 255 : 65535); |
946 |
int total, want; |
947 |
unsigned int newval; |
948 |
double newmin, newmax; |
949 |
char *outa; |
950 |
fprintf(stderr," CALLING set_scaling case MINMAX %d \n", MINMAX); |
951 |
*minp = 0; |
952 |
*maxp = 0; |
953 |
outa = set_scaling(in, minp, maxp, nmissp, "GREY", 1, 2, MINMAX, 0); |
954 |
|
955 |
fprintf(stderr,"CONTINUING: set_scaling, case MAXMIN99 %f %f \n", *minp, *maxp); |
956 |
|
957 |
for (ihist=0; ihist<nhist; ihist++) |
958 |
hist[ihist] = 0; |
959 |
for (idata=0; idata<ndata; idata++) |
960 |
{ |
961 |
hist[*((unsigned short *)outa+idata)] += 1; |
962 |
} |
963 |
|
964 |
want = ndata/600; |
965 |
fprintf(stderr,"ndata %d want %d nhist %d \n", ndata, want, nhist); |
966 |
total = 0; |
967 |
for (ihist=0; ihist<nhist; total += hist[ihist++]) |
968 |
if (total >= want) |
969 |
break; |
970 |
newmin = *minp + ((double)ihist/(double)nhist) * (*maxp - *minp); |
971 |
|
972 |
total = 0; |
973 |
for (ihist=nhist - 1; ihist>=0; total += hist[ihist--]) |
974 |
if (total >= want) |
975 |
break; |
976 |
newmax = *minp + ((double)ihist/(double)nhist) * (*maxp - *minp); |
977 |
fprintf(stderr,"ihist %d newmax=%f newmin=%f \n", ihist, newmax, newmin); |
978 |
if (newmax <= newmin) |
979 |
{ |
980 |
newmax = *maxp; |
981 |
newmin = *minp; |
982 |
} |
983 |
|
984 |
fprintf(stderr,"newmax %f minp %f \n", newmax, *minp); |
985 |
for (idata=0; idata<ndata; idata++) |
986 |
{ |
987 |
float val = inData[idata]; |
988 |
unsigned short newval; |
989 |
if (!isnan(val)){ |
990 |
if (val <= newmin) val=newmin; |
991 |
if (val >= newmax) val=newmax; |
992 |
newval = maxcolor*(val-newmin)/(newmax-newmin); |
993 |
if (scaling == MAXMIN99) |
994 |
newval = maxcolor - newval; |
995 |
if (newval > maxcolor) newval = maxcolor; |
996 |
if (newval < 1) newval = 1; |
997 |
} |
998 |
|
999 |
else |
1000 |
newval = missingcolor; |
1001 |
for (color=0; color<colors; color++) |
1002 |
{ |
1003 |
if (bytepercolor == 1) |
1004 |
*((unsigned char *)out + colors*idata + color) = colortable[newval*colors + color]; |
1005 |
else |
1006 |
*((unsigned short *)out + colors*idata + color) = colortable[newval*colors + color]; |
1007 |
} |
1008 |
} |
1009 |
free(outa); |
1010 |
free(hist); |
1011 |
break; |
1012 |
} |
1013 |
} |
1014 |
return(out); |
1015 |
} |
1016 |
|
1017 |
// ---------------------------------------------------------------------- |
1018 |
int make_png(char *filename, unsigned char *data, |
1019 |
int height, int width, char *palette, int bytepercolor, int colors) |
1020 |
{ |
1021 |
int row; |
1022 |
FILE *fp; // = NULL; |
1023 |
png_byte **row_pointers = NULL; |
1024 |
png_structp png_ptr = NULL; |
1025 |
png_infop info_ptr = NULL; |
1026 |
|
1027 |
fp = fopen(filename, "w"); |
1028 |
if (!fp) |
1029 |
PNGDIE("cant open output file"); |
1030 |
|
1031 |
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, |
1032 |
NULL, NULL); |
1033 |
if (!png_ptr) |
1034 |
PNGDIE("cant create png_struct"); |
1035 |
|
1036 |
info_ptr = png_create_info_struct(png_ptr); |
1037 |
if (!info_ptr) |
1038 |
PNGDIE("cant create png_infop"); |
1039 |
|
1040 |
if (setjmp(png_jmpbuf(png_ptr))) |
1041 |
PNGDIE("png fatal error"); |
1042 |
|
1043 |
png_init_io(png_ptr, fp); |
1044 |
// fprintf(stderr, "ready png, bitdepth=8*bytepercolor=%d, colors=%d \n",8*bytepercolor,colors); |
1045 |
png_set_IHDR(png_ptr, info_ptr, width, height, 8*bytepercolor, |
1046 |
(colors == 1 ? PNG_COLOR_TYPE_GRAY : PNG_COLOR_TYPE_RGB), PNG_INTERLACE_ADAM7, |
1047 |
PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); |
1048 |
png_write_info(png_ptr, info_ptr); |
1049 |
if (bytepercolor > 1) |
1050 |
png_set_swap(png_ptr); |
1051 |
png_set_gAMA(png_ptr, info_ptr, 2.2); |
1052 |
png_set_sRGB(png_ptr, info_ptr, PNG_sRGB_INTENT_ABSOLUTE); |
1053 |
row_pointers = (png_byte **)malloc(height * sizeof(png_byte *)); |
1054 |
|
1055 |
for (row=0; row<height ; row++) |
1056 |
{ |
1057 |
if (bytepercolor == 1) |
1058 |
row_pointers[height - row - 1] = (png_byte *)((char *)data + colors*row*width); |
1059 |
else |
1060 |
row_pointers[height - row - 1] = (png_byte *)((short *)data + colors*row*width); |
1061 |
} |
1062 |
png_set_rows(png_ptr, info_ptr, row_pointers); |
1063 |
png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_SWAP_ENDIAN, NULL); |
1064 |
fclose(fp); |
1065 |
|
1066 |
png_destroy_write_struct(&png_ptr, &info_ptr); |
1067 |
free(row_pointers); |
1068 |
return(0); |
1069 |
} |
1070 |
|
1071 |
// ---------------------------------------------------------------------- |
1072 |
|
1073 |
/* center whith whole pixel shifts and rotate by 180 if needed */ |
1074 |
/* Only apply center if it will not result in an image crop. I.e. not ever |
1075 |
for AIA, and not for HMI or MDI or other if a shift of more than 20 arcsec |
1076 |
is implied */ |
1077 |
int upNcenter(DRMS_Array_t *arr, ObsInfo_t *ObsLoc) |
1078 |
{ |
1079 |
int nx, ny, ix, iy, i, j, xoff, yoff, max_off; |
1080 |
double rot, x0, y0, midx, midy; |
1081 |
float *data; |
1082 |
float *data2; |
1083 |
if (!arr || !ObsLoc) |
1084 |
return(1); |
1085 |
data = arr->data; |
1086 |
nx = arr->axis[0]; |
1087 |
ny = arr->axis[1]; |
1088 |
x0 = ObsLoc->crpix1 - 1; |
1089 |
y0 = ObsLoc->crpix2 - 1; |
1090 |
midx = (nx-1.0)/2.0; |
1091 |
midy = (ny-1.0)/2.0; |
1092 |
if ((rot = fabs(ObsLoc->crota2)) > 179 && rot < 181) |
1093 |
{ |
1094 |
// rotate image by 180 degrees by a flip flip |
1095 |
float val; |
1096 |
int half = ny / 2; |
1097 |
int odd = ny & 1; |
1098 |
if (odd) half++; |
1099 |
for (iy=0; iy<half; iy++) |
1100 |
{ |
1101 |
for (ix=0; ix<nx; ix++) |
1102 |
{ |
1103 |
i = iy*nx + ix; |
1104 |
j = (ny - 1 - iy)*nx + (nx - 1 - ix); |
1105 |
val = data[i]; |
1106 |
data[i] = data[j]; |
1107 |
data[j] = val; |
1108 |
} |
1109 |
} |
1110 |
x0 = nx - 1 - x0; |
1111 |
y0 = ny - 1 - y0; |
1112 |
rot = ObsLoc->crota2 - 180.0; |
1113 |
if (rot < -90.0) rot += 360.0; |
1114 |
ObsLoc->crota2 = rot; |
1115 |
} |
1116 |
// Center to nearest pixel - if OK to do so |
1117 |
xoff = round(x0 - midx); |
1118 |
yoff = round(y0 - midy); |
1119 |
max_off = 20.0 / ObsLoc->cdelt1; |
1120 |
if (arr->parent_segment && |
1121 |
arr->parent_segment->record && |
1122 |
arr->parent_segment->record->seriesinfo && |
1123 |
arr->parent_segment->record->seriesinfo->seriesname && |
1124 |
strncasecmp(arr->parent_segment->record->seriesinfo->seriesname, "aia", 3) && |
1125 |
abs(xoff) < max_off && abs(yoff) < max_off) |
1126 |
{ |
1127 |
if (abs(xoff) >= 1 || abs(yoff) >= 1) |
1128 |
{ |
1129 |
data2 = malloc(4*nx*ny); |
1130 |
for (iy=0; iy<ny; iy++) |
1131 |
{ |
1132 |
int jy = iy + yoff; |
1133 |
for (ix=0; ix<nx; ix++) |
1134 |
{ |
1135 |
int jx = ix + xoff; |
1136 |
int idx = jy*nx + jx; |
1137 |
int idx2 = iy*nx + ix; |
1138 |
if (jx<0 || jx>=nx || jy<0 || jy>=ny) |
1139 |
data2[idx2] = DRMS_MISSING_FLOAT; |
1140 |
else |
1141 |
data2[idx2] = data[idx]; |
1142 |
} |
1143 |
} |
1144 |
x0 -= xoff; |
1145 |
y0 -= yoff; |
1146 |
free(data); |
1147 |
arr->data = data2; |
1148 |
} |
1149 |
} |
1150 |
// update center location |
1151 |
ObsLoc->crpix1 = x0 + 1; |
1152 |
ObsLoc->crpix2 = y0 + 1; |
1153 |
return(0); |
1154 |
} |
1155 |
|
1156 |
// ---------------------------------------------------------------------- |
1157 |
|
1158 |
int crop_image(DRMS_Array_t *arr, ObsInfo_t *ObsLoc) |
1159 |
{ |
1160 |
int nx, ny, ix, iy, i, j, xoff, yoff; |
1161 |
double x0, y0; |
1162 |
double rsun = ObsLoc->rsun_obs/ObsLoc->cdelt1; |
1163 |
double scale, crop_limit; |
1164 |
float *data; |
1165 |
if (!arr || !ObsLoc) |
1166 |
return(1); |
1167 |
data = arr->data; |
1168 |
nx = arr->axis[0]; |
1169 |
ny = arr->axis[1]; |
1170 |
x0 = ObsLoc->crpix1 - 1; |
1171 |
y0 = ObsLoc->crpix2 - 1; |
1172 |
scale = 1.0/rsun; |
1173 |
crop_limit = 0.99975; // 1 - 1/4000, 1/2 HMI pixel. |
1174 |
for (iy=0; iy<ny; iy++) |
1175 |
for (ix=0; ix<nx; ix++) |
1176 |
{ |
1177 |
double x, y, R2; |
1178 |
float *Ip = data + iy*nx + ix; |
1179 |
if (drms_ismissing_float(*Ip)) |
1180 |
continue; |
1181 |
x = ((double)ix - x0) * scale; /* x,y in pixel coords */ |
1182 |
y = ((double)iy - y0) * scale; |
1183 |
R2 = x*x + y*y; |
1184 |
if (R2 > crop_limit) |
1185 |
*Ip = DRMS_MISSING_FLOAT; |
1186 |
} |
1187 |
return(0); |
1188 |
} |
1189 |
|
1190 |
#define CHECK(keyname) {if (status) {fprintf(stderr,"Keyword failure to find: %s, status=%d\n",keyname,status); *rstatus=status; return(NULL);}} |
1191 |
|
1192 |
ObsInfo_t *GetObsInfo(DRMS_Segment_t *seg, ObsInfo_t *pObsLoc, int *rstatus) |
1193 |
{ |
1194 |
TIME t_prev; |
1195 |
DRMS_Record_t *rec; |
1196 |
TIME t_obs; |
1197 |
double dv; |
1198 |
ObsInfo_t *ObsLoc; |
1199 |
int status; |
1200 |
char t_key[100]; |
1201 |
|
1202 |
if (!seg || !(rec = seg->record)) |
1203 |
{ *rstatus = 1; return(NULL); } |
1204 |
|
1205 |
ObsLoc = (pObsLoc ? pObsLoc : (ObsInfo_t *)malloc(sizeof(ObsInfo_t))); |
1206 |
if (!pObsLoc) |
1207 |
memset(ObsLoc, 0, sizeof(ObsInfo_t)); |
1208 |
|
1209 |
t_prev = ObsLoc->t_obs; |
1210 |
if (drms_keyword_lookup(rec, "T_OBS", 0)) |
1211 |
strcpy(t_key, "T_OBS"); |
1212 |
else |
1213 |
strcpy(t_key, "T_REC"); |
1214 |
t_obs = drms_getkey_time(rec, t_key, &status); CHECK(t_key); |
1215 |
|
1216 |
if (t_obs <= 0.0) |
1217 |
{ *rstatus = 2; return(NULL); } |
1218 |
|
1219 |
if (t_obs != t_prev) |
1220 |
{ |
1221 |
ObsLoc->crpix1 = drms_getkey_double(rec, "CRPIX1", &status); CHECK("CRPIX1"); |
1222 |
ObsLoc->crpix2 = drms_getkey_double(rec, "CRPIX2", &status); CHECK("CRPIX2"); |
1223 |
ObsLoc->crval1 = drms_getkey_double(rec, "CRVAL1", &status); CHECK("CRVAL1"); |
1224 |
ObsLoc->crval2 = drms_getkey_double(rec, "CRVAL2", &status); CHECK("CRVAL2"); |
1225 |
ObsLoc->cdelt1 = drms_getkey_double(rec, "CDELT1", &status); CHECK("CDELT1"); |
1226 |
ObsLoc->cdelt2 = drms_getkey_double(rec, "CDELT2", &status); CHECK("CDELT1"); |
1227 |
ObsLoc->crota2 = drms_getkey_double(rec, "CROTA2", &status); if (status) ObsLoc->crota2 = 0.0; // WCS default |
1228 |
ObsLoc->sina = sin(ObsLoc->crota2*Deg2Rad); |
1229 |
ObsLoc->cosa = sqrt (1.0 - ObsLoc->sina*ObsLoc->sina); |
1230 |
ObsLoc->rsun_obs = drms_getkey_double(rec, "RSUN_OBS", &status); |
1231 |
if (status) |
1232 |
{ |
1233 |
double dsun_obs = drms_getkey_double(rec, "DSUN_OBS", &status); CHECK("DSUN_OBS"); |
1234 |
ObsLoc->rsun_obs = asin(696000000.0/dsun_obs)/arcsec2Rad; |
1235 |
} |
1236 |
ObsLoc->obs_vr = drms_getkey_double(rec, "OBS_VR", &status); CHECK("OBS_VR"); |
1237 |
ObsLoc->obs_vw = drms_getkey_double(rec, "OBS_VW", &status); CHECK("OBS_VW"); |
1238 |
ObsLoc->obs_vn = drms_getkey_double(rec, "OBS_VN", &status); CHECK("OBS_VN"); |
1239 |
ObsLoc->obs_b0 = drms_getkey_double(rec, "CRLT_OBS", &status); CHECK("CRLT_OBS"); |
1240 |
ObsLoc->t_obs = t_obs; |
1241 |
} |
1242 |
*rstatus = 0; |
1243 |
return(ObsLoc); |
1244 |
} |
1245 |
|
1246 |
|
1247 |
// ---------------------------------------------------------------------- |