/xbmc/guilib/JpegIO.cpp

http://github.com/xbmc/xbmc · C++ · 844 lines · 650 code · 104 blank · 90 comment · 148 complexity · ac909f4ff357a0a61ee4c60aa1e0ebfb MD5 · raw file

  1. /*
  2. * Copyright (C) 2005-2013 Team XBMC
  3. * http://xbmc.org
  4. *
  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, or (at your option)
  8. * any later version.
  9. *
  10. * This Program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with XBMC; see the file COPYING. If not, see
  17. * <http://www.gnu.org/licenses/>.
  18. *
  19. * Parts of this code taken from Guido Vollbeding <http://sylvana.net/jpegcrop/exif_orientation.html>
  20. *
  21. */
  22. #include "lib/libexif/libexif.h"
  23. #include "windowing/WindowingFactory.h"
  24. #include "settings/AdvancedSettings.h"
  25. #include "filesystem/File.h"
  26. #include "utils/log.h"
  27. #include "XBTF.h"
  28. #include "JpegIO.h"
  29. #include <setjmp.h>
  30. #define EXIF_TAG_ORIENTATION 0x0112
  31. struct my_error_mgr
  32. {
  33. struct jpeg_error_mgr pub; // "public" fields
  34. jmp_buf setjmp_buffer; // for return to caller
  35. };
  36. #if JPEG_LIB_VERSION < 80
  37. /*Versions of libjpeg prior to 8.0 did not have a pre-made mechanism for
  38. decoding directly from memory. Here we backport the functions from v8.
  39. When using v8 or higher, the built-in functions are used instead.
  40. Original formatting left intact for the most part for easy comparison. */
  41. static void x_init_mem_source (j_decompress_ptr cinfo)
  42. {
  43. /* no work necessary here */
  44. }
  45. void x_term_source (j_decompress_ptr cinfo)
  46. {
  47. /* no work necessary here */
  48. }
  49. static boolean x_fill_mem_input_buffer (j_decompress_ptr cinfo)
  50. {
  51. static JOCTET mybuffer[4];
  52. /* The whole JPEG data is expected to reside in the supplied memory
  53. * buffer, so any request for more data beyond the given buffer size
  54. * is treated as an error.
  55. */
  56. /* Insert a fake EOI marker */
  57. mybuffer[0] = (JOCTET) 0xFF;
  58. mybuffer[1] = (JOCTET) JPEG_EOI;
  59. cinfo->src->next_input_byte = mybuffer;
  60. cinfo->src->bytes_in_buffer = 2;
  61. return true;
  62. }
  63. static void x_skip_input_data (j_decompress_ptr cinfo, long num_bytes)
  64. {
  65. struct jpeg_source_mgr * src = cinfo->src;
  66. /* Just a dumb implementation for now. Could use fseek() except
  67. * it doesn't work on pipes. Not clear that being smart is worth
  68. * any trouble anyway --- large skips are infrequent.
  69. */
  70. if (num_bytes > 0) {
  71. while (num_bytes > (long) src->bytes_in_buffer) {
  72. num_bytes -= (long) src->bytes_in_buffer;
  73. (void) (*src->fill_input_buffer) (cinfo);
  74. /* note we assume that fill_input_buffer will never return FALSE,
  75. * so suspension need not be handled.
  76. */
  77. }
  78. src->next_input_byte += (size_t) num_bytes;
  79. src->bytes_in_buffer -= (size_t) num_bytes;
  80. }
  81. }
  82. static void x_mem_src (j_decompress_ptr cinfo, unsigned char * inbuffer, unsigned long insize)
  83. {
  84. struct jpeg_source_mgr * src;
  85. if (inbuffer == NULL || insize == 0) /* Treat empty input as fatal error */
  86. {
  87. (cinfo)->err->msg_code = 0;
  88. (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo));
  89. }
  90. /* The source object is made permanent so that a series of JPEG images
  91. * can be read from the same buffer by calling jpeg_mem_src only before
  92. * the first one.
  93. */
  94. if (cinfo->src == NULL) { /* first time for this JPEG object? */
  95. cinfo->src = (struct jpeg_source_mgr *)
  96. (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
  97. sizeof(struct jpeg_source_mgr));
  98. }
  99. src = cinfo->src;
  100. src->init_source = x_init_mem_source;
  101. src->fill_input_buffer = x_fill_mem_input_buffer;
  102. src->skip_input_data = x_skip_input_data;
  103. src->resync_to_restart = jpeg_resync_to_restart; /* use default method */
  104. src->term_source = x_term_source;
  105. src->bytes_in_buffer = (size_t) insize;
  106. src->next_input_byte = (JOCTET *) inbuffer;
  107. }
  108. #define OUTPUT_BUF_SIZE 4096
  109. typedef struct {
  110. struct jpeg_destination_mgr pub; /* public fields */
  111. unsigned char ** outbuffer; /* target buffer */
  112. unsigned long * outsize;
  113. unsigned char * newbuffer; /* newly allocated buffer */
  114. JOCTET * buffer; /* start of buffer */
  115. size_t bufsize;
  116. } x_mem_destination_mgr;
  117. typedef x_mem_destination_mgr * x_mem_dest_ptr;
  118. static void x_init_mem_destination (j_compress_ptr cinfo)
  119. {
  120. /* no work necessary here */
  121. }
  122. static boolean x_empty_mem_output_buffer (j_compress_ptr cinfo)
  123. {
  124. size_t nextsize;
  125. JOCTET * nextbuffer;
  126. x_mem_dest_ptr dest = (x_mem_dest_ptr) cinfo->dest;
  127. /* Try to allocate new buffer with double size */
  128. nextsize = dest->bufsize * 2;
  129. nextbuffer = (JOCTET*) malloc(nextsize);
  130. if (nextbuffer == NULL)
  131. {
  132. (cinfo)->err->msg_code = 0;
  133. (cinfo)->err->msg_parm.i[0] = 10;
  134. (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo));
  135. }
  136. memcpy(nextbuffer, dest->buffer, dest->bufsize);
  137. if (dest->newbuffer != NULL)
  138. free(dest->newbuffer);
  139. dest->newbuffer = nextbuffer;
  140. dest->pub.next_output_byte = nextbuffer + dest->bufsize;
  141. dest->pub.free_in_buffer = dest->bufsize;
  142. dest->buffer = nextbuffer;
  143. dest->bufsize = nextsize;
  144. return TRUE;
  145. }
  146. static void x_term_mem_destination (j_compress_ptr cinfo)
  147. {
  148. x_mem_dest_ptr dest = (x_mem_dest_ptr) cinfo->dest;
  149. *dest->outbuffer = dest->buffer;
  150. *dest->outsize = dest->bufsize - dest->pub.free_in_buffer;
  151. }
  152. static void x_jpeg_mem_dest (j_compress_ptr cinfo,
  153. unsigned char ** outbuffer, unsigned long * outsize)
  154. {
  155. x_mem_dest_ptr dest;
  156. if (outbuffer == NULL || outsize == NULL) /* sanity check */
  157. {
  158. (cinfo)->err->msg_code = 0;
  159. (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo));
  160. }
  161. /* The destination object is made permanent so that multiple JPEG images
  162. * can be written to the same buffer without re-executing jpeg_mem_dest.
  163. */
  164. if (cinfo->dest == NULL) { /* first time for this JPEG object? */
  165. cinfo->dest = (struct jpeg_destination_mgr *)
  166. (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
  167. sizeof(x_mem_destination_mgr));
  168. }
  169. dest = (x_mem_dest_ptr) cinfo->dest;
  170. dest->pub.init_destination = x_init_mem_destination;
  171. dest->pub.empty_output_buffer = x_empty_mem_output_buffer;
  172. dest->pub.term_destination = x_term_mem_destination;
  173. dest->outbuffer = outbuffer;
  174. dest->outsize = outsize;
  175. dest->newbuffer = NULL;
  176. if (*outbuffer == NULL || *outsize == 0) {
  177. /* Allocate initial buffer */
  178. dest->newbuffer = *outbuffer = (unsigned char*)malloc(OUTPUT_BUF_SIZE);
  179. if (dest->newbuffer == NULL)
  180. {
  181. (cinfo)->err->msg_code = 0;
  182. (cinfo)->err->msg_parm.i[0] = 10;
  183. (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo));
  184. }
  185. *outsize = OUTPUT_BUF_SIZE;
  186. }
  187. dest->pub.next_output_byte = dest->buffer = *outbuffer;
  188. dest->pub.free_in_buffer = dest->bufsize = *outsize;
  189. }
  190. #endif
  191. CJpegIO::CJpegIO()
  192. {
  193. m_width = 0;
  194. m_height = 0;
  195. m_orientation = 0;
  196. m_inputBuffSize = 0;
  197. m_inputBuff = NULL;
  198. m_texturePath = "";
  199. memset(&m_cinfo, 0, sizeof(m_cinfo));
  200. m_thumbnailbuffer = NULL;
  201. }
  202. CJpegIO::~CJpegIO()
  203. {
  204. Close();
  205. }
  206. void CJpegIO::Close()
  207. {
  208. free(m_inputBuff);
  209. m_inputBuff = NULL;
  210. m_inputBuffSize = 0;
  211. ReleaseThumbnailBuffer();
  212. }
  213. bool CJpegIO::Open(const CStdString &texturePath, unsigned int minx, unsigned int miny, bool read)
  214. {
  215. Close();
  216. m_texturePath = texturePath;
  217. XFILE::CFile file;
  218. if (file.Open(m_texturePath.c_str(), READ_TRUNCATED))
  219. {
  220. /*
  221. GetLength() will typically return values that fall into three cases:
  222. 1. The real filesize. This is the typical case.
  223. 2. Zero. This is the case for some http:// streams for example.
  224. 3. Some value smaller than the real filesize. This is the case for an expanding file.
  225. In order to handle all three cases, we read the file in chunks, relying on Read()
  226. returning 0 at EOF. To minimize (re)allocation of the buffer, the chunksize in
  227. cases 1 and 3 is set to one byte larger** than the value returned by GetLength().
  228. The chunksize in case 2 is set to the larger of 64k and GetChunkSize().
  229. We fill the buffer entirely before reallocation. Thus, reallocation never occurs in case 1
  230. as the buffer is larger than the file, so we hit EOF before we hit the end of buffer.
  231. To minimize reallocation, we double the chunksize each time up to a maxchunksize of 2MB.
  232. */
  233. unsigned int filesize = (unsigned int)file.GetLength();
  234. unsigned int chunksize = filesize ? (filesize + 1) : std::max(65536U, (unsigned int)file.GetChunkSize());
  235. unsigned int maxchunksize = 2048*1024U; /* max 2MB chunksize */
  236. unsigned int total_read = 0, free_space = 0;
  237. while (true)
  238. {
  239. if (!free_space)
  240. { // (re)alloc
  241. m_inputBuffSize += chunksize;
  242. unsigned char* new_buf = (unsigned char *)realloc(m_inputBuff, m_inputBuffSize);
  243. if (!new_buf)
  244. {
  245. CLog::Log(LOGERROR, "%s unable to allocate buffer of size %u", __FUNCTION__, m_inputBuffSize);
  246. free(m_inputBuff);
  247. return false;
  248. }
  249. else
  250. m_inputBuff = new_buf;
  251. free_space = chunksize;
  252. chunksize = std::min(chunksize*2, maxchunksize);
  253. }
  254. unsigned int read = file.Read(m_inputBuff + total_read, free_space);
  255. free_space -= read;
  256. total_read += read;
  257. if (!read)
  258. break;
  259. }
  260. m_inputBuffSize = total_read;
  261. file.Close();
  262. if (m_inputBuffSize == 0)
  263. return false;
  264. }
  265. else
  266. return false;
  267. if (!read)
  268. return true;
  269. if (Read(m_inputBuff, m_inputBuffSize, minx, miny))
  270. return true;
  271. return false;
  272. }
  273. bool CJpegIO::Read(unsigned char* buffer, unsigned int bufSize, unsigned int minx, unsigned int miny)
  274. {
  275. struct my_error_mgr jerr;
  276. m_cinfo.err = jpeg_std_error(&jerr.pub);
  277. jerr.pub.error_exit = jpeg_error_exit;
  278. if (buffer == NULL || !bufSize )
  279. return false;
  280. jpeg_create_decompress(&m_cinfo);
  281. #if JPEG_LIB_VERSION < 80
  282. x_mem_src(&m_cinfo, buffer, bufSize);
  283. #else
  284. jpeg_mem_src(&m_cinfo, buffer, bufSize);
  285. #endif
  286. if (setjmp(jerr.setjmp_buffer))
  287. {
  288. jpeg_destroy_decompress(&m_cinfo);
  289. return false;
  290. }
  291. else
  292. {
  293. jpeg_save_markers (&m_cinfo, JPEG_APP0 + 1, 0xFFFF);
  294. jpeg_read_header(&m_cinfo, true);
  295. /* libjpeg can scale the image for us if it is too big. It must be in the format
  296. num/denom, where (for our purposes) that is [1-8]/8 where 8/8 is the unscaled image.
  297. The only way to know how big a resulting image will be is to try a ratio and
  298. test its resulting size.
  299. If the res is greater than the one desired, use that one since there's no need
  300. to decode a bigger one just to squish it back down. If the res is greater than
  301. the gpu can hold, use the previous one.*/
  302. if (minx == 0 || miny == 0)
  303. {
  304. miny = g_advancedSettings.m_imageRes;
  305. if (g_advancedSettings.m_fanartRes > g_advancedSettings.m_imageRes)
  306. { // a separate fanart resolution is specified - check if the image is exactly equal to this res
  307. if (m_cinfo.image_width == (unsigned int)g_advancedSettings.m_fanartRes * 16/9 &&
  308. m_cinfo.image_height == (unsigned int)g_advancedSettings.m_fanartRes)
  309. { // special case for fanart res
  310. miny = g_advancedSettings.m_fanartRes;
  311. }
  312. }
  313. minx = miny * 16/9;
  314. }
  315. m_cinfo.scale_denom = 8;
  316. m_cinfo.out_color_space = JCS_RGB;
  317. unsigned int maxtexsize = g_Windowing.GetMaxTextureSize();
  318. for (m_cinfo.scale_num = 1; m_cinfo.scale_num <= 8; m_cinfo.scale_num++)
  319. {
  320. jpeg_calc_output_dimensions(&m_cinfo);
  321. if ((m_cinfo.output_width > maxtexsize) || (m_cinfo.output_height > maxtexsize))
  322. {
  323. m_cinfo.scale_num--;
  324. break;
  325. }
  326. if (m_cinfo.output_width >= minx && m_cinfo.output_height >= miny)
  327. break;
  328. }
  329. jpeg_calc_output_dimensions(&m_cinfo);
  330. m_width = m_cinfo.output_width;
  331. m_height = m_cinfo.output_height;
  332. if (m_cinfo.marker_list)
  333. m_orientation = GetExifOrientation(m_cinfo.marker_list->data, m_cinfo.marker_list->data_length);
  334. return true;
  335. }
  336. }
  337. bool CJpegIO::Decode(const unsigned char *pixels, unsigned int pitch, unsigned int format)
  338. {
  339. unsigned char *dst = (unsigned char*)pixels;
  340. struct my_error_mgr jerr;
  341. m_cinfo.err = jpeg_std_error(&jerr.pub);
  342. jerr.pub.error_exit = jpeg_error_exit;
  343. if (setjmp(jerr.setjmp_buffer))
  344. {
  345. jpeg_destroy_decompress(&m_cinfo);
  346. return false;
  347. }
  348. else
  349. {
  350. jpeg_start_decompress(&m_cinfo);
  351. if (format == XB_FMT_RGB8)
  352. {
  353. while (m_cinfo.output_scanline < m_height)
  354. {
  355. jpeg_read_scanlines(&m_cinfo, &dst, 1);
  356. dst += pitch;
  357. }
  358. }
  359. else if (format == XB_FMT_A8R8G8B8)
  360. {
  361. unsigned char* row = new unsigned char[m_width * 3];
  362. while (m_cinfo.output_scanline < m_height)
  363. {
  364. jpeg_read_scanlines(&m_cinfo, &row, 1);
  365. unsigned char *src2 = row;
  366. unsigned char *dst2 = dst;
  367. for (unsigned int x = 0; x < m_width; x++, src2 += 3)
  368. {
  369. *dst2++ = src2[2];
  370. *dst2++ = src2[1];
  371. *dst2++ = src2[0];
  372. *dst2++ = 0xff;
  373. }
  374. dst += pitch;
  375. }
  376. delete[] row;
  377. }
  378. else
  379. {
  380. CLog::Log(LOGWARNING, "JpegIO: Incorrect output format specified");
  381. jpeg_destroy_decompress(&m_cinfo);
  382. return false;
  383. }
  384. jpeg_finish_decompress(&m_cinfo);
  385. }
  386. jpeg_destroy_decompress(&m_cinfo);
  387. return true;
  388. }
  389. bool CJpegIO::CreateThumbnail(const CStdString& sourceFile, const CStdString& destFile, int minx, int miny, bool rotateExif)
  390. {
  391. //Copy sourceFile to buffer, pass to CreateThumbnailFromMemory for decode+re-encode
  392. if (!Open(sourceFile, minx, miny, false))
  393. return false;
  394. return CreateThumbnailFromMemory(m_inputBuff, m_inputBuffSize, destFile, minx, miny);
  395. }
  396. bool CJpegIO::CreateThumbnailFromMemory(unsigned char* buffer, unsigned int bufSize, const CStdString& destFile, unsigned int minx, unsigned int miny)
  397. {
  398. //Decode a jpeg residing in buffer, pass to CreateThumbnailFromSurface for re-encode
  399. unsigned int pitch = 0;
  400. unsigned char *sourceBuf = NULL;
  401. if (!Read(buffer, bufSize, minx, miny))
  402. return false;
  403. pitch = Width() * 3;
  404. sourceBuf = new unsigned char [Height() * pitch];
  405. if (!Decode(sourceBuf,pitch,XB_FMT_RGB8))
  406. {
  407. delete [] sourceBuf;
  408. return false;
  409. }
  410. if (!CreateThumbnailFromSurface(sourceBuf, Width(), Height() , XB_FMT_RGB8, pitch, destFile))
  411. {
  412. delete [] sourceBuf;
  413. return false;
  414. }
  415. delete [] sourceBuf;
  416. return true;
  417. }
  418. bool CJpegIO::CreateThumbnailFromSurface(unsigned char* buffer, unsigned int width, unsigned int height, unsigned int format, unsigned int pitch, const CStdString& destFile)
  419. {
  420. //Encode raw data from buffer, save to destFile
  421. struct jpeg_compress_struct cinfo;
  422. struct my_error_mgr jerr;
  423. JSAMPROW row_pointer[1];
  424. long unsigned int outBufSize = width * height;
  425. unsigned char* result;
  426. unsigned char* src = buffer;
  427. unsigned char* rgbbuf;
  428. if(buffer == NULL)
  429. {
  430. CLog::Log(LOGERROR, "JpegIO::CreateThumbnailFromSurface no buffer");
  431. return false;
  432. }
  433. result = (unsigned char*) malloc(outBufSize); //Initial buffer. Grows as-needed.
  434. if (result == NULL)
  435. {
  436. CLog::Log(LOGERROR, "JpegIO::CreateThumbnailFromSurface error allocating memory for image buffer");
  437. return false;
  438. }
  439. if(format == XB_FMT_RGB8)
  440. {
  441. rgbbuf = buffer;
  442. }
  443. else if(format == XB_FMT_A8R8G8B8)
  444. {
  445. // create a copy for bgra -> rgb.
  446. rgbbuf = new unsigned char [(width * height * 3)];
  447. unsigned char* dst = rgbbuf;
  448. for (unsigned int y = 0; y < height; y++)
  449. {
  450. unsigned char* dst2 = dst;
  451. unsigned char* src2 = src;
  452. for (unsigned int x = 0; x < width; x++, src2 += 4)
  453. {
  454. *dst2++ = src2[2];
  455. *dst2++ = src2[1];
  456. *dst2++ = src2[0];
  457. }
  458. dst += width * 3;
  459. src += pitch;
  460. }
  461. }
  462. else
  463. {
  464. CLog::Log(LOGWARNING, "JpegIO::CreateThumbnailFromSurface Unsupported format");
  465. free(result);
  466. return false;
  467. }
  468. cinfo.err = jpeg_std_error(&jerr.pub);
  469. jerr.pub.error_exit = jpeg_error_exit;
  470. jpeg_create_compress(&cinfo);
  471. if (setjmp(jerr.setjmp_buffer))
  472. {
  473. jpeg_destroy_compress(&cinfo);
  474. free(result);
  475. if(format != XB_FMT_RGB8)
  476. delete [] rgbbuf;
  477. return false;
  478. }
  479. else
  480. {
  481. #if JPEG_LIB_VERSION < 80
  482. x_jpeg_mem_dest(&cinfo, &result, &outBufSize);
  483. #else
  484. jpeg_mem_dest(&cinfo, &result, &outBufSize);
  485. #endif
  486. cinfo.image_width = width;
  487. cinfo.image_height = height;
  488. cinfo.input_components = 3;
  489. cinfo.in_color_space = JCS_RGB;
  490. jpeg_set_defaults(&cinfo);
  491. jpeg_set_quality(&cinfo, 90, TRUE);
  492. jpeg_start_compress(&cinfo, TRUE);
  493. while (cinfo.next_scanline < cinfo.image_height)
  494. {
  495. row_pointer[0] = &rgbbuf[cinfo.next_scanline * width * 3];
  496. jpeg_write_scanlines(&cinfo, row_pointer, 1);
  497. }
  498. jpeg_finish_compress(&cinfo);
  499. jpeg_destroy_compress(&cinfo);
  500. }
  501. if(format != XB_FMT_RGB8)
  502. delete [] rgbbuf;
  503. XFILE::CFile file;
  504. if (file.OpenForWrite(destFile, true))
  505. {
  506. file.Write(result, outBufSize);
  507. file.Close();
  508. free(result);
  509. return true;
  510. }
  511. free(result);
  512. return false;
  513. }
  514. // override libjpeg's error function to avoid an exit() call
  515. void CJpegIO::jpeg_error_exit(j_common_ptr cinfo)
  516. {
  517. CStdString msg;
  518. msg.Format("Error %i: %s",cinfo->err->msg_code, cinfo->err->jpeg_message_table[cinfo->err->msg_code]);
  519. CLog::Log(LOGWARNING, "JpegIO: %s", msg.c_str());
  520. my_error_mgr *myerr = (my_error_mgr*)cinfo->err;
  521. longjmp(myerr->setjmp_buffer, 1);
  522. }
  523. unsigned int CJpegIO::GetExifOrientation(unsigned char* exif_data, unsigned int exif_data_size)
  524. {
  525. unsigned int offset = 0;
  526. unsigned int numberOfTags = 0;
  527. unsigned int tagNumber = 0;
  528. bool isMotorola = false;
  529. unsigned const char ExifHeader[] = "Exif\0\0";
  530. unsigned int orientation = 0;
  531. // read exif head, check for "Exif"
  532. // next we want to read to current offset + length
  533. // check if buffer is big enough
  534. if (exif_data_size && memcmp(exif_data, ExifHeader, 6) == 0)
  535. {
  536. //read exif body
  537. exif_data += 6;
  538. }
  539. else
  540. {
  541. return 0;
  542. }
  543. // Discover byte order
  544. if (exif_data[0] == 'I' && exif_data[1] == 'I')
  545. isMotorola = false;
  546. else if (exif_data[0] == 'M' && exif_data[1] == 'M')
  547. isMotorola = true;
  548. else
  549. return 0;
  550. // Check Tag Mark
  551. if (isMotorola)
  552. {
  553. if (exif_data[2] != 0 || exif_data[3] != 0x2A)
  554. return 0;
  555. }
  556. else
  557. {
  558. if (exif_data[3] != 0 || exif_data[2] != 0x2A)
  559. return 0;
  560. }
  561. // Get first IFD offset (offset to IFD0)
  562. if (isMotorola)
  563. {
  564. if (exif_data[4] != 0 || exif_data[5] != 0)
  565. return 0;
  566. offset = exif_data[6];
  567. offset <<= 8;
  568. offset += exif_data[7];
  569. }
  570. else
  571. {
  572. if (exif_data[7] != 0 || exif_data[6] != 0)
  573. return 0;
  574. offset = exif_data[5];
  575. offset <<= 8;
  576. offset += exif_data[4];
  577. }
  578. if (offset > exif_data_size - 2)
  579. return 0; // check end of data segment
  580. // Get the number of directory entries contained in this IFD
  581. if (isMotorola)
  582. {
  583. numberOfTags = exif_data[offset];
  584. numberOfTags <<= 8;
  585. numberOfTags += exif_data[offset+1];
  586. }
  587. else
  588. {
  589. numberOfTags = exif_data[offset+1];
  590. numberOfTags <<= 8;
  591. numberOfTags += exif_data[offset];
  592. }
  593. if (numberOfTags == 0)
  594. return 0;
  595. offset += 2;
  596. // Search for Orientation Tag in IFD0 - hey almost there! :D
  597. while(1)//hopefully this jpeg has correct exif data...
  598. {
  599. if (offset > exif_data_size - 12)
  600. return 0; // check end of data segment
  601. // Get Tag number
  602. if (isMotorola)
  603. {
  604. tagNumber = exif_data[offset];
  605. tagNumber <<= 8;
  606. tagNumber += exif_data[offset+1];
  607. }
  608. else
  609. {
  610. tagNumber = exif_data[offset+1];
  611. tagNumber <<= 8;
  612. tagNumber += exif_data[offset];
  613. }
  614. if (tagNumber == EXIF_TAG_ORIENTATION)
  615. break; //found orientation tag
  616. if ( --numberOfTags == 0)
  617. return 0;//no orientation found
  618. offset += 12;//jump to next tag
  619. }
  620. // Get the Orientation value
  621. if (isMotorola)
  622. {
  623. if (exif_data[offset+8] != 0)
  624. return 0;
  625. orientation = exif_data[offset+9];
  626. }
  627. else
  628. {
  629. if (exif_data[offset+9] != 0)
  630. return 0;
  631. orientation = exif_data[offset+8];
  632. }
  633. if (orientation > 8)
  634. orientation = 0;
  635. return orientation;//done
  636. }
  637. bool CJpegIO::LoadImageFromMemory(unsigned char* buffer, unsigned int bufSize, unsigned int width, unsigned int height)
  638. {
  639. return Read(buffer, bufSize, width, height);
  640. }
  641. bool CJpegIO::CreateThumbnailFromSurface(unsigned char* bufferin, unsigned int width, unsigned int height, unsigned int format, unsigned int pitch, const CStdString& destFile,
  642. unsigned char* &bufferout, unsigned int &bufferoutSize)
  643. {
  644. //Encode raw data from buffer, save to destbuffer
  645. struct jpeg_compress_struct cinfo;
  646. struct my_error_mgr jerr;
  647. JSAMPROW row_pointer[1];
  648. long unsigned int outBufSize = width * height;
  649. unsigned char* src = bufferin;
  650. unsigned char* rgbbuf;
  651. if(bufferin == NULL)
  652. {
  653. CLog::Log(LOGERROR, "JpegIO::CreateThumbnailFromSurface no buffer");
  654. return false;
  655. }
  656. m_thumbnailbuffer = (unsigned char*) malloc(outBufSize); //Initial buffer. Grows as-needed.
  657. if (m_thumbnailbuffer == NULL)
  658. {
  659. CLog::Log(LOGERROR, "JpegIO::CreateThumbnailFromSurface error allocating memory for image buffer");
  660. return false;
  661. }
  662. if(format == XB_FMT_RGB8)
  663. {
  664. rgbbuf = bufferin;
  665. }
  666. else if(format == XB_FMT_A8R8G8B8)
  667. {
  668. // create a copy for bgra -> rgb.
  669. rgbbuf = new unsigned char [(width * height * 3)];
  670. unsigned char* dst = rgbbuf;
  671. for (unsigned int y = 0; y < height; y++)
  672. {
  673. unsigned char* dst2 = dst;
  674. unsigned char* src2 = src;
  675. for (unsigned int x = 0; x < width; x++, src2 += 4)
  676. {
  677. *dst2++ = src2[2];
  678. *dst2++ = src2[1];
  679. *dst2++ = src2[0];
  680. }
  681. dst += width * 3;
  682. src += pitch;
  683. }
  684. }
  685. else
  686. {
  687. CLog::Log(LOGWARNING, "JpegIO::CreateThumbnailFromSurface Unsupported format");
  688. free(m_thumbnailbuffer);
  689. return false;
  690. }
  691. cinfo.err = jpeg_std_error(&jerr.pub);
  692. jerr.pub.error_exit = jpeg_error_exit;
  693. jpeg_create_compress(&cinfo);
  694. if (setjmp(jerr.setjmp_buffer))
  695. {
  696. jpeg_destroy_compress(&cinfo);
  697. free(m_thumbnailbuffer);
  698. if(format != XB_FMT_RGB8)
  699. delete [] rgbbuf;
  700. return false;
  701. }
  702. else
  703. {
  704. #if JPEG_LIB_VERSION < 80
  705. x_jpeg_mem_dest(&cinfo, &m_thumbnailbuffer, &outBufSize);
  706. #else
  707. jpeg_mem_dest(&cinfo, &m_thumbnailbuffer, &outBufSize);
  708. #endif
  709. cinfo.image_width = width;
  710. cinfo.image_height = height;
  711. cinfo.input_components = 3;
  712. cinfo.in_color_space = JCS_RGB;
  713. jpeg_set_defaults(&cinfo);
  714. jpeg_set_quality(&cinfo, 90, TRUE);
  715. jpeg_start_compress(&cinfo, TRUE);
  716. while (cinfo.next_scanline < cinfo.image_height)
  717. {
  718. row_pointer[0] = &rgbbuf[cinfo.next_scanline * width * 3];
  719. jpeg_write_scanlines(&cinfo, row_pointer, 1);
  720. }
  721. jpeg_finish_compress(&cinfo);
  722. jpeg_destroy_compress(&cinfo);
  723. }
  724. if(format != XB_FMT_RGB8)
  725. delete [] rgbbuf;
  726. bufferout = m_thumbnailbuffer;
  727. bufferoutSize = outBufSize;
  728. return true;
  729. }
  730. void CJpegIO::ReleaseThumbnailBuffer()
  731. {
  732. if(m_thumbnailbuffer != NULL)
  733. {
  734. free(m_thumbnailbuffer);
  735. m_thumbnailbuffer = NULL;
  736. }
  737. }