From 9e7fde1f92087555a08e3cc678b28bf7314d786d Mon Sep 17 00:00:00 2001 From: fredkiefer Date: Fri, 8 Feb 2008 22:40:38 +0000 Subject: [PATCH] Better support for transparent images and more image formats. Add background image in info panel. git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/gui/trunk@26043 72102866-910b-0410-8b05-ffd578937521 --- ChangeLog | 16 + Images/GNUmakefile | 1 + Images/LogoGNUstep.tiff | Bin 0 -> 84312 bytes Source/GSInfoPanel.m | 17 ++ Source/NSBitmapImageRep+PNG.m | 18 +- Source/NSBitmapImageRep.m | 554 ++++++++++++++++++++++++++++------ 6 files changed, 506 insertions(+), 100 deletions(-) create mode 100644 Images/LogoGNUstep.tiff diff --git a/ChangeLog b/ChangeLog index 63a1f1a83..fde92464c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,19 @@ +2008-02-08 Fred Kiefer + + * Images/LogoGNUstep.tiff: New files + * Images/GNUmakefile: Install new files. + * Source/GSInfoPanel.m (-initWithDictionary:): Add background + logo. Old patch by Nicolas Roard + * Source/NSBitmapImageRep.m : Flag all created bitmaps as having + or not having pre-muliplied alpha. + * Source/NSBitmapImageRep.m (-setColor:atX:y:, -colorAtX:y:, + -setPixel:atX:y:, -getPixel:atX:y:): Correct to handle most + formats correctly. + * Source/NSBitmapImageRep.m (-_premultiply, _unpremultiply): New + helper methods. + * Source/NSBitmapImage+PNG.m: Mark PNG images as not using + pre-muliplied alpha. + 2008-02-07 Fred Kiefer * Headers/AppKit/NSMenu.h, diff --git a/Images/GNUmakefile b/Images/GNUmakefile index ba978a7dc..82bdb8bef 100644 --- a/Images/GNUmakefile +++ b/Images/GNUmakefile @@ -34,6 +34,7 @@ imagedir = $(GNUSTEP_LIBRARY)/Images IMAGE_FILES = \ GNUstep_Images_Copyright \ +LogoGNUstep.tiff \ common_3DArrowUp.tiff \ common_3DArrowLeft.tiff \ common_3DArrowDown.tiff \ diff --git a/Images/LogoGNUstep.tiff b/Images/LogoGNUstep.tiff new file mode 100644 index 0000000000000000000000000000000000000000..bd305a7574c330d267de576a69bece15ef170360 GIT binary patch literal 84312 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 Z<{|aqFSHorj>= shift; + + return value & ((1<= _pixelsWide || y >= _pixelsHigh) { @@ -693,29 +735,90 @@ return; } + // FIXME: The y value is taken from the bottom of the image. + // Not sure if this is correct. + line_offset = _bytesPerRow * (_pixelsHigh - 1 - y); if (_isPlanar) { - // FIXME: The y value is taken from the bottom of the image. Not sure if this is correct. - offset = x + _bytesPerRow * (_pixelsHigh - 1 - y); - for (i = 0; i < _numColors; i++) + if (_bitsPerSample == 8) { - pixelData[i] = _imagePlanes[i][offset]; + offset = x + line_offset; + for (i = 0; i < _numColors; i++) + { + pixelData[i] = _imagePlanes[i][offset]; + } } - } + else + { + offset = _bitsPerPixel * x; + for (i = 0; i < _numColors; i++) + { + pixelData[i] = _get_bit_value(_imagePlanes[i] + line_offset, + offset, _bitsPerSample); + } + } + } else { - offset = _numColors * x + _bytesPerRow * (_pixelsHigh - 1 - y); - for (i = 0; i < _numColors; i++) + if (_bitsPerSample == 8) { - pixelData[i] = _imagePlanes[0][offset + i]; + offset = (_bitsPerPixel * x) / 8 + line_offset; + for (i = 0; i < _numColors; i++) + { + pixelData[i] = _imagePlanes[0][offset + i]; + } + } + else + { + offset = _bitsPerPixel * x; + for (i = 0; i < _numColors; i++) + { + pixelData[i] = _get_bit_value(_imagePlanes[0] + line_offset, + offset, _bitsPerSample); + offset += _bitsPerSample; + } } } } +static void +_set_bit_value(unsigned char *base, long msb_off, int bit_width, + unsigned int value) +{ + long lsb_off, byte1, byte2; + int shift; + int all; + + /* + * Firstly we calculate the position of the msb and lsb in terms + * of bit offsets and thus byte offsets. The shift is the number of + * spare bits left in the byte containing the lsb + */ + lsb_off= msb_off+bit_width-1; + byte1= msb_off/8; + byte2= lsb_off/8; + shift= 7-(lsb_off%8); + + /* + * We now set the value in the byte array, possibly using two bytes if + * the required set of bits crosses the byte boundary. This value is + * first shifted up to it's correct position and extraneous bits are + * masked off. + */ + value &= ((1<> 8) | (base[byte1] ^ (all >> 8)); + base[byte2] = (value & 255) | (base[byte2] ^ (all & 255)); +} + - (void) setPixel: (unsigned int[])pixelData atX: (int)x y: (int)y { int i; - int offset; + long int offset; + long int line_offset; if (x < 0 || y < 0 || x >= _pixelsWide || y >= _pixelsHigh) { @@ -728,20 +831,49 @@ // allocate plane memory [self bitmapData]; } + + // FIXME: The y value is taken from the bottom of the image. + // Not sure if this is correct. + line_offset = _bytesPerRow * (_pixelsHigh - 1 - y); if(_isPlanar) { - offset = x + _bytesPerRow * (_pixelsHigh - 1 - y); - for (i = 0; i < _numColors; i++) + if (_bitsPerSample == 8) { - _imagePlanes[i][offset] = pixelData[i]; + offset = x + line_offset; + for (i = 0; i < _numColors; i++) + { + _imagePlanes[i][offset] = pixelData[i]; + } + } + else + { + offset = _bitsPerPixel * x; + for (i = 0; i < _numColors; i++) + { + _set_bit_value(_imagePlanes[i] + line_offset, + offset, _bitsPerSample, pixelData[i]); + } } } else { - offset = _numColors * x + _bytesPerRow * (_pixelsHigh - 1 - y); - for (i = 0; i < _numColors; i++) + if (_bitsPerSample == 8) { - _imagePlanes[0][offset + i] = pixelData[i]; + offset = (_bitsPerPixel * x) / 8 + line_offset; + for (i = 0; i < _numColors; i++) + { + _imagePlanes[0][offset + i] = pixelData[i]; + } + } + else + { + offset = _bitsPerPixel * x; + for (i = 0; i < _numColors; i++) + { + _set_bit_value(_imagePlanes[0] + line_offset, + offset, _bitsPerSample, pixelData[i]); + offset += _bitsPerSample; + } } } } @@ -767,20 +899,39 @@ scale = (float)((1 << _bitsPerSample) - 1); if (_hasAlpha) { - // FIXME: This order depends on the bitmap format - ir = pixelData[0]; - ig = pixelData[1]; - ib = pixelData[2]; - ia = pixelData[3]; + // This order depends on the bitmap format + if (_format & NSAlphaFirstBitmapFormat) + { + ia = pixelData[0]; + ir = pixelData[1]; + ig = pixelData[2]; + ib = pixelData[3]; + } + else + { + ir = pixelData[0]; + ig = pixelData[1]; + ib = pixelData[2]; + ia = pixelData[3]; + } + // Scale to [0.0 ... 1.0] and undo premultiplication fa = ia / scale; - fr = ir / (scale * fa); - fg = ig / (scale * fa); - fb = ib / (scale * fa); + if (_format & NSAlphaNonpremultipliedBitmapFormat) + { + fr = ir / scale; + fg = ig / scale; + fb = ib / scale; + } + else + { + fr = ir / (scale * fa); + fg = ig / (scale * fa); + fb = ib / (scale * fa); + } } else { - // FIXME: This order depends on the bitmap format ir = pixelData[0]; ig = pixelData[1]; ib = pixelData[2]; @@ -816,11 +967,27 @@ if (_hasAlpha) { // FIXME: This order depends on the bitmap format - iw = pixelData[0]; - ia = pixelData[1]; + if (_format & NSAlphaFirstBitmapFormat) + { + ia = pixelData[0]; + iw = pixelData[1]; + } + else + { + iw = pixelData[0]; + ia = pixelData[1]; + } + // Scale to [0.0 ... 1.0] and undo premultiplication fa = ia / scale; - fw = iw / (scale * fa); + if (_format & NSAlphaNonpremultipliedBitmapFormat) + { + fw = iw / scale; + } + else + { + fw = iw / (scale * fa); + } } else { @@ -851,16 +1018,30 @@ scale = (float)((1 << _bitsPerSample) - 1); if (_hasAlpha) { - // FIXME: This order depends on the bitmap format - ib = pixelData[0]; - ia = pixelData[1]; + // This order depends on the bitmap format + if (_format & NSAlphaFirstBitmapFormat) + { + ia = pixelData[0]; + ib = pixelData[1]; + } + else + { + ib = pixelData[0]; + ia = pixelData[1]; + } // Scale to [0.0 ... 1.0] and undo premultiplication fa = ia / scale; - fw = 1.0 - ib / (scale * fa); + if (_format & NSAlphaNonpremultipliedBitmapFormat) + { + fw = 1.0 - ib / scale; + } + else + { + fw = 1.0 - ib / (scale * fa); + } } else { - // FIXME: This order depends on the bitmap format ib = pixelData[0]; // Scale to [0.0 ... 1.0] fw = 1.0 - ib / scale; @@ -886,22 +1067,43 @@ scale = (float)((1 << _bitsPerSample) - 1); if (_hasAlpha) { - // FIXME: This order depends on the bitmap format - ic = pixelData[0]; - im = pixelData[1]; - iy = pixelData[2]; - ib = pixelData[3]; - ia = pixelData[4]; + // This order depends on the bitmap format + if (_format & NSAlphaFirstBitmapFormat) + { + ia = pixelData[0]; + ic = pixelData[1]; + im = pixelData[2]; + iy = pixelData[3]; + ib = pixelData[4]; + } + else + { + ic = pixelData[0]; + im = pixelData[1]; + iy = pixelData[2]; + ib = pixelData[3]; + ia = pixelData[4]; + } + // Scale to [0.0 ... 1.0] and undo premultiplication fa = ia / scale; - fc = ic / (scale * fa); - fm = im / (scale * fa); - fy = iy / (scale * fa); - fb = ib / (scale * fa); + if (_format & NSAlphaNonpremultipliedBitmapFormat) + { + fc = ic / scale; + fm = im / scale; + fy = iy / scale; + fb = ib / scale; + } + else + { + fc = ic / (scale * fa); + fm = im / (scale * fa); + fy = iy / (scale * fa); + fb = ib / (scale * fa); + } } else { - // FIXME: This order depends on the bitmap format ic = pixelData[0]; im = pixelData[1]; iy = pixelData[2]; @@ -953,15 +1155,35 @@ if(_hasAlpha) { // Scale and premultiply alpha - ir = scale * fr * fa; - ig = scale * fg * fa; - ib = scale * fb * fa; + if (_format & NSAlphaNonpremultipliedBitmapFormat) + { + ir = scale * fr; + ig = scale * fg; + ib = scale * fb; + } + else + { + ir = scale * fr * fa; + ig = scale * fg * fa; + ib = scale * fb * fa; + } ia = scale * fa; - // FIXME: This order depends on the bitmap format - pixelData[0] = ir; - pixelData[1] = ig; - pixelData[2] = ib; - pixelData[3] = ia; + + // This order depends on the bitmap format + if (_format & NSAlphaFirstBitmapFormat) + { + pixelData[0] = ia; + pixelData[1] = ir; + pixelData[2] = ig; + pixelData[3] = ib; + } + else + { + pixelData[0] = ir; + pixelData[1] = ig; + pixelData[2] = ib; + pixelData[3] = ia; + } } else { @@ -969,7 +1191,7 @@ ir = scale * fr; ig = scale * fg; ib = scale * fb; - // FIXME: This order depends on the bitmap format + // This order depends on the bitmap format pixelData[0] = ir; pixelData[1] = ig; pixelData[2] = ib; @@ -986,11 +1208,27 @@ [conv getWhite: &fw alpha: &fa]; if (_hasAlpha) { - iw = scale * fw * fa; + if (_format & NSAlphaNonpremultipliedBitmapFormat) + { + iw = scale * fw; + } + else + { + iw = scale * fw * fa; + } ia = scale * fa; - // FIXME: This order depends on the bitmap format - pixelData[0] = iw; - pixelData[1] = ia; + + // This order depends on the bitmap format + if (_format & NSAlphaFirstBitmapFormat) + { + pixelData[0] = ia; + pixelData[1] = iw; + } + else + { + pixelData[0] = iw; + pixelData[1] = ia; + } } else { @@ -1009,11 +1247,27 @@ [conv getWhite: &fw alpha: &fa]; if (_hasAlpha) { - iw = scale * (1 - fw) * fa; + if (_format & NSAlphaNonpremultipliedBitmapFormat) + { + iw = scale * (1 - fw); + } + else + { + iw = scale * (1 - fw) * fa; + } ia = scale * fa; - // FIXME: This order depends on the bitmap format - pixelData[0] = iw; - pixelData[1] = ia; + + // This order depends on the bitmap format + if (_format & NSAlphaFirstBitmapFormat) + { + pixelData[0] = ia; + pixelData[1] = iw; + } + else + { + pixelData[0] = iw; + pixelData[1] = ia; + } } else { @@ -1031,17 +1285,39 @@ [conv getCyan: &fc magenta: &fm yellow: &fy black: &fb alpha: &fa]; if(_hasAlpha) { - ic = scale * fc * fa; - im = scale * fm * fa; - iy = scale * fy * fa; - ib = scale * fb * fa; + if (_format & NSAlphaNonpremultipliedBitmapFormat) + { + ic = scale * fc; + im = scale * fm; + iy = scale * fy; + ib = scale * fb; + } + else + { + ic = scale * fc * fa; + im = scale * fm * fa; + iy = scale * fy * fa; + ib = scale * fb * fa; + } ia = scale * fa; - // FIXME: This order depends on the bitmap format - pixelData[0] = ic; - pixelData[1] = im; - pixelData[2] = iy; - pixelData[3] = ib; - pixelData[4] = ia; + + // This order depends on the bitmap format + if (_format & NSAlphaFirstBitmapFormat) + { + pixelData[0] = ia; + pixelData[1] = ic; + pixelData[2] = im; + pixelData[3] = iy; + pixelData[4] = ib; + } + else + { + pixelData[0] = ic; + pixelData[1] = im; + pixelData[2] = iy; + pixelData[3] = ib; + pixelData[4] = ia; + } } else { @@ -1049,7 +1325,7 @@ im = scale * fm; iy = scale * fy; ib = scale * fb; - // FIXME: This order depends on the bitmap format + // This order depends on the bitmap format pixelData[0] = ic; pixelData[1] = im; pixelData[2] = iy; @@ -1183,6 +1459,7 @@ } info.extraSamples = (_hasAlpha) ? 1 : 0; + info.assocAlpha = (_format & NSAlphaNonpremultipliedBitmapFormat) ? 0 : 1; info.compression = [NSBitmapImageRep _localFromCompressionType: type]; if (factor < 0) factor = 0; @@ -1587,15 +1864,17 @@ } [self initWithBitmapDataPlanes: NULL - pixelsWide: info->width - pixelsHigh: info->height - bitsPerSample: info->bitsPerSample - samplesPerPixel: info->samplesPerPixel - hasAlpha: (info->extraSamples > 0) - isPlanar: (info->planarConfig == PLANARCONFIG_SEPARATE) - colorSpaceName: space - bytesPerRow: 0 - bitsPerPixel: 0]; + pixelsWide: info->width + pixelsHigh: info->height + bitsPerSample: info->bitsPerSample + samplesPerPixel: info->samplesPerPixel + hasAlpha: (info->extraSamples > 0) + isPlanar: (info->planarConfig == PLANARCONFIG_SEPARATE) + colorSpaceName: space + bitmapFormat: (info->assocAlpha ? 0 : + NSAlphaNonpremultipliedBitmapFormat) + bytesPerRow: 0 + bitsPerPixel: 0]; _compression = [NSBitmapImageRep _compressionTypeFromLocal: info->compression]; _comp_factor = 255 * (1 - ((float)info->quality)/100.0); @@ -1617,5 +1896,96 @@ return self; } -@end +- (void) _premultiply +{ + int x, y; + unsigned int pixelData[5]; + int start, end, i, ai; + float scale; + float alpha; + SEL getPSel = @selector(getPixel:atX:y:); + SEL setPSel = @selector(setPixel:atX:y:); + IMP getP = [self methodForSelector: getPSel]; + IMP setP = [self methodForSelector: setPSel]; + if (!_hasAlpha || !(_format & NSAlphaNonpremultipliedBitmapFormat)) + return; + + scale = (float)((1 << _bitsPerSample) - 1); + if (_format & NSAlphaFirstBitmapFormat) + { + ai = 0; + start = 1; + end = _numColors; + } + else + { + ai = _numColors - 1; + start = 0; + end = _numColors - 1; + } + + for (y = 0; y < _pixelsHigh; y++) + { + for (x = 0; x < _pixelsWide; x++) + { + //[self getPixel: pixelData atX: x y: y]; + getP(self, getPSel, pixelData, x, y); + alpha = pixelData[ai] / scale; + for (i = start; i < end; i++) + { + pixelData[i] *= alpha; + } + //[self setPixel: pixelData atX: x y: y]; + setP(self, setPSel, pixelData, x, y); + } + } +} + +- (void) _unpremultiply +{ + int x, y; + unsigned int pixelData[5]; + int start, end, i, ai; + float scale; + float alpha; + SEL getPSel = @selector(getPixel:atX:y:); + SEL setPSel = @selector(setPixel:atX:y:); + IMP getP = [self methodForSelector: getPSel]; + IMP setP = [self methodForSelector: setPSel]; + + if (!_hasAlpha || (_format & NSAlphaNonpremultipliedBitmapFormat)) + return; + + scale = (float)((1 << _bitsPerSample) - 1); + if (_format & NSAlphaFirstBitmapFormat) + { + ai = 0; + start = 1; + end = _numColors; + } + else + { + ai = _numColors - 1; + start = 0; + end = _numColors - 1; + } + + for (y = 0; y < _pixelsHigh; y++) + { + for (x = 0; x < _pixelsWide; x++) + { + //[self getPixel: pixelData atX: x y: y]; + getP(self, getPSel, pixelData, x, y); + alpha = pixelData[ai] / scale; + for (i = start; i < end; i++) + { + pixelData[i] /= alpha; + } + //[self setPixel: pixelData atX: x y: y]; + setP(self, setPSel, pixelData, x, y); + } + } +} + +@end