mirror of
https://github.com/TomHarte/CLK.git
synced 2024-12-27 16:31:31 +00:00
Merge pull request #505 from TomHarte/MacScreenshots
Attempts to introduce screenshot capture for macOS.
This commit is contained in:
commit
85ce21c79f
@ -111,6 +111,12 @@
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="aJh-i4-bef"/>
|
||||
<menuItem title="Save Screenshot" keyEquivalent="D" id="BVJ-oQ-hUp">
|
||||
<connections>
|
||||
<action selector="saveScreenshot:" target="-1" id="7ky-xD-tip"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="rXU-KX-GkZ"/>
|
||||
<menuItem title="Page Setup…" enabled="NO" keyEquivalent="P" id="qIS-W8-SiK">
|
||||
<modifierMask key="keyEquivalentModifierMask" shift="YES" command="YES"/>
|
||||
<connections>
|
||||
|
@ -4,6 +4,8 @@
|
||||
<dict>
|
||||
<key>com.apple.security.app-sandbox</key>
|
||||
<true/>
|
||||
<key>com.apple.security.assets.pictures.read-write</key>
|
||||
<true/>
|
||||
<key>com.apple.security.device.bluetooth</key>
|
||||
<true/>
|
||||
<key>com.apple.security.device.usb</key>
|
||||
|
@ -6,8 +6,8 @@
|
||||
// Copyright 2016 Thomas Harte. All rights reserved.
|
||||
//
|
||||
|
||||
import Cocoa
|
||||
import AudioToolbox
|
||||
import Cocoa
|
||||
|
||||
class MachineDocument:
|
||||
NSDocument,
|
||||
@ -310,6 +310,29 @@ class MachineDocument:
|
||||
return super.validateUserInterfaceItem(item)
|
||||
}
|
||||
|
||||
// Screenshot capture.
|
||||
@IBAction func saveScreenshot(_ sender: AnyObject!) {
|
||||
// Grab a date formatter and form a file name.
|
||||
let dateFormatter = DateFormatter()
|
||||
dateFormatter.dateStyle = .short
|
||||
dateFormatter.timeStyle = .long
|
||||
|
||||
let filename = ("Clock Signal Screen Shot " + dateFormatter.string(from: Date()) + ".png").replacingOccurrences(of: "/", with: "-")
|
||||
.replacingOccurrences(of: ":", with: ".")
|
||||
let pictursURL = FileManager.default.urls(for: .picturesDirectory, in: .userDomainMask)[0]
|
||||
let url = pictursURL.appendingPathComponent(filename)
|
||||
|
||||
// Obtain the machine's current display.
|
||||
var imageRepresentation: NSBitmapImageRep? = nil
|
||||
self.openGLView.perform {
|
||||
imageRepresentation = self.machine.imageRepresentation
|
||||
}
|
||||
|
||||
// Encode as a PNG and save.
|
||||
let pngData = imageRepresentation!.representation(using: .png, properties: [:])
|
||||
try! pngData?.write(to: url)
|
||||
}
|
||||
|
||||
// MARK: Activity display.
|
||||
class LED {
|
||||
let levelIndicator: NSLevelIndicator
|
||||
|
@ -64,6 +64,7 @@ typedef NS_ENUM(NSInteger, CSMachineKeyboardInputMode) {
|
||||
@property (nonatomic, readonly, nonnull) NSString *userDefaultsPrefix;
|
||||
|
||||
- (void)paste:(nonnull NSString *)string;
|
||||
@property (nonatomic, readonly, nonnull) NSBitmapImageRep *imageRepresentation;
|
||||
|
||||
@property (nonatomic, assign) BOOL useFastLoadingHack;
|
||||
@property (nonatomic, assign) CSMachineVideoSignal videoSignal;
|
||||
|
@ -243,6 +243,43 @@ struct ActivityObserver: public Activity::Observer {
|
||||
keyboardMachine->type_string([paste UTF8String]);
|
||||
}
|
||||
|
||||
- (NSBitmapImageRep *)imageRepresentation {
|
||||
// Get the current viewport to establish framebuffer size. Then determine how wide the
|
||||
// centre 4/3 of that would be.
|
||||
GLint dimensions[4];
|
||||
glGetIntegerv(GL_VIEWPORT, dimensions);
|
||||
GLint proportionalWidth = (dimensions[3] * 4) / 3;
|
||||
|
||||
// Grab the framebuffer contents.
|
||||
std::vector<uint8_t> temporaryData(static_cast<size_t>(proportionalWidth * dimensions[3] * 3));
|
||||
glReadPixels((dimensions[2] - proportionalWidth) >> 1, 0, proportionalWidth, dimensions[3], GL_RGB, GL_UNSIGNED_BYTE, temporaryData.data());
|
||||
|
||||
// Generate an NSBitmapImageRep and populate it with a vertical flip
|
||||
// of the original data.
|
||||
NSBitmapImageRep *const result =
|
||||
[[NSBitmapImageRep alloc]
|
||||
initWithBitmapDataPlanes:NULL
|
||||
pixelsWide:proportionalWidth
|
||||
pixelsHigh:dimensions[3]
|
||||
bitsPerSample:8
|
||||
samplesPerPixel:3
|
||||
hasAlpha:NO
|
||||
isPlanar:NO
|
||||
colorSpaceName:NSDeviceRGBColorSpace
|
||||
bytesPerRow:3 * proportionalWidth
|
||||
bitsPerPixel:0];
|
||||
|
||||
const size_t line_size = static_cast<size_t>(proportionalWidth * 3);
|
||||
for(GLint y = 0; y < dimensions[3]; ++y) {
|
||||
memcpy(
|
||||
&result.bitmapData[static_cast<size_t>(y) * line_size],
|
||||
&temporaryData[static_cast<size_t>(dimensions[3] - y - 1) * line_size],
|
||||
line_size);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
- (void)applyMedia:(const Analyser::Static::Media &)media {
|
||||
@synchronized(self) {
|
||||
MediaTarget::Machine *const mediaTarget = _machine->media_target();
|
||||
|
Loading…
Reference in New Issue
Block a user