image.cpp 24 KB

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