00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include <stdio.h>
00028 #include <stdlib.h>
00029 #include <string.h>
00030 #include "ImageIO.h"
00031 #include "Inform.h"
00032 #include "utilities.h"
00033
00034 #if defined(VMDLIBPNG)
00035 #include "png.h"
00036 #endif
00037
00038 static void putbyte(FILE * outf, unsigned char val) {
00039 unsigned char buf[1];
00040 buf[0] = val;
00041 fwrite(buf, 1, 1, outf);
00042 }
00043
00044 static void putshort(FILE * outf, unsigned short val) {
00045 unsigned char buf[2];
00046 buf[0] = val >> 8;
00047 buf[1] = val & 0xff;
00048 fwrite(buf, 2, 1, outf);
00049 }
00050
00051 static void putint(FILE * outf, unsigned int val) {
00052 unsigned char buf[4];
00053 buf[0] = (unsigned char) (val >> 24);
00054 buf[1] = (unsigned char) (val >> 16);
00055 buf[2] = (unsigned char) (val >> 8);
00056 buf[3] = (unsigned char) (val & 0xff);
00057 fwrite(buf, 4, 1, outf);
00058 }
00059
00060
00061 unsigned char * cvt_rgb4u_rgb3u(const unsigned char * rgb4u, int xs, int ys) {
00062 int rowlen3u = xs*3;
00063 int sz = xs * ys * 3;
00064 unsigned char * rgb3u = (unsigned char *) calloc(1, sz);
00065
00066 int x3u, x4f, y;
00067 for (y=0; y<ys; y++) {
00068 int addr3u = y * xs * 3;
00069 int addr4f = y * xs * 4;
00070 for (x3u=0,x4f=0; x3u<rowlen3u; x3u+=3,x4f+=4) {
00071 rgb3u[addr3u + x3u ] = rgb4u[addr4f + x4f ];
00072 rgb3u[addr3u + x3u + 1] = rgb4u[addr4f + x4f + 1];
00073 rgb3u[addr3u + x3u + 2] = rgb4u[addr4f + x4f + 2];
00074 }
00075 }
00076
00077 return rgb3u;
00078 }
00079
00080
00081 unsigned char * cvt_rgb4f_rgb3u(const float * rgb4f, int xs, int ys) {
00082 int rowlen3u = xs*3;
00083 int sz = xs * ys * 3;
00084 unsigned char * rgb3u = (unsigned char *) calloc(1, sz);
00085
00086 int x3u, x4f, y;
00087 for (y=0; y<ys; y++) {
00088 int addr3u = y * xs * 3;
00089 int addr4f = y * xs * 4;
00090 for (x3u=0,x4f=0; x3u<rowlen3u; x3u+=3,x4f+=4) {
00091 int tmp;
00092
00093 tmp = int(rgb4f[addr4f + x4f ] * 255.0f);
00094 rgb3u[addr3u + x3u ] = (tmp < 0) ? 0 : ((tmp > 255) ? 255 : tmp);
00095
00096 tmp = int(rgb4f[addr4f + x4f + 1] * 255.0f);
00097 rgb3u[addr3u + x3u + 1] = (tmp < 0) ? 0 : ((tmp > 255) ? 255 : tmp);
00098
00099 tmp = int(rgb4f[addr4f + x4f + 2] * 255.0f);
00100 rgb3u[addr3u + x3u + 2] = (tmp < 0) ? 0 : ((tmp > 255) ? 255 : tmp);
00101 }
00102 }
00103
00104 return rgb3u;
00105 }
00106
00107
00108 unsigned char * cvt_rgba4f_rgba4u(const float * rgba4f, int xs, int ys) {
00109 int rowlen4u = xs*4;
00110 int sz = xs * ys * 4;
00111 unsigned char * rgba4u = (unsigned char *) calloc(1, sz);
00112
00113 int x4u, x4f, y;
00114 for (y=0; y<ys; y++) {
00115 int addr4 = y * xs * 4;
00116 for (x4u=0,x4f=0; x4u<rowlen4u; x4u+=4,x4f+=4) {
00117 int tmp;
00118
00119 tmp = int(rgba4f[addr4 + x4f ] * 255.0f);
00120 rgba4u[addr4 + x4u ] = (tmp < 0) ? 0 : ((tmp > 255) ? 255 : tmp);
00121
00122 tmp = int(rgba4f[addr4 + x4f + 1] * 255.0f);
00123 rgba4u[addr4 + x4u + 1] = (tmp < 0) ? 0 : ((tmp > 255) ? 255 : tmp);
00124
00125 tmp = int(rgba4f[addr4 + x4f + 2] * 255.0f);
00126 rgba4u[addr4 + x4u + 2] = (tmp < 0) ? 0 : ((tmp > 255) ? 255 : tmp);
00127
00128 tmp = int(rgba4f[addr4 + x4f + 3] * 255.0f);
00129 rgba4u[addr4 + x4u + 3] = (tmp < 0) ? 0 : ((tmp > 255) ? 255 : tmp);
00130 }
00131 }
00132
00133 return rgba4u;
00134 }
00135
00136
00137 static int checkfileextension(const char *s, const char *extension) {
00138 int sz, extsz;
00139 sz = strlen(s);
00140 extsz = strlen(extension);
00141
00142 if (extsz > sz) return 0;
00143
00144 if (!strupncmp(s + (sz - extsz), extension, extsz)) return 1;
00145
00146 return 0;
00147 }
00148
00149
00150 int write_image_file_rgb3u(const char *filename,
00151 const unsigned char *rgb3u, int xs, int ys) {
00152 FILE *outfile=NULL;
00153 if ((outfile = fopen(filename, "wb")) == NULL) {
00154 msgErr << "Could not open file " << filename
00155 << " in current directory for writing!" << sendmsg;
00156 return -1;
00157 }
00158
00159
00160 if (checkfileextension(filename, ".bmp")) {
00161 vmd_writebmp(outfile, rgb3u, xs, ys);
00162 #if defined(VMDLIBPNG)
00163 } else if (checkfileextension(filename, ".png")) {
00164 vmd_writepng(outfile, rgb3u, xs, ys);
00165 #endif
00166 } else if (checkfileextension(filename, ".ppm")) {
00167 vmd_writeppm(outfile, rgb3u, xs, ys);
00168 } else if (checkfileextension(filename, ".rgb")) {
00169 vmd_writergb(outfile, rgb3u, xs, ys);
00170 } else if (checkfileextension(filename, ".tga")) {
00171 vmd_writetga(outfile, rgb3u, xs, ys);
00172 } else {
00173 #if defined(_MSC_VER) || defined(WIN32)
00174 msgErr << "Unrecognized image file extension, writing Windows Bitmap file."
00175 << sendmsg;
00176 vmd_writebmp(outfile, rgb3u, xs, ys);
00177 #else
00178 msgErr << "Unrecognized image file extension, writing Targa file."
00179 << sendmsg;
00180 vmd_writetga(outfile, rgb3u, xs, ys);
00181 #endif
00182 }
00183
00184 fclose(outfile);
00185 return 0;
00186 }
00187
00188
00189 int write_image_file_rgb4u(const char *filename,
00190 const unsigned char *rgb4u, int xs, int ys) {
00191 unsigned char *rgb3u = cvt_rgb4u_rgb3u(rgb4u, xs, ys);
00192 if (rgb3u == NULL)
00193 return -1;
00194
00195 if (write_image_file_rgb3u(filename, rgb3u, xs, ys)) {
00196 free(rgb3u);
00197 return -1;
00198 }
00199
00200 free(rgb3u);
00201 return 0;
00202 }
00203
00204
00205 int write_image_file_rgb4f(const char *filename,
00206 const float *rgb4f, int xs, int ys) {
00207 unsigned char *rgb3u = cvt_rgb4f_rgb3u(rgb4f, xs, ys);
00208 if (rgb3u == NULL)
00209 return -1;
00210
00211 if (write_image_file_rgb3u(filename, rgb3u, xs, ys)) {
00212 free(rgb3u);
00213 return -1;
00214 }
00215
00216 free(rgb3u);
00217 return 0;
00218 }
00219
00220
00221 int write_image_file_rgba4u(const char *filename,
00222 const unsigned char *rgba4u, int xs, int ys) {
00223 FILE *outfile=NULL;
00224 if ((outfile = fopen(filename, "wb")) == NULL) {
00225 msgErr << "Could not open file " << filename
00226 << " in current directory for writing!" << sendmsg;
00227 return -1;
00228 }
00229
00230 if (checkfileextension(filename, ".png")) {
00231 #if defined(VMDLIBPNG)
00232 vmd_writepng_alpha(outfile, rgba4u, xs, ys);
00233 #else
00234 msgErr << "Unrecognized or unsupported alpha-channel image format."
00235 << sendmsg;
00236
00237 fclose(outfile);
00238 return -1;
00239 #endif
00240 } else {
00241 msgErr << "Unrecognized or unsupported alpha-channel image format."
00242 << sendmsg;
00243
00244 fclose(outfile);
00245 return -1;
00246 }
00247
00248 fclose(outfile);
00249 return 0;
00250 }
00251
00252
00253 int write_image_file_rgba4f(const char *filename,
00254 const float *rgba4f, int xs, int ys) {
00255 unsigned char *rgba4u = cvt_rgba4f_rgba4u(rgba4f, xs, ys);
00256 if (rgba4u == NULL)
00257 return -1;
00258
00259 if (write_image_file_rgba4u(filename, rgba4u, xs, ys)) {
00260 free(rgba4u);
00261 return -1;
00262 }
00263
00264 free(rgba4u);
00265 return 0;
00266 }
00267
00268
00269 void vmd_writergb(FILE *dfile, const unsigned char * img, int xs, int ys) {
00270 char iname[80];
00271 int x, y, i;
00272
00273 if (img == NULL)
00274 return;
00275
00276 putshort(dfile, 474);
00277 putbyte(dfile, 0);
00278 putbyte(dfile, 1);
00279 putshort(dfile, 3);
00280 putshort(dfile, xs);
00281 putshort(dfile, ys);
00282 putshort(dfile, 3);
00283 putint(dfile, 0);
00284 putint(dfile, 255);
00285
00286 for(i=0; i<4; i++)
00287 putbyte(dfile, 0);
00288
00289 strcpy(iname, "VMD Snapshot");
00290 fwrite(iname, 80, 1, dfile);
00291 putint(dfile, 0);
00292 for(i=0; i<404; i++)
00293 putbyte(dfile,0);
00294
00295 for(i=0; i<3; i++)
00296 for(y=0; y<ys; y++)
00297 for(x=0; x<xs; x++)
00298 fwrite(&img[(y*xs + x)*3 + i], 1, 1, dfile);
00299 }
00300
00301 static void write_le_int32(FILE * dfile, int num) {
00302 fputc((num ) & 0xFF, dfile);
00303 fputc((num >> 8 ) & 0xFF, dfile);
00304 fputc((num >> 16) & 0xFF, dfile);
00305 fputc((num >> 24) & 0xFF, dfile);
00306 }
00307
00308 static void write_le_int16(FILE * dfile, int num) {
00309 fputc((num ) & 0xFF, dfile);
00310 fputc((num >> 8 ) & 0xFF, dfile);
00311 }
00312
00313
00314 void vmd_writebmp(FILE *dfile, const unsigned char * img, int xs, int ys) {
00315 if (img != NULL) {
00316 int imgdataoffset = 14 + 40;
00317 int rowlen = xs * 3;
00318 int rowsz = ((rowlen) + 3) & -4;
00319 int imgdatasize = rowsz * ys;
00320 int filesize = imgdataoffset + imgdatasize;
00321
00322
00323 fputc('B', dfile);
00324 fputc('M', dfile);
00325 write_le_int32(dfile, filesize);
00326 write_le_int16(dfile, 0);
00327 write_le_int16(dfile, 0);
00328 write_le_int32(dfile, imgdataoffset);
00329
00330
00331 write_le_int32(dfile, 40);
00332 write_le_int32(dfile, xs);
00333 write_le_int32(dfile, ys);
00334 write_le_int16(dfile, 1);
00335 write_le_int16(dfile, 24);
00336
00337
00338 write_le_int32(dfile, 0);
00339 write_le_int32(dfile, imgdatasize);
00340
00341
00342
00343 write_le_int32(dfile, 11811);
00344 write_le_int32(dfile, 11811);
00345 write_le_int32(dfile, 0);
00346 write_le_int32(dfile, 0);
00347
00348
00349 int i, y;
00350 unsigned char * rowbuf = (unsigned char *) malloc(rowsz);
00351 if (rowbuf != NULL) {
00352 memset(rowbuf, 0, rowsz);
00353
00354 for (y=0; y<ys; y++) {
00355 int addr = xs * 3 * y;
00356
00357
00358
00359 for (i=0; i<rowlen; i+=3) {
00360 rowbuf[i ] = img[addr + i + 2];
00361 rowbuf[i + 1] = img[addr + i + 1];
00362 rowbuf[i + 2] = img[addr + i ];
00363 }
00364
00365 fwrite(rowbuf, rowsz, 1, dfile);
00366 }
00367 free(rowbuf);
00368 } else {
00369 msgErr << "Failed to save snapshot image!" << sendmsg;
00370 }
00371
00372 }
00373 }
00374
00375
00376 void vmd_writeppm(FILE *dfile, const unsigned char * img, int xs, int ys) {
00377 if (img != NULL) {
00378 int y;
00379
00380 fprintf(dfile,"%s\n","P6");
00381 fprintf(dfile,"%d\n", xs);
00382 fprintf(dfile,"%d\n", ys);
00383 fprintf(dfile,"%d\n",255);
00384
00385 for (y=(ys - 1); y>=0; y--) {
00386 fwrite(&img[xs * 3 * y], 1, (xs * 3), dfile);
00387 }
00388 }
00389 }
00390
00391
00392 void vmd_writetga(FILE *dfile, const unsigned char * img, int xs, int ys) {
00393 int x, y;
00394
00395 const unsigned char * bufpos;
00396 int filepos, numbytes;
00397 unsigned char * fixbuf;
00398
00399 fputc(0, dfile);
00400 fputc(0, dfile);
00401 fputc(2, dfile);
00402 fputc(0, dfile);
00403 fputc(0, dfile);
00404 fputc(0, dfile);
00405 fputc(0, dfile);
00406 fputc(0, dfile);
00407 fputc(0, dfile);
00408 fputc(0, dfile);
00409 fputc(0, dfile);
00410 fputc(0, dfile);
00411 fputc((xs & 0xff), dfile);
00412 fputc(((xs >> 8) & 0xff), dfile);
00413 fputc((ys & 0xff), dfile);
00414 fputc(((ys >> 8) & 0xff), dfile);
00415 fputc(24, dfile);
00416 fputc(0x20, dfile);
00417
00418 fixbuf = (unsigned char *) malloc(xs * 3);
00419 if (fixbuf == NULL) {
00420 msgErr << "vmd_writetga: failed memory allocation!" << sendmsg;
00421 return;
00422 }
00423
00424 for (y=0; y<ys; y++) {
00425 bufpos=img + (xs*3)*(ys-y-1);
00426 filepos=18 + xs*3*y;
00427
00428 if (filepos >= 18) {
00429 fseek(dfile, filepos, 0);
00430
00431 for (x=0; x<(3*xs); x+=3) {
00432 fixbuf[x ] = bufpos[x + 2];
00433 fixbuf[x + 1] = bufpos[x + 1];
00434 fixbuf[x + 2] = bufpos[x ];
00435 }
00436
00437 numbytes = fwrite(fixbuf, 3, xs, dfile);
00438
00439 if (numbytes != xs) {
00440 msgErr << "vmd_writetga: file write problem, "
00441 << numbytes << " bytes written." << sendmsg;
00442 }
00443 }
00444 else {
00445 msgErr << "vmd_writetga: file ptr out of range!!!" << sendmsg;
00446 return;
00447 }
00448 }
00449
00450 free(fixbuf);
00451 }
00452
00453 #if defined(VMDLIBPNG)
00454 void vmd_writepng(FILE *dfile, const unsigned char * img, int xs, int ys) {
00455 png_structp png_ptr;
00456 png_infop info_ptr;
00457 png_bytep *row_pointers;
00458 png_textp text_ptr;
00459 int y;
00460
00461
00462 png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
00463 if (png_ptr == NULL) {
00464 msgErr << "Failed to write PNG file" << sendmsg;
00465 return;
00466 }
00467
00468
00469 info_ptr = png_create_info_struct(png_ptr);
00470 if (info_ptr == NULL) {
00471 png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
00472 msgErr << "Failed to write PNG file" << sendmsg;
00473 return;
00474 }
00475
00476
00477 if (setjmp(png_jmpbuf(png_ptr))) {
00478
00479 png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
00480
00481 msgErr << "Failed to write PNG file" << sendmsg;
00482 return;
00483 }
00484
00485
00486 png_init_io(png_ptr, dfile);
00487
00488 png_set_IHDR(png_ptr, info_ptr, xs, ys,
00489 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
00490 PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
00491
00492 png_set_gAMA(png_ptr, info_ptr, 1.0);
00493
00494 text_ptr = (png_textp) png_malloc(png_ptr, (png_uint_32)sizeof(png_text) * 2);
00495
00496 text_ptr[0].key = (char *) "Description";
00497 text_ptr[0].text = (char *) "A molecular scene rendered by VMD";
00498 text_ptr[0].compression = PNG_TEXT_COMPRESSION_NONE;
00499 #ifdef PNG_iTXt_SUPPORTED
00500 text_ptr[0].lang = NULL;
00501 #endif
00502
00503 text_ptr[1].key = (char *) "Software";
00504 text_ptr[1].text = (char *) "VMD -- Visual Molecular Dynamics";
00505 text_ptr[1].compression = PNG_TEXT_COMPRESSION_NONE;
00506 #ifdef PNG_iTXt_SUPPORTED
00507 text_ptr[1].lang = NULL;
00508 #endif
00509 png_set_text(png_ptr, info_ptr, text_ptr, 1);
00510
00511 row_pointers = (png_bytep *) png_malloc(png_ptr, ys*sizeof(png_bytep));
00512 for (y=0; y<ys; y++) {
00513 row_pointers[ys - y - 1] = (png_bytep) &img[y * xs * 3];
00514 }
00515
00516 png_set_rows(png_ptr, info_ptr, row_pointers);
00517
00518
00519 png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);
00520
00521 png_free(png_ptr, row_pointers);
00522 png_free(png_ptr, text_ptr);
00523
00524
00525 png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
00526
00527 return;
00528 }
00529
00530
00531 void vmd_writepng_alpha(FILE *dfile, const unsigned char * img, int xs, int ys) {
00532 png_structp png_ptr;
00533 png_infop info_ptr;
00534 png_bytep *row_pointers;
00535 png_textp text_ptr;
00536 int y;
00537
00538
00539 png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
00540 if (png_ptr == NULL) {
00541 msgErr << "Failed to write PNG file" << sendmsg;
00542 return;
00543 }
00544
00545
00546 info_ptr = png_create_info_struct(png_ptr);
00547 if (info_ptr == NULL) {
00548 png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
00549 msgErr << "Failed to write PNG file" << sendmsg;
00550 return;
00551 }
00552
00553
00554 if (setjmp(png_jmpbuf(png_ptr))) {
00555
00556 png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
00557
00558 msgErr << "Failed to write PNG file" << sendmsg;
00559 return;
00560 }
00561
00562
00563 png_init_io(png_ptr, dfile);
00564
00565 png_set_IHDR(png_ptr, info_ptr, xs, ys,
00566 8, PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE,
00567 PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
00568
00569
00570
00571 #if 0
00572
00573 png_color_8 sig_bit;
00574 memset(&sig_bit, 0, sizeof(sig_bit));
00575
00576 sig_bit.red = 8;
00577 sig_bit.green = 8;
00578 sig_bit.blue = 8;
00579 sig_bit.alpha = 8;
00580
00581 png_set_sBIT(png_ptr, info_ptr, &sig_bit);
00582 #endif
00583
00584 png_set_gAMA(png_ptr, info_ptr, 1.0);
00585
00586 text_ptr = (png_textp) png_malloc(png_ptr, (png_uint_32)sizeof(png_text) * 2);
00587
00588 text_ptr[0].key = (char *) "Description";
00589 text_ptr[0].text = (char *) "A molecular scene rendered by VMD";
00590 text_ptr[0].compression = PNG_TEXT_COMPRESSION_NONE;
00591 #ifdef PNG_iTXt_SUPPORTED
00592 text_ptr[0].lang = NULL;
00593 #endif
00594
00595 text_ptr[1].key = (char *) "Software";
00596 text_ptr[1].text = (char *) "VMD -- Visual Molecular Dynamics";
00597 text_ptr[1].compression = PNG_TEXT_COMPRESSION_NONE;
00598 #ifdef PNG_iTXt_SUPPORTED
00599 text_ptr[1].lang = NULL;
00600 #endif
00601 png_set_text(png_ptr, info_ptr, text_ptr, 1);
00602
00603
00604
00605 row_pointers = (png_bytep *) png_malloc(png_ptr, ys*sizeof(png_bytep));
00606 for (y=0; y<ys; y++) {
00607 row_pointers[ys - y - 1] = (png_bytep) &img[y * xs * 4];
00608 }
00609
00610 png_set_rows(png_ptr, info_ptr, row_pointers);
00611
00612
00613 png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);
00614
00615 png_free(png_ptr, row_pointers);
00616 png_free(png_ptr, text_ptr);
00617
00618
00619 png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
00620
00621 return;
00622 }
00623
00624 #endif