37- (id)
initWithW : (
unsigned) width H : (
unsigned) height scaleFactor : (CGFloat) scaleFactor
53- (BOOL)
resizeW : (
unsigned) width H : (
unsigned) height scaleFactor : (CGFloat) scaleFactor
55 assert(
width > 0 &&
"resizeW:H:, Pixmap width must be positive");
56 assert(
height > 0 &&
"resizeW:H:, Pixmap height must be positive");
60 std::vector<unsigned char>
memory;
67 }
catch (
const std::bad_alloc &) {
68 NSLog(
@"QuartzPixmap: -resizeW:H:, memory allocation failed");
74 NSLog(
@"QuartzPixmap: -resizeW:H:, CGColorSpaceCreateDeviceRGB failed");
82 NSLog(
@"QuartzPixmap: -resizeW:H:, CGBitmapContextCreateWithData failed");
104 return [
self createImageFromPixmap : X11::Rectangle(0, 0, fWidth, fHeight)];
115 assert(
cropArea.fX >= 0 &&
"createImageFromPixmap:, cropArea.fX is negative");
116 assert(
cropArea.fY >= 0 &&
"createImageFromPixmap:, cropArea.fY is negative");
126 if (!provider.Get()) {
127 NSLog(
@"QuartzPixmap: -pixmapToImage, CGDataProviderCreateWithData failed");
134 NSLog(
@"QuartzPixmap: -pixmapToImage, CGColorSpaceCreateDeviceRGB failed");
192 withMask : (
QuartzImage *) mask clipOrigin : (
X11::Point) clipXY toPoint : (
X11::Point) dstPoint
197 assert(
srcImage !=
nil &&
"copyImage:area:withMask:clipOrigin:toPoint:, srcImage parameter is nil");
198 assert(
srcImage.fImage !=
nil &&
"copyImage:area:withMask:clipOrigin:toPoint:, srcImage.fImage is nil");
201 NSLog(
@"QuartzPixmap: -copyImage:srcImage:area:withMask:clipOrigin"
202 ":toPoint, srcRect and copyRect do not intersect");
212 NSLog(
@"QuartzPixmap: -copyImage:area:withMask:clipOrigin:toPoint:, subimage creation failed");
222 assert(
mask.fImage !=
nil &&
"copyImage:area:withMask:clipOrigin:toPoint, mask is not nil, but mask.fImage is nil");
241 withMask : (
QuartzImage *)mask clipOrigin : (
X11::Point) clipXY toPoint : (
X11::Point) dstPoint
246 "copyPixmap:area:withMask:clipOrigin:toPoint, srcPixmap parameter is nil");
249 NSLog(
@"QuartzPixmap: -copyPixmap:area:withMask:clipOrigin:"
250 "toPoint, srcRect and copyRect do not intersect");
262 "copyPixmap:area:withMask:clipOrigin:toPoint, mask is not nil, but mask.fImage is nil");
264 "copyPixmap:area:withMask:clipOrigin:toPoint, mask.fImage is not a mask");
279 withMask : (
QuartzImage *)mask clipOrigin : (
X11::Point) origin toPoint : (
X11::Point) dstPoint
282 "copy:area:widthMask:clipOrigin:toPoint, empty area to copy");
285 [
self copyImage : (QuartzImage *)src area : area withMask : mask clipOrigin : origin toPoint : dstPoint];
287 [
self copyPixmap : (QuartzPixmap *)src area : area withMask : mask clipOrigin : origin toPoint : dstPoint];
289 assert(0 &&
"Can copy only from pixmap or image");
295 assert(
area.fWidth &&
area.fHeight &&
"readColorBits:, empty area to copy");
298 NSLog(
@"QuartzPixmap: readColorBits:intoBuffer:, src and copy area do not intersect");
303 unsigned char *buffer = 0;
305 buffer =
new unsigned char[
area.fWidth * area.fHeight * 4]();
306 }
catch (
const std::bad_alloc &) {
307 NSLog(
@"QuartzImage: -readColorBits:, memory allocation failed");
317 NSLog(
@"QuartzImage: -readColorBits:, can not create scaled pixmap");
321 [
scaledPixmap.Get() copy : self area : X11::Rectangle(0, 0, fWidth, fHeight)
322 withMask : nil clipOrigin : X11::Point() toPoint : X11::Point()];
330 : &scaledPixmap.Get()->fData[0] + area.fY * fWidth * 4;
334 for (
unsigned i = 0; i <
area.fHeight; ++i) {
350- (
unsigned char *)
fData
356- (void)
putPixel : (
const unsigned char *) rgb X : (
unsigned) x Y : (
unsigned) y
359 assert(
rgb != 0 &&
"putPixel:X:Y:, rgb parameter is null");
363 unsigned char * const data = &fData[0];
364 if (fScaleFactor > 1) {
365 //Ooops, and what should I do now???
366 const unsigned scaledW = fWidth * fScaleFactor;
367 unsigned char *dst = data + unsigned(y * fScaleFactor * scaledW * 4) + unsigned(x * fScaleFactor * 4);
369 for (unsigned i = 0; i < 2; ++i, dst += 4) {
379 for (unsigned i = 0; i < 2; ++i, dst += 4) {
386 unsigned char *dst = data + y * fWidth * 4 + x * 4;
395//______________________________________________________________________________
396- (void) addPixel : (const unsigned char *) rgb
398 //Primitive version of XAddPixel.
401 for (unsigned i = 0; i < fHeight; ++i) {
402 for (unsigned j = 0; j < fWidth; ++j) {
403 fData[i * fWidth * 4 + j * 4] = rgb[0];
404 fData[i * fWidth * 4 + j * 4 + 1] = rgb[1];
405 fData[i * fWidth * 4 + j * 4 + 2] = rgb[2];
406 fData[i * fWidth * 4 + j * 4 + 3] = rgb[3];
413@implementation QuartzImage
415@synthesize fIsStippleMask;
418//______________________________________________________________________________
419- (id) initWithW : (unsigned) width H : (unsigned) height data : (unsigned char *) data
425 if (self = [super init]) {
426 Util::NSScopeGuard<QuartzImage> selfGuard(self);
428 //This w * h * 4 is ONLY for TGCocoa::CreatePixmapFromData.
429 //If needed something else, I'll make this code more generic.
431 fImageData.resize(width * height * 4);
432 } catch (const std::bad_alloc &) {
437 std::copy(data, data + width * height * 4, &fImageData[0]);
440 const Util::CFScopeGuard<CGDataProviderRef>
441 provider(CGDataProviderCreateWithData(nullptr, &fImageData[0], width * height * 4, nullptr));
442 if (!provider.Get()) {
447 //RGB - this is only for TGCocoa::CreatePixmapFromData.
448 const Util::CFScopeGuard<CGColorSpaceRef> colorSpace(CGColorSpaceCreateDeviceRGB());
449 if (!colorSpace.Get()) {
454 //8 bits per component, 32 bits per pixel, 4 bytes per pixel, kCGImageAlphaLast:
455 //all values hardcoded for TGCocoa::CreatePixmapFromData.
456 fImage.Reset(CGImageCreate(width, height, 8, 32, width * 4, colorSpace.Get(),
457 kCGImageAlphaLast, provider.Get(), 0, false,
458 kCGRenderingIntentDefault));
474//______________________________________________________________________________
475- (id) initMaskWithW : (unsigned) width H : (unsigned) height bitmapMask : (unsigned char *) mask
481 if (self = [super init]) {
482 Util::NSScopeGuard<QuartzImage> selfGuard(self);
485 fImageData.resize(width * height);
486 } catch (const std::bad_alloc &) {
491 std::copy(mask, mask + width * height, &fImageData[0]);
493 fIsStippleMask = YES;
494 const Util::CFScopeGuard<CGDataProviderRef> provider(CGDataProviderCreateWithData(nullptr, &fImageData[0],
495 width * height, nullptr));
496 if (!provider.Get()) {
501 //0 -> decode, false -> shouldInterpolate.
502 fImage.Reset(CGImageMaskCreate(width, height, 8, 8, width, provider.Get(), 0, false));
517//______________________________________________________________________________
518- (id) initMaskWithW : (unsigned) width H : (unsigned) height
520 //Two-step initialization.
525 if (self = [super init]) {
526 Util::NSScopeGuard<QuartzImage> selfGuard(self);
529 fImageData.resize(width * height);
530 } catch (const std::bad_alloc &) {
535 fIsStippleMask = YES;
536 const Util::CFScopeGuard<CGDataProviderRef> provider(CGDataProviderCreateWithData(nullptr, &fImageData[0],
537 width * height, nullptr));
538 if (!provider.Get()) {
543 //0 -> decode, false -> shouldInterpolate.
544 fImage.Reset(CGImageMaskCreate(width, height, 8, 8, width, provider.Get(), 0, false));
559//______________________________________________________________________________
560- (id) initFromPixmap : (QuartzPixmap *) pixmap
562 //Two-step initialization.
567 return [self initWithW : pixmap.fWidth H : pixmap.fHeight data : pixmap.fData];
570//______________________________________________________________________________
571- (id) initFromImage : (QuartzImage *) image
578 return [self initWithW : image.fWidth H : image.fHeight data : &image->fImageData[0]];
581//______________________________________________________________________________
582- (id) initFromImageFlipped : (QuartzImage *) image
588 const unsigned bpp = image.fIsStippleMask ? 1 : 4;
590 if (self = [super init]) {
591 const unsigned width = image.fWidth;
592 const unsigned height = image.fHeight;
594 Util::NSScopeGuard<QuartzImage> selfGuard(self);
597 fImageData.resize(width * height * bpp);
598 } catch (const std::bad_alloc &) {
603 const unsigned lineSize = bpp * width;
604 const unsigned char * const src = &image->fImageData[0];
605 unsigned char * const dst = &fImageData[0];
606 for (unsigned i = 0; i < height; ++i) {
607 const unsigned char *sourceLine = src + lineSize * (height - 1 - i);
608 unsigned char *dstLine = dst + i * lineSize;
609 std::copy(sourceLine, sourceLine + lineSize, dstLine);
613 fIsStippleMask = YES;
614 const Util::CFScopeGuard<CGDataProviderRef> provider(CGDataProviderCreateWithData(nullptr, &fImageData[0],
615 width * height, nullptr));
616 if (!provider.Get()) {
621 //0 -> decode, false -> shouldInterpolate.
622 fImage.Reset(CGImageMaskCreate(width, height, 8, 8, width, provider.Get(), 0, false));
629 const Util::CFScopeGuard<CGDataProviderRef> provider(CGDataProviderCreateWithData(nullptr, &fImageData[0],
630 width * height * 4, nullptr));
631 if (!provider.Get()) {
636 const Util::CFScopeGuard<CGColorSpaceRef> colorSpace(CGColorSpaceCreateDeviceRGB());
637 if (!colorSpace.Get()) {
642 //8 bits per component, 32 bits per pixel, 4 bytes per pixel, kCGImageAlphaLast:
643 //all values hardcoded for TGCocoa::CreatePixmapFromData.
644 fImage.Reset(CGImageCreate(width, height, 8, 32, width * 4, colorSpace.Get(), kCGImageAlphaLast,
645 provider.Get(), 0, false, kCGRenderingIntentDefault));
661//______________________________________________________________________________
662- (BOOL) isRectInside : (X11::Rectangle) area
664 if (area.fX < 0 || (unsigned)area.fX >= fWidth)
666 if (area.fY < 0 || (unsigned)area.fY >= fHeight)
668 if (area.fWidth > fWidth || !area.fWidth)
670 if (area.fHeight > fHeight || !area.fHeight)
676//______________________________________________________________________________
677- (unsigned char *) readColorBits : (X11::Rectangle) area
680 //Image, bitmap - they all must be converted to ARGB (bitmap) or BGRA (image) (for libAfterImage).
681 //Raw pointer - we pass the ownership.
682 unsigned char *buffer = 0;
685 buffer = new unsigned char[area.fWidth * area.fHeight * 4]();
686 } catch (const std::bad_alloc &) {
691 unsigned char *dstPixel = buffer;
692 if (CGImageIsMask(fImage.Get())) {
693 //fImageData has 1 byte per pixel.
694 const unsigned char *line = &fImageData[0] + area.fY * fWidth;
695 const unsigned char *srcPixel = line + area.fX;
697 for (unsigned i = 0; i < area.fHeight; ++i) {
698 for (unsigned j = 0; j < area.fWidth; ++j, ++srcPixel, dstPixel += 4) {
700 dstPixel[0] = 255;//can be 1 or anything different from 0.
704 srcPixel = line + area.fX;
708 //fImageData has 4 bytes per pixel.
709 const unsigned char *line = &fImageData[0] + area.fY * fWidth * 4;
710 const unsigned char *srcPixel = line + area.fX * 4;
712 for (unsigned i = 0; i < area.fHeight; ++i) {
713 for (unsigned j = 0; j < area.fWidth; ++j, srcPixel += 4, dstPixel += 4) {
714 dstPixel[0] = srcPixel[2];
715 dstPixel[1] = srcPixel[1];
716 dstPixel[2] = srcPixel[0];
717 dstPixel[3] = srcPixel[3];
721 srcPixel = line + area.fX * 4;
730//______________________________________________________________________________
736//______________________________________________________________________________
737- (BOOL) fIsOpenGLWidget
742//______________________________________________________________________________
743- (CGFloat) fScaleFactor
745 // TODO: this is to be understood yet ...
749//______________________________________________________________________________
755//______________________________________________________________________________
761//______________________________________________________________________________
773//______________________________________________________________________________
774CGImageRef CreateSubImage(QuartzImage *image, const Rectangle &area)
778 const CGRect subImageRect = CGRectMake(area.fX, area.fY, area.fHeight, area.fWidth);
779 return CGImageCreateWithImageInRect(image.fImage, subImageRect);
784//Now, close your eyes and open them at the end of this block. :)
785//Sure, this can be done easy, but I hate to convert between negative signed integers and
786//unsigned integers and the other way, so I have this implementation (integers will be always
787//positive and they obviously fit into unsigned integers).
789typedef std::pair<int, unsigned> range_type;
791//______________________________________________________________________________
792bool FindOverlapSameSigns(const range_type &left, const range_type &right, range_type &intersection)
794 //"Same
" means both xs are non-negative, or both are negative.
796 const unsigned dX(right.first - left.first);//diff fits into the positive range of int.
798 if (dX >= left.second)
800 //Find an intersection.
801 intersection.first = right.first;
802 intersection.second = std::min(right.second, left.second - dX);//left.second is always > dX.
807//______________________________________________________________________________
808bool FindOverlapDifferentSigns(const range_type &left, const range_type &right, range_type &intersection)
810 //x2 - x1 can overflow.
811 //Left.x is negative, right.x is non-negative (0 included).
812 const unsigned signedMinAbs(std::numeric_limits<unsigned>::max() / 2 + 1);
814 if (left.first == std::numeric_limits<int>::min()) {//hehehe
815 if (left.second <= signedMinAbs)
818 if (left.second - signedMinAbs <= unsigned(right.first))
821 intersection.first = right.first;
822 intersection.second = std::min(right.second, left.second - signedMinAbs - unsigned(right.first));
824 const unsigned leftXAbs(-left.first);//-left.first can't overflow.
825 if (leftXAbs >= left.second)
828 if (left.second - leftXAbs <= unsigned(right.first))
831 intersection.first = right.first;
832 intersection.second = std::min(right.second, left.second - leftXAbs - unsigned(right.first));
838//______________________________________________________________________________
839bool FindOverlap(const range_type &range1, const range_type &range2, range_type &intersection)
844 if (range1.first < range2.first) {
853 return right.first < 0 ? FindOverlapSameSigns(left, right, intersection) :
854 FindOverlapDifferentSigns(left, right, intersection);
856 return FindOverlapSameSigns(left, right, intersection);
861//______________________________________________________________________________
862bool AdjustCropArea(const Rectangle &srcRect, Rectangle &cropArea)
864 //Find rects intersection.
865 range_type xIntersection;
866 if (!FindOverlap(range_type(srcRect.fX, srcRect.fWidth),
867 range_type(cropArea.fX, cropArea.fWidth), xIntersection))
870 range_type yIntersection;
871 if (!FindOverlap(range_type(srcRect.fY, srcRect.fHeight),
872 range_type(cropArea.fY, cropArea.fHeight), yIntersection))
875 cropArea.fX = xIntersection.first;
876 cropArea.fWidth = xIntersection.second;
878 cropArea.fY = yIntersection.first;
879 cropArea.fHeight = yIntersection.second;
884//______________________________________________________________________________
885bool AdjustCropArea(QuartzImage *srcImage, Rectangle &cropArea)
890 return AdjustCropArea(X11::Rectangle(0, 0, srcImage.fWidth, srcImage.fHeight), cropArea);
893//______________________________________________________________________________
894bool AdjustCropArea(QuartzImage *srcImage, NSRect &cropArea)
899 const Rectangle srcRect(0, 0, srcImage.fWidth, srcImage.fHeight);
900 Rectangle dstRect(int(cropArea.origin.x), int(cropArea.origin.y),
901 unsigned(cropArea.size.width), unsigned(cropArea.size.height));
903 if (AdjustCropArea(srcRect, dstRect)) {
904 cropArea.origin.x = dstRect.fX;
905 cropArea.origin.y = dstRect.fY;
906 cropArea.size.width = dstRect.fWidth;
907 cropArea.size.height = dstRect.fHeight;
915//______________________________________________________________________________
916bool AdjustCropArea(QuartzPixmap *srcPixmap, X11::Rectangle &cropArea)
920 return AdjustCropArea(X11::Rectangle(0, 0, srcPixmap.fWidth, srcPixmap.fHeight), cropArea);
923//______________________________________________________________________________
924bool TestBitmapBit(const unsigned char *bitmap, unsigned w, unsigned i, unsigned j)
926 //Test if a bit (i,j) is set in a bitmap (w, h).
928 //Code in ROOT's GUI suggests, that byte is octet.
933 const unsigned bytesPerLine = (w + 7) / 8;
934 const unsigned char *line = bitmap + j * bytesPerLine;
935 const unsigned char byteValue = line[i / 8];
937 return byteValue & (1 << (i % 8));
940//______________________________________________________________________________
941void FillPixmapBuffer(const unsigned char *bitmap, unsigned width, unsigned height,
942 ULong_t foregroundPixel, ULong_t backgroundPixel, unsigned depth,
943 unsigned char *imageData)
951 unsigned char foregroundColor[4] = {};
952 PixelToRGB(foregroundPixel, foregroundColor);
953 unsigned char backgroundColor[4] = {};
954 PixelToRGB(backgroundPixel, backgroundColor);
956 for (unsigned j = 0; j < height; ++j) {
957 const unsigned line = j * width * 4;
958 for (unsigned i = 0; i < width; ++i) {
959 const unsigned pixel = line + i * 4;
961 if (TestBitmapBit(bitmap, width, i, j)) {
963 imageData[pixel] = foregroundColor[0];
964 imageData[pixel + 1] = foregroundColor[1];
965 imageData[pixel + 2] = foregroundColor[2];
967 imageData[pixel] = backgroundColor[0];
968 imageData[pixel + 1] = backgroundColor[1];
969 imageData[pixel + 2] = backgroundColor[2];
972 imageData[pixel + 3] = 255;
976 for (unsigned j = 0; j < height; ++j) {
977 const unsigned line = j * width;
978 for (unsigned i = 0; i < width; ++i) {
979 const unsigned pixel = line + i;
980 if (TestBitmapBit(bitmap, width, i, j))
981 imageData[pixel] = 0;
983 imageData[pixel] = 255;//mask out pixel.
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 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 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 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 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
std::vector< unsigned char > fData
ROOT::MacOSX::Util::CFScopeGuard< CGContextRef > fContext
CGImageRef createImageFromPixmap()
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)