1 #include "EXGLImageUtils.h"
2 
3 #define STB_IMAGE_IMPLEMENTATION
4 #include "stb_image.h"
5 
6 namespace jsi = facebook::jsi;
7 
8 namespace expo {
9 namespace gl_cpp {
10 
bytesPerPixel(GLenum type,GLenum format)11 GLuint bytesPerPixel(GLenum type, GLenum format) {
12   int bytesPerComponent = 0;
13   switch (type) {
14     case GL_UNSIGNED_BYTE:
15       bytesPerComponent = 1;
16       break;
17     case GL_FLOAT:
18       bytesPerComponent = 4;
19       break;
20     case GL_HALF_FLOAT:
21       bytesPerComponent = 2;
22       break;
23     case GL_UNSIGNED_SHORT_5_6_5:
24     case GL_UNSIGNED_SHORT_4_4_4_4:
25     case GL_UNSIGNED_SHORT_5_5_5_1:
26       return 2;
27   }
28 
29   switch (format) {
30     case GL_LUMINANCE:
31     case GL_ALPHA:
32       return 1 * bytesPerComponent;
33     case GL_LUMINANCE_ALPHA:
34       return 2 * bytesPerComponent;
35     case GL_RGB:
36       return 3 * bytesPerComponent;
37     case GL_RGBA:
38       return 4 * bytesPerComponent;
39   }
40   return 0;
41 }
42 
flipPixels(GLubyte * pixels,size_t bytesPerRow,size_t rows)43 void flipPixels(GLubyte *pixels, size_t bytesPerRow, size_t rows) {
44   if (!pixels) {
45     return;
46   }
47 
48   GLuint middle = (GLuint)rows / 2;
49   GLuint intsPerRow = (GLuint)bytesPerRow / sizeof(GLuint);
50   GLuint remainingBytes = (GLuint)bytesPerRow - intsPerRow * sizeof(GLuint);
51 
52   for (GLuint rowTop = 0, rowBottom = (GLuint)rows - 1; rowTop < middle; ++rowTop, --rowBottom) {
53     // Swap in packs of sizeof(GLuint) bytes
54     GLuint *iTop = (GLuint *)(pixels + rowTop * bytesPerRow);
55     GLuint *iBottom = (GLuint *)(pixels + rowBottom * bytesPerRow);
56     GLuint iTmp;
57     GLuint n = intsPerRow;
58     do {
59       iTmp = *iTop;
60       *iTop++ = *iBottom;
61       *iBottom++ = iTmp;
62     } while (--n > 0);
63 
64     // Swap remainder bytes
65     GLubyte *bTop = (GLubyte *)iTop;
66     GLubyte *bBottom = (GLubyte *)iBottom;
67     GLubyte bTmp;
68     switch (remainingBytes) {
69       case 3:
70         bTmp = *bTop;
71         *bTop++ = *bBottom;
72         *bBottom++ = bTmp;
73       case 2:
74         bTmp = *bTop;
75         *bTop++ = *bBottom;
76         *bBottom++ = bTmp;
77       case 1:
78         bTmp = *bTop;
79         *bTop = *bBottom;
80         *bBottom = bTmp;
81     }
82   }
83 }
84 
decodeURI(char * dst,const char * src)85 void decodeURI(char *dst, const char *src) {
86   char a, b;
87   while (*src) {
88     if ((*src == '%') && ((a = src[1]) && (b = src[2])) && (isxdigit(a) && isxdigit(b))) {
89       if (a >= 'a') {
90         a -= 'a' - 'A';
91       }
92       if (a >= 'A') {
93         a -= ('A' - 10);
94       } else {
95         a -= '0';
96       }
97       if (b >= 'a') {
98         b -= 'a' - 'A';
99       }
100       if (b >= 'A') {
101         b -= ('A' - 10);
102       } else {
103         b -= '0';
104       }
105       *dst++ = 16 * a + b;
106       src += 3;
107     } else if (*src == '+') {
108       *dst++ = ' ';
109       src++;
110     } else {
111       *dst++ = *src++;
112     }
113   }
114   *dst++ = '\0';
115 }
116 
loadImage(jsi::Runtime & runtime,const jsi::Object & jsPixels,int * fileWidth,int * fileHeight,int * fileComp)117 std::shared_ptr<uint8_t> loadImage(
118     jsi::Runtime &runtime,
119     const jsi::Object &jsPixels,
120     int *fileWidth,
121     int *fileHeight,
122     int *fileComp) {
123   auto localUriProp = jsPixels.getProperty(runtime, "localUri");
124   if (localUriProp.isString()) {
125     auto localUri = localUriProp.asString(runtime).utf8(runtime);
126     if (strncmp(localUri.c_str(), "file://", 7) != 0) {
127       return std::shared_ptr<uint8_t>(nullptr);
128     }
129     char localPath[localUri.size()];
130     decodeURI(localPath, localUri.c_str() + 7);
131 
132     return std::shared_ptr<uint8_t>(
133         stbi_load(localPath, fileWidth, fileHeight, fileComp, STBI_rgb_alpha),
134         [](void *data) { stbi_image_free(data); });
135   }
136   return std::shared_ptr<uint8_t>(nullptr);
137 }
138 } // namespace gl_cpp
139 } // namespace expo
140