Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

MrFusion

macrumors 6502a
Original poster
Jun 8, 2005
613
0
West-Europe
After some searching the net, I came up with/to this code. It reads an img file, goes through it pixel by pixel and makes a new image pixel by pixel and saves that.
White pixels are made transparant and non-whites are made black.
But the problem is that the image gets destorted. The only thing I need it for is to make a few images transparant, so the code doesn't have to be that good.

Any idea?

Code:
int i, j, cell_width, cell_height;
	
	//old image
	NSImage *image =[[NSImage alloc] initWithContentsOfFile:@"testIN.pdf"];
       NSBitmapImageRep *bitmap = [[[NSBitmapImageRep alloc] initWithData: [image TIFFRepresentation]] autorelease];
	unsigned char *bytes = [bitmap bitmapData];
	//new image
	[view1 setImage:image];
	cell_width = [bitmap pixelsWide];
	cell_height = [bitmap pixelsHigh];
	NSImage *newImage = [[NSImage alloc] initWithSize:NSMakeSize(cell_width,cell_height)];
		
	NSBitmapImageRep *new_bitmap = [[[NSBitmapImageRep alloc] initWithBitmapDataPlanes: NULL
											pixelsWide: cell_width
											pixelsHigh: cell_height
										 bitsPerSample: 8
									   samplesPerPixel: 4
										  hasAlpha: YES
										  isPlanar: NO
								    colorSpaceName: NSCalibratedRGBColorSpace
									   bytesPerRow: 0
									    bitsPerPixel: 0] autorelease];
	unsigned char *newbytes = [new_bitmap bitmapData];
       j = 0;
    for (i = 0; i < cell_width * cell_height * 3; i += 3) {
             unsigned char r, g, b;
		r = *(bytes + i);
              g = *(bytes + i + 1);
              b = *(bytes + i + 2);
		
        if(r == 255 && g == 255 && b == 255){
            *(newbytes + j + 0) = 0;
            *(newbytes + j + 1) = 0;
            *(newbytes + j + 2) = 0;
            *(newbytes + j + 3) = 0;
        } else {
            *(newbytes + j + 0) = 0;
            *(newbytes + j + 1) = 0;
            *(newbytes + j + 2) = 0;
            *(newbytes + j + 3) = 255;			
        }
        j += 4;
    }
    [newImage lockFocus];
    [new_bitmap draw];
    [newImage unlockFocus];

    NSData *data = [newImage TIFFRepresentation];
    [data writeToFile: @"testOut.tiff" atomically: NO]
 

robbieduncan

Moderator emeritus
Jul 24, 2002
25,611
893
Harrogate
You've made some unsafe assumptions about the number of bytes in a row (I did this when I first started using these classes too).

The number of bytes in a row is not guaranteed to be pixels wide * samples per pixel. It's often padded for efficiency in reads a writes. You should use the methods in NSBitmapImageRep to read this. Also you should assuming RGB without Alpha may work but it's not always true!

Use this method to find the actual bytes per row instead of calculating it...
 

MrFusion

macrumors 6502a
Original poster
Jun 8, 2005
613
0
West-Europe
The number of bytes in a row is not guaranteed to be pixels wide * samples per pixel. It's often padded for efficiency in reads a writes. You should use the methods in NSBitmapImageRep to read this. Also you should assuming RGB without Alpha may work but it's not always true!

So, I should replace
Code:
cell_width * cell_height * 3
by
Code:
[bitmap bytesPerRow]
?

That doesn't work, I am afraid. Sorry, I am not familiar with these classes and how they behave. And unfortunately I don't have much time to find out, in contrast to the other simple cocoa things I am working on.
 

robbieduncan

Moderator emeritus
Jul 24, 2002
25,611
893
Harrogate
Nope.

Your assumption is the cell_width * 3 is the number of bytes in a row. This is not the case.

Your loop is over simplistic. You need two loops something like this:

Code:
int i, j, base;

for (i=0; i<cell_height;i++)
{
  for (j=0; j<cell_width; j++)
  {
    base = ([bitmap bytesPerRow] * i) + // This gets us onto the correct row
([bitmap samplesPerPixel] *j) // This moves us the correct number of pixels along the row

// So no r = bytes+base, g = bytes+base+1, b = bytes+base+2
  }
}

Note this is types straight into here: it might have bugs but this is the correct general idea...
 

MrFusion

macrumors 6502a
Original poster
Jun 8, 2005
613
0
West-Europe
Code:
	int cell_width, cell_height;
	
	//old image
	NSImage *image =[[NSImage alloc] initWithContentsOfFile:@"testIn.pdf"];
    NSBitmapImageRep *bitmap = [[[NSBitmapImageRep alloc] initWithData: [image TIFFRepresentation]] autorelease];
	unsigned char *bytes = [bitmap bitmapData];
	//new image
	[view1 setImage:image];
	cell_width = [bitmap pixelsWide];
	cell_height = [bitmap pixelsHigh];
	NSImage *newImage = [[NSImage alloc] initWithSize:NSMakeSize(cell_width,cell_height)];
		
	NSBitmapImageRep *new_bitmap = [[[NSBitmapImageRep alloc] initWithBitmapDataPlanes: NULL									pixelsWide: cell_width
				pixelsHigh: cell_height
			 bitsPerSample: 8
		   samplesPerPixel: 4
				  hasAlpha: YES
				  isPlanar: NO
		colorSpaceName: NSCalibratedRGBColorSpace
		   bytesPerRow: [bitmap bytesPerRow]
			  bitsPerPixel: 0] autorelease];
	unsigned char *newbytes = [new_bitmap bitmapData];
    
	int i,j, base,k=0;
		for (i=0;i< cell_height; i++) {
			for (j=0;j < cell_width; j++) { 
				unsigned char r, g, b;
				base =  ([bitmap bytesPerRow] * i) + ([bitmap samplesPerPixel] *j);
				r = *(bytes + base);
				g = *(bytes + base +1);
				b = *(bytes + base +2);
				if(r == 255 && g == 255 && b == 255){
					*(newbytes + k + 0) = 0;
					*(newbytes + k + 1) = 0;
					*(newbytes + k + 2) = 0;
					*(newbytes + k + 3) = 0;
				} else {
					*(newbytes + k + 0) = 0;
					*(newbytes + k + 1) = 0;
					*(newbytes + k + 2) = 0;
					*(newbytes + k + 3) = 255;			
				}
				k +=4;
			}
	}
    [newImage lockFocus];
    [new_bitmap draw];
   [newImage unlockFocus];

	NSData *data = [newImage TIFFRepresentation];
	[data writeToFile: @"testout.tiff"
		   atomically: NO];
		[view2 setImage:newImage];

This works!
Thanks.
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.