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 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 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 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 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