utility.hpp 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. #pragma once
  2. namespace nall {
  3. //scan all four sides of the image for fully transparent pixels, and then crop them
  4. //imagine an icon centered on a transparent background: this function removes the bordering
  5. //this certainly won't win any speed awards, but nall::image is meant to be correct and simple, not fast
  6. inline auto image::shrink(uint64_t transparentColor) -> void {
  7. //top
  8. { uint padding = 0;
  9. for(uint y : range(_height)) {
  10. const uint8_t* sp = _data + pitch() * y;
  11. bool found = false;
  12. for(uint x : range(_width)) {
  13. if(read(sp) != transparentColor) { found = true; break; }
  14. sp += stride();
  15. }
  16. if(found) break;
  17. padding++;
  18. }
  19. crop(0, padding, _width, _height - padding);
  20. }
  21. //bottom
  22. { uint padding = 0;
  23. for(uint y : reverse(range(_height))) {
  24. const uint8_t* sp = _data + pitch() * y;
  25. bool found = false;
  26. for(uint x : range(_width)) {
  27. if(read(sp) != transparentColor) { found = true; break; }
  28. sp += stride();
  29. }
  30. if(found) break;
  31. padding++;
  32. }
  33. crop(0, 0, _width, _height - padding);
  34. }
  35. //left
  36. { uint padding = 0;
  37. for(uint x : range(_width)) {
  38. const uint8_t* sp = _data + stride() * x;
  39. bool found = false;
  40. for(uint y : range(_height)) {
  41. if(read(sp) != transparentColor) { found = true; break; }
  42. sp += pitch();
  43. }
  44. if(found) break;
  45. padding++;
  46. }
  47. crop(padding, 0, _width - padding, _height);
  48. }
  49. //right
  50. { uint padding = 0;
  51. for(uint x : reverse(range(_width))) {
  52. const uint8_t* sp = _data + stride() * x;
  53. bool found = false;
  54. for(uint y : range(_height)) {
  55. if(read(sp) != transparentColor) { found = true; break; }
  56. sp += pitch();
  57. }
  58. if(found) break;
  59. padding++;
  60. }
  61. crop(0, 0, _width - padding, _height);
  62. }
  63. }
  64. inline auto image::crop(uint outputX, uint outputY, uint outputWidth, uint outputHeight) -> bool {
  65. if(outputX + outputWidth > _width) return false;
  66. if(outputY + outputHeight > _height) return false;
  67. uint8_t* outputData = allocate(outputWidth, outputHeight, stride());
  68. uint outputPitch = outputWidth * stride();
  69. for(uint y = 0; y < outputHeight; y++) {
  70. const uint8_t* sp = _data + pitch() * (outputY + y) + stride() * outputX;
  71. uint8_t* dp = outputData + outputPitch * y;
  72. for(uint x = 0; x < outputWidth; x++) {
  73. write(dp, read(sp));
  74. sp += stride();
  75. dp += stride();
  76. }
  77. }
  78. delete[] _data;
  79. _data = outputData;
  80. _width = outputWidth;
  81. _height = outputHeight;
  82. return true;
  83. }
  84. inline auto image::alphaBlend(uint64_t alphaColor) -> void {
  85. uint64_t alphaR = (alphaColor & _red.mask() ) >> _red.shift();
  86. uint64_t alphaG = (alphaColor & _green.mask()) >> _green.shift();
  87. uint64_t alphaB = (alphaColor & _blue.mask() ) >> _blue.shift();
  88. for(uint y = 0; y < _height; y++) {
  89. uint8_t* dp = _data + pitch() * y;
  90. for(uint x = 0; x < _width; x++) {
  91. uint64_t color = read(dp);
  92. uint64_t colorA = (color & _alpha.mask()) >> _alpha.shift();
  93. uint64_t colorR = (color & _red.mask() ) >> _red.shift();
  94. uint64_t colorG = (color & _green.mask()) >> _green.shift();
  95. uint64_t colorB = (color & _blue.mask() ) >> _blue.shift();
  96. double alphaScale = (double)colorA / (double)((1 << _alpha.depth()) - 1);
  97. colorA = (1 << _alpha.depth()) - 1;
  98. colorR = (colorR * alphaScale) + (alphaR * (1.0 - alphaScale));
  99. colorG = (colorG * alphaScale) + (alphaG * (1.0 - alphaScale));
  100. colorB = (colorB * alphaScale) + (alphaB * (1.0 - alphaScale));
  101. write(dp, (colorA << _alpha.shift()) | (colorR << _red.shift()) | (colorG << _green.shift()) | (colorB << _blue.shift()));
  102. dp += stride();
  103. }
  104. }
  105. }
  106. inline auto image::alphaMultiply() -> void {
  107. uint divisor = (1 << _alpha.depth()) - 1;
  108. for(uint y = 0; y < _height; y++) {
  109. uint8_t* dp = _data + pitch() * y;
  110. for(uint x = 0; x < _width; x++) {
  111. uint64_t color = read(dp);
  112. uint64_t colorA = (color & _alpha.mask()) >> _alpha.shift();
  113. uint64_t colorR = (color & _red.mask() ) >> _red.shift();
  114. uint64_t colorG = (color & _green.mask()) >> _green.shift();
  115. uint64_t colorB = (color & _blue.mask() ) >> _blue.shift();
  116. colorR = (colorR * colorA) / divisor;
  117. colorG = (colorG * colorA) / divisor;
  118. colorB = (colorB * colorA) / divisor;
  119. write(dp, (colorA << _alpha.shift()) | (colorR << _red.shift()) | (colorG << _green.shift()) | (colorB << _blue.shift()));
  120. dp += stride();
  121. }
  122. }
  123. }
  124. inline auto image::transform(const image& source) -> void {
  125. return transform(source._endian, source._depth, source._alpha.mask(), source._red.mask(), source._green.mask(), source._blue.mask());
  126. }
  127. inline auto image::transform(bool outputEndian, uint outputDepth, uint64_t outputAlphaMask, uint64_t outputRedMask, uint64_t outputGreenMask, uint64_t outputBlueMask) -> void {
  128. if(_endian == outputEndian && _depth == outputDepth && _alpha.mask() == outputAlphaMask && _red.mask() == outputRedMask && _green.mask() == outputGreenMask && _blue.mask() == outputBlueMask) return;
  129. image output(outputEndian, outputDepth, outputAlphaMask, outputRedMask, outputGreenMask, outputBlueMask);
  130. output.allocate(_width, _height);
  131. for(uint y = 0; y < _height; y++) {
  132. const uint8_t* sp = _data + pitch() * y;
  133. uint8_t* dp = output._data + output.pitch() * y;
  134. for(uint x = 0; x < _width; x++) {
  135. uint64_t color = read(sp);
  136. sp += stride();
  137. uint64_t a = (color & _alpha.mask()) >> _alpha.shift();
  138. uint64_t r = (color & _red.mask() ) >> _red.shift();
  139. uint64_t g = (color & _green.mask()) >> _green.shift();
  140. uint64_t b = (color & _blue.mask() ) >> _blue.shift();
  141. a = normalize(a, _alpha.depth(), output._alpha.depth());
  142. r = normalize(r, _red.depth(), output._red.depth());
  143. g = normalize(g, _green.depth(), output._green.depth());
  144. b = normalize(b, _blue.depth(), output._blue.depth());
  145. output.write(dp, (a << output._alpha.shift()) | (r << output._red.shift()) | (g << output._green.shift()) | (b << output._blue.shift()));
  146. dp += output.stride();
  147. }
  148. }
  149. operator=(move(output));
  150. }
  151. }