ExifOrientedBitmap.h 3.7 KB

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