image.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473
  1. /**
  2. * WinPR: Windows Portable Runtime
  3. * Image Utils
  4. *
  5. * Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
  6. * Copyright 2016 Inuvika Inc.
  7. * Copyright 2016 David PHAM-VAN <d.phamvan@inuvika.com>
  8. *
  9. * Licensed under the Apache License, Version 2.0 (the "License");
  10. * you may not use this file except in compliance with the License.
  11. * You may obtain a copy of the License at
  12. *
  13. * http://www.apache.org/licenses/LICENSE-2.0
  14. *
  15. * Unless required by applicable law or agreed to in writing, software
  16. * distributed under the License is distributed on an "AS IS" BASIS,
  17. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  18. * See the License for the specific language governing permissions and
  19. * limitations under the License.
  20. */
  21. #ifdef HAVE_CONFIG_H
  22. #include "config.h"
  23. #endif
  24. #include <winpr/wtypes.h>
  25. #include <winpr/crt.h>
  26. #include <winpr/image.h>
  27. #include "lodepng/lodepng.h"
  28. #include <winpr/stream.h>
  29. #include "../log.h"
  30. #define TAG WINPR_TAG("utils.image")
  31. static BOOL writeBitmapFileHeader(wStream* s, const WINPR_BITMAP_FILE_HEADER* bf)
  32. {
  33. if (!Stream_EnsureRemainingCapacity(s, sizeof(WINPR_BITMAP_FILE_HEADER)))
  34. return FALSE;
  35. Stream_Write_UINT8(s, bf->bfType[0]);
  36. Stream_Write_UINT8(s, bf->bfType[1]);
  37. Stream_Write_UINT32(s, bf->bfSize);
  38. Stream_Write_UINT16(s, bf->bfReserved1);
  39. Stream_Write_UINT16(s, bf->bfReserved2);
  40. Stream_Write_UINT32(s, bf->bfOffBits);
  41. return TRUE;
  42. }
  43. static BOOL readBitmapFileHeader(wStream* s, WINPR_BITMAP_FILE_HEADER* bf)
  44. {
  45. if (!s || !bf || (Stream_GetRemainingLength(s) < sizeof(WINPR_BITMAP_FILE_HEADER)))
  46. return FALSE;
  47. Stream_Read_UINT8(s, bf->bfType[0]);
  48. Stream_Read_UINT8(s, bf->bfType[1]);
  49. Stream_Read_UINT32(s, bf->bfSize);
  50. Stream_Read_UINT16(s, bf->bfReserved1);
  51. Stream_Read_UINT16(s, bf->bfReserved2);
  52. Stream_Read_UINT32(s, bf->bfOffBits);
  53. return TRUE;
  54. }
  55. static BOOL writeBitmapInfoHeader(wStream* s, const WINPR_BITMAP_INFO_HEADER* bi)
  56. {
  57. if (!Stream_EnsureRemainingCapacity(s, sizeof(WINPR_BITMAP_INFO_HEADER)))
  58. return FALSE;
  59. Stream_Write_UINT32(s, bi->biSize);
  60. Stream_Write_UINT32(s, bi->biWidth);
  61. Stream_Write_UINT32(s, bi->biHeight);
  62. Stream_Write_UINT16(s, bi->biPlanes);
  63. Stream_Write_UINT16(s, bi->biBitCount);
  64. Stream_Write_UINT32(s, bi->biCompression);
  65. Stream_Write_UINT32(s, bi->biSizeImage);
  66. Stream_Write_UINT32(s, bi->biXPelsPerMeter);
  67. Stream_Write_UINT32(s, bi->biYPelsPerMeter);
  68. Stream_Write_UINT32(s, bi->biClrUsed);
  69. Stream_Write_UINT32(s, bi->biClrImportant);
  70. return TRUE;
  71. }
  72. static BOOL readBitmapInfoHeader(wStream* s, WINPR_BITMAP_INFO_HEADER* bi)
  73. {
  74. if (!s || !bi || (Stream_GetRemainingLength(s) < sizeof(WINPR_BITMAP_INFO_HEADER)))
  75. return FALSE;
  76. Stream_Read_UINT32(s, bi->biSize);
  77. Stream_Read_INT32(s, bi->biWidth);
  78. Stream_Read_INT32(s, bi->biHeight);
  79. Stream_Read_UINT16(s, bi->biPlanes);
  80. Stream_Read_UINT16(s, bi->biBitCount);
  81. Stream_Read_UINT32(s, bi->biCompression);
  82. Stream_Read_UINT32(s, bi->biSizeImage);
  83. Stream_Read_INT32(s, bi->biXPelsPerMeter);
  84. Stream_Read_INT32(s, bi->biYPelsPerMeter);
  85. Stream_Read_UINT32(s, bi->biClrUsed);
  86. Stream_Read_UINT32(s, bi->biClrImportant);
  87. return TRUE;
  88. }
  89. /**
  90. * Refer to "Compressed Image File Formats: JPEG, PNG, GIF, XBM, BMP" book
  91. */
  92. int winpr_bitmap_write(const char* filename, const BYTE* data, int width, int height, int bpp)
  93. {
  94. FILE* fp;
  95. WINPR_BITMAP_FILE_HEADER bf;
  96. WINPR_BITMAP_INFO_HEADER bi;
  97. wStream* s;
  98. int ret = -1;
  99. fp = fopen(filename, "w+b");
  100. if (!fp)
  101. {
  102. WLog_ERR(TAG, "failed to open file %s", filename);
  103. return -1;
  104. }
  105. bf.bfType[0] = 'B';
  106. bf.bfType[1] = 'M';
  107. bf.bfReserved1 = 0;
  108. bf.bfReserved2 = 0;
  109. bf.bfOffBits = sizeof(WINPR_BITMAP_FILE_HEADER) + sizeof(WINPR_BITMAP_INFO_HEADER);
  110. bi.biSizeImage = width * height * (bpp / 8);
  111. bf.bfSize = bf.bfOffBits + bi.biSizeImage;
  112. bi.biWidth = width;
  113. bi.biHeight = -1 * height;
  114. bi.biPlanes = 1;
  115. bi.biBitCount = bpp;
  116. bi.biCompression = 0;
  117. bi.biXPelsPerMeter = width;
  118. bi.biYPelsPerMeter = height;
  119. bi.biClrUsed = 0;
  120. bi.biClrImportant = 0;
  121. bi.biSize = sizeof(WINPR_BITMAP_INFO_HEADER);
  122. s = Stream_New(NULL, sizeof(WINPR_BITMAP_FILE_HEADER) + sizeof(WINPR_BITMAP_INFO_HEADER));
  123. if (!s)
  124. goto fail;
  125. if (!writeBitmapFileHeader(s, &bf))
  126. goto fail;
  127. if (!writeBitmapInfoHeader(s, &bi))
  128. goto fail;
  129. Stream_SealLength(s);
  130. if (fwrite(Stream_Buffer(s), Stream_Length(s), 1, fp) != 1 ||
  131. fwrite((void*)data, bi.biSizeImage, 1, fp) != 1)
  132. goto fail;
  133. ret = 1;
  134. fail:
  135. fclose(fp);
  136. Stream_Free(s, TRUE);
  137. return ret;
  138. }
  139. int winpr_image_write(wImage* image, const char* filename)
  140. {
  141. int status = -1;
  142. if (image->type == WINPR_IMAGE_BITMAP)
  143. {
  144. status = winpr_bitmap_write(filename, image->data, image->width, image->height,
  145. image->bitsPerPixel);
  146. }
  147. else
  148. {
  149. int lodepng_status;
  150. lodepng_status = lodepng_encode32_file(filename, image->data, image->width, image->height);
  151. status = (lodepng_status) ? -1 : 1;
  152. }
  153. return status;
  154. }
  155. static int winpr_image_png_read_fp(wImage* image, FILE* fp)
  156. {
  157. INT64 size;
  158. BYTE* data;
  159. UINT32 width;
  160. UINT32 height;
  161. int lodepng_status;
  162. _fseeki64(fp, 0, SEEK_END);
  163. size = _ftelli64(fp);
  164. _fseeki64(fp, 0, SEEK_SET);
  165. data = (BYTE*)malloc(size);
  166. if (!data)
  167. return -1;
  168. if (fread((void*)data, size, 1, fp) != 1)
  169. {
  170. free(data);
  171. return -1;
  172. }
  173. lodepng_status = lodepng_decode32(&(image->data), &width, &height, data, size);
  174. free(data);
  175. if (lodepng_status)
  176. return -1;
  177. image->width = width;
  178. image->height = height;
  179. image->bitsPerPixel = 32;
  180. image->bytesPerPixel = 4;
  181. image->scanline = image->bytesPerPixel * image->width;
  182. return 1;
  183. }
  184. static int winpr_image_png_read_buffer(wImage* image, const BYTE* buffer, size_t size)
  185. {
  186. UINT32 width;
  187. UINT32 height;
  188. int lodepng_status;
  189. lodepng_status = lodepng_decode32(&(image->data), &width, &height, buffer, size);
  190. if (lodepng_status)
  191. return -1;
  192. image->width = width;
  193. image->height = height;
  194. image->bitsPerPixel = 32;
  195. image->bytesPerPixel = 4;
  196. image->scanline = image->bytesPerPixel * image->width;
  197. return 1;
  198. }
  199. static int winpr_image_bitmap_read_fp(wImage* image, FILE* fp)
  200. {
  201. int rc = -1;
  202. int index;
  203. BOOL vFlip;
  204. BYTE* pDstData;
  205. wStream* s;
  206. WINPR_BITMAP_FILE_HEADER bf;
  207. WINPR_BITMAP_INFO_HEADER bi;
  208. if (!image || !fp)
  209. return -1;
  210. image->data = NULL;
  211. s = Stream_New(NULL, sizeof(WINPR_BITMAP_FILE_HEADER) + sizeof(WINPR_BITMAP_INFO_HEADER));
  212. if (!s)
  213. return -1;
  214. if (fread(Stream_Buffer(s), Stream_Capacity(s), 1, fp) != 1)
  215. goto fail;
  216. if (!readBitmapFileHeader(s, &bf) || !readBitmapInfoHeader(s, &bi))
  217. goto fail;
  218. if ((bf.bfType[0] != 'B') || (bf.bfType[1] != 'M'))
  219. goto fail;
  220. image->type = WINPR_IMAGE_BITMAP;
  221. if (_ftelli64(fp) != bf.bfOffBits)
  222. _fseeki64(fp, bf.bfOffBits, SEEK_SET);
  223. image->width = bi.biWidth;
  224. if (bi.biHeight < 0)
  225. {
  226. vFlip = FALSE;
  227. image->height = -1 * bi.biHeight;
  228. }
  229. else
  230. {
  231. vFlip = TRUE;
  232. image->height = bi.biHeight;
  233. }
  234. image->bitsPerPixel = bi.biBitCount;
  235. image->bytesPerPixel = (image->bitsPerPixel / 8);
  236. image->scanline = (bi.biSizeImage / image->height);
  237. image->data = (BYTE*)malloc(bi.biSizeImage);
  238. if (!image->data)
  239. goto fail;
  240. if (!vFlip)
  241. {
  242. if (fread((void*)image->data, bi.biSizeImage, 1, fp) != 1)
  243. goto fail;
  244. }
  245. else
  246. {
  247. pDstData = &(image->data[(image->height - 1) * image->scanline]);
  248. for (index = 0; index < image->height; index++)
  249. {
  250. if (fread((void*)pDstData, image->scanline, 1, fp) != 1)
  251. goto fail;
  252. pDstData -= image->scanline;
  253. }
  254. }
  255. rc = 1;
  256. fail:
  257. if (rc < 0)
  258. {
  259. free(image->data);
  260. image->data = NULL;
  261. }
  262. Stream_Free(s, TRUE);
  263. return 1;
  264. }
  265. static int winpr_image_bitmap_read_buffer(wImage* image, const BYTE* buffer, size_t size)
  266. {
  267. int rc = -1;
  268. int index;
  269. BOOL vFlip;
  270. BYTE* pDstData;
  271. WINPR_BITMAP_FILE_HEADER bf;
  272. WINPR_BITMAP_INFO_HEADER bi;
  273. wStream* s = Stream_New((BYTE*)buffer, size);
  274. if (!s)
  275. return -1;
  276. if (!readBitmapFileHeader(s, &bf) || !readBitmapInfoHeader(s, &bi))
  277. goto fail;
  278. if ((bf.bfType[0] != 'B') || (bf.bfType[1] != 'M'))
  279. goto fail;
  280. image->type = WINPR_IMAGE_BITMAP;
  281. if (Stream_Capacity(s) < bf.bfOffBits + bi.biSizeImage)
  282. goto fail;
  283. Stream_SetPosition(s, bf.bfOffBits);
  284. image->width = bi.biWidth;
  285. if (bi.biHeight < 0)
  286. {
  287. vFlip = FALSE;
  288. image->height = -1 * bi.biHeight;
  289. }
  290. else
  291. {
  292. vFlip = TRUE;
  293. image->height = bi.biHeight;
  294. }
  295. image->bitsPerPixel = bi.biBitCount;
  296. image->bytesPerPixel = (image->bitsPerPixel / 8);
  297. image->scanline = (bi.biSizeImage / image->height);
  298. image->data = (BYTE*)malloc(bi.biSizeImage);
  299. if (!image->data)
  300. goto fail;
  301. if (!vFlip)
  302. Stream_Read(s, image->data, bi.biSizeImage);
  303. else
  304. {
  305. pDstData = &(image->data[(image->height - 1) * image->scanline]);
  306. for (index = 0; index < image->height; index++)
  307. {
  308. Stream_Read(s, pDstData, image->scanline);
  309. pDstData -= image->scanline;
  310. }
  311. }
  312. rc = 1;
  313. fail:
  314. if (rc < 0)
  315. {
  316. free(image->data);
  317. image->data = NULL;
  318. }
  319. Stream_Free(s, FALSE);
  320. return rc;
  321. }
  322. int winpr_image_read(wImage* image, const char* filename)
  323. {
  324. FILE* fp;
  325. BYTE sig[8];
  326. int status = -1;
  327. fp = fopen(filename, "rb");
  328. if (!fp)
  329. {
  330. WLog_ERR(TAG, "failed to open file %s", filename);
  331. return -1;
  332. }
  333. if (fread((void*)&sig, sizeof(sig), 1, fp) != 1 || _fseeki64(fp, 0, SEEK_SET) < 0)
  334. {
  335. fclose(fp);
  336. return -1;
  337. }
  338. if ((sig[0] == 'B') && (sig[1] == 'M'))
  339. {
  340. image->type = WINPR_IMAGE_BITMAP;
  341. status = winpr_image_bitmap_read_fp(image, fp);
  342. }
  343. else if ((sig[0] == 0x89) && (sig[1] == 'P') && (sig[2] == 'N') && (sig[3] == 'G') &&
  344. (sig[4] == '\r') && (sig[5] == '\n') && (sig[6] == 0x1A) && (sig[7] == '\n'))
  345. {
  346. image->type = WINPR_IMAGE_PNG;
  347. status = winpr_image_png_read_fp(image, fp);
  348. }
  349. fclose(fp);
  350. return status;
  351. }
  352. int winpr_image_read_buffer(wImage* image, const BYTE* buffer, int size)
  353. {
  354. BYTE sig[8];
  355. int status = -1;
  356. if (size < 8)
  357. return -1;
  358. CopyMemory(sig, buffer, 8);
  359. if ((sig[0] == 'B') && (sig[1] == 'M'))
  360. {
  361. image->type = WINPR_IMAGE_BITMAP;
  362. status = winpr_image_bitmap_read_buffer(image, buffer, size);
  363. }
  364. else if ((sig[0] == 0x89) && (sig[1] == 'P') && (sig[2] == 'N') && (sig[3] == 'G') &&
  365. (sig[4] == '\r') && (sig[5] == '\n') && (sig[6] == 0x1A) && (sig[7] == '\n'))
  366. {
  367. image->type = WINPR_IMAGE_PNG;
  368. status = winpr_image_png_read_buffer(image, buffer, size);
  369. }
  370. return status;
  371. }
  372. wImage* winpr_image_new(void)
  373. {
  374. wImage* image;
  375. image = (wImage*)calloc(1, sizeof(wImage));
  376. if (!image)
  377. return NULL;
  378. return image;
  379. }
  380. void winpr_image_free(wImage* image, BOOL bFreeBuffer)
  381. {
  382. if (!image)
  383. return;
  384. if (bFreeBuffer)
  385. free(image->data);
  386. free(image);
  387. }