Skip to content

Commit

Permalink
Mac OS: more efficient handling of ARGB image data produced under
Browse files Browse the repository at this point in the history
Mac OS 10.11 when capturing screen data.

git-svn-id: file:///fltk/svn/fltk/branches/branch-1.3@10833 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
  • Loading branch information
Manolo Gouy authored and Manolo Gouy committed Aug 16, 2015
1 parent 9fe9fbe commit 60a7888
Showing 1 changed file with 29 additions and 31 deletions.
60 changes: 29 additions & 31 deletions src/Fl_cocoa.mm
Expand Up @@ -4093,6 +4093,15 @@ static void write_bitmap_inside(NSBitmapImageRep *to, int to_width, NSBitmapImag
to_width is the width in screen units of "to". On retina, its pixel width is twice that.
*/
{
const uchar *from_data = [from bitmapData];
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
if (fl_mac_os_version >= 100400 && ([to bitmapFormat] & NSAlphaFirstBitmapFormat) && !([from bitmapFormat] & NSAlphaFirstBitmapFormat) ) { // 10.4
// "to" is ARGB and "from" is RGBA --> convert "from" to ARGB
// it is enough to read "from" starting one byte earlier, because A is always 0xFF:
// RGBARGBA becomes (A)RGBARGB
from_data--;
}
#endif
int to_w = (int)[to pixelsWide]; // pixel width of "to"
int from_w = (int)[from pixelsWide]; // pixel width of "from"
int from_h = [from pixelsHigh]; // pixel height of "from"
Expand All @@ -4105,17 +4114,23 @@ static void write_bitmap_inside(NSBitmapImageRep *to, int to_width, NSBitmapImag
to_y = factor*to_y;
// perform the copy
uchar *tobytes = [to bitmapData] + to_y * to_w * to_depth + to_x * to_depth;
uchar *frombytes = [from bitmapData];
uchar *first = tobytes;
const uchar *frombytes = from_data;
for (int i = 0; i < from_h; i++) {
if (depth == 0) memcpy(tobytes, frombytes, from_w * from_depth);
else {
if (depth == 0) {
if (i > 0 || from_data >= [from bitmapData]) memcpy(tobytes, frombytes, from_w * from_depth);
else memcpy(tobytes+1, frombytes+1, from_w * from_depth-1); // avoid reading before [from bitmapData]
} else {
for (int j = 0; j < from_w; j++) {
memcpy(tobytes + j * to_depth, frombytes + j * from_depth, depth);
// avoid reading before [from bitmapData]
if (j==0 && i==0 && from_data < [from bitmapData]) memcpy(tobytes+1, frombytes+1, depth-1);
else memcpy(tobytes + j * to_depth, frombytes + j * from_depth, depth);
}
}
tobytes += to_w * to_depth;
frombytes += from_w * from_depth;
}
if (from_data == [from bitmapData] - 1) *first = 0xFF; // set the very first A byte
}


Expand Down Expand Up @@ -4191,20 +4206,6 @@ static void write_bitmap_inside(NSBitmapImageRep *to, int to_width, NSBitmapImag
if (childbitmap) {
// if bitmap is high res and childbitmap is not, childbitmap must be rescaled
if ([bitmap pixelsWide] > w && [childbitmap pixelsWide] == clip.size.width) childbitmap = scale_nsbitmapimagerep(childbitmap, 2);
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
if (fl_mac_os_version >= 100400 && ([bitmap bitmapFormat] & NSAlphaFirstBitmapFormat) && !([childbitmap bitmapFormat] & NSAlphaFirstBitmapFormat) ) { // 10.4
// bitmap is ARGB and childbitmap is RGBA --> convert childbitmap to ARGB too
uchar *b = [childbitmap bitmapData];
for (int i = 0; i < [childbitmap pixelsHigh]; i++) {
for (int j = 0; j < [childbitmap pixelsWide]; j++) {
uchar A = *(b+3);
memmove(b+1, b, 3);
*b = A;
b += 4;
}
}
}
#endif
write_bitmap_inside(bitmap, w, childbitmap,
clip.origin.x - x, win->h() - clip.origin.y - clip.size.height - y );
}
Expand All @@ -4228,22 +4229,18 @@ static void write_bitmap_inside(NSBitmapImageRep *to, int to_width, NSBitmapImag
int bpr = (int)[bitmap bytesPerRow];
int hh = bpp/bpr; // sometimes hh = h-1 for unclear reason, and hh = 2*h with retina
int ww = bpr/(*bytesPerPixel); // sometimes ww = w-1, and ww = 2*w with retina
const uchar *start = [bitmap bitmapData]; // start of the bitmap data
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
if (fl_mac_os_version >= 100400 && ([bitmap bitmapFormat] & NSAlphaFirstBitmapFormat)) { // imagerep is ARGB --> convert it to RGBA
uchar *b = [bitmap bitmapData];
for (int i = 0; i < hh; i++) {
for (int j = 0; j < ww; j++) {
uchar A = *b;
memmove(b, b+1, 3);
*(b+3) = A;
b += 4;
}
}
if (fl_mac_os_version >= 100400 && ([bitmap bitmapFormat] & NSAlphaFirstBitmapFormat)) {
// bitmap is ARGB --> convert it to RGBA
// it is enough to offset reading by one byte because A is always 0xFF
// so ARGBARGB becomes RGBARGBA as needed
start++;
}
#endif
unsigned char *data;
if (ww > w) { // with a retina display
Fl_RGB_Image *rgb = new Fl_RGB_Image([bitmap bitmapData], ww, hh, 4);
Fl_RGB_Image *rgb = new Fl_RGB_Image(start, ww, hh, 4);
Fl_RGB_Scaling save_scaling = Fl_Image::RGB_scaling();
Fl_Image::RGB_scaling(FL_RGB_SCALING_BILINEAR);
Fl_RGB_Image *rgb2 = (Fl_RGB_Image*)rgb->copy(w, h);
Expand All @@ -4256,9 +4253,9 @@ static void write_bitmap_inside(NSBitmapImageRep *to, int to_width, NSBitmapImag
else {
data = new unsigned char[w * h * *bytesPerPixel];
if (w == ww) {
memcpy(data, [bitmap bitmapData], w * hh * *bytesPerPixel);
memcpy(data, start, w * hh * *bytesPerPixel);
} else {
unsigned char *p = [bitmap bitmapData];
const uchar *p = start;
unsigned char *q = data;
for(int i = 0;i < hh; i++) {
memcpy(q, p, *bytesPerPixel * ww);
Expand All @@ -4267,6 +4264,7 @@ static void write_bitmap_inside(NSBitmapImageRep *to, int to_width, NSBitmapImag
}
}
}
if (start == [bitmap bitmapData] + 1) data[w*h*4-1] = 0xFF; // set the last A byte
[bitmap release];
return data;
}
Expand Down

0 comments on commit 60a7888

Please sign in to comment.