A Simple X Image Viewer
Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.
 
 
 
 
 
 

131 рядки
2.9 KiB

  1. /* sxiv: exif.c
  2. * Copyright (c) 2012 Bert Muennich <be.muennich at googlemail.com>
  3. *
  4. * This program is free software; you can redistribute it and/or modify it
  5. * under the terms of the GNU General Public License as published by the
  6. * Free Software Foundation; either version 2 of the License, or (at your
  7. * option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful, but
  10. * WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License along
  15. * with this program; if not, write to the Free Software Foundation, Inc.,
  16. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  17. */
  18. #define _POSIX_C_SOURCE 200112L
  19. #include <stdlib.h>
  20. #include <fcntl.h>
  21. #include <sys/stat.h>
  22. #include <unistd.h>
  23. #include "exif.h"
  24. #include "util.h"
  25. ssize_t s_read(int fd, const char *fn, void *buf, size_t n) {
  26. ssize_t ret;
  27. ret = read(fd, buf, n);
  28. if (ret < n) {
  29. warn("unexpected end-of-file: %s", fn);
  30. return -1;
  31. } else {
  32. return ret;
  33. }
  34. }
  35. unsigned short btous(unsigned char *buf, byteorder_t order) {
  36. if (buf == NULL)
  37. return 0;
  38. if (order == BO_BIG_ENDIAN)
  39. return buf[0] << 8 | buf[1];
  40. else
  41. return buf[1] << 8 | buf[0];
  42. }
  43. unsigned int btoui(unsigned char *buf, byteorder_t order) {
  44. if (buf == NULL)
  45. return 0;
  46. if (order == BO_BIG_ENDIAN)
  47. return buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3];
  48. else
  49. return buf[3] << 24 | buf[2] << 16 | buf[1] << 8 | buf[0];
  50. }
  51. int exif_orientation(const fileinfo_t *file) {
  52. int fd;
  53. unsigned char data[EXIF_MAX_LEN];
  54. byteorder_t order = BO_BIG_ENDIAN;
  55. unsigned int cnt, len, idx, val;
  56. if (file == NULL || file->path == NULL)
  57. return -1;
  58. fd = open(file->path, O_RDONLY);
  59. if (fd < 0)
  60. return -1;
  61. if (s_read(fd, file->name, data, 4) < 0)
  62. goto abort;
  63. if (btous(data, order) != JPEG_MARKER_SOI)
  64. goto abort;
  65. if (btous(data + 2, order) != JPEG_MARKER_APP1)
  66. goto abort;
  67. if (s_read(fd, file->name, data, 2) < 0)
  68. goto abort;
  69. len = btous(data, order);
  70. if (len < 8)
  71. goto abort;
  72. if (s_read(fd, file->name, data, 6) < 0)
  73. goto abort;
  74. if (btoui(data, order) != EXIF_HEAD)
  75. goto abort;
  76. len -= 8;
  77. if (len < 12 || len > EXIF_MAX_LEN)
  78. goto abort;
  79. if (s_read(fd, file->name, data, len) < 0)
  80. goto abort;
  81. switch (btous(data, order)) {
  82. case EXIF_BO_BIG_ENDIAN:
  83. order = BO_BIG_ENDIAN;
  84. break;
  85. case EXIF_BO_LITTLE_ENDIAN:
  86. order = BO_LITTLE_ENDIAN;
  87. break;
  88. default:
  89. goto abort;
  90. break;
  91. }
  92. if (btous(data + 2, order) != EXIF_TAG_MARK)
  93. goto abort;
  94. idx = btoui(data + 4, order);
  95. if (idx > len - 2)
  96. goto abort;
  97. val = 0;
  98. cnt = btous(data + idx, order);
  99. for (idx += 2; cnt > 0 && idx < len - 12; cnt--, idx += 12) {
  100. if (btous(data + idx, order) == EXIF_TAG_ORIENTATION) {
  101. val = btous(data + idx + 8, order);
  102. break;
  103. }
  104. }
  105. close(fd);
  106. return val;
  107. abort:
  108. close(fd);
  109. return -1;
  110. }