PDA

View Full Version : Transparency




MrFusion
Mar 1, 2007, 04:44 AM
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?


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
Mar 1, 2007, 08:09 AM
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 (http://developer.apple.com/documentation/Cocoa/Reference/ApplicationKit/Classes/NSBitmapImageRep_Class/Reference/Reference.html#//apple_ref/occ/instm/NSBitmapImageRep/bytesPerRow) to find the actual bytes per row instead of calculating it...

MrFusion
Mar 1, 2007, 08:56 AM
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

cell_width * cell_height * 3

by

[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
Mar 1, 2007, 09:06 AM
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:


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
Mar 1, 2007, 09:43 AM
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.