NCEPLIBS-g2c  1.8.0
pngpack.c
Go to the documentation of this file.
1 
5 #include <stdlib.h>
6 #include <math.h>
7 #include "grib2_int.h"
8 
52 static int
53 pngpack_int(void *fld, int fld_is_double, g2int width, g2int height, g2int *idrstmpl,
54  unsigned char *cpack, g2int *lcpack, int verbose)
55 {
56  g2int *ifld = NULL;
57  static float alog2 = ALOG2; /* ln(2.0) */
58  g2int j, nbits, imin, imax, maxdif;
59  g2int ndpts, nbytes;
60  float bscale, dscale, rmax, rmin, temp;
61  double rmaxd, rmind;
62  unsigned char *ctemp;
63  float *ffld = fld;
64  double *dfld = fld;
65  int ret = G2C_NOERROR;
66 
67  LOG((2, "pngpack_int fld_is_double %d width %ld height %ld idrstmpl[1] %d",
68  fld_is_double, width, height, idrstmpl[1]));
69 
70  ndpts = width * height;
71  bscale = int_power(2.0, -idrstmpl[1]);
72  dscale = int_power(10.0, idrstmpl[2]);
73  LOG((3, "ndpts %d bscale %g dscale %g", ndpts, bscale, dscale));
74 
75  /* Find max and min values in the data. Either rmax and rmin will
76  * be used (if fld_is_double is not true), or rmaxd and rmind will
77  * be used (if fld_is_double is true). */
78  rmaxd = dfld[0];
79  rmind = dfld[0];
80  rmax = ffld[0];
81  rmin = ffld[0];
82  if (fld_is_double)
83  {
84  for (j = 1; j < ndpts; j++)
85  {
86  if (dfld[j] > rmaxd)
87  rmaxd = dfld[j];
88  if (dfld[j] < rmind)
89  rmind = dfld[j];
90  }
91  maxdif = (g2int)rint((rmaxd - rmind) * dscale * bscale);
92  }
93  else
94  {
95  for (j = 1; j < ndpts; j++)
96  {
97  if (ffld[j] > rmax)
98  rmax = ffld[j];
99  if (ffld[j] < rmin)
100  rmin = ffld[j];
101  }
102  maxdif = (g2int)rint((rmax - rmin) * dscale * bscale);
103  }
104  LOG((3, "rmax %g rmaxd %g rmin %g rmind %g", rmax, rmaxd, rmin, rmind));
105 
106  /* If max and min values are not equal, pack up field. If they are
107  * equal, we have a constant field, and the reference value (rmin)
108  * is the value for each point in the field and set nbits to 0. */
109  if (((fld_is_double && rmind != rmaxd) || (!fld_is_double && rmin != rmax)) && maxdif != 0)
110  {
111  ifld = malloc(ndpts * sizeof(g2int));
112 
113  /* Determine which algorithm to use based on user-supplied
114  * binary scale factor and number of bits. */
115  if (idrstmpl[1] == 0)
116  {
117  /* No binary scaling and calculate minumum number of bits
118  * in which the data will fit. */
119  imin = (g2int)rint((fld_is_double ? rmind : rmin) * dscale);
120  imax = (g2int)rint((fld_is_double ? rmaxd : rmax) * dscale);
121  maxdif = imax - imin;
122  temp = log((double)(maxdif + 1)) / alog2;
123  nbits = (g2int)ceil(temp);
124  /* scale data */
125  if (fld_is_double)
126  {
127  rmind = (float)imin;
128  for(j = 0; j < ndpts; j++)
129  ifld[j] = (g2int)rint(dfld[j] * dscale) - imin;
130  }
131  else
132  {
133  rmin = (float)imin;
134  for(j = 0; j < ndpts; j++)
135  ifld[j] = (g2int)rint(ffld[j] * dscale) - imin;
136  }
137  }
138  else
139  {
140  /* Use binary scaling factor and calculate minumum number
141  * of bits in which the data will fit. */
142  if (fld_is_double)
143  {
144  rmind = rmind * dscale;
145  rmaxd = rmaxd * dscale;
146  maxdif = (g2int)rint((rmaxd - rmind) * bscale);
147  }
148  else
149  {
150  rmin = rmin * dscale;
151  rmax = rmax * dscale;
152  maxdif = (g2int)rint((rmax - rmin) * bscale);
153  }
154  temp = log((double)(maxdif + 1)) / alog2;
155  nbits = (g2int)ceil(temp);
156  /* scale data */
157  if (fld_is_double)
158  {
159  for (j = 0; j < ndpts; j++)
160  ifld[j] = (g2int)rint(((dfld[j] * dscale) - rmind) * bscale);
161  }
162  else
163  {
164  for (j = 0; j < ndpts; j++)
165  ifld[j] = (g2int)rint(((ffld[j] * dscale) - rmin) * bscale);
166  }
167  }
168 
169  /* Pack data into full octets, then do PNG encode and
170  * calculate the length of the packed data in bytes. */
171  if (nbits <= 8)
172  nbits = 8;
173  else if (nbits <= 16)
174  nbits = 16;
175  else if (nbits <= 24)
176  nbits = 24;
177  else
178  nbits = 32;
179 
180  nbytes = (nbits / 8) * ndpts;
181  ctemp = calloc(nbytes, 1);
182  sbits(ctemp, ifld, 0, nbits, 0, ndpts);
183 
184  /* Encode data into PNG Format. */
185  if ((*lcpack = (g2int)enc_png(ctemp, width, height, nbits, cpack)) <= 0)
186  {
187  if (verbose)
188  printf("pngpack: ERROR Packing PNG = %d\n", (int)*lcpack);
189  ret = G2C_EPNG;
190  }
191  free(ctemp);
192  }
193  else
194  {
195  nbits = 0;
196  *lcpack = 0;
197  }
198 
199  /* Fill in ref value and number of bits in Template 5.0. */
200  if (fld_is_double)
201  rmin = (float)rmind;
202  mkieee(&rmin, idrstmpl, 1); /* ensure reference value is IEEE format */
203  idrstmpl[3] = nbits;
204  idrstmpl[4] = 0; /* original data were reals */
205 
206  if (ifld)
207  free(ifld);
208 
209  return ret;
210 }
211 
241 void
242 pngpack(float *fld, g2int width, g2int height, g2int *idrstmpl,
243  unsigned char *cpack, g2int *lcpack)
244 {
245  /* Ignore the return value. */
246  pngpack_int(fld, 0, width, height, idrstmpl, cpack, lcpack, 1);
247 }
248 
281 int
282 g2c_pngpackf(float *fld, size_t width, size_t height, int *idrstmpl,
283  unsigned char *cpack, int *lcpack)
284 {
285  g2int width8 = width, height8 = height, lcpack8 = *lcpack;
286  g2int idrstmpl8[G2C_PNG_DRS_TEMPLATE_LEN];
287  int i, ret;
288 
289  for (i = 0; i < G2C_PNG_DRS_TEMPLATE_LEN; i++)
290  idrstmpl8[i] = idrstmpl[i];
291 
292  ret = pngpack_int(fld, 0, width8, height8, idrstmpl8, cpack, &lcpack8, 0);
293 
294  if (!ret)
295  {
296  for (i = 0; i < G2C_PNG_DRS_TEMPLATE_LEN; i++)
297  idrstmpl[i] = (int)idrstmpl8[i];
298  *lcpack = (g2int)lcpack8;
299  }
300  return ret;
301 }
302 
335 int
336 g2c_pngpackd(double *fld, size_t width, size_t height, int *idrstmpl,
337  unsigned char *cpack, int *lcpack)
338 {
339  g2int width8 = width, height8 = height, lcpack8 = *lcpack;
340  g2int idrstmpl8[G2C_PNG_DRS_TEMPLATE_LEN];
341  int i, ret;
342 
343  for (i = 0; i < G2C_PNG_DRS_TEMPLATE_LEN; i++)
344  idrstmpl8[i] = idrstmpl[i];
345 
346  ret = pngpack_int(fld, 1, width8, height8, idrstmpl8, cpack, &lcpack8, 0);
347 
348  if (!ret)
349  {
350  for (i = 0; i < G2C_PNG_DRS_TEMPLATE_LEN; i++)
351  idrstmpl[i] = (int)idrstmpl8[i];
352  *lcpack = (g2int)lcpack8;
353  }
354  return ret;
355 }
356 
int enc_png(unsigned char *data, g2int width, g2int height, g2int nbits, unsigned char *pngbuf)
Encode PNG.
Definition: enc_png.c:75
void sbits(unsigned char *out, g2int *in, g2int iskip, g2int nbits, g2int nskip, g2int n)
Store bits - put arbitrary size values into a packed bit string, taking the low order bits from each ...
Definition: gbits.c:180
#define G2C_EPNG
Error encoding/decoding PNG data.
Definition: grib2.h:511
#define G2C_PNG_DRS_TEMPLATE_LEN
Length of the idrstmpl array for PNG packing.
Definition: grib2.h:421
int64_t g2int
Long integer type.
Definition: grib2.h:33
#define G2C_NOERROR
No error.
Definition: grib2.h:491
Header file with internal function prototypes NCEPLIBS-g2c library.
void mkieee(float *a, g2int *rieee, g2int num)
This subroutine stores a list of real values in 32-bit IEEE floating point format.
Definition: mkieee.c:22
double int_power(double x, g2int y)
Function similar to C pow() power function.
Definition: int_power.c:18
#define LOG(e)
Ignore logging to stdout.
Definition: grib2_int.h:426
#define ALOG2
ln(2.0)
Definition: grib2_int.h:30
void pngpack(float *fld, g2int width, g2int height, g2int *idrstmpl, unsigned char *cpack, g2int *lcpack)
This subroutine packs up a float data field into PNG image format.
Definition: pngpack.c:242
int g2c_pngpackd(double *fld, size_t width, size_t height, int *idrstmpl, unsigned char *cpack, int *lcpack)
This subroutine packs up a double data field into PNG image format.
Definition: pngpack.c:336
int g2c_pngpackf(float *fld, size_t width, size_t height, int *idrstmpl, unsigned char *cpack, int *lcpack)
This subroutine packs up a float data field into PNG image format.
Definition: pngpack.c:282
static int pngpack_int(void *fld, int fld_is_double, g2int width, g2int height, g2int *idrstmpl, unsigned char *cpack, g2int *lcpack, int verbose)
This internal function packs up float or double data into PNG image format.
Definition: pngpack.c:53