From 67d2f79ab684a21e940de611aacb20de11ea1064 Mon Sep 17 00:00:00 2001 From: rh101 Date: Thu, 30 May 2019 18:59:47 +1000 Subject: [PATCH 1/3] Added RenderTexture::saveToFileAsNonPMA() to save images without PMA. Set the PMA parameter to true when calling initWithRawData() inside RenderTexture::newImage(), since textures are PMA. Renamed Image::premultipliedAlpha() to Image::premultiplyAlpha() to better reflect it's action, and made it public. Added Image::reversePremultipliedAlpha() to allow the reversing of the PMA. Updated CCImage-ios.mm to set the correct bitmapInfo for PMA and non-PMA images before saving a file. Updated RenderTextureTest::RenderTextureSave() to cater for non-PMA file saving. --- cocos/2d/CCRenderTexture.cpp | 50 ++++++++++++-- cocos/2d/CCRenderTexture.h | 27 +++++++- cocos/platform/CCImage.cpp | 27 +++++++- cocos/platform/CCImage.h | 4 +- cocos/platform/ios/CCImage-ios.mm | 9 ++- .../RenderTextureTest/RenderTextureTest.cpp | 65 ++++++++++++++++--- .../RenderTextureTest/RenderTextureTest.h | 6 +- 7 files changed, 168 insertions(+), 20 deletions(-) diff --git a/cocos/2d/CCRenderTexture.cpp b/cocos/2d/CCRenderTexture.cpp index fb63b9cac6cd..3b2b54a5d153 100644 --- a/cocos/2d/CCRenderTexture.cpp +++ b/cocos/2d/CCRenderTexture.cpp @@ -506,6 +506,28 @@ void RenderTexture::visit(Renderer *renderer, const Mat4 &parentTransform, uint3 // setOrderOfArrival(0); } +bool RenderTexture::saveToFileAsNonPMA(const std::string& filename, bool isRGBA, std::function callback) +{ + std::string basename(filename); + std::transform(basename.begin(), basename.end(), basename.begin(), ::tolower); + + if (basename.find(".png") != std::string::npos) + { + return saveToFileAsNonPMA(filename, Image::Format::PNG, isRGBA, callback); + } + else if (basename.find(".jpg") != std::string::npos) + { + if (isRGBA) CCLOG("RGBA is not supported for JPG format."); + return saveToFileAsNonPMA(filename, Image::Format::JPG, false, callback); + } + else + { + CCLOG("Only PNG and JPG format are supported now!"); + } + + return saveToFileAsNonPMA(filename, Image::Format::JPG, false, callback); +} + bool RenderTexture::saveToFile(const std::string& filename, bool isRGBA, std::function callback) { std::string basename(filename); @@ -528,6 +550,22 @@ bool RenderTexture::saveToFile(const std::string& filename, bool isRGBA, std::fu return saveToFile(filename, Image::Format::JPG, false, callback); } +bool RenderTexture::saveToFileAsNonPMA(const std::string& fileName, Image::Format format, bool isRGBA, std::function callback) +{ + CCASSERT(format == Image::Format::JPG || format == Image::Format::PNG, + "the image can only be saved as JPG or PNG format"); + if (isRGBA && format == Image::Format::JPG) CCLOG("RGBA is not supported for JPG format"); + + _saveFileCallback = callback; + + std::string fullpath = FileUtils::getInstance()->getWritablePath() + fileName; + _saveToFileCommand.init(_globalZOrder); + _saveToFileCommand.func = CC_CALLBACK_0(RenderTexture::onSaveToFile, this, fullpath, isRGBA, true); + + Director::getInstance()->getRenderer()->addCommand(&_saveToFileCommand); + return true; +} + bool RenderTexture::saveToFile(const std::string& fileName, Image::Format format, bool isRGBA, std::function callback) { CCASSERT(format == Image::Format::JPG || format == Image::Format::PNG, @@ -538,17 +576,21 @@ bool RenderTexture::saveToFile(const std::string& fileName, Image::Format format std::string fullpath = FileUtils::getInstance()->getWritablePath() + fileName; _saveToFileCommand.init(_globalZOrder); - _saveToFileCommand.func = CC_CALLBACK_0(RenderTexture::onSaveToFile, this, fullpath, isRGBA); + _saveToFileCommand.func = CC_CALLBACK_0(RenderTexture::onSaveToFile, this, fullpath, isRGBA, false); Director::getInstance()->getRenderer()->addCommand(&_saveToFileCommand); return true; } -void RenderTexture::onSaveToFile(const std::string& filename, bool isRGBA) +void RenderTexture::onSaveToFile(const std::string& filename, bool isRGBA, bool forceNonPMA) { Image *image = newImage(true); if (image) { + if (forceNonPMA && image->hasPremultipliedAlpha()) + { + image->reversePremultipliedAlpha(); + } image->saveToFile(filename, !isRGBA); } if(_saveFileCallback) @@ -620,11 +662,11 @@ Image* RenderTexture::newImage(bool flipImage) savedBufferWidth * 4); } - image->initWithRawData(buffer, savedBufferWidth * savedBufferHeight * 4, savedBufferWidth, savedBufferHeight, 8); + image->initWithRawData(buffer, savedBufferWidth * savedBufferHeight * 4, savedBufferWidth, savedBufferHeight, 8, true); } else { - image->initWithRawData(tempData, savedBufferWidth * savedBufferHeight * 4, savedBufferWidth, savedBufferHeight, 8); + image->initWithRawData(tempData, savedBufferWidth * savedBufferHeight * 4, savedBufferWidth, savedBufferHeight, 8, true); } } while (0); diff --git a/cocos/2d/CCRenderTexture.h b/cocos/2d/CCRenderTexture.h index 03a27ab334e4..771645501375 100644 --- a/cocos/2d/CCRenderTexture.h +++ b/cocos/2d/CCRenderTexture.h @@ -151,6 +151,17 @@ class CC_DLL RenderTexture : public Node CC_DEPRECATED_ATTRIBUTE Image* newCCImage(bool flipImage = true) { return newImage(flipImage); }; + /** Saves the texture into a file using JPEG format. The file will be saved in the Documents folder. + * Returns true if the operation is successful. + * + * @param filename The file name. + * @param isRGBA The file is RGBA or not. + * @param callback When the file is save finished,it will callback this function. + * @return Returns true if the operation is successful. + */ + bool saveToFileAsNonPMA(const std::string& filename, bool isRGBA = true, std::function callback = nullptr); + + /** Saves the texture into a file using JPEG format. The file will be saved in the Documents folder. * Returns true if the operation is successful. * @@ -161,6 +172,20 @@ class CC_DLL RenderTexture : public Node */ bool saveToFile(const std::string& filename, bool isRGBA = true, std::function callback = nullptr); + /** saves the texture into a file in non-PMA. The format could be JPG or PNG. The file will be saved in the Documents folder. + Returns true if the operation is successful. + * Notes: since v3.x, saveToFile will generate a custom command, which will be called in the following render->render(). + * So if this function is called in a event handler, the actual save file will be called in the next frame. If we switch to a different scene, the game will crash. + * To solve this, add Director::getInstance()->getRenderer()->render(); after this function. + * + * @param filename The file name. + * @param format The image format. + * @param isRGBA The file is RGBA or not. + * @param callback When the file is save finished,it will callback this function. + * @return Returns true if the operation is successful. + */ + bool saveToFileAsNonPMA(const std::string& fileName, Image::Format format, bool isRGBA, std::function callback); + /** saves the texture into a file. The format could be JPG or PNG. The file will be saved in the Documents folder. Returns true if the operation is successful. * Notes: since v3.x, saveToFile will generate a custom command, which will be called in the following render->render(). @@ -363,7 +388,7 @@ class CC_DLL RenderTexture : public Node void onClear(); void onClearDepth(); - void onSaveToFile(const std::string& fileName, bool isRGBA = true); + void onSaveToFile(const std::string& fileName, bool isRGBA = true, bool forceNonPMA = false); void setupDepthAndStencil(int powW, int powH); diff --git a/cocos/platform/CCImage.cpp b/cocos/platform/CCImage.cpp index 1ffb8e743462..eb01683400c0 100644 --- a/cocos/platform/CCImage.cpp +++ b/cocos/platform/CCImage.cpp @@ -1149,7 +1149,7 @@ bool Image::initWithPngData(const unsigned char * data, ssize_t dataLen) { if (PNG_PREMULTIPLIED_ALPHA_ENABLED) { - premultipliedAlpha(); + premultiplyAlpha(); } else { @@ -2454,7 +2454,7 @@ bool Image::saveImageToJPG(const std::string& filePath) #endif // CC_USE_JPEG } -void Image::premultipliedAlpha() +void Image::premultiplyAlpha() { #if CC_ENABLE_PREMULTIPLIED_ALPHA == 0 _hasPremultipliedAlpha = false; @@ -2473,6 +2473,29 @@ void Image::premultipliedAlpha() #endif } +static inline unsigned char clamp(int x) { + return (unsigned char)(x >= 0 ? (x < 255 ? x : 255) : 0); +} + +void Image::reversePremultipliedAlpha() +{ + CCASSERT(_renderFormat == Texture2D::PixelFormat::RGBA8888, "The pixel format should be RGBA8888!"); + + unsigned int* fourBytes = (unsigned int*)_data; + for (int i = 0; i < _width * _height; i++) + { + unsigned char* p = _data + i * 4; + if (p[3] > 0) + { + fourBytes[i] = clamp(int(std::ceil((p[0] * 255.0f) / p[3]))) | + clamp(int(std::ceil((p[1] * 255.0f) / p[3]))) << 8 | + clamp(int(std::ceil((p[2] * 255.0f) / p[3]))) << 16 | + p[3] << 24; + } + } + + _hasPremultipliedAlpha = false; +} void Image::setPVRImagesHavePremultipliedAlpha(bool haveAlphaPremultiplied) { diff --git a/cocos/platform/CCImage.h b/cocos/platform/CCImage.h index 6a7cebf20a53..a864944905fb 100644 --- a/cocos/platform/CCImage.h +++ b/cocos/platform/CCImage.h @@ -160,6 +160,8 @@ class CC_DLL Image : public Ref @param isToRGB whether the image is saved as RGB format. */ bool saveToFile(const std::string &filename, bool isToRGB = true); + void premultiplyAlpha(); + void reversePremultipliedAlpha(); protected: #if CC_USE_WIC @@ -182,8 +184,6 @@ class CC_DLL Image : public Ref bool saveImageToPNG(const std::string& filePath, bool isToRGB = true); bool saveImageToJPG(const std::string& filePath); - void premultipliedAlpha(); - protected: /** @brief Determine how many mipmaps can we have. diff --git a/cocos/platform/ios/CCImage-ios.mm b/cocos/platform/ios/CCImage-ios.mm index baad43f45aea..da0f1f7548fe 100644 --- a/cocos/platform/ios/CCImage-ios.mm +++ b/cocos/platform/ios/CCImage-ios.mm @@ -91,7 +91,14 @@ of this software and associated documentation files (the "Software"), to deal CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault; if (saveToPNG && hasAlpha() && (! isToRGB)) { - bitmapInfo |= kCGImageAlphaPremultipliedLast; + if (_hasPremultipliedAlpha) + { + bitmapInfo |= kCGImageAlphaPremultipliedLast; + } + else + { + bitmapInfo |= kCGImageAlphaLast; + } } CGDataProviderRef provider = CGDataProviderCreateWithData(nullptr, pixels, myDataLength, nullptr); CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB(); diff --git a/tests/cpp-tests/Classes/RenderTextureTest/RenderTextureTest.cpp b/tests/cpp-tests/Classes/RenderTextureTest/RenderTextureTest.cpp index da772b0dfd55..d2775645c2e4 100644 --- a/tests/cpp-tests/Classes/RenderTextureTest/RenderTextureTest.cpp +++ b/tests/cpp-tests/Classes/RenderTextureTest/RenderTextureTest.cpp @@ -62,12 +62,15 @@ RenderTextureSave::RenderTextureSave() // Save Image menu MenuItemFont::setFontSize(16); - auto item1 = MenuItemFont::create("Save Image", CC_CALLBACK_1(RenderTextureSave::saveImage, this)); - auto item2 = MenuItemFont::create("Clear", CC_CALLBACK_1(RenderTextureSave::clearImage, this)); - auto menu = Menu::create(item1, item2, nullptr); + auto item1 = MenuItemFont::create("Save Image PMA", CC_CALLBACK_1(RenderTextureSave::saveImageWithPremultipliedAlpha, this)); + auto item2 = MenuItemFont::create("Save Image Non-PMA", CC_CALLBACK_1(RenderTextureSave::saveImageWithNonPremultipliedAlpha, this)); + auto item3 = MenuItemFont::create("Add Image", CC_CALLBACK_1(RenderTextureSave::addImage, this)); + auto item4 = MenuItemFont::create("Clear to Random", CC_CALLBACK_1(RenderTextureSave::clearImage, this)); + auto item5 = MenuItemFont::create("Clear to Transparent", CC_CALLBACK_1(RenderTextureSave::clearImageTransparent, this)); + auto menu = Menu::create(item1, item2, item3, item4, item5, nullptr); this->addChild(menu); menu->alignItemsVertically(); - menu->setPosition(Vec2(VisibleRect::rightTop().x - 80, VisibleRect::rightTop().y - 30)); + menu->setPosition(Vec2(VisibleRect::rightTop().x - 80, VisibleRect::rightTop().y - 100)); } std::string RenderTextureSave::title() const @@ -80,17 +83,46 @@ std::string RenderTextureSave::subtitle() const return "Press 'Save Image' to create an snapshot of the render texture"; } -void RenderTextureSave::clearImage(cocos2d::Ref *sender) +void RenderTextureSave::clearImage(cocos2d::Ref* sender) { _target->clear(CCRANDOM_0_1(), CCRANDOM_0_1(), CCRANDOM_0_1(), CCRANDOM_0_1()); } -void RenderTextureSave::saveImage(cocos2d::Ref *sender) +void RenderTextureSave::clearImageTransparent(cocos2d::Ref* sender) +{ + _target->clear(0, 0, 0, 0); +} + +void RenderTextureSave::saveImageWithPremultipliedAlpha(cocos2d::Ref* sender) +{ + static int counter = 0; + + char png[20]; + sprintf(png, "image-pma-%d.png", counter); + + auto callback = [&](RenderTexture* rt, const std::string& path) + { + auto sprite = Sprite::create(path); + addChild(sprite); + sprite->setScale(0.3f); + sprite->setPosition(Vec2(40, 40)); + sprite->setRotation(counter * 3); + }; + + _target->saveToFile(png, Image::Format::PNG, true, callback); + //Add this function to avoid crash if we switch to a new scene. + Director::getInstance()->getRenderer()->render(); + CCLOG("Image saved %s", png); + + counter++; +} + +void RenderTextureSave::saveImageWithNonPremultipliedAlpha(cocos2d::Ref *sender) { static int counter = 0; char png[20]; - sprintf(png, "image-%d.png", counter); + sprintf(png, "image-no-pma-%d.png", counter); auto callback = [&](RenderTexture* rt, const std::string& path) { @@ -101,7 +133,7 @@ void RenderTextureSave::saveImage(cocos2d::Ref *sender) sprite->setRotation(counter * 3); }; - _target->saveToFile(png, Image::Format::PNG, true, callback); + _target->saveToFileAsNonPMA(png, Image::Format::PNG, true, callback); //Add this function to avoid crash if we switch to a new scene. Director::getInstance()->getRenderer()->render(); CCLOG("Image saved %s", png); @@ -109,6 +141,21 @@ void RenderTextureSave::saveImage(cocos2d::Ref *sender) counter++; } +void RenderTextureSave::addImage(cocos2d::Ref* sender) +{ + auto s = Director::getInstance()->getWinSize(); + + // begin drawing to the render texture + _target->begin(); + + Sprite* sprite = Sprite::create("Images/test-rgba1.png"); + sprite->setPosition(sprite->getContentSize().width + CCRANDOM_0_1() * (s.width - sprite->getContentSize().width), sprite->getContentSize().height + CCRANDOM_0_1() * (s.height - sprite->getContentSize().height)); + sprite->visit(); + + // finish drawing and return context back to the screen + _target->end(); +} + RenderTextureSave::~RenderTextureSave() { _target->release(); @@ -849,4 +896,4 @@ std::string RenderTextureWithSprite3DIssue16894::title() const std::string RenderTextureWithSprite3DIssue16894::subtitle() const { return "3 ships, 1st & 3rd are the same"; -} +} \ No newline at end of file diff --git a/tests/cpp-tests/Classes/RenderTextureTest/RenderTextureTest.h b/tests/cpp-tests/Classes/RenderTextureTest/RenderTextureTest.h index 8d0940037b76..591e5ff8ff9c 100644 --- a/tests/cpp-tests/Classes/RenderTextureTest/RenderTextureTest.h +++ b/tests/cpp-tests/Classes/RenderTextureTest/RenderTextureTest.h @@ -44,7 +44,11 @@ class RenderTextureSave : public RenderTextureTest virtual std::string subtitle() const override; void onTouchesMoved(const std::vector& touches, cocos2d::Event* event); void clearImage(cocos2d::Ref* pSender); - void saveImage(cocos2d::Ref* pSender); + void clearImageTransparent(cocos2d::Ref* sender); + void saveImageWithPremultipliedAlpha(cocos2d::Ref* pSender); + void saveImageWithNonPremultipliedAlpha(cocos2d::Ref* pSender); + + void addImage(cocos2d::Ref* sender); private: cocos2d::RenderTexture* _target; From b5bdada7e2be3a87ba950c2c29756c06f0117ba3 Mon Sep 17 00:00:00 2001 From: rh101 Date: Tue, 4 Jun 2019 16:02:39 +1000 Subject: [PATCH 2/3] [CCImage-ios.mm] Fixed indentation. --- cocos/platform/ios/CCImage-ios.mm | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/cocos/platform/ios/CCImage-ios.mm b/cocos/platform/ios/CCImage-ios.mm index da0f1f7548fe..ac6b04ed3f0b 100644 --- a/cocos/platform/ios/CCImage-ios.mm +++ b/cocos/platform/ios/CCImage-ios.mm @@ -91,14 +91,14 @@ of this software and associated documentation files (the "Software"), to deal CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault; if (saveToPNG && hasAlpha() && (! isToRGB)) { - if (_hasPremultipliedAlpha) - { - bitmapInfo |= kCGImageAlphaPremultipliedLast; - } - else - { - bitmapInfo |= kCGImageAlphaLast; - } + if (_hasPremultipliedAlpha) + { + bitmapInfo |= kCGImageAlphaPremultipliedLast; + } + else + { + bitmapInfo |= kCGImageAlphaLast; + } } CGDataProviderRef provider = CGDataProviderCreateWithData(nullptr, pixels, myDataLength, nullptr); CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB(); From 7858425b92e7b1a95996d02800c65a2a933240b0 Mon Sep 17 00:00:00 2001 From: rh101 Date: Fri, 20 Sep 2019 18:03:55 +1000 Subject: [PATCH 3/3] Corrects the PMA setting on the internal Texture2D instance created by RenderTexture. --- cocos/2d/CCRenderTexture.cpp | 14 +++++++++----- cocos/renderer/CCTexture2D.cpp | 29 +++++++---------------------- cocos/renderer/CCTexture2D.h | 6 ++++-- 3 files changed, 20 insertions(+), 29 deletions(-) diff --git a/cocos/2d/CCRenderTexture.cpp b/cocos/2d/CCRenderTexture.cpp index fc6ff53f44a8..3cf845e6997b 100644 --- a/cocos/2d/CCRenderTexture.cpp +++ b/cocos/2d/CCRenderTexture.cpp @@ -253,7 +253,7 @@ bool RenderTexture::initWithWidthAndHeight(int w, int h, Texture2D::PixelFormat _texture = new (std::nothrow) Texture2D(); if (_texture) { - _texture->initWithData(data, dataLen, (Texture2D::PixelFormat)_pixelFormat, powW, powH, Size((float)w, (float)h)); + _texture->initWithData(data, dataLen, (Texture2D::PixelFormat)_pixelFormat, powW, powH, Size((float)w, (float)h), CC_ENABLE_PREMULTIPLIED_ALPHA != 0); } else { @@ -267,7 +267,7 @@ bool RenderTexture::initWithWidthAndHeight(int w, int h, Texture2D::PixelFormat _textureCopy = new (std::nothrow) Texture2D(); if (_textureCopy) { - _textureCopy->initWithData(data, dataLen, (Texture2D::PixelFormat)_pixelFormat, powW, powH, Size((float)w, (float)h)); + _textureCopy->initWithData(data, dataLen, (Texture2D::PixelFormat)_pixelFormat, powW, powH, Size((float)w, (float)h), CC_ENABLE_PREMULTIPLIED_ALPHA != 0); } else { @@ -303,7 +303,11 @@ bool RenderTexture::initWithWidthAndHeight(int w, int h, Texture2D::PixelFormat _texture->release(); _sprite->setFlippedY(true); - _sprite->setBlendFunc( BlendFunc::ALPHA_PREMULTIPLIED ); +#if CC_ENABLE_PREMULTIPLIED_ALPHA != 0 + _sprite->setBlendFunc(BlendFunc::ALPHA_PREMULTIPLIED); +#else + _sprite->setBlendFunc(BlendFunc::ALPHA_NON_PREMULTIPLIED); +#endif _sprite->setOpacityModifyRGB(true); glBindRenderbuffer(GL_RENDERBUFFER, oldRBO); @@ -664,11 +668,11 @@ Image* RenderTexture::newImage(bool flipImage) savedBufferWidth * 4); } - image->initWithRawData(buffer, savedBufferWidth * savedBufferHeight * 4, savedBufferWidth, savedBufferHeight, 8, true); + image->initWithRawData(buffer, savedBufferWidth * savedBufferHeight * 4, savedBufferWidth, savedBufferHeight, 8, _texture->hasPremultipliedAlpha()); } else { - image->initWithRawData(tempData, savedBufferWidth * savedBufferHeight * 4, savedBufferWidth, savedBufferHeight, 8, true); + image->initWithRawData(tempData, savedBufferWidth * savedBufferHeight * 4, savedBufferWidth, savedBufferHeight, 8, _texture->hasPremultipliedAlpha()); } } while (0); diff --git a/cocos/renderer/CCTexture2D.cpp b/cocos/renderer/CCTexture2D.cpp index 218c85ebd8ff..22fb891c4c0a 100644 --- a/cocos/renderer/CCTexture2D.cpp +++ b/cocos/renderer/CCTexture2D.cpp @@ -554,7 +554,7 @@ bool Texture2D::hasPremultipliedAlpha() const return _hasPremultipliedAlpha; } -bool Texture2D::initWithData(const void *data, ssize_t dataLen, Texture2D::PixelFormat pixelFormat, int pixelsWide, int pixelsHigh, const Size& /*contentSize*/) +bool Texture2D::initWithData(const void *data, ssize_t dataLen, Texture2D::PixelFormat pixelFormat, int pixelsWide, int pixelsHigh, const Size& /*contentSize*/, bool preMultipliedAlpha) { CCASSERT(dataLen>0 && pixelsWide>0 && pixelsHigh>0, "Invalid size"); @@ -562,13 +562,11 @@ bool Texture2D::initWithData(const void *data, ssize_t dataLen, Texture2D::Pixel MipmapInfo mipmap; mipmap.address = (unsigned char*)data; mipmap.len = static_cast(dataLen); - return initWithMipmaps(&mipmap, 1, pixelFormat, pixelsWide, pixelsHigh); + return initWithMipmaps(&mipmap, 1, pixelFormat, pixelsWide, pixelsHigh, preMultipliedAlpha); } -bool Texture2D::initWithMipmaps(MipmapInfo* mipmaps, int mipmapsNum, PixelFormat pixelFormat, int pixelsWide, int pixelsHigh) +bool Texture2D::initWithMipmaps(MipmapInfo* mipmaps, int mipmapsNum, PixelFormat pixelFormat, int pixelsWide, int pixelsHigh, bool preMultipliedAlpha) { - - //the pixelFormat must be a certain value CCASSERT(pixelFormat != PixelFormat::NONE && pixelFormat != PixelFormat::AUTO, "the \"pixelFormat\" param must be a certain value!"); CCASSERT(pixelsWide>0 && pixelsHigh>0, "Invalid size"); @@ -579,7 +577,6 @@ bool Texture2D::initWithMipmaps(MipmapInfo* mipmaps, int mipmapsNum, PixelFormat return false; } - auto formatItr = _pixelFormatInfoTables.find(pixelFormat); if(formatItr == _pixelFormatInfoTables.end()) { @@ -706,7 +703,7 @@ bool Texture2D::initWithMipmaps(MipmapInfo* mipmaps, int mipmapsNum, PixelFormat _maxS = 1; _maxT = 1; - _hasPremultipliedAlpha = false; + _hasPremultipliedAlpha = preMultipliedAlpha; _hasMipmaps = mipmapsNum > 1; // shader @@ -764,7 +761,6 @@ bool Texture2D::initWithImage(Image *image, PixelFormat format) PixelFormat renderFormat = image->getRenderFormat(); size_t tempDataLen = image->getDataLen(); - if (image->getNumberOfMipmaps() > 1) { if (pixelFormat != image->getRenderFormat()) @@ -772,10 +768,7 @@ bool Texture2D::initWithImage(Image *image, PixelFormat format) CCLOG("cocos2d: WARNING: This image has more than 1 mipmaps and we will not convert the data format"); } - initWithMipmaps(image->getMipmaps(), image->getNumberOfMipmaps(), image->getRenderFormat(), imageWidth, imageHeight); - - // set the premultiplied tag - _hasPremultipliedAlpha = image->hasPremultipliedAlpha(); + initWithMipmaps(image->getMipmaps(), image->getNumberOfMipmaps(), image->getRenderFormat(), imageWidth, imageHeight, image->hasPremultipliedAlpha()); return true; } @@ -786,10 +779,7 @@ bool Texture2D::initWithImage(Image *image, PixelFormat format) CCLOG("cocos2d: WARNING: This image is compressed and we can't convert it for now"); } - initWithData(tempData, tempDataLen, image->getRenderFormat(), imageWidth, imageHeight, imageSize); - - // set the premultiplied tag - _hasPremultipliedAlpha = image->hasPremultipliedAlpha(); + initWithData(tempData, tempDataLen, image->getRenderFormat(), imageWidth, imageHeight, imageSize, image->hasPremultipliedAlpha()); return true; } @@ -800,18 +790,13 @@ bool Texture2D::initWithImage(Image *image, PixelFormat format) pixelFormat = convertDataToFormat(tempData, tempDataLen, renderFormat, pixelFormat, &outTempData, &outTempDataLen); - initWithData(outTempData, outTempDataLen, pixelFormat, imageWidth, imageHeight, imageSize); - + initWithData(outTempData, outTempDataLen, pixelFormat, imageWidth, imageHeight, imageSize, image->hasPremultipliedAlpha()); if (outTempData != nullptr && outTempData != tempData) { - free(outTempData); } - // set the premultiplied tag - _hasPremultipliedAlpha = image->hasPremultipliedAlpha(); - return true; } } diff --git a/cocos/renderer/CCTexture2D.h b/cocos/renderer/CCTexture2D.h index d237ec1b6ebc..112d9f5dcf73 100644 --- a/cocos/renderer/CCTexture2D.h +++ b/cocos/renderer/CCTexture2D.h @@ -226,10 +226,11 @@ class CC_DLL Texture2D : public Ref @param pixelsWide The image width. @param pixelsHigh The image height. @param contentSize The image content size. + @param preMultipliedAlpha The texture has premultiplied alpha * @js NA * @lua NA */ - bool initWithData(const void *data, ssize_t dataLen, Texture2D::PixelFormat pixelFormat, int pixelsWide, int pixelsHigh, const Size& contentSize); + bool initWithData(const void *data, ssize_t dataLen, Texture2D::PixelFormat pixelFormat, int pixelsWide, int pixelsHigh, const Size& contentSize, bool preMultipliedAlpha = false); /** Initializes with mipmaps. @@ -238,8 +239,9 @@ class CC_DLL Texture2D : public Ref @param pixelFormat The image pixelFormat. @param pixelsWide The image width. @param pixelsHigh The image height. + @param preMultipliedAlpha The texture has premultiplied alpha */ - bool initWithMipmaps(MipmapInfo* mipmaps, int mipmapsNum, Texture2D::PixelFormat pixelFormat, int pixelsWide, int pixelsHigh); + bool initWithMipmaps(MipmapInfo* mipmaps, int mipmapsNum, Texture2D::PixelFormat pixelFormat, int pixelsWide, int pixelsHigh, bool preMultipliedAlpha = false); /** Update with texture data.