Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
QuartzPixmap.mm
Go to the documentation of this file.
1// @(#)root/graf2d:$Id$
2// Author: Timur Pocheptsov 16/02/2012
3
4/*************************************************************************
5 * Copyright (C) 1995-2012, Rene Brun and Fons Rademakers. *
6 * All rights reserved. *
7 * *
8 * For the licensing terms see $ROOTSYS/LICENSE. *
9 * For the list of contributors see $ROOTSYS/README/CREDITS. *
10 *************************************************************************/
11
12//#define NDEBUG
13
14#include <algorithm>
15#include <utility>
16#include <cassert>
17#include <cstddef>
18#include <limits>
19#include <new>
20
21#include "CocoaGuiTypes.h"
22#include "QuartzWindow.h"
23#include "QuartzPixmap.h"
24#include "QuartzUtils.h"
25#include "CocoaUtils.h"
26#include "X11Colors.h"
27
28namespace X11 = ROOT::MacOSX::X11;
29namespace Util = ROOT::MacOSX::Util;
30namespace Quartz = ROOT::Quartz;
31
32@implementation QuartzPixmap
33
34@synthesize fID;
35
36//______________________________________________________________________________
37- (id) initWithW : (unsigned) width H : (unsigned) height scaleFactor : (CGFloat) scaleFactor
38{
39 if (self = [super init]) {
40 fWidth = 0;
41 fHeight = 0;
43
44 if (![self resizeW : width H : height scaleFactor : scaleFactor]) {
45 [self release];
46 return nil;
47 }
48 }
49
50 return self;
51}
52
53//______________________________________________________________________________
54- (BOOL) resizeW : (unsigned) width H : (unsigned) height scaleFactor : (CGFloat) scaleFactor
55{
56 assert(width > 0 && "resizeW:H:, Pixmap width must be positive");
57 assert(height > 0 && "resizeW:H:, Pixmap height must be positive");
58
59 fScaleFactor = scaleFactor;
60
61 std::vector<unsigned char> memory;
62
63 const unsigned scaledW = width * fScaleFactor;
64 const unsigned scaledH = height * fScaleFactor;
65
66 try {
67 memory.resize(scaledW * scaledH * 4);//[0]
68 } catch (const std::bad_alloc &) {
69 NSLog(@"QuartzPixmap: -resizeW:H:, memory allocation failed");
70 return NO;
71 }
72
74 if (!colorSpace.Get()) {
75 NSLog(@"QuartzPixmap: -resizeW:H:, CGColorSpaceCreateDeviceRGB failed");
76 return NO;
77 }
78
80 scaledW * 4, colorSpace.Get(),
82 if (!ctx.Get()) {
83 NSLog(@"QuartzPixmap: -resizeW:H:, CGBitmapContextCreateWithData failed");
84 return NO;
85 }
86
87 //Now, apply scaling.
88
89 if (fScaleFactor > 1)
91
92 fContext.Reset(ctx.Release());
93
94 //sizes, data.
95 fWidth = width;
97 fData.swap(memory);
98
99 return YES;
100}
101
102//______________________________________________________________________________
104{
105 return [self createImageFromPixmap : X11::Rectangle(0, 0, fWidth, fHeight)];
106}
107
108//______________________________________________________________________________
109- (CGImageRef) createImageFromPixmap : (X11::Rectangle) cropArea
110{
111 //Crop area must be valid and adjusted by caller.
112
113 //This function is incorrect in a general case, it does not care about
114 //cropArea.fX and cropArea.fY, very sloppy implementation.
115
116 assert(cropArea.fX >= 0 && "createImageFromPixmap:, cropArea.fX is negative");
117 assert(cropArea.fY >= 0 && "createImageFromPixmap:, cropArea.fY is negative");
118 assert(cropArea.fWidth <= fWidth && "createImageFromPixmap:, bad cropArea.fWidth");
119 assert(cropArea.fHeight <= fHeight && "createImageFromPixmap:, bad cropArea.fHeight");
120
121 const unsigned scaledW = fWidth * fScaleFactor;
122 const unsigned scaledH = fHeight * fScaleFactor;
123
124
126 scaledW * scaledH * 4, nullptr));
127 if (!provider.Get()) {
128 NSLog(@"QuartzPixmap: -pixmapToImage, CGDataProviderCreateWithData failed");
129 return 0;
130 }
131
132 //RGB - this is only for TGCocoa::CreatePixmapFromData.
134 if (!colorSpace.Get()) {
135 NSLog(@"QuartzPixmap: -pixmapToImage, CGColorSpaceCreateDeviceRGB failed");
136 return 0;
137 }
138
139 //8 bits per component, 32 bits per pixel, 4 bytes per pixel, kCGImageAlphaLast:
140 //all values hardcoded for TGCocoa.
142 8, 32, fWidth * 4 * fScaleFactor, colorSpace.Get(),
143 kCGImageAlphaPremultipliedLast, provider.Get(), 0,
145
146 return image;
147}
148
149//______________________________________________________________________________
150- (BOOL) fIsPixmap
151{
152 return YES;
153}
154
155//______________________________________________________________________________
156- (BOOL) fIsOpenGLWidget
157{
158 return NO;
159}
160
161//______________________________________________________________________________
162- (CGFloat) fScaleFactor
163{
164 return fScaleFactor;
165}
166
167//______________________________________________________________________________
169{
170 assert(fContext.Get() != 0 && "fContext, called for bad pixmap");
171
172 return fContext.Get();
173}
174
175//______________________________________________________________________________
176- (unsigned) fWidth
177{
178 assert(fContext.Get() != 0 && "fWidth, called for bad pixmap");
179
180 return fWidth;
181}
182
183//______________________________________________________________________________
184- (unsigned) fHeight
185{
186 assert(fContext.Get() != 0 && "fHeight, called for bad pixmap");
187
188 return fHeight;
189}
190
191//______________________________________________________________________________
192- (TAttLine *) attLine
193{
194 return &fAttLine;
195}
196
197//______________________________________________________________________________
198- (TAttFill *) attFill
199{
200 return &fAttFill;
201}
202
203//______________________________________________________________________________
205{
206 return &fAttMarker;
207}
208
209//______________________________________________________________________________
210- (TAttText *) attText
211{
212 return &fAttText;
213}
214
215//______________________________________________________________________________
216- (void) setDirectDraw : (BOOL) mode
217{
219}
220
221//______________________________________________________________________________
222- (BOOL) isDirectDraw
223{
224 return fDirectDraw;
225}
226
227//______________________________________________________________________________
228- (void) copyImage : (QuartzImage *) srcImage area : (X11::Rectangle) area
229 withMask : (QuartzImage *) mask clipOrigin : (X11::Point) clipXY toPoint : (X11::Point) dstPoint
230{
231 using namespace ROOT::MacOSX::X11;
232
233 //Check parameters.
234 assert(srcImage != nil && "copyImage:area:withMask:clipOrigin:toPoint:, srcImage parameter is nil");
235 assert(srcImage.fImage != nil && "copyImage:area:withMask:clipOrigin:toPoint:, srcImage.fImage is nil");
236
238 NSLog(@"QuartzPixmap: -copyImage:srcImage:area:withMask:clipOrigin"
239 ":toPoint, srcRect and copyRect do not intersect");
240 return;
241 }
242
243 CGImageRef subImage = 0;//RAII not really needed.
244 bool needSubImage = false;
245 if (area.fX || area.fY || area.fWidth != srcImage.fWidth || area.fHeight != srcImage.fHeight) {
246 needSubImage = true;
248 if (!subImage) {
249 NSLog(@"QuartzPixmap: -copyImage:area:withMask:clipOrigin:toPoint:, subimage creation failed");
250 return;
251 }
252 } else
253 subImage = srcImage.fImage;
254
255 //Save context state.
257
258 if (mask) {
259 assert(mask.fImage != nil && "copyImage:area:withMask:clipOrigin:toPoint, mask is not nil, but mask.fImage is nil");
260 assert(CGImageIsMask(mask.fImage) && "copyImage:area:withMask:clipOrigin:toPoint, mask.fImage is not a mask");
261 //TODO: fix the possible overflow? (though, who can have such images???)
262 clipXY.fY = LocalYROOTToCocoa(self, clipXY.fY + mask.fHeight);
263 const CGRect clipRect = CGRectMake(clipXY.fX, clipXY.fY, mask.fWidth, mask.fHeight);
265 }
266
267 //TODO: fix the possible overflow? (though, who can have such images???)
268 dstPoint.fY = LocalYROOTToCocoa(self, dstPoint.fY + area.fHeight);
269 const CGRect imageRect = CGRectMake(dstPoint.fX, dstPoint.fY, area.fWidth, area.fHeight);
271
272 if (needSubImage)
274}
275
276//______________________________________________________________________________
277- (void) copyPixmap : (QuartzPixmap *) srcPixmap area : (X11::Rectangle) area
278 withMask : (QuartzImage *)mask clipOrigin : (X11::Point) clipXY toPoint : (X11::Point) dstPoint
279{
280 using namespace ROOT::MacOSX::X11;
281
282 assert(srcPixmap != nil &&
283 "copyPixmap:area:withMask:clipOrigin:toPoint, srcPixmap parameter is nil");
284
286 NSLog(@"QuartzPixmap: -copyPixmap:area:withMask:clipOrigin:"
287 "toPoint, srcRect and copyRect do not intersect");
288 return;
289 }
290
292 if (!image.Get())
293 return;
294
296
297 if (mask) {
298 assert(mask.fImage != nil &&
299 "copyPixmap:area:withMask:clipOrigin:toPoint, mask is not nil, but mask.fImage is nil");
300 assert(CGImageIsMask(mask.fImage) &&
301 "copyPixmap:area:withMask:clipOrigin:toPoint, mask.fImage is not a mask");
302 //TODO: fix the possible overflow? (though, who can have such images???)
303 clipXY.fY = LocalYROOTToCocoa(self, clipXY.fY + mask.fHeight);
304 const CGRect clipRect = CGRectMake(clipXY.fX, clipXY.fY, mask.fWidth, mask.fHeight);
306 }
307
308 //TODO: fix the possible overflow? (though, who can have such images???)
309 dstPoint.fY = LocalYROOTToCocoa(self, dstPoint.fY + area.fHeight);
310 const CGRect imageRect = CGRectMake(dstPoint.fX, dstPoint.fY, area.fWidth, area.fHeight);
312}
313
314//______________________________________________________________________________
315- (void) copy : (NSObject<X11Drawable> *) src area : (X11::Rectangle) area
316 withMask : (QuartzImage *)mask clipOrigin : (X11::Point) origin toPoint : (X11::Point) dstPoint
317{
318 assert(area.fWidth && area.fHeight &&
319 "copy:area:widthMask:clipOrigin:toPoint, empty area to copy");
320
322 [self copyImage : (QuartzImage *)src area : area withMask : mask clipOrigin : origin toPoint : dstPoint];
323 } else if ([src isKindOfClass : [QuartzPixmap class]]) {
324 [self copyPixmap : (QuartzPixmap *)src area : area withMask : mask clipOrigin : origin toPoint : dstPoint];
325 } else
326 assert(0 && "Can copy only from pixmap or image");
327}
328
329//______________________________________________________________________________
330- (unsigned char *) readColorBits : (X11::Rectangle) area
331{
332 assert(area.fWidth && area.fHeight && "readColorBits:, empty area to copy");
333
335 NSLog(@"QuartzPixmap: readColorBits:intoBuffer:, src and copy area do not intersect");
336 return 0;
337 }
338
339 // Not std::vector, since we pass the ownership ...
340 unsigned char *buffer = 0;
341 try {
342 buffer = new unsigned char[area.fWidth * area.fHeight * 4]();
343 } catch (const std::bad_alloc &) {
344 NSLog(@"QuartzImage: -readColorBits:, memory allocation failed");
345 return 0;
346 }
347
349
350 if (fScaleFactor > 1) {
351 scaledPixmap.Reset([[QuartzPixmap alloc] initWithW : fWidth H : fHeight scaleFactor : 1.]);
352 //Ooops, all screwed up!!!
353 if (!scaledPixmap.Get()) {
354 NSLog(@"QuartzImage: -readColorBits:, can not create scaled pixmap");
355 return buffer;//empty buffer.
356 }
357
358 [scaledPixmap.Get() copy : self area : X11::Rectangle(0, 0, fWidth, fHeight)
359 withMask : nil clipOrigin : X11::Point() toPoint : X11::Point()];
360 }
361
362 unsigned char *dstPixel = buffer;
363
364 //fImageData has 4 bytes per pixel.
365 //TODO: possible overflows everywhere :(
366 const unsigned char *line = fScaleFactor == 1 ? &fData[0] + area.fY * fWidth * 4
367 : &scaledPixmap.Get()->fData[0] + area.fY * fWidth * 4;
368
369 const unsigned char *srcPixel = line + area.fX * 4;
370
371 for (unsigned i = 0; i < area.fHeight; ++i) {
372 for (unsigned j = 0; j < area.fWidth; ++j, srcPixel += 4, dstPixel += 4) {
373 dstPixel[0] = srcPixel[0];
374 dstPixel[1] = srcPixel[1];
375 dstPixel[2] = srcPixel[2];
376 dstPixel[3] = srcPixel[3];
377 }
378
379 line += fWidth * 4;
380 srcPixel = line + area.fX * 4;
381 }
382
383 return buffer;
384}
385
386//______________________________________________________________________________
387- (unsigned char *) fData
388{
389 return &fData[0];
390}
391
392//______________________________________________________________________________
393- (void) putPixel : (const unsigned char *) rgb X : (unsigned) x Y : (unsigned) y
394{
395 //Primitive version of XPutPixel.
396 assert(rgb != 0 && "putPixel:X:Y:, rgb parameter is null");
398 assert(y < fHeight && "putPixel:X:Y:, y parameter is >= self.fHeight");
399
400 unsigned char * const data = &fData[0];
401 if (fScaleFactor > 1) {
402 //Ooops, and what should I do now???
403 const unsigned scaledW = fWidth * fScaleFactor;
404 unsigned char *dst = data + unsigned(y * fScaleFactor * scaledW * 4) + unsigned(x * fScaleFactor * 4);
405
406 for (unsigned i = 0; i < 2; ++i, dst += 4) {
407 dst[0] = rgb[0];
408 dst[1] = rgb[1];
409 dst[2] = rgb[2];
410 dst[3] = 255;
411 }
412
413 dst -= 8;
414 dst += scaledW * 4;
415
416 for (unsigned i = 0; i < 2; ++i, dst += 4) {
417 dst[0] = rgb[0];
418 dst[1] = rgb[1];
419 dst[2] = rgb[2];
420 dst[3] = 255;
421 }
422 } else {
423 unsigned char *dst = data + y * fWidth * 4 + x * 4;
424
425 dst[0] = rgb[0];
426 dst[1] = rgb[1];
427 dst[2] = rgb[2];
428 dst[3] = 255;
429 }
430}
431
432//______________________________________________________________________________
433- (void) addPixel : (const unsigned char *) rgb
434{
435 //Primitive version of XAddPixel.
436 assert(rgb != 0 && "addPixel:, rgb parameter is null");
437
438 for (unsigned i = 0; i < fHeight; ++i) {
439 for (unsigned j = 0; j < fWidth; ++j) {
440 fData[i * fWidth * 4 + j * 4] = rgb[0];
441 fData[i * fWidth * 4 + j * 4 + 1] = rgb[1];
442 fData[i * fWidth * 4 + j * 4 + 2] = rgb[2];
443 fData[i * fWidth * 4 + j * 4 + 3] = rgb[3];
444 }
445 }
446}
447
448@end
449
450
451@implementation QuartzImage
452
453@synthesize fIsStippleMask;
454@synthesize fID;
455
456//______________________________________________________________________________
457- (id) initWithW : (unsigned) width H : (unsigned) height data : (unsigned char *) data
458{
459 assert(width != 0 && "initWithW:H:data:, width parameter is 0");
460 assert(height != 0 && "initWithW:H:data:, height parameter is 0");
461 assert(data != 0 && "initWithW:H:data:, data parameter is null");
462
463 if (self = [super init]) {
464 Util::NSScopeGuard<QuartzImage> selfGuard(self);
465
466 //This w * h * 4 is ONLY for TGCocoa::CreatePixmapFromData.
467 //If needed something else, I'll make this code more generic.
468 try {
469 fImageData.resize(width * height * 4);
470 } catch (const std::bad_alloc &) {
471 NSLog(@"QuartzImage: -initWithW:H:data:, memory allocation failed");
472 return nil;
473 }
474
475 std::copy(data, data + width * height * 4, &fImageData[0]);
476
477 fIsStippleMask = NO;
478 const Util::CFScopeGuard<CGDataProviderRef>
479 provider(CGDataProviderCreateWithData(nullptr, &fImageData[0], width * height * 4, nullptr));
480 if (!provider.Get()) {
482 return nil;
483 }
484
485 //RGB - this is only for TGCocoa::CreatePixmapFromData.
486 const Util::CFScopeGuard<CGColorSpaceRef> colorSpace(CGColorSpaceCreateDeviceRGB());
487 if (!colorSpace.Get()) {
489 return nil;
490 }
491
492 //8 bits per component, 32 bits per pixel, 4 bytes per pixel, kCGImageAlphaLast:
493 //all values hardcoded for TGCocoa::CreatePixmapFromData.
494 fImage.Reset(CGImageCreate(width, height, 8, 32, width * 4, colorSpace.Get(),
495 kCGImageAlphaLast, provider.Get(), 0, false,
496 kCGRenderingIntentDefault));
497
498 if (!fImage.Get()) {
499 NSLog(@"QuartzImage: -initWithW:H:data: CGImageCreate failed");
500 return nil;
501 }
502
503 fWidth = width;
504 fHeight = height;
505
506 selfGuard.Release();
507 }
508
509 return self;
510}
511
512//______________________________________________________________________________
513- (id) initMaskWithW : (unsigned) width H : (unsigned) height bitmapMask : (unsigned char *) mask
514{
515 assert(width != 0 && "initMaskWithW:H:bitmapMask:, width parameter is zero");
516 assert(height != 0 && "initMaskWithW:H:bitmapMask:, height parameter is zero");
517 assert(mask != 0 && "initMaskWithW:H:bitmapMask:, mask parameter is null");
518
519 if (self = [super init]) {
520 Util::NSScopeGuard<QuartzImage> selfGuard(self);
521
522 try {
523 fImageData.resize(width * height);
524 } catch (const std::bad_alloc &) {
526 return nil;
527 }
528
529 std::copy(mask, mask + width * height, &fImageData[0]);
530
531 fIsStippleMask = YES;
532 const Util::CFScopeGuard<CGDataProviderRef> provider(CGDataProviderCreateWithData(nullptr, &fImageData[0],
533 width * height, nullptr));
534 if (!provider.Get()) {
536 return nil;
537 }
538
539 //0 -> decode, false -> shouldInterpolate.
540 fImage.Reset(CGImageMaskCreate(width, height, 8, 8, width, provider.Get(), 0, false));
541 if (!fImage.Get()) {
543 return nil;
544 }
545
546 fWidth = width;
547 fHeight = height;
548
549 selfGuard.Release();
550 }
551
552 return self;
553}
554
555//______________________________________________________________________________
556- (id) initMaskWithW : (unsigned) width H : (unsigned) height
557{
558 //Two-step initialization.
559
560 assert(width != 0 && "initMaskWithW:H:, width parameter is zero");
561 assert(height != 0 && "initMaskWithW:H:, height parameter is zero");
562
563 if (self = [super init]) {
564 Util::NSScopeGuard<QuartzImage> selfGuard(self);
565
566 try {
567 fImageData.resize(width * height);
568 } catch (const std::bad_alloc &) {
569 NSLog(@"QuartzImage: -initMaskWithW:H:, memory allocation failed");
570 return nil;
571 }
572
573 fIsStippleMask = YES;
574 const Util::CFScopeGuard<CGDataProviderRef> provider(CGDataProviderCreateWithData(nullptr, &fImageData[0],
575 width * height, nullptr));
576 if (!provider.Get()) {
578 return nil;
579 }
580
581 //0 -> decode, false -> shouldInterpolate.
582 fImage.Reset(CGImageMaskCreate(width, height, 8, 8, width, provider.Get(), 0, false));
583 if (!fImage.Get()) {
584 NSLog(@"QuartzImage: -initMaskWithW:H:, CGImageMaskCreate failed");
585 return nil;
586 }
587
588 selfGuard.Release();
589
590 fWidth = width;
591 fHeight = height;
592 }
593
594 return self;
595}
596
597//______________________________________________________________________________
598- (id) initFromPixmap : (QuartzPixmap *) pixmap
599{
600 //Two-step initialization.
601 assert(pixmap != nil && "initFromPixmap:, pixmap parameter is nil");
602 assert(pixmap.fWidth != 0 && "initFromPixmap:, pixmap width is zero");
603 assert(pixmap.fHeight != 0 && "initFromPixmap:, pixmap height is zero");
604
605 return [self initWithW : pixmap.fWidth H : pixmap.fHeight data : pixmap.fData];
606}
607
608//______________________________________________________________________________
609- (id) initFromImage : (QuartzImage *) image
610{
611 assert(image != nil && "initFromImage:, image parameter is nil");
612 assert(image.fWidth != 0 && "initFromImage:, image width is 0");
613 assert(image.fHeight != 0 && "initFromImage:, image height is 0");
614 assert(image.fIsStippleMask == NO && "initFromImage:, image is a stipple mask, not implemented");
615
616 return [self initWithW : image.fWidth H : image.fHeight data : &image->fImageData[0]];
617}
618
619//______________________________________________________________________________
620- (id) initFromImageFlipped : (QuartzImage *) image
621{
622 assert(image != nil && "initFromImageFlipped:, image parameter is nil");
623 assert(image.fWidth != 0 && "initFromImageFlipped:, image width is 0");
624 assert(image.fHeight != 0 && "initFromImageFlipped:, image height is 0");
625
626 const unsigned bpp = image.fIsStippleMask ? 1 : 4;
627
628 if (self = [super init]) {
629 const unsigned width = image.fWidth;
630 const unsigned height = image.fHeight;
631
632 Util::NSScopeGuard<QuartzImage> selfGuard(self);
633
634 try {
635 fImageData.resize(width * height * bpp);
636 } catch (const std::bad_alloc &) {
638 return nil;
639 }
640
641 const unsigned lineSize = bpp * width;
642 const unsigned char * const src = &image->fImageData[0];
643 unsigned char * const dst = &fImageData[0];
644 for (unsigned i = 0; i < height; ++i) {
645 const unsigned char *sourceLine = src + lineSize * (height - 1 - i);
646 unsigned char *dstLine = dst + i * lineSize;
647 std::copy(sourceLine, sourceLine + lineSize, dstLine);
648 }
649
650 if (bpp == 1) {
651 fIsStippleMask = YES;
652 const Util::CFScopeGuard<CGDataProviderRef> provider(CGDataProviderCreateWithData(nullptr, &fImageData[0],
653 width * height, nullptr));
654 if (!provider.Get()) {
656 return nil;
657 }
658
659 //0 -> decode, false -> shouldInterpolate.
660 fImage.Reset(CGImageMaskCreate(width, height, 8, 8, width, provider.Get(), 0, false));
661 if (!fImage.Get()) {
663 return nil;
664 }
665 } else {
666 fIsStippleMask = NO;
667 const Util::CFScopeGuard<CGDataProviderRef> provider(CGDataProviderCreateWithData(nullptr, &fImageData[0],
668 width * height * 4, nullptr));
669 if (!provider.Get()) {
671 return nil;
672 }
673
674 const Util::CFScopeGuard<CGColorSpaceRef> colorSpace(CGColorSpaceCreateDeviceRGB());
675 if (!colorSpace.Get()) {
677 return nil;
678 }
679
680 //8 bits per component, 32 bits per pixel, 4 bytes per pixel, kCGImageAlphaLast:
681 //all values hardcoded for TGCocoa::CreatePixmapFromData.
682 fImage.Reset(CGImageCreate(width, height, 8, 32, width * 4, colorSpace.Get(), kCGImageAlphaLast,
683 provider.Get(), 0, false, kCGRenderingIntentDefault));
684 if (!fImage.Get()) {
686 return nil;
687 }
688 }
689
690 fWidth = width;
691 fHeight = height;
692
693 selfGuard.Release();
694 }
695
696 return self;
697}
698
699//______________________________________________________________________________
700- (BOOL) isRectInside : (X11::Rectangle) area
701{
702 if (area.fX < 0 || (unsigned)area.fX >= fWidth)
703 return NO;
704 if (area.fY < 0 || (unsigned)area.fY >= fHeight)
705 return NO;
706 if (area.fWidth > fWidth || !area.fWidth)
707 return NO;
708 if (area.fHeight > fHeight || !area.fHeight)
709 return NO;
710
711 return YES;
712}
713
714//______________________________________________________________________________
715- (unsigned char *) readColorBits : (X11::Rectangle) area
716{
717 assert([self isRectInside : area] == YES && "readColorBits: bad area parameter");
718 //Image, bitmap - they all must be converted to ARGB (bitmap) or BGRA (image) (for libAfterImage).
719 //Raw pointer - we pass the ownership.
720 unsigned char *buffer = 0;
721
722 try {
723 buffer = new unsigned char[area.fWidth * area.fHeight * 4]();
724 } catch (const std::bad_alloc &) {
725 NSLog(@"QuartzImage: -readColorBits:, memory allocation failed");
726 return 0;
727 }
728
729 unsigned char *dstPixel = buffer;
730 if (CGImageIsMask(fImage.Get())) {
731 //fImageData has 1 byte per pixel.
732 const unsigned char *line = &fImageData[0] + area.fY * fWidth;
733 const unsigned char *srcPixel = line + area.fX;
734
735 for (unsigned i = 0; i < area.fHeight; ++i) {
736 for (unsigned j = 0; j < area.fWidth; ++j, ++srcPixel, dstPixel += 4) {
737 if (!srcPixel[0])
738 dstPixel[0] = 255;//can be 1 or anything different from 0.
739 }
740
741 line += fWidth;
742 srcPixel = line + area.fX;
743 }
744
745 } else {
746 //fImageData has 4 bytes per pixel.
747 const unsigned char *line = &fImageData[0] + area.fY * fWidth * 4;
748 const unsigned char *srcPixel = line + area.fX * 4;
749
750 for (unsigned i = 0; i < area.fHeight; ++i) {
751 for (unsigned j = 0; j < area.fWidth; ++j, srcPixel += 4, dstPixel += 4) {
752 dstPixel[0] = srcPixel[2];
753 dstPixel[1] = srcPixel[1];
754 dstPixel[2] = srcPixel[0];
755 dstPixel[3] = srcPixel[3];
756 }
757
758 line += fWidth * 4;
759 srcPixel = line + area.fX * 4;
760 }
761
762 return buffer;
763 }
764
765 return buffer;
766}
767
768//______________________________________________________________________________
769- (BOOL) fIsPixmap
770{
771 return YES;
772}
773
774//______________________________________________________________________________
775- (BOOL) fIsOpenGLWidget
776{
777 return NO;
778}
779
780//______________________________________________________________________________
781- (CGFloat) fScaleFactor
782{
783 // TODO: this is to be understood yet ...
784 return 1.;
785}
786
787//______________________________________________________________________________
788- (unsigned) fWidth
789{
790 return fWidth;
791}
792
793//______________________________________________________________________________
794- (unsigned) fHeight
795{
796 return fHeight;
797}
798
799//______________________________________________________________________________
800- (TAttLine *) attLine
801{
802 return &fAttLine;
803}
804
805//______________________________________________________________________________
806- (TAttFill *) attFill
807{
808 return &fAttFill;
809}
810
811//______________________________________________________________________________
812- (TAttMarker *) attMarker
813{
814 return &fAttMarker;
815}
816
817//______________________________________________________________________________
818- (TAttText *) attText
819{
820 return &fAttText;
821}
822
823//______________________________________________________________________________
824- (CGImageRef) fImage
825{
826 return fImage.Get();
827}
828
829@end
830
831namespace ROOT {
832namespace MacOSX {
833namespace X11 {
834
835//______________________________________________________________________________
836CGImageRef CreateSubImage(QuartzImage *image, const Rectangle &area)
837{
838 assert(image != nil && "CreateSubImage, image parameter is nil");
839
840 const CGRect subImageRect = CGRectMake(area.fX, area.fY, area.fHeight, area.fWidth);
841 return CGImageCreateWithImageInRect(image.fImage, subImageRect);
842}
843
844namespace {
845
846//Now, close your eyes and open them at the end of this block. :)
847//Sure, this can be done easy, but I hate to convert between negative signed integers and
848//unsigned integers and the other way, so I have this implementation (integers will be always
849//positive and they obviously fit into unsigned integers).
850
851typedef std::pair<int, unsigned> range_type;
852
853//______________________________________________________________________________
854bool FindOverlapSameSigns(const range_type &left, const range_type &right, range_type &intersection)
855{
856 //"Same" means both xs are non-negative, or both are negative.
857 //left.x <= right.x.
858 const unsigned dX(right.first - left.first);//diff fits into the positive range of int.
859 //No intersection.
860 if (dX >= left.second)
861 return false;
862 //Find an intersection.
863 intersection.first = right.first;
864 intersection.second = std::min(right.second, left.second - dX);//left.second is always > dX.
865
866 return true;
867}
868
869//______________________________________________________________________________
870bool FindOverlapDifferentSigns(const range_type &left, const range_type &right, range_type &intersection)
871{
872 //x2 - x1 can overflow.
873 //Left.x is negative, right.x is non-negative (0 included).
874 const unsigned signedMinAbs(std::numeric_limits<unsigned>::max() / 2 + 1);
875
876 if (left.first == std::numeric_limits<int>::min()) {//hehehe
877 if (left.second <= signedMinAbs)
878 return false;
879
880 if (left.second - signedMinAbs <= unsigned(right.first))
881 return false;
882
883 intersection.first = right.first;
884 intersection.second = std::min(right.second, left.second - signedMinAbs - unsigned(right.first));
885 } else {
886 const unsigned leftXAbs(-left.first);//-left.first can't overflow.
887 if (leftXAbs >= left.second)
888 return false;
889
890 if (left.second - leftXAbs <= unsigned(right.first))
891 return false;
892
893 intersection.first = right.first;
894 intersection.second = std::min(right.second, left.second - leftXAbs - unsigned(right.first));
895 }
896
897 return true;
898}
899
900//______________________________________________________________________________
901bool FindOverlap(const range_type &range1, const range_type &range2, range_type &intersection)
902{
903 range_type left;
904 range_type right;
905
906 if (range1.first < range2.first) {
907 left = range1;
908 right = range2;
909 } else {
910 left = range2;
911 right = range1;
912 }
913
914 if (left.first < 0)
915 return right.first < 0 ? FindOverlapSameSigns(left, right, intersection) :
916 FindOverlapDifferentSigns(left, right, intersection);
917
918 return FindOverlapSameSigns(left, right, intersection);
919}
920
921}
922
923//______________________________________________________________________________
924bool AdjustCropArea(const Rectangle &srcRect, Rectangle &cropArea)
925{
926 //Find rects intersection.
927 range_type xIntersection;
928 if (!FindOverlap(range_type(srcRect.fX, srcRect.fWidth),
929 range_type(cropArea.fX, cropArea.fWidth), xIntersection))
930 return false;
931
932 range_type yIntersection;
933 if (!FindOverlap(range_type(srcRect.fY, srcRect.fHeight),
934 range_type(cropArea.fY, cropArea.fHeight), yIntersection))
935 return false;
936
937 cropArea.fX = xIntersection.first;
938 cropArea.fWidth = xIntersection.second;
939
940 cropArea.fY = yIntersection.first;
941 cropArea.fHeight = yIntersection.second;
942
943 return true;
944}
945
946//______________________________________________________________________________
947bool AdjustCropArea(QuartzImage *srcImage, Rectangle &cropArea)
948{
949 assert(srcImage != nil && "AdjustCropArea, srcImage parameter is nil");
950 assert(srcImage.fImage != nil && "AdjustCropArea, srcImage.fImage is nil");
951
952 return AdjustCropArea(X11::Rectangle(0, 0, srcImage.fWidth, srcImage.fHeight), cropArea);
953}
954
955//______________________________________________________________________________
956bool AdjustCropArea(QuartzImage *srcImage, NSRect &cropArea)
957{
958 assert(srcImage != nil && "AdjustCropArea, srcImage parameter is nil");
959 assert(srcImage.fImage != 0 && "AdjustCropArea, srcImage.fImage is null");
960
961 const Rectangle srcRect(0, 0, srcImage.fWidth, srcImage.fHeight);
962 Rectangle dstRect(int(cropArea.origin.x), int(cropArea.origin.y),
963 unsigned(cropArea.size.width), unsigned(cropArea.size.height));
964
965 if (AdjustCropArea(srcRect, dstRect)) {
966 cropArea.origin.x = dstRect.fX;
967 cropArea.origin.y = dstRect.fY;
968 cropArea.size.width = dstRect.fWidth;
969 cropArea.size.height = dstRect.fHeight;
970
971 return true;
972 }
973
974 return false;
975}
976
977//______________________________________________________________________________
978bool AdjustCropArea(QuartzPixmap *srcPixmap, X11::Rectangle &cropArea)
979{
980 assert(srcPixmap != nil && "AdjustCropArea, srcPixmap parameter is nil");
981
982 return AdjustCropArea(X11::Rectangle(0, 0, srcPixmap.fWidth, srcPixmap.fHeight), cropArea);
983}
984
985//______________________________________________________________________________
986bool TestBitmapBit(const unsigned char *bitmap, unsigned w, unsigned i, unsigned j)
987{
988 //Test if a bit (i,j) is set in a bitmap (w, h).
989
990 //Code in ROOT's GUI suggests, that byte is octet.
991 assert(bitmap != 0 && "TestBitmapBit, bitmap parameter is null");
992 assert(w != 0 && "TestBitmapBit, w parameter is 0");
993 assert(i < w && "TestBitmapBit, i parameter is >= w");
994
995 const unsigned bytesPerLine = (w + 7) / 8;
996 const unsigned char *line = bitmap + j * bytesPerLine;
997 const unsigned char byteValue = line[i / 8];
998
999 return byteValue & (1 << (i % 8));
1000}
1001
1002//______________________________________________________________________________
1003void FillPixmapBuffer(const unsigned char *bitmap, unsigned width, unsigned height,
1004 ULong_t foregroundPixel, ULong_t backgroundPixel, unsigned depth,
1005 unsigned char *imageData)
1006{
1007 assert(bitmap != 0 && "FillPixmapBuffer, bitmap parameter is null");
1008 assert(width != 0 && "FillPixmapBuffer, width parameter is 0");
1009 assert(height != 0 && "FillPixmapBuffer, height parameter is 0");
1010 assert(imageData != 0 && "FillPixmapBuffer, imageData parameter is null");
1011
1012 if (depth > 1) {
1013 unsigned char foregroundColor[4] = {};
1014 PixelToRGB(foregroundPixel, foregroundColor);
1015 unsigned char backgroundColor[4] = {};
1016 PixelToRGB(backgroundPixel, backgroundColor);
1017
1018 for (unsigned j = 0; j < height; ++j) {
1019 const unsigned line = j * width * 4;
1020 for (unsigned i = 0; i < width; ++i) {
1021 const unsigned pixel = line + i * 4;
1022
1023 if (TestBitmapBit(bitmap, width, i, j)) {
1024 //Foreground color.
1025 imageData[pixel] = foregroundColor[0];
1026 imageData[pixel + 1] = foregroundColor[1];
1027 imageData[pixel + 2] = foregroundColor[2];
1028 } else {
1029 imageData[pixel] = backgroundColor[0];
1030 imageData[pixel + 1] = backgroundColor[1];
1031 imageData[pixel + 2] = backgroundColor[2];
1032 }
1033
1034 imageData[pixel + 3] = 255;
1035 }
1036 }
1037 } else {
1038 for (unsigned j = 0; j < height; ++j) {
1039 const unsigned line = j * width;
1040 for (unsigned i = 0; i < width; ++i) {
1041 const unsigned pixel = line + i;
1042 if (TestBitmapBit(bitmap, width, i, j))
1043 imageData[pixel] = 0;
1044 else
1045 imageData[pixel] = 255;//mask out pixel.
1046 }
1047 }
1048 }
1049}
1050
1051}//X11
1052}//MacOSX
1053}//ROOT
#define a(i)
Definition RSha256.hxx:99
#define X(type, name)
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void data
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t mask
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char bitmap
Option_t Option_t TPoint TPoint const char mode
Option_t Option_t width
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t src
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t height
Fill Area Attributes class.
Definition TAttFill.h:21
Line Attributes class.
Definition TAttLine.h:21
Marker Attributes class.
Definition TAttMarker.h:21
Text Attributes class.
Definition TAttText.h:21
TLine * line
TAttLine fAttLine
current line attributes
TAttMarker * attMarker
TAttText fAttText
current text attribute
TAttLine * attLine
TAttFill fAttFill
current fill attributes
unsigned fHeight
std::vector< unsigned char > fData
TAttMarker fAttMarker
current marker attribute
ROOT::MacOSX::Util::CFScopeGuard< CGContextRef > fContext
CGImageRef createImageFromPixmap()
TAttFill * attFill
unsigned fWidth
TAttText * attText
CGFloat fScaleFactor
unsigned fID
Double_t y[n]
Definition legend1.C:17
#define H(x, y, z)
bool TestBitmapBit(const unsigned char *bitmap, unsigned w, unsigned i, unsigned j)
void FillPixmapBuffer(const unsigned char *bitmap, unsigned width, unsigned height, ULong_t foregroundPixel, ULong_t backgroundPixel, unsigned depth, unsigned char *imageData)
CGImageRef CreateSubImage(QuartzImage *image, const Rectangle &area)
int LocalYROOTToCocoa(NSView< X11Window > *parentView, CGFloat yROOT)
bool AdjustCropArea(const Rectangle &srcRect, Rectangle &cropArea)
null_t< F > null()