2013-08-09 1 views
0

J'essaie d'utiliser l'interface C de CoreGraphics & CoreFoundation pour enregistrer un tampon de données RGBA 32 bits (en tant que void *) dans un fichier PNG. Lorsque je tente de finialize le CGImageDestinationRef, le message d'erreur suivant est imprimé à la console: Pour autant que je peux direCoreGraphics: Encoder les données RGBA au format PNG

libpng error: No IDATs written into file

, le CGImageRef j'ajouter à la CGImageDestinationRef est valide.

code relavent:

void saveImage(const char* szImage, void* data, size_t dataSize, size_t width, size_t height) 
{ 
    CFStringRef name = CFStringCreateWithCString(NULL, szImage, kCFStringEncodingASCII); 
    CFURLRef texture_url = CFURLCreateWithFileSystemPath(
                NULL, 
                name, 
                kCFURLPOSIXPathStyle, 
                false); 

    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 
    CGDataProviderRef dataProvider = CGDataProviderCreateWithData(NULL, data, dataSize, NULL); 
    CGImageRef image = CGImageCreate(width, height, 8, 32, 32 * width, colorSpace, 
           kCGImageAlphaLast | kCGBitmapByteOrderDefault, dataProvider, 
           NULL, FALSE, kCGRenderingIntentDefault); 

    // From Image I/O Programming Guide, "Working with Image Destinations" 
    float compression = 1.0; // Lossless compression if available. 
    int orientation = 4; // Origin is at bottom, left. 
    CFStringRef myKeys[3]; 
    CFTypeRef myValues[3]; 
    CFDictionaryRef myOptions = NULL; 
    myKeys[0] = kCGImagePropertyOrientation; 
    myValues[0] = CFNumberCreate(NULL, kCFNumberIntType, &orientation); 
    myKeys[1] = kCGImagePropertyHasAlpha; 
    myValues[1] = kCFBooleanTrue; 
    myKeys[2] = kCGImageDestinationLossyCompressionQuality; 
    myValues[2] = CFNumberCreate(NULL, kCFNumberFloatType, &compression); 
    myOptions = CFDictionaryCreate(NULL, (const void **)myKeys, (const void **)myValues, 3, 
           &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 

    CFStringRef type = CFStringCreateWithCString(NULL, "public.png", kCFStringEncodingASCII); 
    CGImageDestinationRef dest = CGImageDestinationCreateWithURL(texture_url, type, 1, myOptions); 

    CGImageDestinationAddImage(dest, image, NULL); 

    if (!CGImageDestinationFinalize(dest)) 
    { 
     // ERROR! 
    } 

    CFRelease(image); 
    CFRelease(colorSpace); 
    CFRelease(dataProvider); 
    CFRelease(dest); 
    CFRelease(texture_url); 
} 

Ce poste est similaire, sauf que je ne suis pas à l'aide de l'interface Objectif C: Saving a 32 bit RGBA buffer into a .png file (Cocoa OSX)

Répondre

0

Il existe de nombreux problèmes avec votre code.

Ici, il est réécrite comment je le ferais:

void saveImage(const char* szImage, void* data, size_t dataSize, size_t width, size_t height) 
{ 
    CFStringRef name = CFStringCreateWithCString(NULL, szImage, kCFStringEncodingUTF8); 
    CFURLRef texture_url = CFURLCreateWithFileSystemPath(
                NULL, 
                name, 
                kCFURLPOSIXPathStyle, 
                false); 

    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 
    CGDataProviderRef dataProvider = CGDataProviderCreateWithData(NULL, data, 
                   dataSize, NULL); 
    CGImageRef image = CGImageCreate(width, height, 8, 32, 32 * width, colorSpace, 
           kCGImageAlphaLast | kCGBitmapByteOrderDefault, 
          dataProvider, NULL, FALSE, kCGRenderingIntentDefault); 

    // From Image I/O Programming Guide, "Working with Image Destinations" 
    float compression = 1.0; // Lossless compression if available. 
    int orientation = 4; // Origin is at bottom, left. 
    CFStringRef myKeys[3]; 
    CFTypeRef myValues[3]; 
    CFDictionaryRef myOptions = NULL; 
    myKeys[0] = kCGImagePropertyOrientation; 
    myValues[0] = CFNumberCreate(NULL, kCFNumberIntType, &orientation); 
    myKeys[1] = kCGImagePropertyHasAlpha; 
    myValues[1] = kCFBooleanTrue; 
    myKeys[2] = kCGImageDestinationLossyCompressionQuality; 
    myValues[2] = CFNumberCreate(NULL, kCFNumberFloatType, &compression); 
    myOptions = CFDictionaryCreate(NULL, (const void **)myKeys, 
        (const void **)myValues, 3, &kCFTypeDictionaryKeyCallBacks, 
              &kCFTypeDictionaryValueCallBacks); 

    CGImageDestinationRef dest = 
      CGImageDestinationCreateWithURL(texture_url, kUTTypePNG, 1, NULL); 

    CGImageDestinationAddImage(dest, image, NULL); 
    CGImageDestinationSetProperties(dest, myOptions); 

    if (!CGImageDestinationFinalize(dest)) 
    { 
     // ERROR! 
    } 

} 

Tout d'abord, ne jamais utiliser ASCII lorsqu'ils traitent avec des chemins du système de fichiers, utilisez UTF8. Deuxièmement, vous construisiez un dictionnaire à utiliser pour définir les propriétés de l'image, mais vous l'utilisiez avec la mauvaise fonction. La documentation pour CGImageDestinationCreateWithURL() dit ce qui suit:

CGImageDestinationCreateWithURL

Creates an image destination that writes to a location specified by a URL.

CGImageDestinationRef CGImageDestinationCreateWithURL (
    CFURLRef url, 
    CFStringRef type, 
    size_t count, 
    CFDictionaryRef options 
); 

Parameters options - Reserved for future use. Pass NULL .

Vous essayez de passer un dictionnaire de propriétés lorsque vous étiez censé passer NULL. (De plus, vous pouvez simplement utiliser la constante de chaîne kUTTypePNG Uniform Type Identifiant au lieu de la recréer). Commencez par appeler le CGImageDestinationCreateWithURL(), puis appelez le CGImageDestinationAddImage() pour ajouter l'image, puis appelez le CGImageDestinationSetProperties() et transmettez le dictionnaire des propriétés que vous avez créées.

[UPDATE]: Si après ces changements que vous rencontrez toujours des problèmes libpng error: No IDATs written into file, essayez ce qui suit: Tout d'abord, assurez-vous que dataProvider est non NULL - en d'autres termes, assurez-vous que la fonction CGDataProviderCreateWithData() a réussi. Deuxièmement, si dataProvider est valide, essayez peut-être de changer les options de kCGImageAlphaLast | kCGBitmapByteOrderDefault en simplement kCGImageAlphaPremultipliedLast et voyez si cela réussit.

+0

Merci pour les pointeurs. Je suis toujours à la recherche de ce fichier UTCoreTypes.h qui a la constante kUTTypePNG définie. La documentation dit que c'est dans MobileCoreServices.framework, mais je n'ai pas ce framework dans mon SDK MacOSX10.8. Le problème sous-jacent existe toujours, cependant: je reçois toujours l'erreur «libpng error: No IDAT écrit dans le fichier» après l'application de vos correctifs pour le dictionnaire des options. – Chris

+0

@Chris: MobileCoreServices est pour iOS, qui n'a pas vraiment un framework CoreServices complet comme OS X le fait. Dans OS X, UTCoreTypes.h fera partie de 'LaunchServices.framework », qui est un sous-cadre du framework« CoreServices.framework ». Mis à jour la réponse aussi (ou le sera bientôt). – NSGod

+0

Ugh, n'a pas vu votre propre réponse avant d'écrire le mien. – NSGod

0

répondre à mes propres questions:

  1. En plus des questions signalées par NSGod, la question IDAT était un paramètre non valide à CGImageCreate(): paramètre 5 est bytesPerRow, pas bitsPerRow. Donc 32 * width était incorrect; 4 * width est correct.

  2. Malgré ce que this page des listes de documents officiels, UTCoreTypes.h est situé dans le CoreServices.framework pour MacOSX, non MobileCoreServices.framework.

Questions connexes