Browse Source

recovery: minui: Implement image scaling

res_create_scaled_surface() is a bilinear interpolation implementation:
  https://rosettacode.org/wiki/Bilinear_interpolation

Change-Id: I1d9371048211af15ba1dcdfe72d906f90374c4f3
Tom Marshall 3 years ago
parent
commit
346257170a
2 changed files with 60 additions and 0 deletions
  1. 3
    0
      minui/include/minui/minui.h
  2. 57
    0
      minui/resources.cpp

+ 3
- 0
minui/include/minui/minui.h View File

@@ -142,6 +142,9 @@ int res_create_alpha_surface(const char* name, GRSurface** pSurface);
142 142
 int res_create_localized_alpha_surface(const char* name, const char* locale,
143 143
                                        GRSurface** pSurface);
144 144
 
145
+int res_create_scaled_surface(GRSurface** dst, GRSurface* src,
146
+                              float sx, float sy);
147
+
145 148
 // Return a list of locale strings embedded in |png_name|. Return a empty list in case of failure.
146 149
 std::vector<std::string> get_locales_in_png(const std::string& png_name);
147 150
 

+ 57
- 0
minui/resources.cpp View File

@@ -493,6 +493,63 @@ int res_create_localized_alpha_surface(const char* name,
493 493
   return 0;
494 494
 }
495 495
 
496
+static uint32_t getpixel(GRSurface* surface, int x, int y) {
497
+    uint32_t* pixels = (uint32_t*)surface->data;
498
+    return pixels[y * surface->width + x];
499
+}
500
+
501
+static void putpixel(GRSurface* surface, int x, int y, uint32_t color) {
502
+    uint32_t* pixels = (uint32_t*)surface->data;
503
+    pixels[y * surface->width + x] = color;
504
+}
505
+
506
+static float lerp(float s, float e, float t) {
507
+    return s + (e - s) * t;
508
+}
509
+
510
+static float blerp(float c00, float c10, float c01, float c11, float tx, float ty) {
511
+    return lerp(lerp(c00, c10, tx), lerp(c01, c11, tx), ty);
512
+}
513
+
514
+static uint8_t getbyte(uint32_t value, int n) {
515
+    return (value >> (n * 8)) & 0xff;
516
+}
517
+
518
+int res_create_scaled_surface(GRSurface** dst, GRSurface* src,
519
+                               float scalex, float scaley) {
520
+    int new_w = (int)src->width * scalex;
521
+    int new_h = (int)src->height * scaley;
522
+    GRSurface* scaled = init_display_surface(new_w, new_h);
523
+    if (scaled == NULL) {
524
+        return -8; // Same as res_create_display_surface()
525
+    }
526
+
527
+    int x, y;
528
+    for (y = 0; y < new_h; ++y) {
529
+        for (x = 0; x < new_w; ++x) {
530
+            float gx = x / (float)new_w * (src->width - 1);
531
+            float gy = y / (float)new_h * (src->height - 1);
532
+            int gxi = (int)gx;
533
+            int gyi = (int)gy;
534
+            uint32_t result = 0;
535
+            uint32_t c00 = getpixel(src, gxi, gyi);
536
+            uint32_t c10 = getpixel(src, gxi + 1, gyi);
537
+            uint32_t c01 = getpixel(src, gxi, gyi + 1);
538
+            uint32_t c11 = getpixel(src, gxi + 1, gyi + 1);
539
+            int i;
540
+            for (i = 0; i < 3; ++i) {
541
+                result |= (uint8_t)blerp(getbyte(c00, i), getbyte(c10, i),
542
+                                         getbyte(c01, i), getbyte(c11, i),
543
+                                         gx - gxi, gy - gyi) << (8*i);
544
+            }
545
+            putpixel(scaled, x, y, result);
546
+        }
547
+    }
548
+
549
+    *dst = scaled;
550
+    return 0;
551
+}
552
+
496 553
 void res_free_surface(GRSurface* surface) {
497 554
   free(surface);
498 555
 }