OSX スクリーンキャストツール
への布石
- http://subtech.g.hatena.ne.jp/cho45/20061201/1164982639
- http://subtech.g.hatena.ne.jp/cho45/20061202/1165057216
を組み合わせてスクリーンショットをとりまくって変換してみる。
#!/usr/bin/ruby
require 'rubygems'
require 'RMagick'
require 'ostruct'
require 'pathname'
require 'osx/cocoa'
require 'ext/osxscreen'
require 'zlib'
require 'progressbar'
include OSX
system('rm test/*')
size = eval( `./fullscreen.rb` )
p size
fps = 12 # frames per second
interval = 1.0 / fps
time = Time.now + 3
nextrun = 0
loop do
true while Time.now.to_f < nextrun
nextrun = Time.now.to_f + interval
filename = "test/temp-#{Time.now.to_i}.#{Time.now.usec}.bin"
File.open(filename, 'wb') do |f|
f.write OSX::ScreenData.data
end
# Zlib::GzipWriter.open(filename + '.gz', Zlib::BEST_SPEED) do |f|
# f.write OSX::ScreenData.data
# end
puts filename
break if Time.now > time
end
frame = NSScreen.mainScreen.frame.size
files = Pathname.glob('test/*')
bar = ProgressBar.new('Convert', files.size)
files.each do |f|
img = Magick::Image.new(frame.width, frame.height)
img.import_pixels(0, 0, frame.width, frame.height, "BGRA", f.read, Magick::CharPixel)
img.crop!(*size)
img.write(f.to_s + '.png')
f.unlink
bar.inc
endzlib は使わない方がいい気がする。ハードディスクあいてないときは使わざるを得ないけど……
fullscreen.rb (名前わるすぎ)
#!/usr/bin/ruby
require 'osx/cocoa'
include OSX
class SelectionView < NSView
attr_accessor :delegate
def drawRect(rect)
NSColor.colorWithCalibratedRed(0, :green, 0, :blue, 0, :alpha, 0.1).set
NSRectFill(bounds)
if @start && @end
NSColor.colorWithCalibratedRed(0.5, :green, 0.5, :blue, 0.5, :alpha, 0.5).set
NSRectFill(calc_rect)
end
end
def mouseDown(event)
@start = NSEvent.mouseLocation
end
def mouseDragged(event)
@end = NSEvent.mouseLocation
setNeedsDisplay(true)
end
def mouseUp(event)
@end = NSEvent.mouseLocation
delegate.windowShouldClose(nil)
window.close
end
def calc_rect
x = [@start.x , @end.x].min
y = [@start.y , @end.y].min
w = (@start.x - @end.x).abs
h = (@start.y - @end.y).abs
[x, y, w, h]
end
end
class TEST < NSObject
def applicationDidFinishLaunching(aNotification)
size = NSScreen.mainScreen.frame.size
rect = [0, 0, size.width, size.height]
@window = NSWindow.alloc.initWithContentRect(rect,
:styleMask, NSBorderlessWindowMask,
:backing, NSBackingStoreBuffered,
:defer, 0)
@window.setDelegate(self)
@window.setOpaque(0)
@window.setHasShadow(0)
@window.setLevel(1000) # NSScreenSaverWindowLevel
@view = SelectionView.alloc.initWithFrame(rect)
@view.delegate = self
@window.setContentView(@view)
@window.makeKeyAndOrderFront(nil)
@window.orderFrontRegardless
end
def windowShouldClose(sender)
size = NSScreen.mainScreen.frame.size
rect = @view.calc_rect
rect[1] = size.height - rect[1] - rect[3]
p rect
exit
true
end
end
$App = NSApplication.sharedApplication
$App.setDelegate(TEST.alloc.init)
$App.runext/screendata は C
#include <Carbon/Carbon.h>
#include <ruby.h>
VALUE
screendata_data () {
VALUE ret;
int w = CGDisplayPixelsWide(kCGDirectMainDisplay);
int h = CGDisplayPixelsHigh(kCGDirectMainDisplay);
unsigned char* _screenBytesActual = (unsigned char*)CGDisplayBaseAddress(kCGDirectMainDisplay);
unsigned char* _screenBytes = (unsigned char*)malloc(w * h * 4);
//NSAssert(_screenBytes != 0, "fail malloc");
int bitPerPixel = CGDisplayBitsPerPixel(kCGDirectMainDisplay);
int bitPerSample = CGDisplayBitsPerSample(kCGDirectMainDisplay);
int samplePerPixel = CGDisplaySamplesPerPixel(kCGDirectMainDisplay);
int bytePerRow = CGDisplayBytesPerRow(kCGDirectMainDisplay);
int bytePerPixel = bitPerPixel / 8;
int x, y;
// for (y = 0; y < h; y++) {
// unsigned long step = y * bytePerRow;
// for (x = 0; x < w; x++) {
// unsigned long pixel;
// pixel = *((unsigned long*)(_screenBytesActual + (x * bytePerPixel) + step));
// // pixel on Intel => AABBGGRR
// // bitmap data planes => AARRGGBB
// pixel = ((pixel & 0x00ff0000) >> 16) | ((pixel & 0x000000ff) << 16) | (pixel & 0xff00ff00);
// *((unsigned long*)(_screenBytes + x * 4 + y * w * 4)) = pixel;
// }
// }
for (y = 0; y < h; y ++) {
memcpy(_screenBytes + y * w * 4, _screenBytesActual + y * bytePerRow, w * bytePerPixel);
}
ret = rb_str_new((const char*)_screenBytes, w * h * 4);
free(_screenBytes);
return ret;
}
void
Init_osxscreen () {
VALUE ScreenData;
VALUE module;
rb_eval_string("require 'osx/cocoa'");
module = rb_eval_string("OSX");
ScreenData = rb_define_module_under(module, "ScreenData");
rb_define_module_function(ScreenData, "data", screendata_data, 0);
}memcpy の引数を逆にしてひどいことになった。すぐなおるからいいけど(CGDisplayBaseAddress の先には直接書き込める。すなわち直接描画できる。)
ここから flv に変換したい。
rmovie という gem があるんだけど、コンパイルできない。ffmpeg を port で入れて云々がうまくいかない。深く追ってない。