How to save image by using HttpRequest in cocos2dx3.0?

Hi,
Does any one know how to save image by using HttpRequest?

In cocos2dx2.1.4, we can use

    cocos2d::extension::CCHttpResponse *response = (cocos2d::extension::CCHttpResponse*)data;

    // dump data
    std::vector *buffer = response->getResponseData();

    printf("Http Test, dump data: ");
    CCImage* image = new CCImage();
    image->initWithImageData(&(buffer->front()), buffer->size());
    image->saveToFile(create_fully_path.c_str());    //Save to File

Because cocos2dx 3.0 has already changed the parameter in initWithImageData method from

    bool initWithImageData(void * pData, 
                           int nDataLen, 
                           EImageFormat eFmt = kFmtUnKnown,
                           int nWidth = 0,
                           int nHeight = 0,
                           int nBitsPerComponent = 8);

to

bool initWithImageData(const unsigned char * data, int dataLen);

Last I tried initWithRawData() method,
but not work:

 HttpResponse *response = (HttpResponse*)data;
 // dump data
    std::vector *buffer = response->getResponseData();
    char* z = new char[buffer->size()];
    std::copy(buffer->begin(), buffer->end(),  z);

    const char * destPtr;
    destPtr=z;
    cout<(destPtr);
    unsigned const char * p =(unsigned const char*)destPtr;
    Image* image = new Image();
    image->initWithRawData(p,sizeof(p),400,393,8,false);
    image->saveToFile(_save_path.c_str());    //Save to File

Can someone help me?
Thanks!

Maybe it’s too late (I hope you already found a solution!), but I find a way to make initWithImageData method working in Cocos2d-x 3.0, just casting buffer argument. Basically, the code is similar to that working on Cocos2d-x v.2, but with little changes, like this:

cocos2d::extension::HttpResponse *response = (cocos2d::extension::HttpResponse*)data;
std::vector *buffer = response->getResponseData();
Image* image = new Image();
image->initWithImageData(reinterpret_cast (&(buffer->front())), buffer->size()); 

//In my project, I need the image to be shown, and not saved, so I didn't use 'saveToFile', but just create a Sprite
Texture2D* texture = new Texture2D();
texture->initWithImage(image);    
Sprite* img_sprite = Sprite::createWithTexture(texture); 

Very Thanks!
Because cocos2d-x 3.0 pre-alpha have much bugs right now,
I’ve back using 2.1.5.
Thanks.

Hi, I’m getting an issue with what seems like an out of scope texture. When the request responds the sprite is created in the same thread as the response and so the sprites texture goes out of scope. How did you retain the sprites texture after the response call is finished.

You can ->retain() the sprite if you’re talking about having a Sprite::create(…) that you create before downloading the image which you then want to setTexture in the callback of the response success?

I found a solution. When I requested the image data I made a copy of the std::vector<char> * and stored it in the class, then created the texture and sprite based on that data. The problem was that the texture was being created using a pointer to the data originally so when the data in the http request was deleted because it went out of scope the texture was also affected.

The other possible cause of the issue is that the sprite was being created in the response callback thread and not the main thread. This multiple thread use case from callbacks also creates black boxes and other artefacts when sprites are created outside of the main thread.

Code example:
GameController.cpp

#include "cocos2d.h"
#include "extensions/cocos-ext.h"
#include "network/HttpClient.h"

using namespace cocos2d::network;
USING_NS_CC;
void GameController::LoadAvatarImages(std::string &avatarUrl, Player::PlayerNumber playerNumber) {
    CCLOG("onHttpRequestCompleted In the request");
    HttpRequest* request = new (std::nothrow) HttpRequest();
    request->setUrl(avatarUrl);
    request->setRequestType(HttpRequest::Type::POST);
    
    if(playerNumber == Player::PLAYER_ONE) {
        request->setResponseCallback(CC_CALLBACK_2(GameController::onRequestLocalPlayerImgCompleted, this));
    } else if(playerNumber == Player::PLAYER_TWO) {
        request->setResponseCallback(CC_CALLBACK_2(GameController::onRequestOpponentPlayerImgCompleted, this));
    }

    HttpClient::getInstance()->send(request);
    request->release();
}
void GameController::onRequestLocalPlayerImgCompleted(HttpClient *sender, HttpResponse *response) {
    CCLOG("GameController::onRequestLocalPlayerImgCompleted - onHttpRequestCompleted BEGIN");
    if (!response) {
        log("onHttpRequestCompleted - No Response");
        return;
    }
    
    CCLOG("onHttpRequestCompleted - Response code: %lu", response->getResponseCode());
    
    if (!response->isSucceed())
    {
        log("onHttpRequestCompleted - Response failed");
        log("onHttpRequestCompleted - Error buffer: %s", response->getErrorBuffer());
        return;
    }
    CCLOG("onHttpRequestCompleted - Response code: %s", response->getResponseDataString());
    
    std::vector<char> *buffer = response->getResponseData();
    m_pGameBoard->GetLocalPlayer()->SetAvatarImageBuffer(*buffer);
}

Player.h

cocos2d::Sprite *m_pAvatar;
std::vector<char> m_vAvatarImageBuffer;

Player.cpp

void Player::SetAvatarImageBuffer(std::vector<char> &imageBuffer) {
    m_vAvatarImageBuffer = imageBuffer;
}
void Player::CreatePlayerAvatar() {
    cocos2d::Image *image = new cocos2d::Image();
    image->initWithImageData((const unsigned char*)m_vAvatarImageBuffer.data(), m_vAvatarImageBuffer.size());
    cocos2d::Texture2D *texture = new cocos2d::Texture2D();
    texture->initWithImage(image);
    cocos2d::Sprite *avatar = cocos2d::Sprite::createWithTexture(texture);
    m_pAvatar = avatar;
}