node-mac-recorder 2.16.29 → 2.16.30

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-mac-recorder",
3
- "version": "2.16.29",
3
+ "version": "2.16.30",
4
4
  "description": "Native macOS screen recording package for Node.js applications",
5
5
  "main": "index.js",
6
6
  "keywords": [
@@ -65,14 +65,25 @@ extern "C" bool startAVFoundationRecording(const std::string& outputPath,
65
65
  CGFloat scaleY = physicalSize.height / logicalSize.height;
66
66
  CGFloat scaleFactor = MAX(scaleX, scaleY); // Use max to handle non-uniform scaling
67
67
 
68
- // CRITICAL FIX: Use actual captured image dimensions, not logical size
69
- // CGDisplayCreateImage may return higher resolution on Retina displays
68
+ // CRITICAL FIX: Use actual captured image dimensions for pixel buffer
69
+ // CGDisplayCreateImage returns physical pixels on Retina displays
70
70
  CGImageRef testImage = CGDisplayCreateImage(displayID);
71
71
  CGSize actualImageSize = CGSizeMake(CGImageGetWidth(testImage), CGImageGetHeight(testImage));
72
72
  CGImageRelease(testImage);
73
73
 
74
- // CRITICAL FIX: Use logical size for consistency, actual image size only for validation
75
- CGSize recordingSize = captureRect.size.width > 0 ? captureRect.size : logicalSize;
74
+ // CRITICAL FIX: Use actual image dimensions to match what CGDisplayCreateImage returns
75
+ // This prevents the "1/4 recording area" bug on Retina displays
76
+ CGSize recordingSize;
77
+ if (!CGRectIsEmpty(captureRect)) {
78
+ // Scale capture rect to match actual image dimensions
79
+ recordingSize = CGSizeMake(
80
+ captureRect.size.width * (actualImageSize.width / logicalSize.width),
81
+ captureRect.size.height * (actualImageSize.height / logicalSize.height)
82
+ );
83
+ } else {
84
+ // Full screen: use actual image size
85
+ recordingSize = actualImageSize;
86
+ }
76
87
 
77
88
  NSLog(@"🎯 CRITICAL: Logical %.0fx%.0f → Actual image %.0fx%.0f",
78
89
  logicalSize.width, logicalSize.height, actualImageSize.width, actualImageSize.height);
@@ -88,7 +99,7 @@ extern "C" bool startAVFoundationRecording(const std::string& outputPath,
88
99
  NSLog(@"🔍 Scale factor: %.1fx → Standard display", scaleFactor);
89
100
  }
90
101
 
91
- NSLog(@"🎯 Recording size: %.0fx%.0f (using logical dimensions for AVFoundation)", recordingSize.width, recordingSize.height);
102
+ NSLog(@"🎯 Recording size: %.0fx%.0f (using actual physical dimensions for Retina fix)", recordingSize.width, recordingSize.height);
92
103
 
93
104
  // Video settings with macOS compatibility
94
105
  NSString *codecKey;
@@ -154,25 +165,34 @@ extern "C" bool startAVFoundationRecording(const std::string& outputPath,
154
165
  // Store recording parameters with scaling correction
155
166
  g_avDisplayID = displayID;
156
167
 
157
- // CRITICAL FIX: Use coordinates as-is from JS layer (already display-relative)
168
+ // CRITICAL FIX: Scale capture coordinates to match physical pixels
158
169
  if (!CGRectIsEmpty(captureRect)) {
159
- // Use coordinates directly - JS layer already converted global to display-relative
160
- g_avCaptureRect = captureRect;
170
+ // Scale coordinates from logical to physical (for CGDisplayCreateImage)
171
+ CGFloat scaleFactorX = actualImageSize.width / logicalSize.width;
172
+ CGFloat scaleFactorY = actualImageSize.height / logicalSize.height;
173
+
174
+ g_avCaptureRect = CGRectMake(
175
+ captureRect.origin.x * scaleFactorX,
176
+ captureRect.origin.y * scaleFactorY,
177
+ captureRect.size.width * scaleFactorX,
178
+ captureRect.size.height * scaleFactorY
179
+ );
161
180
 
162
- NSLog(@"🔲 macOS 14/13 FIXED: Display-relative capture area: %.0f,%.0f %.0fx%.0f",
163
- captureRect.origin.x, captureRect.origin.y, captureRect.size.width, captureRect.size.height);
181
+ NSLog(@"🔲 RETINA FIX: Logical (%.0f,%.0f %.0fx%.0f) → Physical (%.0f,%.0f %.0fx%.0f)",
182
+ captureRect.origin.x, captureRect.origin.y, captureRect.size.width, captureRect.size.height,
183
+ g_avCaptureRect.origin.x, g_avCaptureRect.origin.y, g_avCaptureRect.size.width, g_avCaptureRect.size.height);
164
184
 
165
- // Validate coordinates are within logical display bounds
166
- if (captureRect.origin.x >= 0 && captureRect.origin.y >= 0 &&
167
- captureRect.origin.x + captureRect.size.width <= logicalSize.width &&
168
- captureRect.origin.y + captureRect.size.height <= logicalSize.height) {
169
- NSLog(@"✅ Coordinates validated within logical display bounds %.0fx%.0f", logicalSize.width, logicalSize.height);
185
+ // Validate coordinates are within physical display bounds
186
+ if (g_avCaptureRect.origin.x >= 0 && g_avCaptureRect.origin.y >= 0 &&
187
+ g_avCaptureRect.origin.x + g_avCaptureRect.size.width <= actualImageSize.width &&
188
+ g_avCaptureRect.origin.y + g_avCaptureRect.size.height <= actualImageSize.height) {
189
+ NSLog(@"✅ Coordinates validated within physical display bounds %.0fx%.0f", actualImageSize.width, actualImageSize.height);
170
190
  } else {
171
- NSLog(@"⚠️ Coordinates may be outside logical display bounds - clipping may occur");
191
+ NSLog(@"⚠️ Coordinates may be outside physical display bounds - clipping may occur");
172
192
  }
173
193
  } else {
174
194
  g_avCaptureRect = CGRectZero; // Full screen
175
- NSLog(@"🖥️ Full screen capture using logical dimensions %.0fx%.0f", logicalSize.width, logicalSize.height);
195
+ NSLog(@"🖥️ Full screen capture using physical dimensions %.0fx%.0f", actualImageSize.width, actualImageSize.height);
176
196
  }
177
197
 
178
198
  g_avFrameNumber = 0;