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