00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include <stdlib.h>
00024 #include <stdio.h>
00025 #include <unistd.h>
00026 #include <sys/stat.h>
00027 #include <sys/ioctl.h>
00028 #include <sys/types.h>
00029 #include <sys/stat.h>
00030 #include <fcntl.h>
00031 #include <math.h>
00032
00033 #include <asm/elphel/autoexp.h>
00034 #include <asm/elphel/hist.h>
00035
00036 #include <sys/mman.h>
00037 #include <asm/elphel/c313a.h>
00038
00039
00040
00041 #include "libpng/png.h"
00042
00043 #define HIST_SIZE 256 * 4 * 4
00044
00045 #define HPNG_PLOT_BARS 1
00046 #define HPNG_CONNECT_DOTS 2
00047 #define HPNG_FILL_ZEROS 4
00048 #define HPNG_LIN_INTERP 8
00049 #define HPNG_RUN_SQRT 16
00050
00051 #define QRY_MAXPARAMS 64
00052
00053 char copyQuery [4096];
00054 const char *uri;
00055 const char *method;
00056 const char *query;
00057
00058 struct key_value {
00059 char *key;
00060 char *value;
00061 };
00062
00063 struct key_value gparams[QRY_MAXPARAMS+1];
00064
00065 int unescape(char *, int);
00066 int hexdigit(char);
00067 char * paramValue(struct key_value *, char *);
00068 int parseQuery(struct key_value *, char *);
00069
00070
00071 struct autoexp_t autoexp;
00072 int write_png(int height, int data[1024], int mode, int colors);
00073 int main(argc, argv)
00074 int argc;
00075 char *argv[];
00076 {
00077 int hists[1536];
00078 int rava[256];
00079
00080 int autoexp_fd;
00081 int i,j,k,a,l;
00082
00083
00084 int png_height=256;
00085 double dscale=3.0;
00086 int mode=14;
00087 int colors=57;
00088 int rav=0;
00089
00090 double dcoeff;
00091 int coeff;
00092 int ww,wh;
00093 int devfd;
00094 int lastmiddle_i,newmiddle_i;
00095 int z;
00096 void *_map;
00097 const char colors_calc[]={ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,0xa,0xb,0xc,0xd,0xe,0xf,
00098 0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,
00099 6, 7, 6, 7, 6, 7, 6, 7,0xe,0xf,0xe,0xf,0xe,0xf,0xe,0xf,
00100 0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf};
00101 char * v;
00102 #if 0
00103 if (argc<5) {printf("pnghist height scale mode colors average"); return 0;}
00104
00105 rav=atoi(argv[5]);
00106 png_height=atoi(argv[1]);
00107 if (png_height>256) png_height=256;
00108 dscale=atof(argv[2]);
00109 mode=atoi(argv[3]);
00110 colors=atoi(argv[4]) & 0x3f;
00111 #endif
00112
00113
00114 method = getenv("REQUEST_METHOD");
00115 query = getenv("QUERY_STRING");
00116 uri = getenv("REQUEST_URI");
00117
00118 i= (query)? strlen (query):0;
00119
00120
00121 if (i>(sizeof(copyQuery)-1)) i= sizeof(copyQuery)-1;
00122 if (i>0) strncpy(copyQuery,query, i);
00123 copyQuery[i]=0;
00124 unescape(copyQuery,sizeof(copyQuery));
00125
00126 if (method == NULL)
00127 {
00128
00129 printf("This program should be run as a CGI from the web server!\n");
00130 exit(1);
00131 }
00132
00133 parseQuery(gparams, copyQuery);
00134 #define HPNG_PLOT_BARS 1
00135
00136
00137
00138
00139
00140
00141 if((v = paramValue(gparams, "height")) != NULL) png_height=atoi(v);
00142 if((v = paramValue(gparams, "draw")) != NULL) mode= (mode & 0xfc) | (atoi(v) & 3);
00143 if((v = paramValue(gparams, "fillz")) != NULL) mode= (mode & (~HPNG_FILL_ZEROS)) | (atoi(v)?HPNG_FILL_ZEROS:0);
00144 if((v = paramValue(gparams, "linterpz")) != NULL) mode= (mode & (~HPNG_LIN_INTERP)) | (atoi(v)?HPNG_LIN_INTERP:0);
00145 if((v = paramValue(gparams, "sqrt")) != NULL) mode= (mode & (~HPNG_RUN_SQRT)) | (atoi(v)?HPNG_RUN_SQRT:0);
00146 if((v = paramValue(gparams, "colors")) != NULL) colors=atoi(v);
00147 if((v = paramValue(gparams, "average")) != NULL) rav=atoi(v);
00148 if((v = paramValue(gparams, "scale")) != NULL) dscale=atof(v);
00149
00150
00151
00152
00153 if ((devfd = open("/dev/ccam_img", O_RDONLY)) < 0) {
00154
00155 fprintf(stdout, "Pragma: no-cache\n");
00156 fprintf(stdout, "Content-Type: text/plain\n\n");
00157 fprintf(stdout, "Device busy (%s)\r\n", "/dev/ccam_img");
00158 fflush(stdout);
00159 return -1;
00160 }
00161
00162 ww=ioctl(devfd, _CCCMD( CCAM_RPARS , P_ACTUAL_WIDTH), 0);
00163 wh=ioctl(devfd, _CCCMD( CCAM_RPARS , P_ACTUAL_HEIGHT), 0);
00164 close (devfd);
00165
00166
00167
00168 int retr=10000;
00169 autoexp_fd=-1;
00170 while ( (((autoexp_fd = open(AUTOEXP_DEV_NAME, O_RDONLY)))<0) && (retr>0)) retr--;
00171 if(autoexp_fd < 0) {
00172
00173 fprintf(stdout, "Pragma: no-cache\n");
00174 fprintf(stdout, "Content-Type: text/plain\n\n");
00175 fprintf(stdout, "open %s failed - may be busy, or not started\r\n", AUTOEXP_DEV_NAME);
00176 fflush(stdout);
00177 return -1;
00178 }
00179 z = ioctl(autoexp_fd, _IO(IOC_AUTOEXP_GET, 0x00), &autoexp);
00180
00181
00182
00183 if((_map = mmap(NULL, HIST_SIZE, PROT_READ, MAP_FIXED | MAP_SHARED, autoexp_fd, 0)) == MAP_FAILED) {
00184
00185 fprintf(stdout, "Pragma: no-cache\n");
00186 fprintf(stdout, "Content-Type: text/plain\n\n");
00187 fprintf(stdout, "broken mmap: %s !!!\n", AUTOEXP_DEV_NAME);
00188 fflush(stdout);
00189 return -1;
00190 }
00191 memcpy (hists,_map,HIST_SIZE);
00192 close (autoexp_fd);
00193
00194 ww=(ww*autoexp.width)/100;
00195 wh=(wh*autoexp.height)/100;
00196 dcoeff=(png_height*1024)/(dscale*ww*wh);
00197 coeff=dcoeff*65536;
00198 #ifdef PNGHISTDEBUG
00199 printf ("w=%d, h=%d\n",ww,wh);
00200 for (i=0;i<1024;i++) {
00201 printf ("%5d ",hists[i]);
00202 if ((i & 0x0f)== 0x0f) printf ("\n");
00203 if ((i & 0xff) == 0xff) printf ("-----------------------------------------------\n");
00204
00205 }
00206 printf ("===============================================\n");
00207 #endif
00208
00209
00210
00211 if ((mode & (HPNG_FILL_ZEROS | HPNG_LIN_INTERP)) | (rav>1)) {
00212 for (j=0;j<4;j++) if (colors_calc[colors] & (1<<j)) {
00213 lastmiddle_i=255;
00214 i=255;
00215 while ((hists[i+(j<<8)]==0) && (i>0)) i--;
00216 while (i>0) {
00217 k=i;
00218 i--;
00219 while ((i>=0) && (hists[i+(j<<8)]==0)) i--;
00220 if ((k-i)>1) {
00221 a=hists[k+(j<<8)]/(k-i);
00222 for (l=k;l>i;l--) hists[l+(j<<8)] = a;
00223 }
00224 if ((mode & HPNG_LIN_INTERP) | (rav>1)) {
00225 newmiddle_i= (k+i+1)/2;
00226 for (l=lastmiddle_i-1;l>newmiddle_i;l--) {
00227 hists[l+(j<<8)]= hists[newmiddle_i+(j<<8)] + ((l-newmiddle_i)* (hists[lastmiddle_i+(j<<8)]-hists[newmiddle_i+(j<<8)]))/(lastmiddle_i-newmiddle_i);
00228 }
00229 lastmiddle_i=newmiddle_i;
00230
00231 }
00232 }
00233
00234 if (rav>0) {
00235 k=0;
00236 l=0;
00237 for (i=0;i<256;i++) {
00238 rava[i]=hists[i+(j<<8)];
00239 k+=rava[i];
00240 if ((i-rav)>=0) k-=rava[i-rav];
00241 else l++;
00242 hists[i+(j<<8)]=k/l;
00243 }
00244 }
00245
00246
00247 }
00248 }
00249
00250 if (colors & 0x10) for (i=0;i<256;i++) hists[i+1024]=(hists[i]+hists[i+256]+hists[i+512]+hists[i+768])>>2;
00251
00252 if (colors & 0x20) for (i=0;i<256;i++) hists[i+1280]=(hists[i+256]+hists[i+512])>>1;
00253
00254 if (mode & HPNG_RUN_SQRT) {
00255 dcoeff=sqrt((32768.0*png_height)/coeff);
00256 for (j=0;j<6;j++) if (colors & (1 << j)) for (i=0;i<256;i++) hists[i+(j<<8)]=sqrt(hists[i+(j<<8)])*dcoeff;
00257 }
00258
00259 for (j=0;j<6;j++) if (colors & (1 << j)) for (i=0;i<256;i++) {
00260 hists[i+(j<<8)]=(hists[i+(j<<8)]*coeff) >> 16;
00261 if (hists[i+(j<<8)] > (png_height-1)) hists[i+(j<<8)] = png_height-1;
00262 }
00263
00264 #ifdef PNGHISTDEBUG
00265 printf ("w=%d, h=%d\n",ww,wh);
00266 for (i=0;i<1536;i++) {
00267 printf ("%5d ",hists[i]);
00268 if ((i & 0x0f)== 0x0f) printf ("\n");
00269 }
00270 #endif
00271
00272
00273
00274
00275 fprintf(stdout, "Pragma: no-cache\n");
00276 fprintf(stdout, "Content-Type: image/png\n\n");
00277 write_png(png_height, hists, mode, colors);
00278 fflush(stdout);
00279
00280 return 0;
00281 }
00282 #define ERROR -1
00283 #define OK 0
00284
00285
00286
00287
00288 int write_png(int png_height, int data[1536], int mode, int colors)
00289 {
00290
00291 png_structp png_ptr;
00292 png_infop info_ptr;
00293
00294 const char clrs[]={1,2,2,4,7,2};
00295
00296 unsigned char cpalette[]= {0, 0, 0,
00297 0xff,0, 0,
00298 0, 0xff,0,
00299 0xff,0xff,0,
00300 0, 0, 0xff,
00301 0xff,0, 0xff,
00302 0, 0xff,0xff,
00303 0xff,0xff,0xff,
00304 0, 0, 0,
00305 0x80,0, 0,
00306 0, 0x80,0,
00307 0x80,0x80,0,
00308 0, 0, 0x80,
00309 0x80,0, 0x80,
00310 0, 0x80,0x80,
00311 0x80,0x80,0x80};
00312 png_colorp palette = (png_colorp ) cpalette;
00313 unsigned char ctransparency[]={0, 255,255,255,255,255,255,255,
00314 255,255,255,255,255,255,255,255};
00315 png_bytep trans = (png_bytep) ctransparency;
00316 png_uint_32 k;
00317 png_uint_32 height=png_height;
00318 png_uint_32 width=256;
00319 png_uint_32 bytes_per_pixel=1;
00320 png_byte image[256][256];
00321 png_bytep row_pointers[256];
00322 int i,j,c0,c,d,l,last;
00323 if (height>256) height=256;
00324
00325 memset(image, 0, sizeof(image));
00326 for (j=0;j<6;j++) if (colors & (1 << j)){
00327 c0= clrs[j];
00328 last=png_height-1;
00329 for (i=0;i<256;i++) {
00330 c=c0 << ((i&1)?0:4);
00331 d=png_height-1-data[i+(j<<8)];
00332 if (d<=0) d=0;
00333 if (d>=png_height) d=png_height-1;
00334 image[d][i>>1] |= c;
00335 if (mode & 1){
00336
00337
00338
00339
00340 for (l=d+1; l<png_height; l++)image[l][i>>1] |= c;
00341
00342 } else if (mode & 2) {
00343 for (l=d+1; l<last; l++) image[l][i>>1] |= c;
00344 for (l=d-1; l>last; l--) image[l][i>>1] |= c;
00345 last=d;
00346
00347 }
00348
00349 }
00350 }
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365 png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
00366 NULL,NULL,NULL);
00367
00368 if (png_ptr == NULL)
00369 {
00370
00371 return (ERROR);
00372 }
00373
00374
00375 info_ptr = png_create_info_struct(png_ptr);
00376 if (info_ptr == NULL)
00377 {
00378
00379 png_destroy_write_struct(&png_ptr, png_infopp_NULL);
00380 return (ERROR);
00381 }
00382
00383
00384
00385
00386 if (setjmp(png_jmpbuf(png_ptr)))
00387 {
00388
00389
00390 png_destroy_write_struct(&png_ptr, &info_ptr);
00391 return (ERROR);
00392 }
00393
00394
00395
00396
00397
00398 png_init_io(png_ptr, stdout);
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417 png_set_IHDR(png_ptr,
00418 info_ptr,
00419 256,
00420 png_height,
00421 4,
00422 PNG_COLOR_TYPE_PALETTE,
00423 PNG_INTERLACE_NONE,
00424 PNG_COMPRESSION_TYPE_BASE,
00425 PNG_FILTER_TYPE_BASE);
00426
00427
00428
00429
00430
00431 png_set_PLTE(png_ptr,
00432 info_ptr,
00433 palette,
00434 PNG_MAX_PALETTE_LENGTH);
00435 png_set_tRNS(png_ptr,
00436 info_ptr,
00437 trans,
00438 sizeof(trans),
00439 NULL);
00440
00441
00442
00443
00444
00445
00446 #if 0
00447 sig_bit.gray = 1;
00448
00449 sig_bit.red = 1;
00450 sig_bit.green = 1;
00451 sig_bit.blue = 1;
00452
00453 sig_bit.alpha = 1;
00454 png_set_sBIT(png_ptr, info_ptr, sig_bit);
00455 #endif
00456
00457
00458
00459
00460
00461
00462
00463 #if 0
00464 text_ptr[0].key = "Title";
00465 text_ptr[0].text = "Histogram";
00466 text_ptr[0].compression = PNG_TEXT_COMPRESSION_NONE;
00467 text_ptr[1].key = "Author";
00468 text_ptr[1].text = "Elphel";
00469 text_ptr[1].compression = PNG_TEXT_COMPRESSION_NONE;
00470 text_ptr[2].key = "Description";
00471 text_ptr[2].text = "color histograms for the camera image/video";
00472 text_ptr[2].compression = PNG_TEXT_COMPRESSION_zTXt;
00473 #ifdef PNG_iTXt_SUPPORTED
00474 text_ptr[0].lang = NULL;
00475 text_ptr[1].lang = NULL;
00476 text_ptr[2].lang = NULL;
00477 #endif
00478 png_set_text(png_ptr, info_ptr, text_ptr, 3);
00479 #endif
00480
00481
00482
00483
00484
00485
00486 png_write_info(png_ptr, info_ptr);
00487
00488
00489
00490
00491
00492
00493
00494
00495
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505
00506
00507
00508
00509
00510
00511
00512
00513
00514
00515
00516
00517
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527
00528
00529
00530
00531
00532
00533
00534
00535
00536
00537
00538 #if 0
00539 if (interlacing)
00540 number_passes = png_set_interlace_handling(png_ptr);
00541 else
00542 number_passes = 1;
00543 #endif
00544
00545
00546
00547
00548
00549
00550
00551
00552
00553 if (height > PNG_UINT_32_MAX/png_sizeof(png_bytep))
00554 png_error (png_ptr, "Image is too tall to process in memory");
00555
00556 for (k = 0; k < height; k++)
00557 row_pointers[k] = (png_bytep) image + k*width*bytes_per_pixel;
00558
00559
00560 png_write_image(png_ptr, row_pointers);
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570 png_write_end(png_ptr, info_ptr);
00571
00572
00573
00574
00575
00576
00577
00578
00579
00580
00581
00582
00583
00584
00585
00586
00587 png_destroy_write_struct(&png_ptr, &info_ptr);
00588
00589
00590
00591
00592
00593 return (OK);
00594 }
00595
00596 int unescape (char * s, int l) {
00597 int i=0;
00598 int j=0;
00599 while ((i<l) && s[i]) {
00600 if ((s[i]=='%') && (i<(l-2)) && s[i+1]){
00601 s[j++]=(hexdigit(s[i+1])<<4) | hexdigit(s[i+2]);
00602 i+=3;
00603 } else s[j++]=s[i++];
00604 }
00605 if (i<l) s[j]=0;
00606 return j;
00607 }
00608
00609 int hexdigit (char c) {
00610 int i;
00611 i=c-'0';
00612 if ((i>=0) && (i<10)) return i;
00613 i=c-'a'+10;
00614 if ((i>=10) && (i<16)) return i;
00615 i=c-'A'+10;
00616 if ((i>=10) && (i<16)) return i;
00617 return 0;
00618 }
00619
00620 char * paramValue(struct key_value * params, char * skey) {
00621 int i=0;
00622 if (skey)
00623 while ((i<QRY_MAXPARAMS) && (params[i].key)) {
00624 if (strcmp(skey,params[i].key)==0) return params[i].value;
00625
00626 i++;
00627 }
00628 return NULL;
00629 }
00630
00631 int parseQuery(struct key_value * params, char * qry) {
00632 char * cp;
00633 int l=0;
00634 cp=strtok(qry,"=");
00635 while ((cp) && (l<QRY_MAXPARAMS)) {
00636 params[l].key=cp;
00637 cp=strtok(NULL,"&");
00638 params[l++].value=cp;
00639 if (cp) cp=strtok(NULL,"=");
00640 }
00641 params[l].key=NULL;
00642 return l;
00643 }