The SDL forums have moved to discourse.libsdl.org.
This is just a read-only archive of the previous forums, to keep old links working.


SDL Forum Index
SDL
Simple Directmedia Layer Forums
Pixel bug in Mac OS X
pixelman


Joined: 20 Sep 2011
Posts: 3
Hey all.

I'm working on a game on Mac OS X (Snow Leopard, SDL 1.2.14). I'm using PNG images (created in Gimp) to store the levels and then build the level based on each pixel's color -- the problem is the colors I'm getting are slightly inaccurate, which is breaking my program.


I'm using the getpixel() method from the SDL website. Each color in the image is off by just a few integers. For example (126, 126, 180) is being read as (127, 127, 178). Also, for the record, I took a screenshot of my program and compared it to the colors to my sprites in Gimp, and the screenshot was slightly off as well.


I think I have an idea of what's going on though. When I change the level image to a .BMP, the pixels are read 100% accurately, so I'm assuming it's just a bug in SDL_image. I did a little digging, and I found this:


http://playcontrol.net/ewing/jibberjabber/big_behind-the-scenes_chang.html#SDL_image


"We are changing the backend of SDL_image to use Apple's ImageIO API"


I had this exact same problem when using ImageIO a few months ago. I can't remember exactly how I was doing it before, but when I load images like below the pixels are read correctly:



- (CGImageRef)loadImageFromFile:(NSString *)pathToResource {
NSString *resourcePath = [[NSBundle mainBundle] resourcePath];
[[NSFileManager defaultManager] changeCurrentDirectoryPath:resourcePath];

NSURL* url = [NSURL fileURLWithPath:pathToResource];
CGImageRef imageRef = NULL;
CGImageSourceRef sourceRef;

sourceRef = CGImageSourceCreateWithURL((CFURLRef)url, NULL);
if(sourceRef) {
imageRef = CGImageSourceCreateImageAtIndex(sourceRef, 0, NULL);
CFRelease(sourceRef);
} else {
NSLog(@"Failed to load image\n");
}
return imageRef;
}






// Example getting the pixel data (it's read-only though -- figures this is how Apple recommends it)


CGImageRef imageRef = [loadImageFromFile:@"example.png"];
CFDataRef imageDataRef = CGDataProviderCopyData(CGImageGetDataProvider(imageRef));
const UInt8 *pixelData = CFDataGetBytePtr(imageDataRef);

Any chance someone could fix this? BMPs are so huge. Smile


Cheers,
- pixelman
Pixel bug in Mac OS X
eclectocrat


Joined: 26 Mar 2011
Posts: 72
This is a persistent problem with OSX, I have the same issue with any program that uses Apple's Image IO, such as Pixen or Seashore. Just on a whim, you might want to take a look at the Color Space (NSColorSpace, CGColorSpace?) settings, or the Color Calibration settings. Alternatively, download a different image loading library like LodePNG, a single source file library for PNG access, it works great for me.

Good luck.

On Wed, Sep 21, 2011 at 9:53 AM, pixelman wrote:
Quote:
Hey all.

I'm working on a game on Mac OS X (Snow Leopard, SDL 1.2.14). I'm using PNG images (created in Gimp) to store the levels and then build the level based on each pixel's color -- the problem is the colors I'm getting are slightly inaccurate, which is breaking my program.


I'm using the getpixel() method from the SDL website. Each color in the image is off by just a few integers. For example (126, 126, 180) is being read as (127, 127, 178). Also, for the record, I took a screenshot of my program and compared it to the colors to my sprites in Gimp, and the screenshot was slightly off as well.


I think I have an idea of what's going on though. When I change the level image to a .BMP, the pixels are read 100% accurately, so I'm assuming it's just a bug in SDL_image. I did a little digging, and I found this:


http://playcontrol.net/ewing/jibberjabber/big_behind-the-scenes_chang.html#SDL_image


"We are changing the backend of SDL_image to use Apple's ImageIO API"


I had this exact same problem when using ImageIO a few months ago. I can't remember exactly how I was doing it before, but when I load images like below the pixels are read correctly:



- (CGImageRef)loadImageFromFile:(NSString *)pathToResource {
NSString *resourcePath = [[NSBundle mainBundle] resourcePath];
[[NSFileManager defaultManager] changeCurrentDirectoryPath:resourcePath];

NSURL* url = [NSURL fileURLWithPath:pathToResource];
CGImageRef imageRef = NULL;
CGImageSourceRef sourceRef;

sourceRef = CGImageSourceCreateWithURL((CFURLRef)url, NULL);
if(sourceRef) {
imageRef = CGImageSourceCreateImageAtIndex(sourceRef, 0, NULL);
CFRelease(sourceRef);
} else {
NSLog(@"Failed to load image\n");
}
return imageRef;
}






// Example getting the pixel data (it's read-only though -- figures this is how Apple recommends it)


CGImageRef imageRef = [loadImageFromFile:@"example.png"];
CFDataRef imageDataRef = CGDataProviderCopyData(CGImageGetDataProvider(imageRef));
const UInt8 *pixelData = CFDataGetBytePtr(imageDataRef);

Any chance someone could fix this? BMPs are so huge. Smile


Cheers,
- pixelman


_______________________________________________
SDL mailing list

http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org

Pixel bug in Mac OS X
Ryan C. Gordon
Guest

Quote:
"We are changing the backend of SDL_image to use Apple's ImageIO API"

We should just disable this, because it constantly causes three problems:
- Slightly different colors when you need pixel-perfect decoding.
- No 8-bit support (which is bad when you use an 8-bit grayscale .png
as, say, a heightmap, and actually wanted an 8-bit surface from SDL_image).
- The first two problems are completely non-obvious to track down when
you realize you have a problem, and a pain to resolve, because now you
have to build your own SDL_image at a minimum.

The benefits to using ImageIO are a smaller compiled library, no need
for us to manage the external dependencies, and no need to worry about
updating the dependencies for security issues. I'm not sure this is the
_worst_ thing, though.

Eric Wing, if you're around: can the color thing be resolved? Maybe with
an NSColorSpace or something?

For the other issue, I imagine that, for correctness, we can convert the
final SDL_Surface to 8-bit if the original PNG is 8-bit too. Maybe?

--ryan.


_______________________________________________
SDL mailing list

http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org
Pixel bug in Mac OS X
pixelman


Joined: 20 Sep 2011
Posts: 3
@Jeremy: Haha trying to write a pixel art editor on the Mac is a nightmare. o_O


I'm reading the SDL_image source right now, and I see in Create_SDL_Surface_From_CGImage they're creating a CGBitmapContext with the surface->pixels and drawing the loaded image to the context. I'm 99% sure this is what I was doing before and getting headaches over.


Check this out: http://developer.apple.com/library/mac/#qa/qa1509/_index.html


Quote:
Warning: The pixel data returned by CGDataProviderCopyData has not been color matched and is in the format that the image is in, as described by the various CGImageGet functions (see for Getting Information About an Image more information). If you want the image in a different format, or color matched to a specific color space,  then you should draw the image to a bitmap context as described later in this Q&A, with the caveat that alpha information from the image will be multiplied into the color components.


So basically, it is possible to get the unaltered pixel data directly from the image with ImageIO. I think the alpha-premultiplication is what's screwing everything up -- would it be possible to copy the raw pixel data into the SDL_Surface?


- pixelman


On Wed, Sep 21, 2011 at 1:04 AM, Ryan C. Gordon wrote:
Quote:

Quote:
"We are changing the backend of SDL_image to use Apple's ImageIO API"


We should just disable this, because it constantly causes three problems:
- Slightly different colors when you need pixel-perfect decoding.
- No 8-bit support (which is bad when you use an 8-bit grayscale .png as, say, a heightmap, and actually wanted an 8-bit surface from SDL_image).
- The first two problems are completely non-obvious to track down when you realize you have a problem, and a pain to resolve, because now you have to build your own SDL_image at a minimum.

The benefits to using ImageIO are a smaller compiled library, no need for us to manage the external dependencies, and no need to worry about updating the dependencies for security issues. I'm not sure this is the _worst_ thing, though.

Eric Wing, if you're around: can the color thing be resolved? Maybe with an NSColorSpace or something?

For the other issue, I imagine that, for correctness, we can convert the final SDL_Surface to 8-bit if the original PNG is 8-bit too. Maybe?

--ryan.



_______________________________________________
SDL mailing list

http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org


Pixel bug in Mac OS X
Eric Wing
Guest

Sorry all. I'm still around, but just been really busy.

I'm going from distant memory here. I thought I recall calling some
memory calibration stuff in the code already. I think I was unsure
which way to go so I think there may have been two lines, one
commented out to go the other way. I thought the current way would not
do color calibration because I thought that would alter the pixel
values.

I recall people were having problems with premulitplied alpha related
issues. Was it Sam that added the code to 'fix' that? Is this always
run? Are these cases orthogonal? Maybe this can be skipped when not
needed and thus avoiding any accidental pixel color changes?

I never did figure out grayscale, but I never deeply pursued this.
Maybe some ambitious person would like to ask on the Quartz mailing
list or something or if they have a spare DTS incident to throw
away...

As a workaround for grayscale, I was thinking it could be done the
brute force way. Check the bitdepth for 8-bit and then go through all
the pixels after blitting to 24/32-bit and check for r==g==b. If it
passes the check, create a SDL_Surface that looks like what you might
get from the other IMG_Load backends.

-Eric

On 9/21/11, pixelman wrote:
Quote:
@Jeremy: Haha trying to write a pixel art editor on the Mac is a nightmare.
o_O

I'm reading the SDL_image source right now, and I see in
Create_SDL_Surface_From_CGImage they're creating a CGBitmapContext with the
surface->pixels and drawing the loaded image to the context. I'm 99% sure
this is what I was doing before and getting headaches over.

Check this out:
http://developer.apple.com/library/mac/#qa/qa1509/_index.html

*Warning:* The pixel data returned by CGDataProviderCopyData has not been
Quote:
color matched and is in the format that the image is in, as described by
the
various CGImageGet functions (see for Getting Information About an
Image<http://developer.apple.com/library/mac/documentation/GraphicsImaging/Reference/CGImage/Reference/reference.html#//apple_ref/doc/uid/TP30000956-CH1g-443784>
more
information). If you want the image in a different format, or color
matched
to a specific color space, then you should draw the image to a bitmap
context as described later in this Q&A, with the caveat that alpha
information from the image will be multiplied into the color components.


So basically, it *is* possible to get the unaltered pixel data directly from
the image with ImageIO. I think the alpha-premultiplication is what's
screwing everything up -- would it be possible to copy the raw pixel data
into the SDL_Surface?

- pixelman


On Wed, Sep 21, 2011 at 1:04 AM, Ryan C. Gordon wrote:

Quote:

"We are changing the backend of SDL_image to use Apple's ImageIO API"

We should just disable this, because it constantly causes three problems:
- Slightly different colors when you need pixel-perfect decoding.
- No 8-bit support (which is bad when you use an 8-bit grayscale .png as,
say, a heightmap, and actually wanted an 8-bit surface from SDL_image).
- The first two problems are completely non-obvious to track down when you
realize you have a problem, and a pain to resolve, because now you have to
build your own SDL_image at a minimum.

The benefits to using ImageIO are a smaller compiled library, no need for
us to manage the external dependencies, and no need to worry about
updating
the dependencies for security issues. I'm not sure this is the _worst_
thing, though.

Eric Wing, if you're around: can the color thing be resolved? Maybe with
an
NSColorSpace or something?

For the other issue, I imagine that, for correctness, we can convert the
final SDL_Surface to 8-bit if the original PNG is 8-bit too. Maybe?

--ryan.



______________________________**_________________
SDL mailing list

http://lists.libsdl.org/**listinfo.cgi/sdl-libsdl.org<http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org>




--
Beginning iPhone Games Development
http://playcontrol.net/iphonegamebook/
_______________________________________________
SDL mailing list

http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org
Pixel bug in Mac OS X
pixelman


Joined: 20 Sep 2011
Posts: 3
Hola,


For convenience, here's the code where the CGImage is copied into the SDL_Surface->pixels


http://pastebin.com/6NJ19HP0


Like I said before, I think the inaccuracy happens when the CGImage is drawn into a CGContext, because I've had this same issue before. If you read the raw pixel data of a loaded CGImage (without changing it in any way) then the pixel data is accurate.


- pixelman


On Fri, Sep 30, 2011 at 1:38 PM, Eric Wing wrote:
Quote:
Sorry all. I'm still around, but just been really busy.

I'm going from distant memory here. I thought I recall calling some
memory calibration stuff in the code already. I think I was unsure
which way to go so I think there may have been two lines, one
commented out to go the other way. I thought the current way would not
do color calibration because I thought that would alter the pixel
values.

I recall people were having problems with premulitplied alpha related
issues. Was it Sam that added the code to 'fix' that? Is this always
run? Are these cases orthogonal? Maybe this can be skipped when not
needed and thus avoiding any accidental pixel color changes?

I never did figure out grayscale, but I never deeply pursued this.
Maybe some ambitious person would like to ask on the Quartz mailing
list or something or if they have a spare DTS incident to throw
away...

As a workaround for grayscale, I was thinking it could be done the
brute force way. Check the bitdepth for 8-bit and then go through all
the pixels after blitting to 24/32-bit and check for r==g==b. If it
passes the check, create a SDL_Surface that looks like what you might
get from the other IMG_Load backends.

-Eric

On 9/21/11, pixelman wrote:
Quote:
@Jeremy: Haha trying to write a pixel art editor on the Mac is a nightmare.
o_O

I'm reading the SDL_image source right now, and I see in
Create_SDL_Surface_From_CGImage they're creating a CGBitmapContext with the
surface->pixels and drawing the loaded image to the context. I'm 99% sure
this is what I was doing before and getting headaches over.

Check this out:
http://developer.apple.com/library/mac/#qa/qa1509/_index.html


Quote:
*Warning:* The pixel data returned by CGDataProviderCopyData has not been
Quote:
color matched and is in the format that the image is in, as described by
the
various CGImageGet functions (see for Getting Information About an

Quote:
Quote:
Image<http://developer.apple.com/library/mac/documentation/GraphicsImaging/Reference/CGImage/Reference/reference.html#//apple_ref/doc/uid/TP30000956-CH1g-443784>
more
information). If you want the image in a different format, or color
matched
to a specific color space,  then you should draw the image to a bitmap
context as described later in this Q&A, with the caveat that alpha
information from the image will be multiplied into the color components.



Quote:
So basically, it *is* possible to get the unaltered pixel data directly from
the image with ImageIO. I think the alpha-premultiplication is what's
screwing everything up -- would it be possible to copy the raw pixel data
into the SDL_Surface?

- pixelman


On Wed, Sep 21, 2011 at 1:04 AM, Ryan C. Gordon wrote:

Quote:

 "We are changing the backend of SDL_image to use Apple's ImageIO API"

We should just disable this, because it constantly causes three problems:
- Slightly different colors when you need pixel-perfect decoding.
- No 8-bit support (which is bad when you use an 8-bit grayscale .png as,
say, a heightmap, and actually wanted an 8-bit surface from SDL_image).
- The first two problems are completely non-obvious to track down when you
realize you have a problem, and a pain to resolve, because now you have to
build your own SDL_image at a minimum.

The benefits to using ImageIO are a smaller compiled library, no need for
us to manage the external dependencies, and no need to worry about
updating
the dependencies for security issues. I'm not sure this is the _worst_
thing, though.

Eric Wing, if you're around: can the color thing be resolved? Maybe with
an
NSColorSpace or something?

For the other issue, I imagine that, for correctness, we can convert the
final SDL_Surface to 8-bit if the original PNG is 8-bit too. Maybe?

--ryan.




Quote:
Quote:
______________________________**_________________
SDL mailing list

[url=http://lists.libsdl.org/**listinfo.cgi/sdl-libsdl.org]http://lists.libsdl.org/**listinfo.cgi/sdl-libsdl.org[/url]<http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org>




--
Beginning iPhone Games Development
http://playcontrol.net/iphonegamebook/

_______________________________________________
SDL mailing list

http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org


Pixel bug in Mac OS X
Eric Wing
Guest

This is a quick experiment to see if CGDataProviderCopyData helps
solve the problem any. My code is not endian clean and I don't know
what it is going to do about alpha. No greyscale either. I only tested
with two basic images, a png and jpg.

In my specific png case, my CGImageGetBitmapInfo always came out as 0.
I was kind of expecting some info about endianess.

Anyway, can you test the following function by replacing the one in
the implementation to see if it improves the pixel value problem any.
If so, maybe we can can fix/finish this implementation, though I'm not
sure what to do about Tiger (10.4) since this is only 10.5+.

-Eric


// Once we have our image, we need to get it into an SDL_Surface
static SDL_Surface* Create_SDL_Surface_From_CGImage(CGImageRef image_ref)
{
/* This code is adapted from Apple's Documentation found here:
* http://developer.apple.com/documentation/GraphicsImaging/Conceptual/OpenGL-MacProgGuide/index.html
* Listing 9-4††Using a Quartz image as a texture source.
* Unfortunately, this guide doesn't show what to do about
* non-RGBA image formats so I'm making the rest up.
* All this code should be scrutinized.
*/
size_t w = CGImageGetWidth(image_ref);
size_t h = CGImageGetHeight(image_ref);

CGImageAlphaInfo alpha = CGImageGetAlphaInfo(image_ref);

SDL_Surface* surface;
Uint32 Amask;
Uint32 Rmask;
Uint32 Gmask;
Uint32 Bmask;


if (alpha == kCGImageAlphaNone ||
alpha == kCGImageAlphaNoneSkipFirst ||
alpha == kCGImageAlphaNoneSkipLast) {
Amask = 0x00000000;
} else {
Amask = 0xFF000000;
}

Rmask = 0x00FF0000;
Gmask = 0x0000FF00;
Bmask = 0x000000FF;

surface = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, 32, Rmask, Gmask,
Bmask, Amask);
if (surface)
{
/* CGDataProviderCopyData will give us a copy of the raw data */
CFDataRef data_copy =
CGDataProviderCopyData(CGImageGetDataProvider(image_ref));
const UInt8* data_byte_ptr = CFDataGetBytePtr(data_copy);
Uint8 *p = (Uint8 *)surface->pixels;
size_t i;
size_t j;

size_t width = CGImageGetWidth(image_ref);
size_t height = CGImageGetHeight(image_ref);

size_t bpr = CGImageGetBytesPerRow(image_ref);
size_t bpp = CGImageGetBitsPerPixel(image_ref);
size_t bpc = CGImageGetBitsPerComponent(image_ref);
size_t bytes_per_pixel = bpp / bpc;

CGBitmapInfo info = CGImageGetBitmapInfo(image_ref);

fprintf(stderr,
"\n"
"CGImageGetHeight: %d\n"
"CGImageGetWidth: %d\n"
// "CGImageGetColorSpace: %@\n"
"CGImageGetBitsPerPixel: %d\n"
"CGImageGetBitsPerComponent: %d\n"
"CGImageGetBytesPerRow: %d\n"
"CGImageGetBitmapInfo: 0x%.8X\n"
" kCGBitmapAlphaInfoMask = %s\n"
" kCGBitmapFloatComponents = %s\n"
" kCGBitmapByteOrderMask = %s\n"
" kCGBitmapByteOrderDefault = %s\n"
" kCGBitmapByteOrder16Little = %s\n"
" kCGBitmapByteOrder32Little = %s\n"
" kCGBitmapByteOrder16Big = %s\n"
" kCGBitmapByteOrder32Big = %s\n",
(int)width,
(int)height,
// CGImageGetColorSpace(image_ref),
(int)bpp,
(int)bpc,
(int)bpr,
(unsigned)info,
(info & kCGBitmapAlphaInfoMask) ? "YES" : "NO",
(info & kCGBitmapFloatComponents) ? "YES" : "NO",
(info & kCGBitmapByteOrderMask) ? "YES" : "NO",
(info & kCGBitmapByteOrderDefault) ? "YES" : "NO",
(info & kCGBitmapByteOrder16Little) ? "YES" : "NO",
(info & kCGBitmapByteOrder32Little) ? "YES" : "NO",
(info & kCGBitmapByteOrder16Big) ? "YES" : "NO",
(info & kCGBitmapByteOrder32Big) ? "YES" : "NO"
);


switch(bytes_per_pixel)
{
case 3:
{
for(i = 0, j=0; i < CFDataGetLength(data_copy); i += 3, j+=4)
{
p[j] = data_byte_ptr[i+2];
p[j+1] = data_byte_ptr[i+1];
p[j+2] = data_byte_ptr[i];
}
break;
}
case 4:
{
// Take away the red pixel, assuming 32-bit RGBA
for(i = 0; i < CFDataGetLength(data_copy); i += 4)
{
p[i] = data_byte_ptr[i+2];
p[i+1] = data_byte_ptr[i+1];
p[i+2] = data_byte_ptr[i];
p[i+3] = data_byte_ptr[i+3];
}
break;
}

}

CFRelease(data_copy);
}
return surface;
}
_______________________________________________
SDL mailing list

http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org