带有NSData的UIImage initWithData返回nil

UIImage with NSData initWithData returns nil

本文关键字:返回 nil initWithData UIImage NSData 带有      更新时间:2023-10-16

我有一个新问题!因为真正的问题不是在c++转换,而是我需要将返回的字符串数据字节转换为CGImageRef。如果有人知道怎么做,请去那个链接回答这个问题。

谢谢。


OK。我没有用protobuf的东西来混淆这个问题,而是简化了我的测试方法来模拟对protobuf的调用。

该测试方法完成以下两部分。第1部分获取一个UIImage并将其转换为std::string。

  1. take a UIImage
  2. 获取NSData
  3. 将数据转换为unsigned char *
  4. 将无符号char *填充到std::string

该字符串是我们将从protobuf调用接收到的字符串。第2部分从字符串中获取数据并将其转换回NSData格式以填充UIImage。以下是执行该操作的步骤:

  • 将std::字符串转换为char数组
  • 将char数组转换为const char *
  • 将char *放入NSData
  • 返回NSData
  • - (NSData *)testProcessedImage:(UIImage *)processedImage
    {
        // UIImage to unsigned char *
        CGImageRef imageRef = processedImage.CGImage;
        NSData *data = (NSData *) CFBridgingRelease(CGDataProviderCopyData(CGImageGetDataProvider(imageRef)));
        unsigned char *pixels = (unsigned char *)[data bytes];
        unsigned long size = [data length];
        // ***************************************************************************
        // This is where we would call transmit and receive the bytes in a std::string
        // ***************************************************************************
        // unsigned char * to string
        std::string byteString(pixels, pixels + size);
    
        // string to char array to const char *
        char myArray[byteString.size()+1];//as 1 char space for null is also required
        strcpy(myArray, byteString.c_str());
        const char *bytes = (const char *)myArray;
        // put byte array back into NSData format
        NSUInteger usize = byteString.length();
        data = [NSData dataWithBytes:(const void *)bytes length:sizeof(unsigned char)*usize];
        NSLog(@"examine data");
        return data;
    }
    

    是返回数据时的代码:

        NSData *data = [self.messageCommand testProcessedImage:processedImage];
        // But when I try to alloc init a UIImage with the data, the image is nil
        UIImage *image = [[UIImage alloc] initWithData:data];
        NSLog(@"examine image");
    

    一切似乎都按计划进行,直到我尝试用数据创建UIImage。用那个数据Alloc初始化UIImage返回nil。

    好的,所以问题很可能与Objective-C, C和c++数据结构之间的重复转换有关。总的来说,您需要确保将字符串初始化为字节数组,而不是文本C字符串,并且您希望返回没有空终止符的原始字节。我认为这样可以正确保存数据:

    - (void)onDataReceived:(NSNotification *)note {
        if ([note.name isEqualToString:@"DataReceived"]) {
            NSDictionary *userData = note.userInfo;
            NSData *imageData = [userData objectForKey:@"ImageData"];
     // Note the two-argument string constructor -- this is necessary for non-textual data!
            std::string byteString = std::string(static_cast<const char*>([imageData bytes]), imageData.length);
    
     // We get the image back as a std::string
            std::string imageStr = [self.message parseMessage:byteString ofSize:byteString.size()];
            NSLog(@"examine imageStr");
     // We get the data from the std::string
            char *imageCStr = new char[imageStr.size()];
            imageStr.copy(imageCStr, imageStr.size());
            NSData *data = [NSData dataWithBytes:imageCStr length:imageStr.size()];
            delete[] imageCStr;
     // But when I try to alloc init a UIImage with the data, the image is nil
            UIImage *image = [[UIImage alloc] initWithData:data];
            NSLog(@"examine image");
        }
    }
    

    我试着回答。为了消除错误,我需要做一些小的修改。此外,我还更改了一些变量名,以尽量减少混淆。这仍然会为UIImage返回nil。

    - (void)onObjectReceived:(NSNotification *)note {
        if ([note.name isEqualToString:@"ObjectReceived"]) {
            NSDictionary *userData = note.userInfo;
            NSData *objectData = [userData objectForKey:@"ObjectData"];
            // Added this because bytes is used below.  Or did you mean something else?
            const char *bytes = (const char *)[objectData bytes];
            // Note the two-argument string constructor -- this is necessary for non-textual data!
            std::string byteString = std::string(static_cast<const char*>(bytes), objectData.length);
            // This is an out parameter in the parseMessage method.
            long unsigned int *msgSize = (long unsigned *)malloc(sizeof(long unsigned int));
            // We get the image back as a std::string
            std::string imageStr = [self.message parseMessage:byteString outMsgSize:msgSize];
            NSLog(@"examine imageStr");
            // We get the data from the std::string
            char *imageCStr = new char[imageStr.size()];
            imageStr.copy(imageCStr, imageStr.size());
            NSData *data = [NSData dataWithBytes:imageCStr length:imageStr.size()];
            delete[] imageCStr;
            // But when I try to alloc init a UIImage with the data, the image is nil
            UIImage *image = [[UIImage alloc] initWithData:data];
            NSLog(@"examine image");
        }
    }
    

    我试着删除中间的一切,它工作。下面是代码:

    - (NSData *)testProcessedImage:(UIImage *)processedImage
    {
        // UIImage to unsigned char *
        CGImageRef imageRef = processedImage.CGImage;
        NSData *data1 = (NSData *) CFBridgingRelease(CGDataProviderCopyData(CGImageGetDataProvider(imageRef)));
        UIImage *image = [UIImage imageWithCGImage:imageRef];
    

    这告诉我NSData dataWithBytes不会工作,因为我使用的是CGImageRef。我的图像是来自相机的原始数据(不是PNG或JPEG)。

    我在网上找到了这个答案,这很有帮助。询者甚至发表了这样的评论,"看起来很简单包装(数据)在CFData对象,然后CGDataProviderCreateWithCFData。"

    我在SO上找到了另一个答案,也很有帮助。它展示了如何使用字符串。

    创建CFDataRef。有很多有用的信息在那里,但仍然没有找到我需要的。我要问另一个问题,当我得到答案时,把它引用到这里。

    谢谢。