ExifOrientedBitmap.h 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  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. #include <LibGfx/ImageFormats/TIFFMetadata.h>
  10. namespace Gfx {
  11. class ExifOrientedBitmap {
  12. public:
  13. template<typename... Args>
  14. static ErrorOr<ExifOrientedBitmap> create(TIFF::Orientation orientation, IntSize size, BitmapFormat format)
  15. {
  16. auto bitmap = TRY(Bitmap::create(format, oriented_size(size, orientation)));
  17. return ExifOrientedBitmap(move(bitmap), size, orientation);
  18. }
  19. void set_pixel(u32 x, u32 y, Color color)
  20. {
  21. auto const new_position = oriented_position(IntPoint(x, y));
  22. m_bitmap->scanline(new_position.y())[new_position.x()] = color.value();
  23. }
  24. NonnullRefPtr<Bitmap>& bitmap()
  25. {
  26. return m_bitmap;
  27. }
  28. static IntSize oriented_size(IntSize size, TIFF::Orientation orientation)
  29. {
  30. switch (orientation) {
  31. case Orientation::Default:
  32. case Orientation::FlipHorizontally:
  33. case Orientation::Rotate180:
  34. case Orientation::FlipVertically:
  35. return size;
  36. case Orientation::Rotate90ClockwiseThenFlipHorizontally:
  37. case Orientation::Rotate90Clockwise:
  38. case Orientation::FlipHorizontallyThenRotate90Clockwise:
  39. case Orientation::Rotate90CounterClockwise:
  40. return { size.height(), size.width() };
  41. }
  42. VERIFY_NOT_REACHED();
  43. }
  44. private:
  45. using Orientation = TIFF::Orientation;
  46. ExifOrientedBitmap(NonnullRefPtr<Bitmap> bitmap, IntSize size, Orientation orientation)
  47. : m_bitmap(move(bitmap))
  48. , m_orientation(orientation)
  49. , m_width(size.width())
  50. , m_height(size.height())
  51. {
  52. }
  53. IntPoint oriented_position(IntPoint point)
  54. {
  55. auto const flip_horizontally = [this](IntPoint point) {
  56. return IntPoint(m_width - point.x() - 1, point.y());
  57. };
  58. auto const rotate_90_clockwise = [this](IntPoint point) {
  59. return IntPoint(m_height - point.y() - 1, point.x());
  60. };
  61. switch (m_orientation) {
  62. case Orientation::Default:
  63. return point;
  64. case Orientation::FlipHorizontally:
  65. return flip_horizontally(point);
  66. case Orientation::Rotate180:
  67. return IntPoint(m_width - point.x() - 1, m_height - point.y() - 1);
  68. case Orientation::FlipVertically:
  69. return IntPoint(point.x(), m_height - point.y() - 1);
  70. case Orientation::Rotate90ClockwiseThenFlipHorizontally:
  71. return flip_horizontally(rotate_90_clockwise(point));
  72. case Orientation::Rotate90Clockwise:
  73. return rotate_90_clockwise(point);
  74. case Orientation::FlipHorizontallyThenRotate90Clockwise:
  75. return rotate_90_clockwise(flip_horizontally(point));
  76. case Orientation::Rotate90CounterClockwise:
  77. return IntPoint(point.y(), m_width - point.x() - 1);
  78. }
  79. VERIFY_NOT_REACHED();
  80. }
  81. NonnullRefPtr<Bitmap> m_bitmap;
  82. Orientation m_orientation;
  83. u32 m_width {};
  84. u32 m_height {};
  85. };
  86. }