From 05b660c8dc30d5115a61ac7cd398d353f680c4a8 Mon Sep 17 00:00:00 2001 From: paul Date: Mon, 24 Sep 2012 09:17:49 +0000 Subject: [PATCH] cocoa: cocoa does not support BGR(A) bitmaps git-svn-id: trunk@38807 - --- lcl/interfaces/cocoa/cocoagdiobjects.pas | 20 +++--- lcl/interfaces/cocoa/cocoaint.pas | 2 +- lcl/interfaces/cocoa/cocoalclintf.inc | 92 +++++++++++++++++++++--- lcl/interfaces/cocoa/cocoalclintfh.inc | 4 +- lcl/interfaces/cocoa/cocoaobject.inc | 32 +-------- 5 files changed, 96 insertions(+), 54 deletions(-) diff --git a/lcl/interfaces/cocoa/cocoagdiobjects.pas b/lcl/interfaces/cocoa/cocoagdiobjects.pas index 7b76f7f935..f629b8c39d 100644 --- a/lcl/interfaces/cocoa/cocoagdiobjects.pas +++ b/lcl/interfaces/cocoa/cocoagdiobjects.pas @@ -27,9 +27,7 @@ type cbtGray, // grayscale bitmap cbtRGB, // color bitmap 8-8-8 R-G-B cbtARGB, // color bitmap with alpha channel first 8-8-8-8 A-R-G-B - cbtRGBA, // color bitmap with alpha channel last 8-8-8-8 R-G-B-A - cbtBGR, // color bitmap 8-8-8 B-G-R (windows compatible) - cbtBGRA // color bitmap with alpha channel 8-8-8-8 B-G-R-A (windows compatible) + cbtRGBA // color bitmap with alpha channel last 8-8-8-8 R-G-B-A ); const @@ -728,15 +726,14 @@ begin FFreeData := False; end; - HasAlpha := AType in [cbtARGB, cbtRGBA, cbtBGRA]; - BitmapFormat := NSAlphaNonpremultipliedBitmapFormat; - if AType = cbtARGB then + HasAlpha := AType in [cbtARGB, cbtRGBA]; + if HasAlpha then + BitmapFormat := NSAlphaNonpremultipliedBitmapFormat + else + BitmapFormat := 0; + if AType in [cbtARGB, cbtRGB] then BitmapFormat := BitmapFormat or NSAlphaFirstBitmapFormat; - {$ifdef VerboseBitmaps} - DebugLn(Format('[TCocoaBitmap.Create] NSBitmapImageRep.alloc HasAlpha=%d', - [Integer(HasAlpha)])); - {$endif} // Create the associated NSImageRep FImagerep := NSBitmapImageRep(NSBitmapImageRep.alloc.initWithBitmapDataPlanes_pixelsWide_pixelsHigh__colorSpaceName_bitmapFormat_bytesPerRow_bitsPerPixel( @FData, // planes, BitmapDataPlanes @@ -820,7 +817,7 @@ begin 32: begin FBitsPerSample := 8; - if AType in [cbtRGB, cbtBGR] then + if AType = cbtRGB then FSamplesPerPixel := 3 else FSamplesPerPixel := 4; @@ -2484,7 +2481,6 @@ end; procedure TCocoaBrush.SetImage(AImage: NSImage); var - AWidth, AHeight: Single; ACallBacks: CGPatternCallbacks; Rect: CGRect; begin diff --git a/lcl/interfaces/cocoa/cocoaint.pas b/lcl/interfaces/cocoa/cocoaint.pas index 8c1afffa96..c0ab522bbc 100644 --- a/lcl/interfaces/cocoa/cocoaint.pas +++ b/lcl/interfaces/cocoa/cocoaint.pas @@ -125,7 +125,7 @@ type function RawImage_DescriptionFromCocoaBitmap(out ADesc: TRawImageDescription; ABitmap: TCocoaBitmap): Boolean; function RawImage_FromCocoaBitmap(out ARawImage: TRawImage; ABitmap, AMask: TCocoaBitmap; ARect: PRect = nil): Boolean; function RawImage_DescriptionToBitmapType(ADesc: TRawImageDescription; out bmpType: TCocoaBitmapType): Boolean; -// function GetImagePixelData(AImage: CGImageRef; var bitmapByteCount: PtrUInt): Pointer; + function GetImagePixelData(AImage: CGImageRef; out bitmapByteCount: PtrUInt): Pointer; property NSApp: NSApplication read FNSApp; // the winapi compatibility methods {$I cocoawinapih.inc} diff --git a/lcl/interfaces/cocoa/cocoalclintf.inc b/lcl/interfaces/cocoa/cocoalclintf.inc index 7c5b42014f..156601d561 100644 --- a/lcl/interfaces/cocoa/cocoalclintf.inc +++ b/lcl/interfaces/cocoa/cocoalclintf.inc @@ -433,7 +433,84 @@ begin then Result := RawImage_FromCocoaBitmap(ARawImage, TCocoaBitmap(ABitmap), TCocoaBitmap(AMask), ARect) else Result := False; end; -(* + +{------------------------------------------------------------------------------ + Method: TCocoaWidgetSet.GetImagePixelData + + Used by RawImage_FromDevice. Copies the data from a CGImageRef into a local + buffer. + + The buffer is created using GetMem, and the caller is responsible for using + FreeMem to free the returned pointer. + + This function throws exceptions in case of errors and may return a nil pointer. + ------------------------------------------------------------------------------} +function TCocoaWidgetSet.GetImagePixelData(AImage: CGImageRef; out bitmapByteCount: PtrUInt): Pointer; +var + bitmapData: Pointer; + context: CGContextRef = nil; + colorSpace: CGColorSpaceRef; + bitmapBytesPerRow, pixelsWide, pixelsHigh: PtrUInt; + imageRect: CGRect; +begin + Result := nil; + + // Get image width, height. The entire image is used. + pixelsWide := CGImageGetWidth(AImage); + pixelsHigh := CGImageGetHeight(AImage); + imageRect.origin.x := 0.0; + imageRect.origin.y := 0.0; + imageRect.size.width := pixelsWide; + imageRect.size.height := pixelsHigh; + + // The target format is fixed in ARGB, DQWord alignment, with 32-bits depth and + // 8-bits per channel, the default image format on the LCL + bitmapBytesPerRow := ((pixelsWide * 4) + $F) and not PtrUInt($F); + bitmapByteCount := (bitmapBytesPerRow * pixelsHigh); + + // Use the generic RGB color space. + colorSpace := CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB); + if (colorSpace = nil) then + raise Exception.Create('Unable to create CGColorSpaceRef'); + + // Allocate memory for image data. This is the destination in memory + // where any drawing to the bitmap context will be rendered. + bitmapData := System.GetMem( bitmapByteCount ); + if (bitmapData = nil) then + raise Exception.Create('Unable to allocate memory'); + + { Creates the bitmap context. + + Regardless of what the source image format is, it will be converted + over to the format specified here by CGBitmapContextCreate. } + context := CGBitmapContextCreate(bitmapData, + pixelsWide, + pixelsHigh, + 8, // bits per component + bitmapBytesPerRow, + colorSpace, + kCGImageAlphaNoneSkipFirst); // The function fails with kCGImageAlphaFirst + if (context = nil) then + begin + System.FreeMem(bitmapData); + raise Exception.Create('Unable to create CGContextRef'); + end; + + // Draw the image to the bitmap context. Once we draw, the memory + // allocated for the context for rendering will then contain the + // raw image data in the specified color space. + CGContextDrawImage(context, imageRect, AImage); + + // Now we can get a pointer to the image data associated with the context. + // ToDo: Verify if we should copy this data to a new buffer + Result := CGBitmapContextGetData(context); + + { Clean-up } + CGColorSpaceRelease(colorSpace); + CGContextRelease(context); +end; + + {------------------------------------------------------------------------------ Function: RawImage_FromDevice Params: ARawImage: Image to create @@ -458,9 +535,9 @@ end; http://developer.apple.com/qa/qa2007/qa1509.html ------------------------------------------------------------------------------} -function TCarbonWidgetSet.RawImage_FromDevice(out ARawImage: TRawImage; ADC: HDC; const ARect: TRect): Boolean; +function TCocoaWidgetSet.RawImage_FromDevice(out ARawImage: TRawImage; ADC: HDC; const ARect: TRect): Boolean; var - CBC: TCarbonBitmapContext absolute ADC; + CBC: TCocoaBitmapContext absolute ADC; Desc: TRawImageDescription absolute ARawImage.Description; displayID: CGDirectDisplayID; ScreenImage: CGImageRef; @@ -469,9 +546,9 @@ begin // Verifies if we are getting the rawimage from a normal DC as opposed to a // desktop DC - if CheckDC(ADC, 'RawImage_FromDevice') and (CBC is TCarbonBitmapContext) then + if CheckDC(ADC, 'RawImage_FromDevice') and (CBC is TCocoaBitmapContext) then begin - Result := RawImage_FromCarbonBitmap(ARawImage, CBC.Bitmap, nil, @ARect); + Result := RawImage_FromCocoaBitmap(ARawImage, CBC.Bitmap, nil, @ARect); Exit; end; @@ -479,8 +556,7 @@ begin { Get's a screenshot } displayID := CGMainDisplayID(); - ScreenImage := grabViaOpenGL(displayID, CGDisplayBounds(displayID)); - //dataProvider := CGImageGetDataProvider(ScreenImage); + ScreenImage := CGDisplayCreateImage(displayID); { Fills the image description } ARawImage.Init; @@ -509,7 +585,7 @@ end; //begin // // override only when queried formats are different from screen description //end; - +(* {------------------------------------------------------------------------------ Method: ReleaseDesignerDC Params: Window - handle of window diff --git a/lcl/interfaces/cocoa/cocoalclintfh.inc b/lcl/interfaces/cocoa/cocoalclintfh.inc index 984d559b49..7317d262e5 100644 --- a/lcl/interfaces/cocoa/cocoalclintfh.inc +++ b/lcl/interfaces/cocoa/cocoalclintfh.inc @@ -52,9 +52,9 @@ function RawImage_CreateBitmaps(const ARawImage: TRawImage; out ABitmap, AMask: function RawImage_DescriptionFromBitmap(ABitmap: HBITMAP; out ADesc: TRawImageDescription): Boolean; override; function RawImage_DescriptionFromDevice(ADC: HDC; out ADesc: TRawImageDescription): Boolean; override; function RawImage_FromBitmap(out ARawImage: TRawImage; ABitmap, AMask: HBITMAP; ARect: PRect = nil): Boolean; override; -{function RawImage_FromDevice(out ARawImage: TRawImage; ADC: HDC; const ARect: TRect): Boolean; override; +function RawImage_FromDevice(out ARawImage: TRawImage; ADC: HDC; const ARect: TRect): Boolean; override; // override only when queried formats are different from screen description //function RawImage_QueryDescription(AFlags: TRawImageQueryFlags; var ADesc: TRawImageDescription): Boolean; override; -function ReleaseDesignerDC(Window: HWND; DC: HDC): Integer; override;} +{function ReleaseDesignerDC(Window: HWND; DC: HDC): Integer; override;} diff --git a/lcl/interfaces/cocoa/cocoaobject.inc b/lcl/interfaces/cocoa/cocoaobject.inc index 49b7451aa4..d2c15c09ac 100644 --- a/lcl/interfaces/cocoa/cocoaobject.inc +++ b/lcl/interfaces/cocoa/cocoaobject.inc @@ -527,7 +527,7 @@ begin if ADesc.Format = ricfGray then Exit; // alpha - if ABitmap.BitmapType in [cbtARGB, cbtRGBA, cbtBGRA] then + if ABitmap.BitmapType in [cbtARGB, cbtRGBA] then ADesc.AlphaPrec := Prec; case ABitmap.BitmapType of @@ -539,14 +539,6 @@ begin Dec(Shift, Prec); ADesc.BlueShift := Shift; end; - cbtBGR: begin - Shift := 32 - Prec; - ADesc.BlueShift := Shift; - Dec(Shift, Prec); - ADesc.GreenShift := Shift; - Dec(Shift, Prec); - ADesc.RedShift := Shift; - end; cbtARGB: begin Shift := 32 - Prec; ADesc.AlphaShift := Shift; @@ -567,16 +559,6 @@ begin Dec(Shift, Prec); ADesc.AlphaShift := Shift; end; - cbtBGRA: begin - Shift := 32 - Prec; - ADesc.BlueShift := Shift; - Dec(Shift, Prec); - ADesc.GreenShift := Shift; - Dec(Shift, Prec); - ADesc.RedShift := Shift; - Dec(Shift, Prec); - ADesc.AlphaShift := Shift; - end; end; Result := True; @@ -646,21 +628,9 @@ begin and (ADesc.GreenShift = 16 ) and (ADesc.BlueShift = 8 ) then bmpType := cbtRGBA - else - if (ADesc.AlphaShift = 0 ) - and (ADesc.RedShift = 8 ) - and (ADesc.GreenShift = 16) - and (ADesc.BlueShift = 24) - then bmpType := cbtBGRA else Exit; end else begin - if (ADesc.AlphaShift = 24) - and (ADesc.RedShift = 16) - and (ADesc.GreenShift = 8 ) - and (ADesc.BlueShift = 0 ) - then bmpType := cbtBGRA - else if (ADesc.AlphaShift = 0 ) and (ADesc.RedShift = 8 ) and (ADesc.GreenShift = 16)