You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

952 lines
22 KiB

  1. /* SLiM - Simple Login Manager
  2. Copyright (C) 2004-06 Simone Rota <sip@varlock.com>
  3. Copyright (C) 2004-06 Johannes Winkelmann <jw@tks6.net>
  4. Copyright (C) 2012 Nobuhiro Iwamatsu <iwamatsu@nigauri.org>
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. The following code has been adapted and extended from
  10. xplanet 1.0.1, Copyright (C) 2002-04 Hari Nair <hari@alumni.caltech.edu>
  11. */
  12. #include <cctype>
  13. #include <cmath>
  14. #include <cstdio>
  15. #include <cstdlib>
  16. #include <cstring>
  17. #include <iostream>
  18. using namespace std;
  19. #include "image.h"
  20. extern "C" {
  21. #include <jpeglib.h>
  22. #include <png.h>
  23. }
  24. Image::Image() : width(0), height(0), area(0),
  25. rgb_data(NULL), png_alpha(NULL), quality_(80) {}
  26. Image::Image(const int w, const int h, const unsigned char *rgb, const unsigned char *alpha) :
  27. width(w), height(h), area(w*h), quality_(80) {
  28. width = w;
  29. height = h;
  30. area = w * h;
  31. rgb_data = (unsigned char *) malloc(3 * area);
  32. memcpy(rgb_data, rgb, 3 * area);
  33. if (alpha == NULL) {
  34. png_alpha = NULL;
  35. } else {
  36. png_alpha = (unsigned char *) malloc(area);
  37. memcpy(png_alpha, alpha, area);
  38. }
  39. }
  40. Image::~Image() {
  41. free(rgb_data);
  42. free(png_alpha);
  43. }
  44. bool
  45. Image::Read(const char *filename) {
  46. char buf[4];
  47. unsigned char *ubuf = (unsigned char *) buf;
  48. int success = 0;
  49. FILE *file;
  50. file = fopen(filename, "rb");
  51. if (file == NULL)
  52. return(false);
  53. /* see what kind of file we have */
  54. fread(buf, 1, 4, file);
  55. fclose(file);
  56. if ((ubuf[0] == 0x89) && !strncmp("PNG", buf+1, 3))
  57. success = readPng(filename, &width, &height, &rgb_data, &png_alpha);
  58. else if ((ubuf[0] == 0xff) && (ubuf[1] == 0xd8))
  59. success = readJpeg(filename, &width, &height, &rgb_data);
  60. else {
  61. fprintf(stderr, "Unknown image format\n");
  62. success = 0;
  63. }
  64. return(success == 1);
  65. }
  66. void
  67. Image::Reduce(const int factor) {
  68. if (factor < 1)
  69. return;
  70. int scale = 1;
  71. for (int i = 0; i < factor; i++)
  72. scale *= 2;
  73. double scale2 = scale*scale;
  74. int w = width / scale;
  75. int h = height / scale;
  76. int new_area = w * h;
  77. unsigned char *new_rgb = (unsigned char *) malloc(3 * new_area);
  78. memset(new_rgb, 0, 3 * new_area);
  79. unsigned char *new_alpha = NULL;
  80. if (png_alpha != NULL) {
  81. new_alpha = (unsigned char *) malloc(new_area);
  82. memset(new_alpha, 0, new_area);
  83. }
  84. int ipos = 0;
  85. for (int j = 0; j < height; j++) {
  86. int js = j / scale;
  87. for (int i = 0; i < width; i++) {
  88. int is = i/scale;
  89. for (int k = 0; k < 3; k++)
  90. new_rgb[3*(js * w + is) + k] += static_cast<unsigned char> ((rgb_data[3*ipos + k] + 0.5) / scale2);
  91. if (png_alpha != NULL)
  92. new_alpha[js * w + is] += static_cast<unsigned char> (png_alpha[ipos]/scale2);
  93. ipos++;
  94. }
  95. }
  96. free(rgb_data);
  97. free(png_alpha);
  98. rgb_data = new_rgb;
  99. png_alpha = new_alpha;
  100. width = w;
  101. height = h;
  102. area = w * h;
  103. }
  104. void
  105. Image::Resize(const int w, const int h) {
  106. if (width==w && height==h){
  107. return;
  108. }
  109. int new_area = w * h;
  110. unsigned char *new_rgb = (unsigned char *) malloc(3 * new_area);
  111. unsigned char *new_alpha = NULL;
  112. if (png_alpha != NULL)
  113. new_alpha = (unsigned char *) malloc(new_area);
  114. const double scale_x = ((double) w) / width;
  115. const double scale_y = ((double) h) / height;
  116. int ipos = 0;
  117. for (int j = 0; j < h; j++) {
  118. const double y = j / scale_y;
  119. for (int i = 0; i < w; i++) {
  120. const double x = i / scale_x;
  121. if (new_alpha == NULL)
  122. getPixel(x, y, new_rgb + 3*ipos);
  123. else
  124. getPixel(x, y, new_rgb + 3*ipos, new_alpha + ipos);
  125. ipos++;
  126. }
  127. }
  128. free(rgb_data);
  129. free(png_alpha);
  130. rgb_data = new_rgb;
  131. png_alpha = new_alpha;
  132. width = w;
  133. height = h;
  134. area = w * h;
  135. }
  136. /* Find the color of the desired point using bilinear interpolation. */
  137. /* Assume the array indices refer to the denter of the pixel, so each */
  138. /* pixel has corners at (i - 0.5, j - 0.5) and (i + 0.5, j + 0.5) */
  139. void
  140. Image::getPixel(double x, double y, unsigned char *pixel) {
  141. getPixel(x, y, pixel, NULL);
  142. }
  143. void
  144. Image::getPixel(double x, double y, unsigned char *pixel, unsigned char *alpha) {
  145. if (x < -0.5)
  146. x = -0.5;
  147. if (x >= width - 0.5)
  148. x = width - 0.5;
  149. if (y < -0.5)
  150. y = -0.5;
  151. if (y >= height - 0.5)
  152. y = height - 0.5;
  153. int ix0 = (int) (floor(x));
  154. int ix1 = ix0 + 1;
  155. if (ix0 < 0)
  156. ix0 = width - 1;
  157. if (ix1 >= width)
  158. ix1 = 0;
  159. int iy0 = (int) (floor(y));
  160. int iy1 = iy0 + 1;
  161. if (iy0 < 0)
  162. iy0 = 0;
  163. if (iy1 >= height)
  164. iy1 = height - 1;
  165. const double t = x - floor(x);
  166. const double u = 1 - (y - floor(y));
  167. double weight[4];
  168. weight[1] = t * u;
  169. weight[0] = u - weight[1];
  170. weight[2] = 1 - t - u + weight[1];
  171. weight[3] = t - weight[1];
  172. unsigned char *pixels[4];
  173. pixels[0] = rgb_data + 3 * (iy0 * width + ix0);
  174. pixels[1] = rgb_data + 3 * (iy0 * width + ix1);
  175. pixels[2] = rgb_data + 3 * (iy1 * width + ix0);
  176. pixels[3] = rgb_data + 3 * (iy1 * width + ix1);
  177. memset(pixel, 0, 3);
  178. for (int i = 0; i < 4; i++) {
  179. for (int j = 0; j < 3; j++)
  180. pixel[j] += (unsigned char) (weight[i] * pixels[i][j]);
  181. }
  182. if (alpha != NULL) {
  183. unsigned char pixels[4];
  184. pixels[0] = png_alpha[iy0 * width + ix0];
  185. pixels[1] = png_alpha[iy0 * width + ix1];
  186. pixels[2] = png_alpha[iy0 * width + ix0];
  187. pixels[3] = png_alpha[iy1 * width + ix1];
  188. for (int i = 0; i < 4; i++)
  189. *alpha = (unsigned char) (weight[i] * pixels[i]);
  190. }
  191. }
  192. /* Merge the image with a background, taking care of the
  193. * image Alpha transparency. (background alpha is ignored).
  194. * The images is merged on position (x, y) on the
  195. * background, the background must contain the image.
  196. */
  197. void Image::Merge(Image* background, const int x, const int y) {
  198. if (x + width > background->Width()|| y + height > background->Height())
  199. return;
  200. if (background->Width()*background->Height() != width*height)
  201. background->Crop(x, y, width, height);
  202. double tmp;
  203. unsigned char *new_rgb = (unsigned char *) malloc(3 * width * height);
  204. memset(new_rgb, 0, 3 * width * height);
  205. const unsigned char *bg_rgb = background->getRGBData();
  206. int ipos = 0;
  207. if (png_alpha != NULL){
  208. for (int j = 0; j < height; j++) {
  209. for (int i = 0; i < width; i++) {
  210. for (int k = 0; k < 3; k++) {
  211. tmp = rgb_data[3*ipos + k]*png_alpha[ipos]/255.0
  212. + bg_rgb[3*ipos + k]*(1-png_alpha[ipos]/255.0);
  213. new_rgb[3*ipos + k] = static_cast<unsigned char> (tmp);
  214. }
  215. ipos++;
  216. }
  217. }
  218. } else {
  219. for (int j = 0; j < height; j++) {
  220. for (int i = 0; i < width; i++) {
  221. for (int k = 0; k < 3; k++) {
  222. tmp = rgb_data[3*ipos + k];
  223. new_rgb[3*ipos + k] = static_cast<unsigned char> (tmp);
  224. }
  225. ipos++;
  226. }
  227. }
  228. }
  229. free(rgb_data);
  230. free(png_alpha);
  231. rgb_data = new_rgb;
  232. png_alpha = NULL;
  233. }
  234. /* Merge the image with a background, taking care of the
  235. * image Alpha transparency. (background alpha is ignored).
  236. * The images is merged on position (x, y) on the
  237. * background, the background must contain the image.
  238. */
  239. #define IMG_POS_RGB(p, x) (3 * p + x)
  240. void Image::Merge_non_crop(Image* background, const int x, const int y)
  241. {
  242. int bg_w = background->Width();
  243. int bg_h = background->Height();
  244. if (x + width > bg_w || y + height > bg_h)
  245. return;
  246. double tmp;
  247. unsigned char *new_rgb = (unsigned char *)malloc(3 * bg_w * bg_h);
  248. const unsigned char *bg_rgb = background->getRGBData();
  249. int pnl_pos = 0;
  250. int bg_pos = 0;
  251. int pnl_w_end = x + width;
  252. int pnl_h_end = y + height;
  253. memcpy(new_rgb, bg_rgb, 3 * bg_w * bg_h);
  254. for (int j = 0; j < bg_h; j++) {
  255. for (int i = 0; i < bg_w; i++) {
  256. if (j >= y && i >= x && j < pnl_h_end && i < pnl_w_end ) {
  257. for (int k = 0; k < 3; k++) {
  258. if (png_alpha != NULL)
  259. tmp = rgb_data[IMG_POS_RGB(pnl_pos, k)]
  260. * png_alpha[pnl_pos]/255.0
  261. + bg_rgb[IMG_POS_RGB(bg_pos, k)]
  262. * (1 - png_alpha[pnl_pos]/255.0);
  263. else
  264. tmp = rgb_data[IMG_POS_RGB(pnl_pos, k)];
  265. new_rgb[IMG_POS_RGB(bg_pos, k)] = static_cast<unsigned char>(tmp);
  266. }
  267. pnl_pos++;
  268. }
  269. bg_pos++;
  270. }
  271. }
  272. width = bg_w;
  273. height = bg_h;
  274. free(rgb_data);
  275. free(png_alpha);
  276. rgb_data = new_rgb;
  277. png_alpha = NULL;
  278. }
  279. /* Tile the image growing its size to the minimum entire
  280. * multiple of w * h.
  281. * The new dimensions should be > of the current ones.
  282. * Note that this flattens image (alpha removed)
  283. */
  284. void Image::Tile(const int w, const int h) {
  285. if (w < width || h < height)
  286. return;
  287. int nx = w / width;
  288. if (w % width > 0)
  289. nx++;
  290. int ny = h / height;
  291. if (h % height > 0)
  292. ny++;
  293. int newwidth = nx*width;
  294. int newheight=ny*height;
  295. unsigned char *new_rgb = (unsigned char *) malloc(3 * newwidth * newheight);
  296. memset(new_rgb, 0, 3 * width * height * nx * ny);
  297. int ipos = 0;
  298. int opos = 0;
  299. for (int r = 0; r < ny; r++) {
  300. for (int c = 0; c < nx; c++) {
  301. for (int j = 0; j < height; j++) {
  302. for (int i = 0; i < width; i++) {
  303. opos = j*width + i;
  304. ipos = r*width*height*nx + j*newwidth + c*width +i;
  305. for (int k = 0; k < 3; k++) {
  306. new_rgb[3*ipos + k] = static_cast<unsigned char> (rgb_data[3*opos + k]);
  307. }
  308. }
  309. }
  310. }
  311. }
  312. free(rgb_data);
  313. free(png_alpha);
  314. rgb_data = new_rgb;
  315. png_alpha = NULL;
  316. width = newwidth;
  317. height = newheight;
  318. area = width * height;
  319. Crop(0,0,w,h);
  320. }
  321. /* Crop the image
  322. */
  323. void Image::Crop(const int x, const int y, const int w, const int h) {
  324. if (x+w > width || y+h > height) {
  325. return;
  326. }
  327. int x2 = x + w;
  328. int y2 = y + h;
  329. unsigned char *new_rgb = (unsigned char *) malloc(3 * w * h);
  330. memset(new_rgb, 0, 3 * w * h);
  331. unsigned char *new_alpha = NULL;
  332. if (png_alpha != NULL) {
  333. new_alpha = (unsigned char *) malloc(w * h);
  334. memset(new_alpha, 0, w * h);
  335. }
  336. int ipos = 0;
  337. int opos = 0;
  338. for (int j = 0; j < height; j++) {
  339. for (int i = 0; i < width; i++) {
  340. if (j>=y && i>=x && j<y2 && i<x2) {
  341. for (int k = 0; k < 3; k++) {
  342. new_rgb[3*ipos + k] = static_cast<unsigned char> (rgb_data[3*opos + k]);
  343. }
  344. if (png_alpha != NULL)
  345. new_alpha[ipos] = static_cast<unsigned char> (png_alpha[opos]);
  346. ipos++;
  347. }
  348. opos++;
  349. }
  350. }
  351. free(rgb_data);
  352. free(png_alpha);
  353. rgb_data = new_rgb;
  354. if (png_alpha != NULL)
  355. png_alpha = new_alpha;
  356. width = w;
  357. height = h;
  358. area = w * h;
  359. }
  360. /* Center the image in a rectangle of given width and height.
  361. * Fills the remaining space (if any) with the hex color
  362. */
  363. void Image::Center(const int w, const int h, const char *hex) {
  364. unsigned long packed_rgb;
  365. sscanf(hex, "%lx", &packed_rgb);
  366. unsigned long r = packed_rgb>>16;
  367. unsigned long g = packed_rgb>>8 & 0xff;
  368. unsigned long b = packed_rgb & 0xff;
  369. unsigned char *new_rgb = (unsigned char *) malloc(3 * w * h);
  370. memset(new_rgb, 0, 3 * w * h);
  371. int x = (w - width) / 2;
  372. int y = (h - height) / 2;
  373. if (x<0) {
  374. Crop((width - w)/2,0,w,height);
  375. x = 0;
  376. }
  377. if (y<0) {
  378. Crop(0,(height - h)/2,width,h);
  379. y = 0;
  380. }
  381. int x2 = x + width;
  382. int y2 = y + height;
  383. int ipos = 0;
  384. int opos = 0;
  385. double tmp;
  386. area = w * h;
  387. for (int i = 0; i < area; i++) {
  388. new_rgb[3*i] = r;
  389. new_rgb[3*i+1] = g;
  390. new_rgb[3*i+2] = b;
  391. }
  392. if (png_alpha != NULL) {
  393. for (int j = 0; j < h; j++) {
  394. for (int i = 0; i < w; i++) {
  395. if (j>=y && i>=x && j<y2 && i<x2) {
  396. ipos = j*w + i;
  397. for (int k = 0; k < 3; k++) {
  398. tmp = rgb_data[3*opos + k]*png_alpha[opos]/255.0
  399. + new_rgb[k]*(1-png_alpha[opos]/255.0);
  400. new_rgb[3*ipos + k] = static_cast<unsigned char> (tmp);
  401. }
  402. opos++;
  403. }
  404. }
  405. }
  406. } else {
  407. for (int j = 0; j < h; j++) {
  408. for (int i = 0; i < w; i++) {
  409. if (j>=y && i>=x && j<y2 && i<x2) {
  410. ipos = j*w + i;
  411. for (int k = 0; k < 3; k++) {
  412. tmp = rgb_data[3*opos + k];
  413. new_rgb[3*ipos + k] = static_cast<unsigned char> (tmp);
  414. }
  415. opos++;
  416. }
  417. }
  418. }
  419. }
  420. free(rgb_data);
  421. free(png_alpha);
  422. rgb_data = new_rgb;
  423. png_alpha = NULL;
  424. width = w;
  425. height = h;
  426. }
  427. /* Fill the image with the given color and adjust its dimensions
  428. * to passed values.
  429. */
  430. void Image::Plain(const int w, const int h, const char *hex) {
  431. unsigned long packed_rgb;
  432. sscanf(hex, "%lx", &packed_rgb);
  433. unsigned long r = packed_rgb>>16;
  434. unsigned long g = packed_rgb>>8 & 0xff;
  435. unsigned long b = packed_rgb & 0xff;
  436. unsigned char *new_rgb = (unsigned char *) malloc(3 * w * h);
  437. memset(new_rgb, 0, 3 * w * h);
  438. area = w * h;
  439. for (int i = 0; i < area; i++) {
  440. new_rgb[3*i] = r;
  441. new_rgb[3*i+1] = g;
  442. new_rgb[3*i+2] = b;
  443. }
  444. free(rgb_data);
  445. free(png_alpha);
  446. rgb_data = new_rgb;
  447. png_alpha = NULL;
  448. width = w;
  449. height = h;
  450. }
  451. void
  452. Image::computeShift(unsigned long mask,
  453. unsigned char &left_shift,
  454. unsigned char &right_shift) {
  455. left_shift = 0;
  456. right_shift = 8;
  457. if (mask != 0) {
  458. while ((mask & 0x01) == 0) {
  459. left_shift++;
  460. mask >>= 1;
  461. }
  462. while ((mask & 0x01) == 1) {
  463. right_shift--;
  464. mask >>= 1;
  465. }
  466. }
  467. }
  468. Pixmap
  469. Image::createPixmap(Display* dpy, int scr, Window win) {
  470. int i, j; /* loop variables */
  471. const int depth = DefaultDepth(dpy, scr);
  472. Visual *visual = DefaultVisual(dpy, scr);
  473. Colormap colormap = DefaultColormap(dpy, scr);
  474. Pixmap tmp = XCreatePixmap(dpy, win, width, height,
  475. depth);
  476. char *pixmap_data = NULL;
  477. switch (depth) {
  478. case 32:
  479. case 24:
  480. pixmap_data = new char[4 * width * height];
  481. break;
  482. case 16:
  483. case 15:
  484. pixmap_data = new char[2 * width * height];
  485. break;
  486. case 8:
  487. pixmap_data = new char[width * height];
  488. break;
  489. default:
  490. break;
  491. }
  492. XImage *ximage = XCreateImage(dpy, visual, depth, ZPixmap, 0,
  493. pixmap_data, width, height,
  494. 8, 0);
  495. int entries;
  496. XVisualInfo v_template;
  497. v_template.visualid = XVisualIDFromVisual(visual);
  498. XVisualInfo *visual_info = XGetVisualInfo(dpy, VisualIDMask,
  499. &v_template, &entries);
  500. unsigned long ipos = 0;
  501. switch (visual_info->c_class) {
  502. case PseudoColor: {
  503. XColor xc;
  504. xc.flags = DoRed | DoGreen | DoBlue;
  505. int num_colors = 256;
  506. XColor *colors = new XColor[num_colors];
  507. for (i = 0; i < num_colors; i++)
  508. colors[i].pixel = (unsigned long) i;
  509. XQueryColors(dpy, colormap, colors, num_colors);
  510. int *closest_color = new int[num_colors];
  511. for (i = 0; i < num_colors; i++) {
  512. xc.red = (i & 0xe0) << 8; /* highest 3 bits */
  513. xc.green = (i & 0x1c) << 11; /* middle 3 bits */
  514. xc.blue = (i & 0x03) << 14; /* lowest 2 bits */
  515. /* find the closest color in the colormap */
  516. double distance, distance_squared, min_distance = 0;
  517. for (int ii = 0; ii < num_colors; ii++) {
  518. distance = colors[ii].red - xc.red;
  519. distance_squared = distance * distance;
  520. distance = colors[ii].green - xc.green;
  521. distance_squared += distance * distance;
  522. distance = colors[ii].blue - xc.blue;
  523. distance_squared += distance * distance;
  524. if ((ii == 0) || (distance_squared <= min_distance)) {
  525. min_distance = distance_squared;
  526. closest_color[i] = ii;
  527. }
  528. }
  529. }
  530. for (j = 0; j < height; j++) {
  531. for (i = 0; i < width; i++) {
  532. xc.red = (unsigned short) (rgb_data[ipos++] & 0xe0);
  533. xc.green = (unsigned short) (rgb_data[ipos++] & 0xe0);
  534. xc.blue = (unsigned short) (rgb_data[ipos++] & 0xc0);
  535. xc.pixel = xc.red | (xc.green >> 3) | (xc.blue >> 6);
  536. XPutPixel(ximage, i, j,
  537. colors[closest_color[xc.pixel]].pixel);
  538. }
  539. }
  540. delete [] colors;
  541. delete [] closest_color;
  542. }
  543. break;
  544. case TrueColor: {
  545. unsigned char red_left_shift;
  546. unsigned char red_right_shift;
  547. unsigned char green_left_shift;
  548. unsigned char green_right_shift;
  549. unsigned char blue_left_shift;
  550. unsigned char blue_right_shift;
  551. computeShift(visual_info->red_mask, red_left_shift,
  552. red_right_shift);
  553. computeShift(visual_info->green_mask, green_left_shift,
  554. green_right_shift);
  555. computeShift(visual_info->blue_mask, blue_left_shift,
  556. blue_right_shift);
  557. unsigned long pixel;
  558. unsigned long red, green, blue;
  559. for (j = 0; j < height; j++) {
  560. for (i = 0; i < width; i++) {
  561. red = (unsigned long)
  562. rgb_data[ipos++] >> red_right_shift;
  563. green = (unsigned long)
  564. rgb_data[ipos++] >> green_right_shift;
  565. blue = (unsigned long)
  566. rgb_data[ipos++] >> blue_right_shift;
  567. pixel = (((red << red_left_shift) & visual_info->red_mask)
  568. | ((green << green_left_shift)
  569. & visual_info->green_mask)
  570. | ((blue << blue_left_shift)
  571. & visual_info->blue_mask));
  572. XPutPixel(ximage, i, j, pixel);
  573. }
  574. }
  575. }
  576. break;
  577. default: {
  578. logStream << "Login.app: could not load image" << endl;
  579. return(tmp);
  580. }
  581. }
  582. GC gc = XCreateGC(dpy, win, 0, NULL);
  583. XPutImage(dpy, tmp, gc, ximage, 0, 0, 0, 0, width, height);
  584. XFreeGC(dpy, gc);
  585. XFree(visual_info);
  586. delete [] pixmap_data;
  587. /* Set ximage data to NULL since pixmap data was deallocated above */
  588. ximage->data = NULL;
  589. XDestroyImage(ximage);
  590. return(tmp);
  591. }
  592. int
  593. Image::readJpeg(const char *filename, int *width, int *height,
  594. unsigned char **rgb)
  595. {
  596. int ret = 0;
  597. struct jpeg_decompress_struct cinfo;
  598. struct jpeg_error_mgr jerr;
  599. unsigned char *ptr = NULL;
  600. FILE *infile = fopen(filename, "rb");
  601. if (infile == NULL) {
  602. logStream << APPNAME << "Cannot fopen file: " << filename << endl;
  603. return ret;
  604. }
  605. cinfo.err = jpeg_std_error(&jerr);
  606. jpeg_create_decompress(&cinfo);
  607. jpeg_stdio_src(&cinfo, infile);
  608. jpeg_read_header(&cinfo, TRUE);
  609. jpeg_start_decompress(&cinfo);
  610. /* Prevent against integer overflow */
  611. if(cinfo.output_width >= MAX_DIMENSION
  612. || cinfo.output_height >= MAX_DIMENSION)
  613. {
  614. logStream << APPNAME << "Unreasonable dimension found in file: "
  615. << filename << endl;
  616. goto close_file;
  617. }
  618. *width = cinfo.output_width;
  619. *height = cinfo.output_height;
  620. rgb[0] = (unsigned char*)
  621. malloc(3 * cinfo.output_width * cinfo.output_height);
  622. if (rgb[0] == NULL) {
  623. logStream << APPNAME << ": Can't allocate memory for JPEG file."
  624. << endl;
  625. goto close_file;
  626. }
  627. if (cinfo.output_components == 3) {
  628. ptr = rgb[0];
  629. while (cinfo.output_scanline < cinfo.output_height) {
  630. jpeg_read_scanlines(&cinfo, &ptr, 1);
  631. ptr += 3 * cinfo.output_width;
  632. }
  633. } else if (cinfo.output_components == 1) {
  634. ptr = (unsigned char*) malloc(cinfo.output_width);
  635. if (ptr == NULL) {
  636. logStream << APPNAME << ": Can't allocate memory for JPEG file."
  637. << endl;
  638. goto rgb_free;
  639. }
  640. unsigned int ipos = 0;
  641. while (cinfo.output_scanline < cinfo.output_height) {
  642. jpeg_read_scanlines(&cinfo, &ptr, 1);
  643. for (unsigned int i = 0; i < cinfo.output_width; i++) {
  644. memset(rgb[0] + ipos, ptr[i], 3);
  645. ipos += 3;
  646. }
  647. }
  648. free(ptr);
  649. }
  650. jpeg_finish_decompress(&cinfo);
  651. ret = 1;
  652. goto close_file;
  653. rgb_free:
  654. free(rgb[0]);
  655. close_file:
  656. jpeg_destroy_decompress(&cinfo);
  657. fclose(infile);
  658. return(ret);
  659. }
  660. int
  661. Image::readPng(const char *filename, int *width, int *height,
  662. unsigned char **rgb, unsigned char **alpha)
  663. {
  664. int ret = 0;
  665. png_structp png_ptr;
  666. png_infop info_ptr;
  667. png_bytepp row_pointers;
  668. unsigned char *ptr = NULL;
  669. png_uint_32 w, h;
  670. int bit_depth, color_type, interlace_type;
  671. int i;
  672. FILE *infile = fopen(filename, "rb");
  673. if (infile == NULL) {
  674. logStream << APPNAME << "Can not fopen file: " << filename << endl;
  675. return ret;
  676. }
  677. png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
  678. (png_voidp) NULL,
  679. (png_error_ptr) NULL,
  680. (png_error_ptr) NULL);
  681. if (!png_ptr) {
  682. goto file_close;
  683. }
  684. info_ptr = png_create_info_struct(png_ptr);
  685. if (!info_ptr) {
  686. png_destroy_read_struct(&png_ptr, (png_infopp) NULL,
  687. (png_infopp) NULL);
  688. }
  689. #if PNG_LIBPNG_VER_MAJOR >= 1 && PNG_LIBPNG_VER_MINOR >= 4
  690. if (setjmp(png_jmpbuf((png_ptr)))) {
  691. #else
  692. if (setjmp(png_ptr->jmpbuf)) {
  693. #endif
  694. goto png_destroy;
  695. }
  696. png_init_io(png_ptr, infile);
  697. png_read_info(png_ptr, info_ptr);
  698. png_get_IHDR(png_ptr, info_ptr, &w, &h, &bit_depth, &color_type,
  699. &interlace_type, (int *) NULL, (int *) NULL);
  700. /* Prevent against integer overflow */
  701. if(w >= MAX_DIMENSION || h >= MAX_DIMENSION) {
  702. logStream << APPNAME << "Unreasonable dimension found in file: "
  703. << filename << endl;
  704. goto png_destroy;
  705. }
  706. *width = (int) w;
  707. *height = (int) h;
  708. if (color_type == PNG_COLOR_TYPE_RGB_ALPHA
  709. || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
  710. {
  711. alpha[0] = (unsigned char *) malloc(*width * *height);
  712. if (alpha[0] == NULL) {
  713. logStream << APPNAME
  714. << ": Can't allocate memory for alpha channel in PNG file."
  715. << endl;
  716. goto png_destroy;
  717. }
  718. }
  719. /* Change a paletted/grayscale image to RGB */
  720. if (color_type == PNG_COLOR_TYPE_PALETTE && bit_depth <= 8)
  721. {
  722. png_set_expand(png_ptr);
  723. }
  724. /* Change a grayscale image to RGB */
  725. if (color_type == PNG_COLOR_TYPE_GRAY
  726. || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
  727. {
  728. png_set_gray_to_rgb(png_ptr);
  729. }
  730. /* If the PNG file has 16 bits per channel, strip them down to 8 */
  731. if (bit_depth == 16) {
  732. png_set_strip_16(png_ptr);
  733. }
  734. /* use 1 byte per pixel */
  735. png_set_packing(png_ptr);
  736. row_pointers = (png_byte **) malloc(*height * sizeof(png_bytep));
  737. if (row_pointers == NULL) {
  738. logStream << APPNAME << ": Can't allocate memory for PNG file." << endl;
  739. goto png_destroy;
  740. }
  741. for (i = 0; i < *height; i++) {
  742. row_pointers[i] = (png_byte*) malloc(4 * *width);
  743. if (row_pointers == NULL) {
  744. logStream << APPNAME << ": Can't allocate memory for PNG file."
  745. << endl;
  746. goto rows_free;
  747. }
  748. }
  749. png_read_image(png_ptr, row_pointers);
  750. rgb[0] = (unsigned char *) malloc(3 * (*width) * (*height));
  751. if (rgb[0] == NULL) {
  752. logStream << APPNAME << ": Can't allocate memory for PNG file." << endl;
  753. goto rows_free;
  754. }
  755. if (alpha[0] == NULL) {
  756. ptr = rgb[0];
  757. for (i = 0; i < *height; i++) {
  758. memcpy(ptr, row_pointers[i], 3 * (*width));
  759. ptr += 3 * (*width);
  760. }
  761. } else {
  762. ptr = rgb[0];
  763. for (i = 0; i < *height; i++) {
  764. unsigned int ipos = 0;
  765. for (int j = 0; j < *width; j++) {
  766. *ptr++ = row_pointers[i][ipos++];
  767. *ptr++ = row_pointers[i][ipos++];
  768. *ptr++ = row_pointers[i][ipos++];
  769. alpha[0][i * (*width) + j] = row_pointers[i][ipos++];
  770. }
  771. }
  772. }
  773. ret = 1; /* data reading is OK */
  774. rows_free:
  775. for (i = 0; i < *height; i++) {
  776. if (row_pointers[i] != NULL ) {
  777. free(row_pointers[i]);
  778. }
  779. }
  780. free(row_pointers);
  781. png_destroy:
  782. png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) NULL);
  783. file_close:
  784. fclose(infile);
  785. return(ret);
  786. }