@@ -249,6 +249,111 @@ + (nullable NSData *)screenMaskPNGDataForDeviceName:(NSString *)deviceName
249249 return [self PNGDataForPDFAtPath: maskPath scale: 1.0 error: error];
250250}
251251
252+ + (nullable NSData *)screenshotPNGDataForDeviceName : (NSString *)deviceName
253+ screenPNGData : (NSData *)screenPNGData
254+ error : (NSError * _Nullable __autoreleasing *)error {
255+ NSDictionary *profile = [self profileForDeviceName: deviceName error: error];
256+ if (profile == nil ) {
257+ return nil ;
258+ }
259+
260+ NSData *chromePNGData = [self PNGDataForDeviceName: deviceName includeButtons: YES error: error];
261+ if (chromePNGData == nil ) {
262+ return nil ;
263+ }
264+
265+ NSImage *screenImage = [[NSImage alloc ] initWithData: screenPNGData];
266+ NSImage *chromeImage = [[NSImage alloc ] initWithData: chromePNGData];
267+ if (screenImage == nil || chromeImage == nil ) {
268+ if (error != NULL ) {
269+ *error = [NSError errorWithDomain: XCWChromeRendererErrorDomain
270+ code: 15
271+ userInfo: @{
272+ NSLocalizedDescriptionKey : @" Unable to decode simulator screenshot or chrome PNG data." ,
273+ }];
274+ }
275+ return nil ;
276+ }
277+
278+ CGFloat scale = 3.0 ;
279+ CGFloat totalWidth = [self numberValue: profile[@" totalWidth" ]];
280+ CGFloat totalHeight = [self numberValue: profile[@" totalHeight" ]];
281+ CGFloat screenX = [self numberValue: profile[@" screenX" ]];
282+ CGFloat screenY = [self numberValue: profile[@" screenY" ]];
283+ CGFloat screenWidth = [self numberValue: profile[@" screenWidth" ]];
284+ CGFloat screenHeight = [self numberValue: profile[@" screenHeight" ]];
285+ NSInteger pixelWidth = MAX ((NSInteger )ceil (totalWidth * scale), 1 );
286+ NSInteger pixelHeight = MAX ((NSInteger )ceil (totalHeight * scale), 1 );
287+ if (totalWidth <= 0.0 || totalHeight <= 0.0 || screenWidth <= 0.0 || screenHeight <= 0.0 ) {
288+ if (error != NULL ) {
289+ *error = [NSError errorWithDomain: XCWChromeRendererErrorDomain
290+ code: 16
291+ userInfo: @{
292+ NSLocalizedDescriptionKey : @" Device chrome profile did not include usable screenshot geometry." ,
293+ }];
294+ }
295+ return nil ;
296+ }
297+
298+ NSBitmapImageRep *bitmap = [[NSBitmapImageRep alloc ] initWithBitmapDataPlanes: NULL
299+ pixelsWide: pixelWidth
300+ pixelsHigh: pixelHeight
301+ bitsPerSample: 8
302+ samplesPerPixel: 4
303+ hasAlpha: YES
304+ isPlanar: NO
305+ colorSpaceName: NSDeviceRGBColorSpace
306+ bytesPerRow: 0
307+ bitsPerPixel: 32 ];
308+ if (bitmap == nil ) {
309+ if (error != NULL ) {
310+ *error = [NSError errorWithDomain: XCWChromeRendererErrorDomain
311+ code: 17
312+ userInfo: @{
313+ NSLocalizedDescriptionKey : @" Unable to create a bitmap for bezeled screenshot rendering." ,
314+ }];
315+ }
316+ return nil ;
317+ }
318+
319+ NSGraphicsContext *graphicsContext = [NSGraphicsContext graphicsContextWithBitmapImageRep: bitmap];
320+ [NSGraphicsContext saveGraphicsState ];
321+ [NSGraphicsContext setCurrentContext: graphicsContext];
322+ graphicsContext.imageInterpolation = NSImageInterpolationHigh;
323+ NSRect outputRect = NSMakeRect (0.0 , 0.0 , pixelWidth, pixelHeight);
324+ [[NSColor clearColor ] setFill ];
325+ NSRectFillUsingOperation (outputRect, NSCompositingOperationClear);
326+
327+ NSRect screenRect = NSMakeRect (screenX * scale,
328+ pixelHeight - ((screenY + screenHeight) * scale),
329+ screenWidth * scale,
330+ screenHeight * scale);
331+ NSDictionary *hints = @{ NSImageHintInterpolation : @(NSImageInterpolationHigh) };
332+ [screenImage drawInRect: screenRect
333+ fromRect: NSZeroRect
334+ operation: NSCompositingOperationSourceOver
335+ fraction: 1.0
336+ respectFlipped: NO
337+ hints: hints];
338+ [chromeImage drawInRect: outputRect
339+ fromRect: NSZeroRect
340+ operation: NSCompositingOperationSourceOver
341+ fraction: 1.0
342+ respectFlipped: NO
343+ hints: hints];
344+ [NSGraphicsContext restoreGraphicsState ];
345+
346+ NSData *pngData = [bitmap representationUsingType: NSBitmapImageFileTypePNG properties: @{}];
347+ if (pngData.length == 0 && error != NULL ) {
348+ *error = [NSError errorWithDomain: XCWChromeRendererErrorDomain
349+ code: 18
350+ userInfo: @{
351+ NSLocalizedDescriptionKey : @" Unable to encode bezeled simulator screenshot PNG." ,
352+ }];
353+ }
354+ return pngData.length > 0 ? pngData : nil ;
355+ }
356+
252357+ (nullable NSDictionary <NSString *, id> *)profileForChromeInfo : (NSDictionary *)chromeInfo
253358 error : (NSError * _Nullable __autoreleasing *)error {
254359 NSDictionary *plist = chromeInfo[@" plist" ];
0 commit comments