1/** <title>NSBitmapImageRep.m</title> 2 3 <abstract>Bitmap image representation.</abstract> 4 5 Copyright (C) 1996-2017 Free Software Foundation, Inc. 6 7 Author: Adam Fedor <fedor@gnu.org> 8 Date: Feb 1996 9 10 This file is part of the GNUstep GUI Library. 11 12 This library is free software; you can redistribute it and/or 13 modify it under the terms of the GNU Lesser General Public 14 License as published by the Free Software Foundation; either 15 version 2 of the License, or (at your option) any later version. 16 17 This library is distributed in the hope that it will be useful, 18 but WITHOUT ANY WARRANTY; without even the implied warranty of 19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 20 Lesser General Public License for more details. 21 22 You should have received a copy of the GNU Lesser General Public 23 License along with this library; see the file COPYING.LIB. 24 If not, see <http://www.gnu.org/licenses/> or write to the 25 Free Software Foundation, 51 Franklin Street, Fifth Floor, 26 Boston, MA 02110-1301, USA. 27*/ 28 29#import "config.h" 30 31#include <stdlib.h> 32#include <math.h> 33#include <tiff.h> 34 35#import <Foundation/NSArray.h> 36#import <Foundation/NSAutoreleasePool.h> 37#import <Foundation/NSData.h> 38#import <Foundation/NSDebug.h> 39#import <Foundation/NSException.h> 40#import <Foundation/NSFileManager.h> 41#import <Foundation/NSValue.h> 42#import "AppKit/AppKitExceptions.h" 43#import "AppKit/NSGraphics.h" 44#import "AppKit/NSGraphicsContext.h" 45#import "AppKit/NSPasteboard.h" 46#import "AppKit/NSView.h" 47#import "AppKit/NSBitmapImageRep.h" 48 49#import "NSBitmapImageRep+GIF.h" 50#import "NSBitmapImageRep+JPEG.h" 51#import "NSBitmapImageRep+PNG.h" 52#import "NSBitmapImageRep+PNM.h" 53#import "NSBitmapImageRep+ICNS.h" 54#import "NSBitmapImageRepPrivate.h" 55#import "GSGuiPrivate.h" 56 57#include "nsimage-tiff.h" 58 59/* Maximum number of planes */ 60#define MAX_PLANES 5 61 62 63/** 64 <unit> 65 <heading>Class Description</heading> 66 <p> 67 NSBitmapImageRep is an image representation for handling images composed 68 of pixels. The standard image format for NSBitmapImageRep is the TIFF 69 format. However, through the use of image filters and other methods, many 70 other standard image formats can be handled by NSBitmapImageRep. 71 72 Images are typically handled through the NSImage class and there is often 73 no need to use the NSBitmapImageRep class directly. However there may 74 be cases where you want to manipulate the image bitmap data directly. 75 </p> 76 </unit> 77*/ 78@implementation NSBitmapImageRep 79 80/** Returns YES if the image stored in data can be read and decoded */ 81+ (BOOL) canInitWithData: (NSData *)data 82{ 83 if (data == nil) 84 { 85 return NO; 86 } 87 88#if HAVE_LIBPNG 89 if ([self _bitmapIsPNG: data]) 90 return YES; 91#endif 92 93 if ([self _bitmapIsPNM: data]) 94 return YES; 95 96#if HAVE_LIBJPEG 97 if ([self _bitmapIsJPEG: data]) 98 return YES; 99#endif 100 101#if HAVE_LIBUNGIF || HAVE_LIBGIF 102 if ([self _bitmapIsGIF: data]) 103 return YES; 104#endif 105 106 if ([self _bitmapIsICNS: data]) 107 return YES; 108 109 if ([self _bitmapIsTIFF: data]) 110 return YES; 111 112 return NO; 113} 114 115/** Returns a list of image filename extensions that are understood by 116 NSBitmapImageRep. */ 117+ (NSArray *) imageUnfilteredFileTypes 118{ 119 static NSArray *types = nil; 120 121 if (types == nil) 122 { 123 types = [[NSArray alloc] initWithObjects: 124 @"tiff", @"tif", 125 @"pnm", @"ppm", 126#if HAVE_LIBUNGIF || HAVE_LIBGIF 127 @"gif", 128#endif 129#if HAVE_LIBJPEG 130 @"jpeg", @"jpg", 131#endif 132#if HAVE_LIBPNG 133 @"png", 134#endif 135 @"icns", 136 nil]; 137 } 138 139 return types; 140} 141 142/** Returns a list of image pasteboard types that are understood by 143 NSBitmapImageRep. */ 144+ (NSArray *) imageUnfilteredPasteboardTypes 145{ 146 static NSArray *types = nil; 147 148 if (types == nil) 149 { 150 types = [[NSArray alloc] initWithObjects: NSTIFFPboardType, nil]; 151 } 152 153 return types; 154} 155 156/** <p>Returns a newly allocated NSBitmapImageRep object representing the 157 image stored in imageData. If the image data contains more than one 158 image, the first one is choosen.</p><p>See Also: +imageRepsWithData:</p> 159*/ 160+ (id) imageRepWithData: (NSData *)imageData 161{ 162 return AUTORELEASE([[self alloc] initWithData: imageData]); 163} 164 165/**<p>Returns an array containing newly allocated NSBitmapImageRep 166 objects representing the images stored in imageData.</p> 167 <p>See Also: +imageRepWithData:</p> 168*/ 169+ (NSArray*) imageRepsWithData: (NSData *)imageData 170{ 171 if (imageData == nil) 172 { 173 NSLog(@"NSBitmapImageRep: nil image data"); 174 return [NSArray array]; 175 } 176 177 if ([self _bitmapIsPNG: imageData]) 178 { 179 NSBitmapImageRep *rep; 180 NSArray *a; 181 182 rep = [[self alloc] _initBitmapFromPNG: imageData]; 183 if (!rep) 184 return [NSArray array]; 185 a = [NSArray arrayWithObject: rep]; 186 DESTROY(rep); 187 return a; 188 } 189 190 if ([self _bitmapIsPNM: imageData]) 191 { 192 NSBitmapImageRep *rep; 193 NSArray *a; 194 195 rep = [[self alloc] _initBitmapFromPNM: imageData 196 errorMessage: NULL]; 197 if (!rep) 198 return [NSArray array]; 199 a = [NSArray arrayWithObject: rep]; 200 DESTROY(rep); 201 return a; 202 } 203 204 if ([self _bitmapIsJPEG: imageData]) 205 { 206 NSBitmapImageRep *rep; 207 NSArray *a; 208 209 rep = [[self alloc] _initBitmapFromJPEG: imageData 210 errorMessage: NULL]; 211 if (!rep) 212 return [NSArray array]; 213 a = [NSArray arrayWithObject: rep]; 214 DESTROY(rep); 215 return a; 216 } 217 218 if ([self _bitmapIsGIF: imageData]) 219 { 220 NSBitmapImageRep *rep; 221 NSArray *a; 222 223 rep = [[self alloc] _initBitmapFromGIF: imageData 224 errorMessage: NULL]; 225 if (!rep) 226 return [NSArray array]; 227 a = [NSArray arrayWithObject: rep]; 228 DESTROY(rep); 229 return a; 230 } 231 232 if ([self _bitmapIsICNS: imageData]) 233 { 234 return [self _imageRepsWithICNSData: imageData]; 235 } 236 237 if ([self _bitmapIsTIFF: imageData]) 238 { 239 return [self _imageRepsWithTIFFData: imageData]; 240 } 241 242 NSLog(@"NSBitmapImageRep: unable to parse bitmap image data"); 243 return [NSArray array]; 244} 245 246/** Loads only the default (first) image from the image contained in 247 data. */ 248- (id) initWithData: (NSData *)imageData 249{ 250 Class class; 251 252 if (imageData == nil) 253 { 254 RELEASE(self); 255 return nil; 256 } 257 258 class = [self class]; 259 if ([class _bitmapIsPNG: imageData]) 260 return [self _initBitmapFromPNG: imageData]; 261 262 if ([class _bitmapIsPNM: imageData]) 263 return [self _initBitmapFromPNM: imageData 264 errorMessage: NULL]; 265 266 if ([class _bitmapIsJPEG: imageData]) 267 return [self _initBitmapFromJPEG: imageData 268 errorMessage: NULL]; 269 270 if ([class _bitmapIsGIF: imageData]) 271 return [self _initBitmapFromGIF: imageData 272 errorMessage: NULL]; 273 274 if ([class _bitmapIsICNS: imageData]) 275 return [self _initBitmapFromICNS: imageData]; 276 277 if ([class _bitmapIsTIFF: imageData]) 278 return [self _initBitmapFromTIFF: imageData]; 279 280 DESTROY(self); 281 return nil; 282} 283 284/** Initialize with bitmap data from a rect within the focused view */ 285- (id) initWithFocusedViewRect: (NSRect)rect 286{ 287 NSInteger bps, spp, alpha, format; 288 NSSize size; 289 NSString *space; 290 unsigned char *planes[4]; 291 NSDictionary *dict; 292 293 dict = [GSCurrentContext() GSReadRect: rect]; 294 if (dict == nil) 295 { 296 NSLog(@"NSBitmapImageRep initWithFocusedViewRect: failed"); 297 RELEASE(self); 298 return nil; 299 } 300 _imageData = RETAIN([dict objectForKey: @"Data"]); 301 if (_imageData == nil || [_imageData length] == 0) 302 { 303 NSLog(@"NSBitmapImageRep initWithFocusedViewRect: failed"); 304 RELEASE(self); 305 return nil; 306 } 307 bps = [[dict objectForKey: @"BitsPerSample"] intValue]; 308 if (bps == 0) 309 bps = 8; 310 spp = [[dict objectForKey: @"SamplesPerPixel"] intValue]; 311 alpha = [[dict objectForKey: @"HasAlpha"] intValue]; 312 size = [[dict objectForKey: @"Size"] sizeValue]; 313 space = [dict objectForKey: @"ColorSpace"]; 314 format = [[dict objectForKey: @"BitmapFormat"] intValue]; 315 planes[0] = (unsigned char *)[_imageData bytes]; 316 self = [self initWithBitmapDataPlanes: planes 317 pixelsWide: size.width 318 pixelsHigh: size.height 319 bitsPerSample: bps 320 samplesPerPixel: spp 321 hasAlpha: (alpha) ? YES : NO 322 isPlanar: NO 323 colorSpaceName: space 324 bitmapFormat: format 325 bytesPerRow: 0 326 bitsPerPixel: 0]; 327 return self; 328} 329 330/** 331 <init /> 332 <p> 333 Initializes a newly created NSBitmapImageRep object to hold image data 334 specified in the planes buffer and organized according to the 335 additional arguments passed into the method. 336 </p> 337 <p> 338 The planes argument is an array of char pointers where each array 339 holds a single component or plane of data. Note that if data is 340 passed into the method via planes, the data is NOT copied and not 341 freed when the object is deallocated. It is assumed that the data 342 will always be available. If planes is NULL, then a suitable amount 343 of memory will be allocated to store the information needed. One can 344 then obtain a pointer to the planes data using the -bitmapData or 345 -getBitmapDataPlanes: method. 346 </p> 347 <p> 348 Each component of the data is in "standard" order, such as red, green, 349 blue for RGB color images. The transparency component, if these is one, should 350 always be last. 351 </p> 352 <p> 353 The other arguments to the method consist of: 354 </p> 355 <deflist> 356 <term>width and height</term> 357 <desc>The width and height of the image in pixels</desc> 358 <term>bps</term> 359 <desc> 360 The bits per sample or the number of bits used to store a number in 361 one component of one pixel of the image. Typically this is 8 (bits) 362 but can be 2 or 4, although not all values are supported. 363 </desc> 364 <term>spp</term> 365 <desc> 366 Samples per pixel, or the number of components of color in the pixel. 367 For instance this would be 4 for an RGB image with transparency. 368 </desc> 369 <term>alpha</term> 370 <desc> 371 Set to YES if the image has a transparency component. 372 </desc> 373 <term>isPlanar</term> 374 <desc> 375 Set to YES if the data is arranged in planes, i.e. one component 376 per buffer as stored in the planes array. If NO, then the image data 377 is mixed in one buffer. For instance, for RGB data, the first sample 378 would contain red, then next green, then blue, followed by red for the 379 next pixel. 380 </desc> 381 <term>colorSpaceName</term> 382 <desc> 383 This argument specifies how the data values are to be interpreted. 384 Possible values include the typical colorspace names (although 385 not all values are currently supported) 386 </desc> 387 <term>rowBytes</term> 388 <desc> 389 Specifies the number of bytes contained in a single scan line of the 390 data. Normally this can be computed from the width of the image, 391 the samples per pixel and the bits per sample. However, if the data 392 is aligned along word boundaries, this value may differ from this. 393 If rowBytes is 0, the method will calculate the value assuming there 394 are no extra bytes at the end of the scan line. 395 </desc> 396 <term>pixelBits</term> 397 <desc> 398 This is normally bps for planar data and bps times spp for non-planar 399 data, but sometimes images have extra bits. If pixelBits is 0 it 400 will be calculated as described above. 401 </desc> 402 </deflist> 403*/ 404- (id) initWithBitmapDataPlanes: (unsigned char **)planes 405 pixelsWide: (NSInteger)width 406 pixelsHigh: (NSInteger)height 407 bitsPerSample: (NSInteger)bitsPerSample 408 samplesPerPixel: (NSInteger)samplesPerPixel 409 hasAlpha: (BOOL)alpha 410 isPlanar: (BOOL)isPlanar 411 colorSpaceName: (NSString *)colorSpaceName 412 bytesPerRow: (NSInteger)rowBytes 413 bitsPerPixel: (NSInteger)pixelBits 414{ 415 return [self initWithBitmapDataPlanes: planes 416 pixelsWide: width 417 pixelsHigh: height 418 bitsPerSample: bitsPerSample 419 samplesPerPixel: samplesPerPixel 420 hasAlpha: alpha 421 isPlanar: isPlanar 422 colorSpaceName: colorSpaceName 423 bitmapFormat: 0 424 bytesPerRow: rowBytes 425 bitsPerPixel: pixelBits]; 426} 427 428- (id) initWithBitmapDataPlanes: (unsigned char**)planes 429 pixelsWide: (NSInteger)width 430 pixelsHigh: (NSInteger)height 431 bitsPerSample: (NSInteger)bps 432 samplesPerPixel: (NSInteger)spp 433 hasAlpha: (BOOL)alpha 434 isPlanar: (BOOL)isPlanar 435 colorSpaceName: (NSString*)colorSpaceName 436 bitmapFormat: (NSBitmapFormat)bitmapFormat 437 bytesPerRow: (NSInteger)rowBytes 438 bitsPerPixel: (NSInteger)pixelBits 439{ 440 NSDebugLLog(@"NSImage", @"Creating bitmap image with pw %d ph %d bps %d spp %d alpha %d, planar %d cs %@", 441 (int)width,(int) height, (int)bps, (int)spp, alpha, isPlanar, colorSpaceName); 442 if (!bps || !spp || !width || !height) 443 { 444 [NSException raise: NSInvalidArgumentException 445 format: @"Required arguments not specified creating NSBitmapImageRep"]; 446 } 447 448 _pixelsWide = width; 449 _pixelsHigh = height; 450 _size.width = width; 451 _size.height = height; 452 _bitsPerSample = bps; 453 _numColors = spp; 454 _hasAlpha = alpha; 455 _isPlanar = isPlanar; 456 _colorSpace = RETAIN(colorSpaceName); 457 _format = bitmapFormat; 458 if (!pixelBits) 459 pixelBits = bps * ((_isPlanar) ? 1 : spp); 460 _bitsPerPixel = pixelBits; 461 if (!rowBytes) 462 rowBytes = ceil((float)width * _bitsPerPixel / 8); 463 _bytesPerRow = rowBytes; 464 465 _imagePlanes = NSAllocateCollectable(sizeof(unsigned char*) * MAX_PLANES, 0); 466 if (planes) 467 { 468 unsigned int i; 469 470 for (i = 0; i < MAX_PLANES; i++) 471 _imagePlanes[i] = NULL; 472 for (i = 0; i < ((_isPlanar) ? _numColors : 1); i++) 473 _imagePlanes[i] = planes[i]; 474 } 475 else 476 { 477 unsigned char *bits; 478 NSUInteger length; 479 unsigned int i; 480 481 // No image data was given, allocate it. 482 length = (NSUInteger)((_isPlanar) ? _numColors : 1) * _bytesPerRow * 483 _pixelsHigh * sizeof(unsigned char); 484 // Create a mutable data object although we never use it as such 485 _imageData = [[NSMutableData alloc] initWithLength: length]; 486 bits = (unsigned char *)[_imageData bytes]; 487 _imagePlanes[0] = bits; 488 if (_isPlanar) 489 { 490 for (i = 1; i < _numColors; i++) 491 _imagePlanes[i] = bits + i * _bytesPerRow * _pixelsHigh; 492 for (i = _numColors; i < MAX_PLANES; i++) 493 _imagePlanes[i] = NULL; 494 } 495 else 496 { 497 for (i = 1; i < MAX_PLANES; i++) 498 _imagePlanes[i] = NULL; 499 } 500 } 501 502 if (alpha) 503 { 504 unsigned char *bData = (unsigned char*)[self bitmapData]; 505 BOOL allOpaque = YES; 506 unsigned offset = _numColors - 1; 507 unsigned limit = _size.height * _size.width; 508 unsigned i; 509 510 for (i = 0; i < limit; i++) 511 { 512 unsigned a; 513 514 bData += offset; 515 a = *bData++; 516 if (a != 255) 517 { 518 allOpaque = NO; 519 break; 520 } 521 } 522 [self setOpaque: allOpaque]; 523 } 524 else 525 { 526 [self setOpaque: YES]; 527 } 528 _properties = [[NSMutableDictionary alloc] init]; 529 530 return self; 531} 532 533- (void)colorizeByMappingGray:(CGFloat)midPoint 534 toColor:(NSColor *)midPointColor 535 blackMapping:(NSColor *)shadowColor 536 whiteMapping:(NSColor *)lightColor 537{ 538 // TODO 539} 540 541- (id)initWithBitmapHandle:(void *)bitmap 542{ 543 // TODO Only needed on MS Windows 544 RELEASE(self); 545 return nil; 546} 547 548- (id)initWithIconHandle:(void *)icon 549{ 550 // TODO Only needed on MS Windows 551 RELEASE(self); 552 return nil; 553} 554 555- (id) initForIncrementalLoad 556{ 557 // FIXME 558 return self; 559} 560 561- (NSInteger) incrementalLoadFromData: (NSData *)data complete: (BOOL)complete 562{ 563 if (!complete) 564 { 565 // we don't implement it really 566 return NSImageRepLoadStatusWillNeedAllData; 567 } 568 return [self initWithData: data] ? NSImageRepLoadStatusCompleted : NSImageRepLoadStatusUnexpectedEOF; 569} 570 571- (void) dealloc 572{ 573 NSZoneFree([self zone],_imagePlanes); 574 RELEASE(_imageData); 575 RELEASE(_properties); 576 [super dealloc]; 577} 578 579// 580// Getting Information about the Image 581// 582/** Returns the number of bits need to contain one pixels worth of data. 583 This is normally the number of samples per pixel times the number of 584 bits in one sample. */ 585- (NSInteger) bitsPerPixel 586{ 587 return _bitsPerPixel; 588} 589 590/** Returns the number of samples in a pixel. For instance, a normal RGB 591 image with transparency would have a samplesPerPixel of 4. */ 592- (NSInteger) samplesPerPixel 593{ 594 return _numColors; 595} 596 597/** Returns YES if the image components are stored separately. Returns 598 NO if the components are meshed (i.e. all the samples for one pixel 599 come before the next pixel). */ 600- (BOOL) isPlanar 601{ 602 return _isPlanar; 603} 604 605/** Returns the number of planes in an image. Typically this is 606 equal to the number of samples in a planar image or 1 for a non-planar 607 image. */ 608- (NSInteger) numberOfPlanes 609{ 610 return (_isPlanar) ? _numColors : 1; 611} 612 613/** Returns the number of bytes in a plane. This is the number of bytes 614 in a row times tne height of the image. */ 615- (NSInteger) bytesPerPlane 616{ 617 return _bytesPerRow*_pixelsHigh; 618} 619 620/** Returns the number of bytes in a row. This is typically based on the 621 width of the image and the bits per sample and samples per pixel (if 622 in medhed configuration). However it may differ from this if set 623 explicitly in -initWithBitmapDataPlanes:pixelsWide:pixelsHigh:bitsPerSample:samplesPerPixel:hasAlpha:isPlanar:colorSpaceName:bytesPerRow:bitsPerPixel:. 624*/ 625- (NSInteger) bytesPerRow 626{ 627 return _bytesPerRow; 628} 629 630// 631// Getting Image Data 632// 633/** Returns the first plane of data representing the image. */ 634- (unsigned char *) bitmapData 635{ 636 unsigned char *planes[MAX_PLANES]; 637 [self getBitmapDataPlanes: planes]; 638 return planes[0]; 639} 640 641/** Files the array data with pointers to each of the data planes 642 representing the image. The data array must be allocated to contain 643 at least -samplesPerPixel pointers. */ 644- (void) getBitmapDataPlanes: (unsigned char **)data 645{ 646 unsigned int i; 647 648 if (data) 649 { 650 for (i = 0; i < _numColors; i++) 651 { 652 data[i] = _imagePlanes[i]; 653 } 654 } 655} 656 657- (NSBitmapFormat) bitmapFormat 658{ 659 return _format; 660} 661 662/* 663 * This code was copied over from XGBitmap.m 664 * Here we extract a value a given number of bits wide from a bit 665 * offset into a block of memory starting at "base". The bit numbering 666 * is assumed to be such that a bit offset of zero and a width of 4 gives 667 * the upper 4 bits of the first byte, *not* the lower 4 bits. We do allow 668 * the value to cross a byte boundary, though it is unclear as to whether 669 * this is strictly necessary for OpenStep tiffs. 670 */ 671static unsigned int 672_get_bit_value(unsigned char *base, long msb_off, int bit_width) 673{ 674 long lsb_off, byte1, byte2; 675 int shift, value; 676 677 /* 678 * Firstly we calculate the position of the msb and lsb in terms 679 * of bit offsets and thus byte offsets. The shift is the number of 680 * spare bits left in the byte containing the lsb 681 */ 682 lsb_off= msb_off+bit_width-1; 683 byte1= msb_off/8; 684 byte2= lsb_off/8; 685 shift= 7-(lsb_off%8); 686 687 /* 688 * We now get the value from the byte array, possibly using two bytes if 689 * the required set of bits crosses the byte boundary. This is then shifted 690 * down to it's correct position and extraneous bits masked off before 691 * being returned. 692 */ 693 value=base[byte2]; 694 if (byte1!=byte2) 695 value|= base[byte1]<<8; 696 value >>= shift; 697 698 return value & ((1<<bit_width)-1); 699} 700 701/** 702 * Returns the values of the components of pixel (x,y), where (0,0) is the 703 * top-left pixel in the image, by storing them in the array pixelData. 704 */ 705- (void) getPixel: (NSUInteger[])pixelData atX: (NSInteger)x y: (NSInteger)y 706{ 707 NSInteger i; 708 NSInteger offset; 709 NSInteger line_offset; 710 711 if (x < 0 || y < 0 || x >= _pixelsWide || y >= _pixelsHigh) 712 { 713 // outside 714 return; 715 } 716 717 line_offset = _bytesPerRow * y; 718 if (_isPlanar) 719 { 720 if (_bitsPerSample == 8) 721 { 722 offset = x + line_offset; 723 for (i = 0; i < _numColors; i++) 724 { 725 pixelData[i] = _imagePlanes[i][offset]; 726 } 727 } 728 else 729 { 730 offset = _bitsPerPixel * x; 731 for (i = 0; i < _numColors; i++) 732 { 733 pixelData[i] = _get_bit_value(_imagePlanes[i] + line_offset, 734 offset, _bitsPerSample); 735 } 736 } 737 } 738 else 739 { 740 if (_bitsPerSample == 8) 741 { 742 offset = (_bitsPerPixel * x) / 8 + line_offset; 743 for (i = 0; i < _numColors; i++) 744 { 745 pixelData[i] = _imagePlanes[0][offset + i]; 746 } 747 } 748 else 749 { 750 offset = _bitsPerPixel * x; 751 for (i = 0; i < _numColors; i++) 752 { 753 pixelData[i] = _get_bit_value(_imagePlanes[0] + line_offset, 754 offset, _bitsPerSample); 755 offset += _bitsPerSample; 756 } 757 } 758 } 759} 760 761static void 762_set_bit_value(unsigned char *base, long msb_off, int bit_width, 763 unsigned int value) 764{ 765 long lsb_off, byte1, byte2; 766 int shift; 767 int all; 768 769 /* 770 * Firstly we calculate the position of the msb and lsb in terms 771 * of bit offsets and thus byte offsets. The shift is the number of 772 * spare bits left in the byte containing the lsb 773 */ 774 lsb_off= msb_off+bit_width-1; 775 byte1= msb_off/8; 776 byte2= lsb_off/8; 777 shift= 7-(lsb_off%8); 778 779 /* 780 * We now set the value in the byte array, possibly using two bytes if 781 * the required set of bits crosses the byte boundary. This value is 782 * first shifted up to it's correct position and extraneous bits are 783 * masked off. 784 */ 785 value &= ((1<<bit_width)-1); 786 value <<= shift; 787 all = ((1<<bit_width)-1) << shift; 788 789 if (byte1 != byte2) 790 base[byte1] = (value >> 8) | (base[byte1] & ~(all >> 8)); 791 base[byte2] = (value & 255) | (base[byte2] & ~(all & 255)); 792} 793 794/** 795 * Sets the components of pixel (x,y), where (0,0) is the top-left pixel in 796 * the image, to the given array of pixel components. 797 */ 798- (void) setPixel: (NSUInteger[])pixelData atX: (NSInteger)x y: (NSInteger)y 799{ 800 NSInteger i; 801 NSInteger offset; 802 NSInteger line_offset; 803 804 if (x < 0 || y < 0 || x >= _pixelsWide || y >= _pixelsHigh) 805 { 806 // outside 807 return; 808 } 809 810 if (!_imagePlanes || !_imagePlanes[0]) 811 { 812 // allocate plane memory 813 [self bitmapData]; 814 } 815 816 line_offset = _bytesPerRow * y; 817 if (_isPlanar) 818 { 819 if (_bitsPerSample == 8) 820 { 821 offset = x + line_offset; 822 for (i = 0; i < _numColors; i++) 823 { 824 _imagePlanes[i][offset] = pixelData[i]; 825 } 826 } 827 else 828 { 829 offset = _bitsPerPixel * x; 830 for (i = 0; i < _numColors; i++) 831 { 832 _set_bit_value(_imagePlanes[i] + line_offset, 833 offset, _bitsPerSample, pixelData[i]); 834 } 835 } 836 } 837 else 838 { 839 if (_bitsPerSample == 8) 840 { 841 offset = (_bitsPerPixel * x) / 8 + line_offset; 842 for (i = 0; i < _numColors; i++) 843 { 844 _imagePlanes[0][offset + i] = pixelData[i]; 845 } 846 } 847 else 848 { 849 offset = _bitsPerPixel * x; 850 for (i = 0; i < _numColors; i++) 851 { 852 _set_bit_value(_imagePlanes[0] + line_offset, 853 offset, _bitsPerSample, pixelData[i]); 854 offset += _bitsPerSample; 855 } 856 } 857 } 858} 859 860/** 861 * Returns an NSColor object representing the color of the pixel (x,y), where 862 * (0,0) is the top-left pixel in the image. 863 */ 864- (NSColor*) colorAtX: (NSInteger)x y: (NSInteger)y 865{ 866 NSUInteger pixelData[5]; 867 868 if (x < 0 || y < 0 || x >= _pixelsWide || y >= _pixelsHigh) 869 { 870 // outside 871 return nil; 872 } 873 874 [self getPixel: pixelData atX: x y: y]; 875 if ([_colorSpace isEqualToString: NSCalibratedRGBColorSpace] 876 || [_colorSpace isEqualToString: NSDeviceRGBColorSpace]) 877 { 878 NSUInteger ir, ig, ib, ia; 879 CGFloat fr, fg, fb, fa; 880 CGFloat scale; 881 882 scale = (CGFloat)((1 << _bitsPerSample) - 1); 883 if (_hasAlpha) 884 { 885 // This order depends on the bitmap format 886 if (_format & NSAlphaFirstBitmapFormat) 887 { 888 ia = pixelData[0]; 889 ir = pixelData[1]; 890 ig = pixelData[2]; 891 ib = pixelData[3]; 892 } 893 else 894 { 895 ir = pixelData[0]; 896 ig = pixelData[1]; 897 ib = pixelData[2]; 898 ia = pixelData[3]; 899 } 900 901 // Scale to [0.0 ... 1.0] and undo premultiplication 902 fa = ia / scale; 903 if (_format & NSAlphaNonpremultipliedBitmapFormat) 904 { 905 fr = ir / scale; 906 fg = ig / scale; 907 fb = ib / scale; 908 } 909 else 910 { 911 fr = ir / (scale * fa); 912 fg = ig / (scale * fa); 913 fb = ib / (scale * fa); 914 } 915 } 916 else 917 { 918 ir = pixelData[0]; 919 ig = pixelData[1]; 920 ib = pixelData[2]; 921 // Scale to [0.0 ... 1.0] 922 fr = ir / scale; 923 fg = ig / scale; 924 fb = ib / scale; 925 fa = 1.0; 926 } 927 if ([_colorSpace isEqualToString: NSCalibratedRGBColorSpace]) 928 { 929 return [NSColor colorWithCalibratedRed: fr 930 green: fg 931 blue: fb 932 alpha: fa]; 933 } 934 else 935 { 936 return [NSColor colorWithDeviceRed: fr 937 green: fg 938 blue: fb 939 alpha: fa]; 940 } 941 } 942 else if ([_colorSpace isEqual: NSDeviceWhiteColorSpace] 943 || [_colorSpace isEqual: NSCalibratedWhiteColorSpace]) 944 { 945 NSUInteger iw, ia; 946 CGFloat fw, fa; 947 CGFloat scale; 948 949 scale = (CGFloat)((1 << _bitsPerSample) - 1); 950 if (_hasAlpha) 951 { 952 // FIXME: This order depends on the bitmap format 953 if (_format & NSAlphaFirstBitmapFormat) 954 { 955 ia = pixelData[0]; 956 iw = pixelData[1]; 957 } 958 else 959 { 960 iw = pixelData[0]; 961 ia = pixelData[1]; 962 } 963 964 // Scale to [0.0 ... 1.0] and undo premultiplication 965 fa = ia / scale; 966 if (_format & NSAlphaNonpremultipliedBitmapFormat) 967 { 968 fw = iw / scale; 969 } 970 else 971 { 972 fw = iw / (scale * fa); 973 } 974 } 975 else 976 { 977 // FIXME: This order depends on the bitmap format 978 iw = pixelData[0]; 979 // Scale to [0.0 ... 1.0] 980 fw = iw / scale; 981 fa = 1.0; 982 } 983 if ([_colorSpace isEqualToString: NSCalibratedWhiteColorSpace]) 984 { 985 return [NSColor colorWithCalibratedWhite: fw 986 alpha: fa]; 987 } 988 else 989 { 990 return [NSColor colorWithDeviceWhite: fw 991 alpha: fa]; 992 } 993 } 994 else if ([_colorSpace isEqual: NSDeviceBlackColorSpace] 995 || [_colorSpace isEqual: NSCalibratedBlackColorSpace]) 996 { 997 NSUInteger ib, ia; 998 CGFloat fw, fa; 999 CGFloat scale; 1000 1001 scale = (CGFloat)((1 << _bitsPerSample) - 1); 1002 if (_hasAlpha) 1003 { 1004 // This order depends on the bitmap format 1005 if (_format & NSAlphaFirstBitmapFormat) 1006 { 1007 ia = pixelData[0]; 1008 ib = pixelData[1]; 1009 } 1010 else 1011 { 1012 ib = pixelData[0]; 1013 ia = pixelData[1]; 1014 } 1015 // Scale to [0.0 ... 1.0] and undo premultiplication 1016 fa = ia / scale; 1017 if (_format & NSAlphaNonpremultipliedBitmapFormat) 1018 { 1019 fw = 1.0 - ib / scale; 1020 } 1021 else 1022 { 1023 fw = 1.0 - ib / (scale * fa); 1024 } 1025 } 1026 else 1027 { 1028 ib = pixelData[0]; 1029 // Scale to [0.0 ... 1.0] 1030 fw = 1.0 - ib / scale; 1031 fa = 1.0; 1032 } 1033 if ([_colorSpace isEqualToString: NSCalibratedBlackColorSpace]) 1034 { 1035 return [NSColor colorWithCalibratedWhite: fw 1036 alpha: fa]; 1037 } 1038 else 1039 { 1040 return [NSColor colorWithDeviceWhite: fw 1041 alpha: fa]; 1042 } 1043 } 1044 else if ([_colorSpace isEqual: NSDeviceCMYKColorSpace]) 1045 { 1046 NSUInteger ic, im, iy, ib, ia; 1047 CGFloat fc, fm, fy, fb, fa; 1048 CGFloat scale; 1049 1050 scale = (CGFloat)((1 << _bitsPerSample) - 1); 1051 if (_hasAlpha) 1052 { 1053 // This order depends on the bitmap format 1054 if (_format & NSAlphaFirstBitmapFormat) 1055 { 1056 ia = pixelData[0]; 1057 ic = pixelData[1]; 1058 im = pixelData[2]; 1059 iy = pixelData[3]; 1060 ib = pixelData[4]; 1061 } 1062 else 1063 { 1064 ic = pixelData[0]; 1065 im = pixelData[1]; 1066 iy = pixelData[2]; 1067 ib = pixelData[3]; 1068 ia = pixelData[4]; 1069 } 1070 1071 // Scale to [0.0 ... 1.0] and undo premultiplication 1072 fa = ia / scale; 1073 if (_format & NSAlphaNonpremultipliedBitmapFormat) 1074 { 1075 fc = ic / scale; 1076 fm = im / scale; 1077 fy = iy / scale; 1078 fb = ib / scale; 1079 } 1080 else 1081 { 1082 fc = ic / (scale * fa); 1083 fm = im / (scale * fa); 1084 fy = iy / (scale * fa); 1085 fb = ib / (scale * fa); 1086 } 1087 } 1088 else 1089 { 1090 ic = pixelData[0]; 1091 im = pixelData[1]; 1092 iy = pixelData[2]; 1093 ib = pixelData[3]; 1094 // Scale to [0.0 ... 1.0] 1095 fc = ic / scale; 1096 fm = im / scale; 1097 fy = iy / scale; 1098 fb = ib / scale; 1099 fa = 1.0; 1100 } 1101 1102 return [NSColor colorWithDeviceCyan: fc 1103 magenta: fm 1104 yellow: fy 1105 black: fb 1106 alpha: fa]; 1107 } 1108 1109 return nil; 1110} 1111 1112/** 1113 * Sets the color of pixel (x,y), where (0,0) is the top-left pixel in the 1114 * image. 1115 */ 1116- (void) setColor: (NSColor*)color atX: (NSInteger)x y: (NSInteger)y 1117{ 1118 NSUInteger pixelData[5]; 1119 NSColor *conv; 1120 1121 if (x < 0 || y < 0 || x >= _pixelsWide || y >= _pixelsHigh) 1122 { 1123 // outside 1124 return; 1125 } 1126 1127 conv = [color colorUsingColorSpaceName: _colorSpace]; 1128 if (!conv) 1129 { 1130 return; 1131 } 1132 1133 if ([_colorSpace isEqualToString: NSCalibratedRGBColorSpace] 1134 || [_colorSpace isEqualToString: NSDeviceRGBColorSpace]) 1135 { 1136 NSUInteger ir, ig, ib, ia; 1137 CGFloat fr, fg, fb, fa; 1138 CGFloat scale; 1139 1140 scale = (CGFloat)((1 << _bitsPerSample) - 1); 1141 [conv getRed: &fr green: &fg blue: &fb alpha: &fa]; 1142 if(_hasAlpha) 1143 { 1144 // Scale and premultiply alpha 1145 if (_format & NSAlphaNonpremultipliedBitmapFormat) 1146 { 1147 ir = scale * fr; 1148 ig = scale * fg; 1149 ib = scale * fb; 1150 } 1151 else 1152 { 1153 ir = scale * fr * fa; 1154 ig = scale * fg * fa; 1155 ib = scale * fb * fa; 1156 } 1157 ia = scale * fa; 1158 1159 // This order depends on the bitmap format 1160 if (_format & NSAlphaFirstBitmapFormat) 1161 { 1162 pixelData[0] = ia; 1163 pixelData[1] = ir; 1164 pixelData[2] = ig; 1165 pixelData[3] = ib; 1166 } 1167 else 1168 { 1169 pixelData[0] = ir; 1170 pixelData[1] = ig; 1171 pixelData[2] = ib; 1172 pixelData[3] = ia; 1173 } 1174 } 1175 else 1176 { 1177 // Scale 1178 ir = scale * fr; 1179 ig = scale * fg; 1180 ib = scale * fb; 1181 // This order depends on the bitmap format 1182 pixelData[0] = ir; 1183 pixelData[1] = ig; 1184 pixelData[2] = ib; 1185 } 1186 } 1187 else if ([_colorSpace isEqual: NSDeviceWhiteColorSpace] 1188 || [_colorSpace isEqual: NSCalibratedWhiteColorSpace]) 1189 { 1190 NSUInteger iw, ia; 1191 CGFloat fw, fa; 1192 CGFloat scale; 1193 1194 scale = (CGFloat)((1 << _bitsPerSample) - 1); 1195 [conv getWhite: &fw alpha: &fa]; 1196 if (_hasAlpha) 1197 { 1198 if (_format & NSAlphaNonpremultipliedBitmapFormat) 1199 { 1200 iw = scale * fw; 1201 } 1202 else 1203 { 1204 iw = scale * fw * fa; 1205 } 1206 ia = scale * fa; 1207 1208 // This order depends on the bitmap format 1209 if (_format & NSAlphaFirstBitmapFormat) 1210 { 1211 pixelData[0] = ia; 1212 pixelData[1] = iw; 1213 } 1214 else 1215 { 1216 pixelData[0] = iw; 1217 pixelData[1] = ia; 1218 } 1219 } 1220 else 1221 { 1222 iw = scale * fw; 1223 pixelData[0] = iw; 1224 } 1225 } 1226 else if ([_colorSpace isEqual: NSDeviceBlackColorSpace] 1227 || [_colorSpace isEqual: NSCalibratedBlackColorSpace]) 1228 { 1229 NSUInteger iw, ia; 1230 CGFloat fw, fa; 1231 CGFloat scale; 1232 1233 scale = (CGFloat)((1 << _bitsPerSample) - 1); 1234 [conv getWhite: &fw alpha: &fa]; 1235 if (_hasAlpha) 1236 { 1237 if (_format & NSAlphaNonpremultipliedBitmapFormat) 1238 { 1239 iw = scale * (1 - fw); 1240 } 1241 else 1242 { 1243 iw = scale * (1 - fw) * fa; 1244 } 1245 ia = scale * fa; 1246 1247 // This order depends on the bitmap format 1248 if (_format & NSAlphaFirstBitmapFormat) 1249 { 1250 pixelData[0] = ia; 1251 pixelData[1] = iw; 1252 } 1253 else 1254 { 1255 pixelData[0] = iw; 1256 pixelData[1] = ia; 1257 } 1258 } 1259 else 1260 { 1261 iw = scale * (1 - fw); 1262 pixelData[0] = iw; 1263 } 1264 } 1265 else if ([_colorSpace isEqual: NSDeviceCMYKColorSpace]) 1266 { 1267 NSUInteger ic, im, iy, ib, ia; 1268 CGFloat fc, fm, fy, fb, fa; 1269 CGFloat scale; 1270 1271 scale = (CGFloat)((1 << _bitsPerSample) - 1); 1272 [conv getCyan: &fc magenta: &fm yellow: &fy black: &fb alpha: &fa]; 1273 if(_hasAlpha) 1274 { 1275 if (_format & NSAlphaNonpremultipliedBitmapFormat) 1276 { 1277 ic = scale * fc; 1278 im = scale * fm; 1279 iy = scale * fy; 1280 ib = scale * fb; 1281 } 1282 else 1283 { 1284 ic = scale * fc * fa; 1285 im = scale * fm * fa; 1286 iy = scale * fy * fa; 1287 ib = scale * fb * fa; 1288 } 1289 ia = scale * fa; 1290 1291 // This order depends on the bitmap format 1292 if (_format & NSAlphaFirstBitmapFormat) 1293 { 1294 pixelData[0] = ia; 1295 pixelData[1] = ic; 1296 pixelData[2] = im; 1297 pixelData[3] = iy; 1298 pixelData[4] = ib; 1299 } 1300 else 1301 { 1302 pixelData[0] = ic; 1303 pixelData[1] = im; 1304 pixelData[2] = iy; 1305 pixelData[3] = ib; 1306 pixelData[4] = ia; 1307 } 1308 } 1309 else 1310 { 1311 ic = scale * fc; 1312 im = scale * fm; 1313 iy = scale * fy; 1314 ib = scale * fb; 1315 // This order depends on the bitmap format 1316 pixelData[0] = ic; 1317 pixelData[1] = im; 1318 pixelData[2] = iy; 1319 pixelData[3] = ib; 1320 } 1321 } 1322 else 1323 { 1324 // FIXME: Other colour spaces not implemented 1325 return; 1326 } 1327 1328 [self setPixel: pixelData atX: x y: y]; 1329} 1330 1331/** Draws the image in the current window according the information 1332 from the current gState, including information about the current 1333 point, scaling, etc. */ 1334- (BOOL) draw 1335{ 1336 NSRect irect = NSMakeRect(0, 0, _size.width, _size.height); 1337 NSGraphicsContext *ctxt = GSCurrentContext(); 1338 1339 [self _premultiply]; 1340 [ctxt GSDrawImage: irect : self]; 1341 return YES; 1342} 1343 1344// 1345// Producing a TIFF Representation of the Image 1346// 1347/** Produces an NSData object containing a TIFF representation of all 1348 the images stored in anArray. BUGS: Currently this only works if the 1349 images are NSBitmapImageRep objects. */ 1350+ (NSData*) TIFFRepresentationOfImageRepsInArray: (NSArray *)anArray 1351{ 1352 NSEnumerator *enumerator = [anArray objectEnumerator]; 1353 NSImageRep *rep; 1354 TIFF *image; 1355 NSTiffInfo info; 1356 char *bytes = 0; 1357 long length = 0; 1358 int num = 0; 1359 NSData *data; 1360 1361 image = NSTiffOpenDataWrite(&bytes, &length); 1362 if (image == 0) 1363 { 1364 [NSException raise: NSTIFFException 1365 format: @"Opening data stream for writing"]; 1366 } 1367 1368 while ((rep = [enumerator nextObject]) != nil) 1369 { 1370 if ([rep isKindOfClass: self]) 1371 { 1372 NSTIFFCompression compression; 1373 float factor; 1374 NSBitmapImageRep *bitmap = (NSBitmapImageRep*)rep; 1375 1376 [bitmap getCompression: &compression 1377 factor: &factor]; 1378 [bitmap _fillTIFFInfo: &info 1379 usingCompression: compression 1380 factor: factor]; 1381 info.imageNumber = num++; 1382 info.numImages = [anArray count]; 1383 info.subfileType = FILETYPE_PAGE; 1384 if (NSTiffWrite(image, &info, [bitmap bitmapData]) != 0) 1385 { 1386 [NSException raise: NSTIFFException format: @"Writing data"]; 1387 } 1388 } 1389 } 1390 1391 NSTiffClose(image); 1392 data = [NSData dataWithBytesNoCopy: bytes length: length]; 1393 if (num > 0) 1394 { 1395 return data; 1396 } 1397 else 1398 { 1399 // FIXME: Not sure wether this is the correct behaviour, at least it was 1400 // the old one of this method. 1401 return nil; 1402 } 1403} 1404 1405/** Produces an NSData object containing a TIFF representation of all 1406 the images stored in anArray. The image is compressed according to 1407 the compression type and factor. BUGS: Currently this only works if 1408 the images are NSBitmapImageRep objects. */ 1409+ (NSData*) TIFFRepresentationOfImageRepsInArray: (NSArray *)anArray 1410 usingCompression: (NSTIFFCompression)compression 1411 factor: (float)factor 1412{ 1413 NSEnumerator *enumerator = [anArray objectEnumerator]; 1414 NSImageRep *rep; 1415 NSTiffInfo info; 1416 TIFF *image; 1417 char *bytes = 0; 1418 long length = 0; 1419 int num = 0; 1420 NSData *data; 1421 1422 image = NSTiffOpenDataWrite(&bytes, &length); 1423 if (image == 0) 1424 { 1425 [NSException raise: NSTIFFException 1426 format: @"Opening data stream for writing"]; 1427 } 1428 1429 while ((rep = [enumerator nextObject]) != nil) 1430 { 1431 if ([rep isKindOfClass: self]) 1432 { 1433 [(NSBitmapImageRep*)rep _fillTIFFInfo: &info 1434 usingCompression: compression 1435 factor: factor]; 1436 info.imageNumber = num++; 1437 info.numImages = [anArray count]; 1438 info.subfileType = FILETYPE_PAGE; 1439 if (NSTiffWrite(image, &info, [(NSBitmapImageRep*)rep bitmapData]) != 0) 1440 { 1441 [NSException raise: NSTIFFException format: @"Writing data"]; 1442 } 1443 } 1444 } 1445 1446 NSTiffClose(image); 1447 data = [NSData dataWithBytesNoCopy: bytes length: length]; 1448 if (num > 0) 1449 { 1450 return data; 1451 } 1452 else 1453 { 1454 // FIXME: Not sure wether this is the correct behaviour, at least it was 1455 // the old one of this method. 1456 return nil; 1457 } 1458} 1459 1460/** Returns an NSData object containing a TIFF representation of the 1461 receiver. */ 1462- (NSData*) TIFFRepresentation 1463{ 1464 if ([self canBeCompressedUsing: _compression] == NO) 1465 { 1466 [self setCompression: NSTIFFCompressionNone factor: 0]; 1467 } 1468 return [self TIFFRepresentationUsingCompression: _compression 1469 factor: _comp_factor]; 1470} 1471 1472/** Returns an NSData object containing a TIFF representation of the 1473 receiver. The TIFF data is compressed using compresssion type 1474 and factor. */ 1475- (NSData*) TIFFRepresentationUsingCompression: (NSTIFFCompression)compression 1476 factor: (float)factor 1477{ 1478 NSTiffInfo info; 1479 TIFF *image; 1480 char *bytes = 0; 1481 long length = 0; 1482 1483 image = NSTiffOpenDataWrite(&bytes, &length); 1484 if (image == 0) 1485 { 1486 [NSException raise: NSTIFFException 1487 format: @"Opening data stream for writing"]; 1488 } 1489 1490 [self _fillTIFFInfo: &info 1491 usingCompression: compression 1492 factor: factor]; 1493 if (NSTiffWrite(image, &info, [self bitmapData]) != 0) 1494 { 1495 [NSException raise: NSTIFFException format: @"Writing data"]; 1496 } 1497 NSTiffClose(image); 1498 return [NSData dataWithBytesNoCopy: bytes length: length]; 1499} 1500 1501/** <p> Returns a data object in the selected format with multiple images.</p> 1502 <p> See Also: -setProperty:withValue: for the options supported in the properties.</p> 1503 <p> FIXME: returns only the first image in the array, and only works for 1504 NSBitmapImageRep or subclasses thereof. </p> 1505*/ 1506+ (NSData *)representationOfImageRepsInArray:(NSArray *)imageReps 1507 usingType:(NSBitmapImageFileType)storageType 1508 properties:(NSDictionary *)properties 1509{ 1510 // Partial implementation only returns data for the first imageRep in the array 1511 // and only works for NSBitmapImageRep or subclasses thereof. 1512 //FIXME: This only outputs one of the ImageReps 1513 NSEnumerator *enumerator = [imageReps objectEnumerator]; 1514 NSImageRep *rep; 1515 1516 if (storageType == NSTIFFFileType) 1517 { 1518 NSNumber *comp_property = [properties objectForKey: NSImageCompressionMethod]; 1519 NSNumber *factor_property = [properties objectForKey: NSImageCompressionFactor]; 1520 1521 if ((comp_property != nil) && (factor_property != nil)) 1522 { 1523 float factor = [factor_property floatValue]; 1524 NSTIFFCompression compression = [comp_property unsignedShortValue]; 1525 1526 return [self TIFFRepresentationOfImageRepsInArray: imageReps 1527 usingCompression: compression 1528 factor: factor]; 1529 } 1530 else 1531 { 1532 return [self TIFFRepresentationOfImageRepsInArray: imageReps]; 1533 } 1534 } 1535 else 1536 { 1537 while ((rep = [enumerator nextObject]) != nil) 1538 { 1539 if ([rep isKindOfClass: self]) 1540 { 1541 return [(NSBitmapImageRep*)rep representationUsingType: storageType 1542 properties: properties]; 1543 } 1544 } 1545 } 1546 1547 return nil; 1548} 1549 1550/** <p> Returns a data object in one of the supported bitmap graphics file types. 1551 A limited set of options may be passed via the properties. If the passed in properties is nil, 1552 it falls back to the options set with -setProperty:withValue:. File types not yet 1553 implemented return nil and log an error message.</p> 1554 <p> See Also: -setProperty:withValue: for supported options in the properties. </p> 1555*/ 1556- (NSData *)representationUsingType:(NSBitmapImageFileType)storageType 1557 properties:(NSDictionary *)properties 1558{ 1559 // if it exists, the passed in properties takes precedence over the internal _properties 1560 NSDictionary * __properties; 1561 __properties = (properties)? properties : (NSDictionary *)_properties; 1562 1563 switch (storageType) 1564 { 1565 case NSTIFFFileType: 1566 { 1567 NSNumber *property; 1568 float factor = _comp_factor; 1569 NSTIFFCompression compression = _compression; 1570 if ((property = [__properties objectForKey: NSImageCompressionMethod])) 1571 compression = [property unsignedShortValue]; 1572 if ((property = [__properties objectForKey: NSImageCompressionFactor])) 1573 factor = [property floatValue]; 1574 if ([self canBeCompressedUsing: compression] == NO) 1575 { 1576 factor = 0.0; 1577 compression = NSTIFFCompressionNone; 1578 } 1579 return [self TIFFRepresentationUsingCompression: compression factor: factor]; 1580 } 1581 1582 case NSBMPFileType: 1583 NSLog(@"BMP representation is not yet implemented"); 1584 return nil; 1585 1586 case NSGIFFileType: 1587 return [self _GIFRepresentationWithProperties: __properties 1588 errorMessage: NULL]; 1589 1590 case NSJPEGFileType: 1591 return [self _JPEGRepresentationWithProperties: __properties 1592 errorMessage: NULL]; 1593 1594 case NSPNGFileType: 1595 return [self _PNGRepresentationWithProperties: __properties]; 1596 1597 case NSJPEG2000FileType: 1598 NSLog(@"JPEG2000 representation is not yet implemented"); 1599 return nil; 1600 } 1601 return nil; 1602} 1603 1604// 1605// Setting and Checking Compression Types 1606// 1607/** Returns a C-array of available TIFF compression types. 1608 */ 1609+ (void) getTIFFCompressionTypes: (const NSTIFFCompression **)list 1610 count: (NSInteger *)numTypes 1611{ 1612 // the GNUstep supported types 1613 static NSTIFFCompression types[] = { 1614 NSTIFFCompressionNone, 1615 NSTIFFCompressionCCITTFAX3, 1616 NSTIFFCompressionCCITTFAX4, 1617 NSTIFFCompressionLZW, 1618 NSTIFFCompressionJPEG, 1619 NSTIFFCompressionNEXT, 1620 NSTIFFCompressionPackBits, 1621 NSTIFFCompressionOldJPEG 1622 }; 1623 1624 // check with libtiff to see what is really available 1625 NSInteger i, j; 1626 static NSTIFFCompression checkedTypes[8]; 1627 for (i = 0, j = 0; i < 8; i++) 1628 { 1629 if (NSTiffIsCodecConfigured([NSBitmapImageRep _localFromCompressionType: types[i]])) 1630 { 1631 checkedTypes[j] = types[i]; 1632 j++; 1633 } 1634 } 1635 if (list) 1636 *list = checkedTypes; 1637 if (numTypes) 1638 *numTypes = j; 1639} 1640 1641/** Returns a localized string describing a TIFF compression type. */ 1642+ (NSString*) localizedNameForTIFFCompressionType: (NSTIFFCompression)type 1643{ 1644 switch (type) 1645 { 1646 case NSTIFFCompressionNone: return _(@"No Compression"); 1647 case NSTIFFCompressionCCITTFAX3: return _(@"CCITTFAX3 Compression"); 1648 case NSTIFFCompressionCCITTFAX4: return _(@"CCITTFAX4 Compression"); 1649 case NSTIFFCompressionLZW: return _(@"LZW Compression"); 1650 case NSTIFFCompressionJPEG: return _(@"JPEG Compression"); 1651 case NSTIFFCompressionNEXT: return _(@"NEXT Compression"); 1652 case NSTIFFCompressionPackBits: return _(@"PackBits Compression"); 1653 case NSTIFFCompressionOldJPEG: return _(@"Old JPEG Compression"); 1654 default: return nil; 1655 } 1656} 1657 1658/** Returns YES if the receiver can be stored in a representation 1659 compressed using the compression type. */ 1660- (BOOL) canBeCompressedUsing: (NSTIFFCompression)compression 1661{ 1662 BOOL does; 1663 int codecConf = 1664 NSTiffIsCodecConfigured([NSBitmapImageRep _localFromCompressionType: compression]); 1665 switch (compression) 1666 { 1667 case NSTIFFCompressionCCITTFAX3: 1668 case NSTIFFCompressionCCITTFAX4: 1669 if (_numColors == 1 && _bitsPerSample == 1 && codecConf != 0) 1670 does = YES; 1671 else 1672 does = NO; 1673 break; 1674 1675 case NSTIFFCompressionLZW: 1676 case NSTIFFCompressionNone: 1677 case NSTIFFCompressionJPEG: // this is a GNUstep extension; Cocoa does not support 1678 case NSTIFFCompressionPackBits: 1679 case NSTIFFCompressionOldJPEG: 1680 case NSTIFFCompressionNEXT: 1681 default: 1682 does = (codecConf != 0); 1683 } 1684 return does; 1685} 1686 1687/** Returns the receivers compression and compression factor, which is 1688 set either when the image is read in or by -setCompression:factor:. 1689 Factor is ignored in many compression schemes. For JPEG compression, 1690 factor can be any value from 0 to 1, with 1 being the maximum 1691 quality. */ 1692- (void) getCompression: (NSTIFFCompression*)compression 1693 factor: (float*)factor 1694{ 1695 *compression = _compression; 1696 *factor = _comp_factor; 1697} 1698 1699- (void) setCompression: (NSTIFFCompression)compression 1700 factor: (float)factor 1701{ 1702 _compression = compression; 1703 _comp_factor = factor; 1704} 1705 1706/** <p> Properties are key-value pairs associated with the representation. Arbitrary 1707 key-value pairs may be set. If the value is nil, the key is erased from properties. 1708 There are standard keys that are used to pass information 1709 and options related to the standard file types that may be read from or written to. 1710 Certain properties are automatically set when reading in image data. 1711 Certain properties may be set by the user prior to writing image data in order to set options 1712 for the data format. </p> 1713 <deflist> 1714 <term> NSImageCompressionMethod </term> 1715 <desc> NSNumber; automatically set when reading TIFF data; writing TIFF data </desc> 1716 <term> NSImageCompressionFactor </term> 1717 <desc> NSNumber 0.0 to 1.0; writing JPEG data 1718 (GNUstep extension: JPEG-compressed TIFFs too) </desc> 1719 <term> NSImageProgressive </term> 1720 <desc> NSNumber boolean; automatically set when reading JPEG data; writing JPEG data. 1721 Note: progressive display is not supported in GNUstep at this time. </desc> 1722 <term> NSImageInterlaced </term> 1723 <desc> NSNumber boolean; only for writing PNG data </desc> 1724 <term> NSImageGamma </term> 1725 <desc> NSNumber 0.0 to 1.0; only for reading or writing PNG data </desc> 1726 <term> NSImageRGBColorTable </term> 1727 <desc> NSData; automatically set when reading GIF data; writing GIF data </desc> 1728 <term> NSImageFrameCount </term> 1729 <desc> NSNumber integer; automatically set when reading animated GIF data. 1730 Not currently implemented. </desc> 1731 <term> NSImageCurrentFrame </term> 1732 <desc> NSNumber integer; only for animated GIF files. Not currently implemented. </desc> 1733 <term> NSImageCurrentFrameDuration </term> 1734 <desc> NSNumber float; automatically set when reading animated GIF data </desc> 1735 <term> NSImageLoopCount </term> 1736 <desc> NSNumber integer; automatically set when reading animated GIF data </desc> 1737 <term> NSImageDitherTranparency </term> 1738 <desc> NSNumber boolean; only for writing GIF data. Not currently supported. </desc> 1739 </deflist> 1740*/ 1741- (void)setProperty:(NSString *)property withValue:(id)value 1742{ 1743 if (value) 1744 { 1745 [_properties setObject: value forKey: property]; 1746 } 1747 else // clear the property 1748 { 1749 [_properties removeObjectForKey: property]; 1750 } 1751} 1752 1753/** Returns the value of a property */ 1754- (id)valueForProperty:(NSString *)property 1755{ 1756 return [_properties objectForKey: property]; 1757} 1758 1759// NSCopying protocol 1760- (id) copyWithZone: (NSZone *)zone 1761{ 1762 NSBitmapImageRep *copy; 1763 1764 copy = (NSBitmapImageRep*)[super copyWithZone: zone]; 1765 1766 copy->_properties = [_properties mutableCopyWithZone: zone]; 1767 copy->_imageData = [_imageData mutableCopyWithZone: zone]; 1768 copy->_imagePlanes = NSZoneMalloc(zone, sizeof(unsigned char*) * MAX_PLANES); 1769 if (_imageData == nil) 1770 { 1771 memcpy(copy->_imagePlanes, _imagePlanes, sizeof(unsigned char*) * MAX_PLANES); 1772 } 1773 else 1774 { 1775 unsigned char *bits; 1776 unsigned int i; 1777 1778 bits = (unsigned char *)[copy->_imageData bytes]; 1779 copy->_imagePlanes[0] = bits; 1780 if (_isPlanar) 1781 { 1782 for (i = 1; i < _numColors; i++) 1783 copy->_imagePlanes[i] = bits + i * _bytesPerRow * _pixelsHigh; 1784 for (i = _numColors; i < MAX_PLANES; i++) 1785 copy->_imagePlanes[i] = NULL; 1786 } 1787 else 1788 { 1789 for (i = 1; i < MAX_PLANES; i++) 1790 copy->_imagePlanes[i] = NULL; 1791 } 1792 } 1793 1794 return copy; 1795} 1796 1797// 1798// NSCoding protocol 1799// 1800- (void) encodeWithCoder: (NSCoder*)aCoder 1801{ 1802 NSData *data = [self TIFFRepresentation]; 1803 1804 [super encodeWithCoder: aCoder]; 1805 if ([aCoder allowsKeyedCoding]) 1806 { 1807 [aCoder encodeObject: data forKey: @"NSTIFFRepresentation"]; 1808 } 1809 else 1810 { 1811 [aCoder encodeObject: data]; 1812 } 1813} 1814 1815- (id) initWithCoder: (NSCoder*)aDecoder 1816{ 1817 NSData *data; 1818 1819 self = [super initWithCoder: aDecoder]; 1820 if ([aDecoder allowsKeyedCoding]) 1821 { 1822 data = [aDecoder decodeObjectForKey: @"NSTIFFRepresentation"]; 1823 } 1824 else 1825 { 1826 data = [aDecoder decodeObject]; 1827 } 1828 return [self initWithData: data]; 1829} 1830 1831@end 1832 1833@implementation NSBitmapImageRep (GSPrivate) 1834 1835+ (int) _localFromCompressionType: (NSTIFFCompression)type 1836{ 1837 switch (type) 1838 { 1839 case NSTIFFCompressionNone: return COMPRESSION_NONE; 1840 case NSTIFFCompressionCCITTFAX3: return COMPRESSION_CCITTFAX3; 1841 case NSTIFFCompressionCCITTFAX4: return COMPRESSION_CCITTFAX4; 1842 case NSTIFFCompressionLZW: return COMPRESSION_LZW; 1843 case NSTIFFCompressionJPEG: return COMPRESSION_JPEG; 1844 case NSTIFFCompressionNEXT: return COMPRESSION_NEXT; 1845 case NSTIFFCompressionPackBits: return COMPRESSION_PACKBITS; 1846 case NSTIFFCompressionOldJPEG: return COMPRESSION_OJPEG; 1847 default: 1848 break; 1849 } 1850 return COMPRESSION_NONE; 1851} 1852 1853+ (NSTIFFCompression) _compressionTypeFromLocal: (int)type 1854{ 1855 switch (type) 1856 { 1857 case COMPRESSION_NONE: return NSTIFFCompressionNone; 1858 case COMPRESSION_CCITTFAX3: return NSTIFFCompressionCCITTFAX3; 1859 case COMPRESSION_CCITTFAX4: return NSTIFFCompressionCCITTFAX4; 1860 case COMPRESSION_LZW: return NSTIFFCompressionLZW; 1861 case COMPRESSION_JPEG: return NSTIFFCompressionJPEG; 1862 case COMPRESSION_NEXT: return NSTIFFCompressionNEXT; 1863 case COMPRESSION_PACKBITS: return NSTIFFCompressionPackBits; 1864 case COMPRESSION_OJPEG: return NSTIFFCompressionOldJPEG; 1865 default: 1866 break; 1867 } 1868 return NSTIFFCompressionNone; 1869} 1870 1871+ (BOOL) _bitmapIsTIFF: (NSData *)data 1872{ 1873 TIFF *image = NSTiffOpenDataRead((char *)[data bytes], [data length]); 1874 1875 if (image != NULL) 1876 { 1877 NSTiffClose(image); 1878 return YES; 1879 } 1880 else 1881 { 1882 return NO; 1883 } 1884} 1885 1886+ (NSArray*) _imageRepsWithTIFFData: (NSData *)imageData 1887{ 1888 int i, images; 1889 TIFF *image; 1890 NSMutableArray *array; 1891 1892 image = NSTiffOpenDataRead((char *)[imageData bytes], [imageData length]); 1893 if (image == NULL) 1894 { 1895 NSLog(@"NSBitmapImageRep: unable to parse TIFF data"); 1896 return [NSArray array]; 1897 } 1898 1899 images = NSTiffGetImageCount(image); 1900 NSDebugLLog(@"NSImage", @"Image contains %d directories", images); 1901 array = [NSMutableArray arrayWithCapacity: images]; 1902 for (i = 0; i < images; i++) 1903 { 1904 NSBitmapImageRep* imageRep; 1905 imageRep = [[self alloc] _initFromTIFFImage: image number: i]; 1906 if (imageRep) 1907 { 1908 [array addObject: imageRep]; 1909 RELEASE(imageRep); 1910 } 1911 } 1912 NSTiffClose(image); 1913 1914 return array; 1915} 1916 1917- (NSBitmapImageRep *) _initBitmapFromTIFF: (NSData *)imageData 1918{ 1919 TIFF *image = NSTiffOpenDataRead((char *)[imageData bytes], [imageData length]); 1920 1921 if (image == NULL) 1922 { 1923 RELEASE(self); 1924 NSLog(@"Tiff read invalid TIFF info from data"); 1925 return nil; 1926 } 1927 1928 [self _initFromTIFFImage: image number: -1]; 1929 NSTiffClose(image); 1930 return self; 1931} 1932 1933/* Given a TIFF image (from the libtiff library), load the image information 1934 into our data structure. Reads the specified image. */ 1935- (NSBitmapImageRep *) _initFromTIFFImage: (TIFF *)image number: (int)imageNumber 1936{ 1937 NSString* space; 1938 NSTiffInfo* info; 1939 1940 /* Seek to the correct image and get the dictionary information */ 1941 info = NSTiffGetInfo(imageNumber, image); 1942 if (!info) 1943 { 1944 RELEASE(self); 1945 NSLog(@"Tiff read invalid TIFF info in directory %d", imageNumber); 1946 return nil; 1947 } 1948 1949 /* 8-bit RGB will be converted to 24-bit by the tiff routines, so account 1950 for this. */ 1951 space = nil; 1952 switch(info->photoInterp) 1953 { 1954 case PHOTOMETRIC_MINISBLACK: space = NSDeviceWhiteColorSpace; break; 1955 case PHOTOMETRIC_MINISWHITE: space = NSDeviceBlackColorSpace; break; 1956 case PHOTOMETRIC_RGB: space = NSDeviceRGBColorSpace; break; 1957 case PHOTOMETRIC_PALETTE: 1958 space = NSDeviceRGBColorSpace; 1959 info->samplesPerPixel = 3; 1960 break; 1961 default: 1962 break; 1963 } 1964 1965 [self initWithBitmapDataPlanes: NULL 1966 pixelsWide: info->width 1967 pixelsHigh: info->height 1968 bitsPerSample: info->bitsPerSample 1969 samplesPerPixel: info->samplesPerPixel 1970 hasAlpha: (info->extraSamples > 0) 1971 isPlanar: (info->planarConfig == PLANARCONFIG_SEPARATE) 1972 colorSpaceName: space 1973 bitmapFormat: (info->assocAlpha ? 0 : 1974 NSAlphaNonpremultipliedBitmapFormat) 1975 bytesPerRow: 0 1976 bitsPerPixel: 0]; 1977 _compression = [NSBitmapImageRep _compressionTypeFromLocal: info->compression]; 1978 _comp_factor = (((float)info->quality)/100.0); 1979 1980 // Note that Cocoa does not do this, even though the docs say it should 1981 [_properties setObject: [NSNumber numberWithUnsignedShort: _compression] 1982 forKey: NSImageCompressionMethod]; 1983 [_properties setObject: [NSNumber numberWithFloat: _comp_factor] 1984 forKey: NSImageCompressionFactor]; 1985 1986 if (info->xdpi > 0 && info->xdpi != 72 && 1987 info->ydpi > 0 && info->ydpi != 72) 1988 { 1989 NSSize pointSize = NSMakeSize((double)info->width * (72.0 / (double)info->xdpi), 1990 (double)info->height * (72.0 / (double)info->ydpi)); 1991 [self setSize: pointSize]; 1992 } 1993 1994 if (NSTiffRead(image, info, [self bitmapData])) 1995 { 1996 free(info); 1997 RELEASE(self); 1998 NSLog(@"Tiff read invalid TIFF image data in directory %d", imageNumber); 1999 return nil; 2000 } 2001 free(info); 2002 2003 return self; 2004} 2005 2006- (void) _fillTIFFInfo: (NSTiffInfo*)info 2007 usingCompression: (NSTIFFCompression)type 2008 factor: (float)factor 2009{ 2010 info->numImages = 1; 2011 info->imageNumber = 0; 2012 info->subfileType = 0; 2013 info->width = _pixelsWide; 2014 info->height = _pixelsHigh; 2015 info->bitsPerSample = _bitsPerSample; 2016 info->samplesPerPixel = _numColors; 2017 2018 // resolution/density 2019 info->xdpi = 0; 2020 info->ydpi = 0; 2021 if (_pixelsWide != (int)(_size.width) || _pixelsHigh != (int)(_size.height)) 2022 { 2023 float x_density, y_density; 2024 x_density = _pixelsWide * 72 / _size.width; 2025 y_density = _pixelsHigh * 72 / _size.height; 2026 info->xdpi = x_density; 2027 info->ydpi = y_density; 2028 } 2029 2030 if (_isPlanar) 2031 info->planarConfig = PLANARCONFIG_SEPARATE; 2032 else 2033 info->planarConfig = PLANARCONFIG_CONTIG; 2034 2035 if ([_colorSpace isEqual: NSDeviceRGBColorSpace] 2036 || [_colorSpace isEqual: NSCalibratedRGBColorSpace]) 2037 info->photoInterp = PHOTOMETRIC_RGB; 2038 else if ([_colorSpace isEqual: NSDeviceWhiteColorSpace] 2039 || [_colorSpace isEqual: NSCalibratedWhiteColorSpace]) 2040 info->photoInterp = PHOTOMETRIC_MINISBLACK; 2041 else if ([_colorSpace isEqual: NSDeviceBlackColorSpace] 2042 || [_colorSpace isEqual: NSCalibratedBlackColorSpace]) 2043 info->photoInterp = PHOTOMETRIC_MINISWHITE; 2044 else 2045 { 2046 NSWarnMLog(@"Unknown colorspace %@.", _colorSpace); 2047 info->photoInterp = PHOTOMETRIC_RGB; 2048 } 2049 2050 info->extraSamples = (_hasAlpha) ? 1 : 0; 2051 info->assocAlpha = (_format & NSAlphaNonpremultipliedBitmapFormat) ? 0 : 1; 2052 2053 if ([self canBeCompressedUsing: type] == NO) 2054 { 2055 type = NSTIFFCompressionNone; 2056 factor = 0; 2057 } 2058 2059 info->compression = [NSBitmapImageRep _localFromCompressionType: type]; 2060 if (factor < 0) 2061 factor = 0; 2062 if (factor > 1) 2063 factor = 1; 2064 info->quality = factor * 100; 2065 info->error = 0; 2066} 2067 2068- (void) _premultiply 2069{ 2070 NSInteger x, y; 2071 NSUInteger pixelData[5]; 2072 NSInteger start, end, i, ai; 2073 SEL getPSel = @selector(getPixel:atX:y:); 2074 SEL setPSel = @selector(setPixel:atX:y:); 2075 IMP getP = [self methodForSelector: getPSel]; 2076 IMP setP = [self methodForSelector: setPSel]; 2077 2078 if (!_hasAlpha || !(_format & NSAlphaNonpremultipliedBitmapFormat)) 2079 return; 2080 2081 if (_format & NSAlphaFirstBitmapFormat) 2082 { 2083 ai = 0; 2084 start = 1; 2085 end = _numColors; 2086 } 2087 else 2088 { 2089 ai = _numColors - 1; 2090 start = 0; 2091 end = _numColors - 1; 2092 } 2093 2094 if (_bitsPerSample == 8) 2095 { 2096 if (!_isPlanar) 2097 { 2098 // Optimize for the most common case 2099 NSUInteger a; 2100 NSInteger offset; 2101 NSInteger line_offset; 2102 2103 for (y = 0; y < _pixelsHigh; y++) 2104 { 2105 line_offset = _bytesPerRow * y; 2106 for (x = 0; x < _pixelsWide; x++) 2107 { 2108 offset = (_bitsPerPixel * x) / 8 + line_offset; 2109 a = _imagePlanes[0][offset + ai]; 2110 if (a != 255) 2111 { 2112 if (a == 0) 2113 { 2114 for (i = start; i < end; i++) 2115 { 2116 _imagePlanes[0][offset + i] = 0; 2117 } 2118 } 2119 else 2120 { 2121 for (i = start; i < end; i++) 2122 { 2123 NSUInteger v = _imagePlanes[0][offset + i]; 2124 NSUInteger t = a * v + 0x80; 2125 2126 v = ((t >> 8) + t) >> 8; 2127 _imagePlanes[0][offset + i] = v; 2128 } 2129 } 2130 } 2131 } 2132 } 2133 } 2134 else 2135 { 2136 NSUInteger a; 2137 2138 for (y = 0; y < _pixelsHigh; y++) 2139 { 2140 for (x = 0; x < _pixelsWide; x++) 2141 { 2142 //[self getPixel: pixelData atX: x y: y]; 2143 getP(self, getPSel, pixelData, x, y); 2144 a = pixelData[ai]; 2145 if (a != 255) 2146 { 2147 for (i = start; i < end; i++) 2148 { 2149 NSUInteger t = a * pixelData[i] + 0x80; 2150 2151 pixelData[i] = ((t >> 8) + t) >> 8; 2152 } 2153 //[self setPixel: pixelData atX: x y: y]; 2154 setP(self, setPSel, pixelData, x, y); 2155 } 2156 } 2157 } 2158 } 2159 } 2160 else 2161 { 2162 CGFloat scale; 2163 CGFloat alpha; 2164 2165 scale = (CGFloat)((1 << _bitsPerSample) - 1); 2166 for (y = 0; y < _pixelsHigh; y++) 2167 { 2168 for (x = 0; x < _pixelsWide; x++) 2169 { 2170 //[self getPixel: pixelData atX: x y: y]; 2171 getP(self, getPSel, pixelData, x, y); 2172 alpha = pixelData[ai] / scale; 2173 for (i = start; i < end; i++) 2174 { 2175 pixelData[i] *= alpha; 2176 } 2177 //[self setPixel: pixelData atX: x y: y]; 2178 setP(self, setPSel, pixelData, x, y); 2179 } 2180 } 2181 } 2182 2183 _format &= ~NSAlphaNonpremultipliedBitmapFormat; 2184} 2185 2186- (void) _unpremultiply 2187{ 2188 NSInteger x, y; 2189 NSUInteger pixelData[5]; 2190 NSInteger start, end, i, ai; 2191 SEL getPSel = @selector(getPixel:atX:y:); 2192 SEL setPSel = @selector(setPixel:atX:y:); 2193 IMP getP = [self methodForSelector: getPSel]; 2194 IMP setP = [self methodForSelector: setPSel]; 2195 2196 if (!_hasAlpha || (_format & NSAlphaNonpremultipliedBitmapFormat)) 2197 return; 2198 2199 if (_format & NSAlphaFirstBitmapFormat) 2200 { 2201 ai = 0; 2202 start = 1; 2203 end = _numColors; 2204 } 2205 else 2206 { 2207 ai = _numColors - 1; 2208 start = 0; 2209 end = _numColors - 1; 2210 } 2211 2212 if (_bitsPerSample == 8) 2213 { 2214 if (!_isPlanar) 2215 { 2216 // Optimize for the most common case 2217 NSUInteger a; 2218 NSInteger offset; 2219 NSInteger line_offset; 2220 2221 for (y = 0; y < _pixelsHigh; y++) 2222 { 2223 line_offset = _bytesPerRow * y; 2224 for (x = 0; x < _pixelsWide; x++) 2225 { 2226 offset = (_bitsPerPixel * x) / 8 + line_offset; 2227 a = _imagePlanes[0][offset + ai]; 2228 if ((a != 0) && (a != 255)) 2229 { 2230 for (i = start; i < end; i++) 2231 { 2232 NSUInteger v = _imagePlanes[0][offset + i]; 2233 NSUInteger c; 2234 2235 c = (v * 255) / a; 2236 if (c >= 255) 2237 { 2238 v = 255; 2239 } 2240 else 2241 { 2242 v = c; 2243 } 2244 2245 _imagePlanes[0][offset + i] = v; 2246 } 2247 } 2248 } 2249 } 2250 } 2251 else 2252 { 2253 NSUInteger a; 2254 2255 for (y = 0; y < _pixelsHigh; y++) 2256 { 2257 for (x = 0; x < _pixelsWide; x++) 2258 { 2259 //[self getPixel: pixelData atX: x y: y]; 2260 getP(self, getPSel, pixelData, x, y); 2261 a = pixelData[ai]; 2262 if ((a != 0) && (a != 255)) 2263 { 2264 for (i = start; i < end; i++) 2265 { 2266 NSUInteger c; 2267 2268 c = (pixelData[i] * 255) / a; 2269 if (c >= 255) 2270 { 2271 pixelData[i] = 255; 2272 } 2273 else 2274 { 2275 pixelData[i] = c; 2276 } 2277 } 2278 //[self setPixel: pixelData atX: x y: y]; 2279 setP(self, setPSel, pixelData, x, y); 2280 } 2281 } 2282 } 2283 } 2284 } 2285 else 2286 { 2287 CGFloat scale; 2288 CGFloat alpha; 2289 2290 scale = (CGFloat)((1 << _bitsPerSample) - 1); 2291 for (y = 0; y < _pixelsHigh; y++) 2292 { 2293 NSUInteger a; 2294 2295 for (x = 0; x < _pixelsWide; x++) 2296 { 2297 //[self getPixel: pixelData atX: x y: y]; 2298 getP(self, getPSel, pixelData, x, y); 2299 a = pixelData[ai]; 2300 if (a != 0) 2301 { 2302 alpha = scale / a; 2303 for (i = start; i < end; i++) 2304 { 2305 CGFloat new = pixelData[i] * alpha; 2306 2307 if (new > scale) 2308 { 2309 pixelData[i] = scale; 2310 } 2311 else 2312 { 2313 pixelData[i] = new; 2314 } 2315 } 2316 //[self setPixel: pixelData atX: x y: y]; 2317 setP(self, setPSel, pixelData, x, y); 2318 } 2319 } 2320 } 2321 } 2322 2323 _format |= NSAlphaNonpremultipliedBitmapFormat; 2324} 2325 2326- (NSBitmapImageRep *) _convertToFormatBitsPerSample: (NSInteger)bps 2327 samplesPerPixel: (NSInteger)spp 2328 hasAlpha: (BOOL)alpha 2329 isPlanar: (BOOL)isPlanar 2330 colorSpaceName: (NSString*)colorSpaceName 2331 bitmapFormat: (NSBitmapFormat)bitmapFormat 2332 bytesPerRow: (NSInteger)rowBytes 2333 bitsPerPixel: (NSInteger)pixelBits 2334{ 2335 if (!pixelBits) 2336 pixelBits = bps * ((isPlanar) ? 1 : spp); 2337 if (!rowBytes) 2338 rowBytes = ceil((float)_pixelsWide * pixelBits / 8); 2339 2340 // Do we already have the correct format? 2341 if ((bps == _bitsPerSample) && (spp == _numColors) 2342 && (alpha == _hasAlpha) && (isPlanar == _isPlanar) 2343 && (bitmapFormat == _format) && (rowBytes == _bytesPerRow) 2344 && (pixelBits == _bitsPerPixel) 2345 && [_colorSpace isEqualToString: colorSpaceName]) 2346 { 2347 return self; 2348 } 2349 else 2350 { 2351 NSBitmapImageRep* new; 2352 2353 new = [[NSBitmapImageRep alloc] 2354 initWithBitmapDataPlanes: NULL 2355 pixelsWide: _pixelsWide 2356 pixelsHigh: _pixelsHigh 2357 bitsPerSample: bps 2358 samplesPerPixel: spp 2359 hasAlpha: alpha 2360 isPlanar: isPlanar 2361 colorSpaceName: colorSpaceName 2362 bitmapFormat: bitmapFormat 2363 bytesPerRow: rowBytes 2364 bitsPerPixel: pixelBits]; 2365 2366 if ([_colorSpace isEqualToString: colorSpaceName] || 2367 ([_colorSpace isEqualToString: NSDeviceRGBColorSpace] && 2368 [colorSpaceName isEqualToString: NSCalibratedRGBColorSpace]) || 2369 ([colorSpaceName isEqualToString: NSDeviceRGBColorSpace] && 2370 [_colorSpace isEqualToString: NSCalibratedRGBColorSpace])) 2371 { 2372 SEL getPSel = @selector(getPixel:atX:y:); 2373 SEL setPSel = @selector(setPixel:atX:y:); 2374 IMP getP = [self methodForSelector: getPSel]; 2375 IMP setP = [new methodForSelector: setPSel]; 2376 NSUInteger pixelData[5]; 2377 NSInteger x, y; 2378 CGFloat _scale; 2379 CGFloat scale; 2380 2381 NSDebugLLog(@"NSImage", @"Converting %@ bitmap data", _colorSpace); 2382 2383 if (_bitsPerSample != bps) 2384 { 2385 _scale = (CGFloat)((1 << _bitsPerSample) - 1); 2386 scale = (CGFloat)((1 << bps) - 1); 2387 } 2388 else 2389 { 2390 _scale = 1.0; 2391 scale = 1.0; 2392 } 2393 2394 for (y = 0; y < _pixelsHigh; y++) 2395 { 2396 for (x = 0; x < _pixelsWide; x++) 2397 { 2398 NSUInteger iv[4], ia; 2399 CGFloat fv[4], fa; 2400 NSInteger i; 2401 2402 //[self getPixel: pixelData atX: x y: y]; 2403 getP(self, getPSel, pixelData, x, y); 2404 2405 if (_hasAlpha) 2406 { 2407 // This order depends on the bitmap format 2408 if (_format & NSAlphaFirstBitmapFormat) 2409 { 2410 ia = pixelData[0]; 2411 for (i = 0; i < _numColors - 1; i++) 2412 { 2413 iv[i] = pixelData[i + 1]; 2414 } 2415 } 2416 else 2417 { 2418 for (i = 0; i < _numColors - 1; i++) 2419 { 2420 iv[i] = pixelData[i]; 2421 } 2422 ia = pixelData[_numColors - 1]; 2423 } 2424 2425 // Scale to [0.0 ... 1.0] 2426 for (i = 0; i < _numColors - 1; i++) 2427 { 2428 fv[i] = iv[i] / _scale; 2429 } 2430 fa = ia / _scale; 2431 2432 if ((ia != 0 && fa < 1.0) && 2433 (_format & NSAlphaNonpremultipliedBitmapFormat) != 2434 (bitmapFormat & NSAlphaNonpremultipliedBitmapFormat)) 2435 { 2436 if (_format & NSAlphaNonpremultipliedBitmapFormat) 2437 { 2438 for (i = 0; i < _numColors - 1; i++) 2439 { 2440 fv[i] = fv[i] * fa; 2441 } 2442 } 2443 else 2444 { 2445 for (i = 0; i < _numColors - 1; i++) 2446 { 2447 fv[i] = fv[i] / fa; 2448 } 2449 } 2450 } 2451 } 2452 else 2453 { 2454 for (i = 0; i < _numColors; i++) 2455 { 2456 iv[i] = pixelData[i]; 2457 } 2458 // Scale to [0.0 ... 1.0] 2459 for (i = 0; i < _numColors; i++) 2460 { 2461 fv[i] = iv[i] / _scale; 2462 } 2463 fa = 1.0; 2464 } 2465 2466 if (alpha) 2467 { 2468 // Scale from [0.0 ... 1.0] 2469 for (i = 0; i < spp - 1; i++) 2470 { 2471 iv[i] = fv[i] * scale; 2472 } 2473 ia = fa * scale; 2474 2475 if (bitmapFormat & NSAlphaFirstBitmapFormat) 2476 { 2477 pixelData[0] = ia; 2478 for (i = 0; i < spp - 1; i++) 2479 { 2480 pixelData[i + 1] = iv[i]; 2481 } 2482 } 2483 else 2484 { 2485 for (i = 0; i < spp - 1; i++) 2486 { 2487 pixelData[i] = iv[i]; 2488 } 2489 pixelData[spp -1] = ia; 2490 } 2491 } 2492 else 2493 { 2494 // Scale from [0.0 ... 1.0] 2495 for (i = 0; i < spp; i++) 2496 { 2497 pixelData[i] = fv[i] * scale; 2498 } 2499 } 2500 2501 //[new setPixel: pixelData atX: x y: y]; 2502 setP(new, setPSel, pixelData, x, y); 2503 } 2504 } 2505 } 2506 else if (([colorSpaceName isEqualToString: NSDeviceRGBColorSpace] || 2507 [colorSpaceName isEqualToString: NSCalibratedRGBColorSpace]) 2508 && ([_colorSpace isEqualToString: NSCalibratedWhiteColorSpace] || 2509 [_colorSpace isEqualToString: NSCalibratedBlackColorSpace] || 2510 [_colorSpace isEqualToString: NSDeviceWhiteColorSpace] || 2511 [_colorSpace isEqualToString: NSDeviceBlackColorSpace])) 2512 { 2513 SEL getPSel = @selector(getPixel:atX:y:); 2514 SEL setPSel = @selector(setPixel:atX:y:); 2515 IMP getP = [self methodForSelector: getPSel]; 2516 IMP setP = [new methodForSelector: setPSel]; 2517 NSUInteger pixelData[4]; 2518 NSInteger x, y; 2519 CGFloat _scale; 2520 CGFloat scale; 2521 NSInteger max = (1 << _bitsPerSample) - 1; 2522 BOOL isWhite = [_colorSpace isEqualToString: NSCalibratedWhiteColorSpace] 2523 || [_colorSpace isEqualToString: NSDeviceWhiteColorSpace]; 2524 2525 NSDebugLLog(@"NSImage", @"Converting black/white bitmap data"); 2526 2527 if (_bitsPerSample != bps) 2528 { 2529 _scale = (CGFloat)((1 << _bitsPerSample) - 1); 2530 scale = (CGFloat)((1 << bps) - 1); 2531 } 2532 else 2533 { 2534 _scale = 1.0; 2535 scale = 1.0; 2536 } 2537 2538 for (y = 0; y < _pixelsHigh; y++) 2539 { 2540 for (x = 0; x < _pixelsWide; x++) 2541 { 2542 NSUInteger iv, ia; 2543 CGFloat fv, fa; 2544 2545 //[self getPixel: pixelData atX: x y: y]; 2546 getP(self, getPSel, pixelData, x, y); 2547 2548 if (_hasAlpha) 2549 { 2550 // This order depends on the bitmap format 2551 if (_format & NSAlphaFirstBitmapFormat) 2552 { 2553 ia = pixelData[0]; 2554 if (isWhite) 2555 iv = pixelData[1]; 2556 else 2557 iv = max - pixelData[1]; 2558 } 2559 else 2560 { 2561 if (isWhite) 2562 iv = pixelData[0]; 2563 else 2564 iv = max - pixelData[0]; 2565 ia = pixelData[1]; 2566 } 2567 2568 // Scale to [0.0 ... 1.0] 2569 fv = iv / _scale; 2570 fa = ia / _scale; 2571 2572 if ((ia != 0 && fa < 1.0) && 2573 (_format & NSAlphaNonpremultipliedBitmapFormat) != 2574 (bitmapFormat & NSAlphaNonpremultipliedBitmapFormat)) 2575 { 2576 if (_format & NSAlphaNonpremultipliedBitmapFormat) 2577 { 2578 fv = fv * fa; 2579 } 2580 else 2581 { 2582 fv = fv / fa; 2583 } 2584 } 2585 } 2586 else 2587 { 2588 if (isWhite) 2589 iv = pixelData[0]; 2590 else 2591 iv = max - pixelData[0]; 2592 // Scale to [0.0 ... 1.0] 2593 fv = iv / _scale; 2594 fa = 1.0; 2595 } 2596 2597 if (alpha) 2598 { 2599 // Scale from [0.0 ... 1.0] 2600 iv = fv * scale; 2601 ia = fa * scale; 2602 2603 if (bitmapFormat & NSAlphaFirstBitmapFormat) 2604 { 2605 pixelData[0] = ia; 2606 pixelData[1] = iv; 2607 pixelData[2] = iv; 2608 pixelData[3] = iv; 2609 } 2610 else 2611 { 2612 pixelData[0] = iv; 2613 pixelData[1] = iv; 2614 pixelData[2] = iv; 2615 pixelData[3] = ia; 2616 } 2617 } 2618 else 2619 { 2620 // Scale from [0.0 ... 1.0] 2621 iv = fv * scale; 2622 pixelData[0] = iv; 2623 pixelData[1] = iv; 2624 pixelData[2] = iv; 2625 } 2626 2627 //[new setPixel: pixelData atX: x y: y]; 2628 setP(new, setPSel, pixelData, x, y); 2629 } 2630 } 2631 } 2632 else 2633 { 2634 SEL getCSel = @selector(colorAtX:y:); 2635 SEL setCSel = @selector(setColor:atX:y:); 2636 IMP getC = [self methodForSelector: getCSel]; 2637 IMP setC = [new methodForSelector: setCSel]; 2638 NSInteger i, j; 2639 2640 NSDebugLLog(@"NSImage", @"Slow converting %@ bitmap data to %@", 2641 _colorSpace, colorSpaceName); 2642 for (j = 0; j < _pixelsHigh; j++) 2643 { 2644 CREATE_AUTORELEASE_POOL(pool); 2645 2646 for (i = 0; i < _pixelsWide; i++) 2647 { 2648 NSColor *c; 2649 2650 //c = [self colorAtX: i y: j]; 2651 c = getC(self, getCSel, i, j); 2652 //[new setColor: c atX: i y: j]; 2653 setC(new, setCSel, c, i, j); 2654 } 2655 [pool drain]; 2656 } 2657 } 2658 2659 return AUTORELEASE(new); 2660 } 2661} 2662 2663@end 2664