scale.hpp 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. #pragma once
  2. namespace nall {
  3. inline auto image::scale(uint outputWidth, uint outputHeight, bool linear) -> void {
  4. if(!_data) return;
  5. if(_width == outputWidth && _height == outputHeight) return; //no scaling necessary
  6. if(linear == false) return scaleNearest(outputWidth, outputHeight);
  7. if(_width == outputWidth ) return scaleLinearHeight(outputHeight);
  8. if(_height == outputHeight) return scaleLinearWidth(outputWidth);
  9. //find fastest scaling method, based on number of interpolation operations required
  10. //magnification usually benefits from two-pass linear interpolation
  11. //minification usually benefits from one-pass bilinear interpolation
  12. uint d1wh = ((_width * outputWidth ) + (outputWidth * outputHeight)) * 1;
  13. uint d1hw = ((_height * outputHeight) + (outputWidth * outputHeight)) * 1;
  14. uint d2wh = (outputWidth * outputHeight) * 3;
  15. if(d1wh <= d1hw && d1wh <= d2wh) return scaleLinearWidth(outputWidth), scaleLinearHeight(outputHeight);
  16. if(d1hw <= d2wh) return scaleLinearHeight(outputHeight), scaleLinearWidth(outputWidth);
  17. return scaleLinear(outputWidth, outputHeight);
  18. }
  19. inline auto image::scaleLinearWidth(uint outputWidth) -> void {
  20. uint8_t* outputData = allocate(outputWidth, _height, stride());
  21. uint outputPitch = outputWidth * stride();
  22. uint64_t xstride = ((uint64_t)(_width - 1) << 32) / max(1u, outputWidth - 1);
  23. for(uint y = 0; y < _height; y++) {
  24. uint64_t xfraction = 0;
  25. const uint8_t* sp = _data + pitch() * y;
  26. uint8_t* dp = outputData + outputPitch * y;
  27. uint64_t a = read(sp);
  28. uint64_t b = read(sp + stride());
  29. sp += stride();
  30. uint x = 0;
  31. while(true) {
  32. while(xfraction < 0x100000000 && x++ < outputWidth) {
  33. write(dp, interpolate4i(a, b, xfraction));
  34. dp += stride();
  35. xfraction += xstride;
  36. }
  37. if(x >= outputWidth) break;
  38. sp += stride();
  39. a = b;
  40. b = read(sp);
  41. xfraction -= 0x100000000;
  42. }
  43. }
  44. free();
  45. _data = outputData;
  46. _width = outputWidth;
  47. }
  48. inline auto image::scaleLinearHeight(uint outputHeight) -> void {
  49. uint8_t* outputData = allocate(_width, outputHeight, stride());
  50. uint64_t ystride = ((uint64_t)(_height - 1) << 32) / max(1u, outputHeight - 1);
  51. for(uint x = 0; x < _width; x++) {
  52. uint64_t yfraction = 0;
  53. const uint8_t* sp = _data + stride() * x;
  54. uint8_t* dp = outputData + stride() * x;
  55. uint64_t a = read(sp);
  56. uint64_t b = read(sp + pitch());
  57. sp += pitch();
  58. uint y = 0;
  59. while(true) {
  60. while(yfraction < 0x100000000 && y++ < outputHeight) {
  61. write(dp, interpolate4i(a, b, yfraction));
  62. dp += pitch();
  63. yfraction += ystride;
  64. }
  65. if(y >= outputHeight) break;
  66. sp += pitch();
  67. a = b;
  68. b = read(sp);
  69. yfraction -= 0x100000000;
  70. }
  71. }
  72. free();
  73. _data = outputData;
  74. _height = outputHeight;
  75. }
  76. inline auto image::scaleLinear(uint outputWidth, uint outputHeight) -> void {
  77. uint8_t* outputData = allocate(outputWidth, outputHeight, stride());
  78. uint outputPitch = outputWidth * stride();
  79. uint64_t xstride = ((uint64_t)(_width - 1) << 32) / max(1u, outputWidth - 1);
  80. uint64_t ystride = ((uint64_t)(_height - 1) << 32) / max(1u, outputHeight - 1);
  81. for(uint y = 0; y < outputHeight; y++) {
  82. uint64_t yfraction = ystride * y;
  83. uint64_t xfraction = 0;
  84. const uint8_t* sp = _data + pitch() * (yfraction >> 32);
  85. uint8_t* dp = outputData + outputPitch * y;
  86. uint64_t a = read(sp);
  87. uint64_t b = read(sp + stride());
  88. uint64_t c = read(sp + pitch());
  89. uint64_t d = read(sp + pitch() + stride());
  90. sp += stride();
  91. uint x = 0;
  92. while(true) {
  93. while(xfraction < 0x100000000 && x++ < outputWidth) {
  94. write(dp, interpolate4i(a, b, c, d, xfraction, yfraction));
  95. dp += stride();
  96. xfraction += xstride;
  97. }
  98. if(x >= outputWidth) break;
  99. sp += stride();
  100. a = b;
  101. c = d;
  102. b = read(sp);
  103. d = read(sp + pitch());
  104. xfraction -= 0x100000000;
  105. }
  106. }
  107. free();
  108. _data = outputData;
  109. _width = outputWidth;
  110. _height = outputHeight;
  111. }
  112. inline auto image::scaleNearest(uint outputWidth, uint outputHeight) -> void {
  113. uint8_t* outputData = allocate(outputWidth, outputHeight, stride());
  114. uint outputPitch = outputWidth * stride();
  115. uint64_t xstride = ((uint64_t)_width << 32) / outputWidth;
  116. uint64_t ystride = ((uint64_t)_height << 32) / outputHeight;
  117. for(uint y = 0; y < outputHeight; y++) {
  118. uint64_t yfraction = ystride * y;
  119. uint64_t xfraction = 0;
  120. const uint8_t* sp = _data + pitch() * (yfraction >> 32);
  121. uint8_t* dp = outputData + outputPitch * y;
  122. uint64_t a = read(sp);
  123. uint x = 0;
  124. while(true) {
  125. while(xfraction < 0x100000000 && x++ < outputWidth) {
  126. write(dp, a);
  127. dp += stride();
  128. xfraction += xstride;
  129. }
  130. if(x >= outputWidth) break;
  131. sp += stride();
  132. a = read(sp);
  133. xfraction -= 0x100000000;
  134. }
  135. }
  136. free();
  137. _data = outputData;
  138. _width = outputWidth;
  139. _height = outputHeight;
  140. }
  141. }