ExifOrientedBitmap.h 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. /*
  2. * Copyright (c) 2023, Lucas Chollet <lucas.chollet@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #pragma once
  7. #include <AK/NonnullOwnPtr.h>
  8. #include <LibGfx/Bitmap.h>
  9. namespace Gfx {
  10. class ExifOrientedBitmap {
  11. public:
  12. // In the EXIF 3.0 specification, 4.6.5.1.6. Orientation
  13. enum class Orientation {
  14. None = 1,
  15. FlipHorizontally = 2,
  16. Rotate180 = 3,
  17. FlipVertically = 4,
  18. Rotate90ClockwiseThenFlipHorizontally = 5,
  19. Rotate90Clockwise = 6,
  20. FlipHorizontallyThenRotate90Clockwise = 7,
  21. Rotate90CounterClockwise = 8,
  22. };
  23. template<typename... Args>
  24. static ErrorOr<ExifOrientedBitmap> create(BitmapFormat format, IntSize size, Orientation orientation)
  25. {
  26. auto bitmap = TRY(Bitmap::create(format, oriented_size(size, orientation)));
  27. return ExifOrientedBitmap(move(bitmap), size, orientation);
  28. }
  29. void set_pixel(u32 x, u32 y, Color color)
  30. {
  31. auto const new_position = oriented_position(IntPoint(x, y));
  32. m_bitmap->set_pixel(new_position, color);
  33. }
  34. NonnullRefPtr<Bitmap>& bitmap()
  35. {
  36. return m_bitmap;
  37. }
  38. private:
  39. ExifOrientedBitmap(NonnullRefPtr<Bitmap> bitmap, IntSize size, Orientation orientation)
  40. : m_bitmap(move(bitmap))
  41. , m_orientation(orientation)
  42. , m_width(size.width())
  43. , m_height(size.height())
  44. {
  45. }
  46. static IntSize oriented_size(IntSize size, Orientation orientation)
  47. {
  48. switch (orientation) {
  49. case Orientation::None:
  50. case Orientation::FlipHorizontally:
  51. case Orientation::Rotate180:
  52. case Orientation::FlipVertically:
  53. return size;
  54. case Orientation::Rotate90ClockwiseThenFlipHorizontally:
  55. case Orientation::Rotate90Clockwise:
  56. case Orientation::FlipHorizontallyThenRotate90Clockwise:
  57. case Orientation::Rotate90CounterClockwise:
  58. return { size.height(), size.width() };
  59. }
  60. VERIFY_NOT_REACHED();
  61. }
  62. IntPoint oriented_position(IntPoint point)
  63. {
  64. auto const flip_horizontally = [this](IntPoint point) {
  65. return IntPoint(m_width - point.x() - 1, point.y());
  66. };
  67. auto const rotate_90_clockwise = [this](IntPoint point) {
  68. return IntPoint(m_height - point.y() - 1, point.x());
  69. };
  70. switch (m_orientation) {
  71. case Orientation::None:
  72. return point;
  73. case Orientation::FlipHorizontally:
  74. return flip_horizontally(point);
  75. case Orientation::Rotate180:
  76. return IntPoint(m_width - point.x() - 1, m_height - point.y() - 1);
  77. case Orientation::FlipVertically:
  78. return IntPoint(point.x(), m_height - point.y() - 1);
  79. case Orientation::Rotate90ClockwiseThenFlipHorizontally:
  80. return flip_horizontally(rotate_90_clockwise(point));
  81. case Orientation::Rotate90Clockwise:
  82. return rotate_90_clockwise(point);
  83. case Orientation::FlipHorizontallyThenRotate90Clockwise:
  84. return rotate_90_clockwise(flip_horizontally(point));
  85. case Orientation::Rotate90CounterClockwise:
  86. return IntPoint(point.y(), m_width - point.x() - 1);
  87. }
  88. VERIFY_NOT_REACHED();
  89. }
  90. NonnullRefPtr<Bitmap> m_bitmap;
  91. Orientation m_orientation;
  92. u32 m_width {};
  93. u32 m_height {};
  94. };
  95. }