diff --git a/.rive_head b/.rive_head index 7e901c4a..25dc1c1e 100644 --- a/.rive_head +++ b/.rive_head @@ -1 +1 @@ -93cc33b45086e528b22d1245a8f7855bac299a21 +ccfcbffdf6dec763774aa8b65d8ce712585218db diff --git a/Source/Renderer/PlatformCGImage.mm b/Source/Renderer/PlatformCGImage.mm index 50e6a2ee..fe4e3d92 100644 --- a/Source/Renderer/PlatformCGImage.mm +++ b/Source/Renderer/PlatformCGImage.mm @@ -49,17 +49,39 @@ bool PlatformCGImageDecode(const uint8_t* encodedBytes, break; } - CFDataRef dataRef = CGDataProviderCopyData(CGImageGetDataProvider(image)); - const UInt8* pixelData = CFDataGetBytePtr(dataRef); const size_t width = CGImageGetWidth(image); const size_t height = CGImageGetHeight(image); const size_t rowBytes = width * 4; // 4 bytes per pixel const size_t size = rowBytes * height; + const size_t bitsPerComponent = 8; + CGBitmapInfo cgInfo = kCGBitmapByteOrder32Big; // rgba + if (isOpaque) + { + cgInfo |= kCGImageAlphaNoneSkipLast; + } + else + { + cgInfo |= kCGImageAlphaPremultipliedLast; + } + + std::vector pixels; + pixels.resize(size); + + AutoCF cs = CGColorSpaceCreateDeviceRGB(); + AutoCF cg = + CGBitmapContextCreate(pixels.data(), width, height, bitsPerComponent, rowBytes, cs, cgInfo); + if (!cg) + { + return false; + } + + CGContextSetBlendMode(cg, kCGBlendModeCopy); + CGContextDrawImage(cg, CGRectMake(0, 0, width, height), image); + platformImage->width = rive::castTo(width); platformImage->height = rive::castTo(height); platformImage->opaque = isOpaque; - platformImage->pixels = std::vector(pixelData, pixelData + size); - CFRelease(dataRef); + platformImage->pixels = std::move(pixels); return true; } diff --git a/Source/Renderer/RenderContextManager.mm b/Source/Renderer/RenderContextManager.mm index 7ae5dfec..dac8b17f 100644 --- a/Source/Renderer/RenderContextManager.mm +++ b/Source/Renderer/RenderContextManager.mm @@ -70,6 +70,21 @@ @implementation RiveRendererContext { return nullptr; } + + // CG only supports premultiplied alpha. Unmultiply now. + size_t imageSizeInBytes = image.height * image.width * 4; + for (size_t i = 0; i < imageSizeInBytes; i += 4) + { + auto alpha = image.pixels[i + 3]; + if (alpha != 0.0f) + { + auto alphaFactor = 255.0f / alpha; + for (size_t j = 0; j < 3; j++) + { + image.pixels[i + j] *= alphaFactor; + } + } + } uint32_t mipLevelCount = rive::math::msb(image.height | image.width); return makeImageTexture(image.width, image.height, mipLevelCount, image.pixels.data()); }