ラベル WebKit の投稿を表示しています。 すべての投稿を表示
ラベル WebKit の投稿を表示しています。 すべての投稿を表示

2011年10月29日土曜日

Sample: Nest of 'WebScriptObject ( Javascript associative array ) to NSDictionary' or 'WebScriptObject ( Javascript array ) to NSArray ) '

SampleAppDelegate.h

#import <Cocoa/Cocoa.h>
#import <WebKit/WebKit.h>
@interface SampleAppDelegate : NSObject <NSApplicationDelegate> {
NSWindow *window;
}

@property (assign) IBOutlet NSWindow *window;

+ (id)structueWithWebScriptObject:(WebScriptObject *)obj
webScriptObject:(WebScriptObject *)scriptObj;

@end

SampleAppDelegate.m

#import "SampleAppDelegate.h"
@implementation SampleAppDelegate
@synthesize window;
+ (NSDictionary *)dictionaryWithWebScriptObject:(WebScriptObject *)obj
webScriptObject:(WebScriptObject *)scriptObj
{
NSMutableDictionary *ret= [NSMutableDictionary dictionary];
id keys= [scriptObj callWebScriptMethod:@"_f0_"
withArguments:[NSArray arrayWithObjects:obj, nil]];
NSArray *keyAry= [SampleAppDelegate structueWithWebScriptObject:keys
webScriptObject:scriptObj];
unsigned i;
for(i= 0; i<[keyAry count]; i++) {
NSString *key= [keyAry objectAtIndex:i];
id val= [obj valueForKey:key];
if ([val isMemberOfClass:[WebScriptObject class]]) {
val= [SampleAppDelegate structueWithWebScriptObject:val
webScriptObject:scriptObj];
}
[ret setObject:val forKey:key];
}
return [[ret retain] autorelease];
}
+ (id)structueWithWebScriptObject:(WebScriptObject *)obj
webScriptObject:(WebScriptObject *)scriptObj
{
@try{
NSMutableArray *ret = [NSMutableArray array];
NSUInteger count = [[obj valueForKey:@"length"] integerValue]; //exception occure if associative array
unsigned i;
for (i = 0; i < count; i++) {
id val= [obj webScriptValueAtIndex:i];
if ([val isMemberOfClass:[WebScriptObject class]]) {
val= [SampleAppDelegate structueWithWebScriptObject:val
webScriptObject:scriptObj];
}
[ret addObject:val];
}
return [[ret retain] autorelease];
}
@catch (NSException *e) {
return [SampleAppDelegate dictionaryWithWebScriptObject:obj
webScriptObject:scriptObj];
}
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
WebView *webView = [[WebView alloc] init];
[[webView mainFrame] loadHTMLString:@"" baseURL:NULL];
WebScriptObject *scriptObject = [webView windowScriptObject];

NSString *_f0_= @"function _f0_(hash){var ret=[];for(var key in hash){ret.push(key);}return ret;}";

NSString *returnValue= @"[{'key0':['val000', 'val001'], 'key1':'val01'}, {'key0':'val10', 'key1':['val110', 'val111']}]";
NSString *code= [NSString stringWithFormat:@"function main(){return %@;}", returnValue];
NSString *script = [NSString stringWithFormat:@"try { %@ %@ } catch (e) { e.toString() }", code, _f0_];

id ret0= [scriptObject evaluateWebScript:script];
if (![ret0 isMemberOfClass:[WebUndefined class]]) {
NSLog(@"ret(main): %@", ret0);
}

id ret= [scriptObject callWebScriptMethod:@"main" withArguments:nil];
if (ret && [ret isMemberOfClass:[WebScriptObject class]]) {
WebScriptObject *obj= (WebScriptObject *)ret;
NSArray *nsRet= [SampleAppDelegate structueWithWebScriptObject:obj
webScriptObject:scriptObject];
NSLog(@"%@", nsRet);
}
}
@end


Result
Javascript

[{'key0':['val000', 'val001'], 'key1':'val01'}, {'key0':'val10', 'key1':['val110', 'val111']}]

Cocoa

(
{
key0 = (
val000,
val001
);
key1 = val01;
},
{
key0 = val10;
key1 = (
val110,
val111
);
}
)

Quartz Composer / Box2DJSをCustom Javascript Patch内で動かすことでQCで物理エンジンしてみた

追記(20111101): この記事のままだと姿勢(回転)の値がとれていません.姿勢を反映した版( Box2DJS_Demo_Stack_With_Rotate.qtz
)をこちらからdownloadしていただきコードを確認してください.



結果








Video streaming by Ustream

Box2DJS - Physics Engine for JavaScript


Custom Javascriptの中身

//import /Users/work/Desktop/box2d-js_0.1.0/lib/prototype-1.6.0.2.js

//import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/common/b2Settings.js
//import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/common/math/b2Vec2.js
//import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/common/math/b2Mat22.js
//import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/common/math/b2Math.js
//import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/collision/b2AABB.js
//import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/collision/b2Bound.js
//import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/collision/b2BoundValues.js
//import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/collision/b2Pair.js
//import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/collision/b2PairCallback.js
//import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/collision/b2BufferedPair.js
//import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/collision/b2PairManager.js
//import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/collision/b2BroadPhase.js
//import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/collision/b2Collision.js
//import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/collision/Features.js
//import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/collision/b2ContactID.js
//import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/collision/b2ContactPoint.js
//import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/collision/b2Distance.js
//import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/collision/b2Manifold.js
//import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/collision/b2OBB.js
//import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/collision/b2Proxy.js
//import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/collision/ClipVertex.js
//import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/collision/shapes/b2Shape.js
//import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/collision/shapes/b2ShapeDef.js
//import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/collision/shapes/b2BoxDef.js
//import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/collision/shapes/b2CircleDef.js
//import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/collision/shapes/b2CircleShape.js
//import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/collision/shapes/b2MassData.js
//import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/collision/shapes/b2PolyDef.js
//import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/collision/shapes/b2PolyShape.js
//import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/dynamics/b2Body.js
//import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/dynamics/b2BodyDef.js
//import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/dynamics/b2CollisionFilter.js
//import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/dynamics/b2Island.js
//import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/dynamics/b2TimeStep.js
//import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/dynamics/contacts/b2ContactNode.js
//import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/dynamics/contacts/b2Contact.js
//import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/dynamics/contacts/b2ContactConstraint.js
//import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/dynamics/contacts/b2ContactConstraintPoint.js
//import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/dynamics/contacts/b2ContactRegister.js
//import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/dynamics/contacts/b2ContactSolver.js
//import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/dynamics/contacts/b2CircleContact.js
//import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/dynamics/contacts/b2Conservative.js
//import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/dynamics/contacts/b2NullContact.js
//import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/dynamics/contacts/b2PolyAndCircleContact.js
//import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/dynamics/contacts/b2PolyContact.js
//import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/dynamics/b2ContactManager.js
//import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/dynamics/b2World.js
//import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/dynamics/b2WorldListener.js
//import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/dynamics/joints/b2JointNode.js
//import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/dynamics/joints/b2Joint.js
//import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/dynamics/joints/b2JointDef.js
//import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/dynamics/joints/b2DistanceJoint.js
//import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/dynamics/joints/b2DistanceJointDef.js
//import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/dynamics/joints/b2Jacobian.js
//import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/dynamics/joints/b2GearJoint.js
//import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/dynamics/joints/b2GearJointDef.js
//import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/dynamics/joints/b2MouseJoint.js
//import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/dynamics/joints/b2MouseJointDef.js
//import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/dynamics/joints/b2PrismaticJoint.js
//import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/dynamics/joints/b2PrismaticJointDef.js
//import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/dynamics/joints/b2PulleyJoint.js
//import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/dynamics/joints/b2PulleyJointDef.js
//import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/dynamics/joints/b2RevoluteJoint.js
//import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/dynamics/joints/b2RevoluteJointDef.js

//import /Users/work/Desktop/box2d-js_0.1.0/demos/demo_base.js
//import /Users/work/Desktop/box2d-js_0.1.0/demos/stack.js

//output QCPortTypeStructure posYs
//output QCPortTypeStructure posXs

//input QCPortTypeNumber foo
//input QCPortTypeBoolean init
//output QCPortTypeNumber dummy

var world = createWorld();
demos.InitWorlds[0](world);

function main(foo, init) {
if (init) {
world = createWorld();
demos.InitWorlds[0](world);
}
world.Step(1.0/60, 1);
var aryX= new Array();
var aryY= new Array();
for (var b = world.m_bodyList; b; b = b.m_next) {
for (var s = b.GetShapeList(); s != null; s = s.GetNext()) {
var pos= s.m_position;
aryX.push(pos.x);
aryY.push(pos.y);
}
}
var ret= new Object();
ret.posXs= aryX;
ret.posYs= aryY;
ret.dummy= foo;
return ret;
}


QC
描画部

fooはCustom JavaScriptを動かし続けるため(時刻で処理するパッチにしてないので).
CountはposXs等のCountで良いのだがDemoのデータに動かない要素が入っていたのでそのあたりを使わないため.

描画部(Iteratorの中)

割り算はスケール合わせ用


Box2DJS: Box2DJS - Physics Engine for JavaScript

Custom Javascript Patch: Custom Javascript Patch - quartz composerのパッチとか

Sample: WebScriptObject ( Javascript associative array ) to NSDictionary ( WebScriptObject ( Javascript array ) to NSArray )

Addtion(20111029T2300): Nest Version



SampleAppDelegate.h

#import <Cocoa/Cocoa.h>
#import <WebKit/WebKit.h>
@interface SampleAppDelegate : NSObject <NSApplicationDelegate> {
NSWindow *window;
}

@property (assign) IBOutlet NSWindow *window;

@end

SampleAppDelegate.m

#import "SampleAppDelegate.h"
@implementation SampleAppDelegate
@synthesize window;
+ (NSArray *)arrayWithWebScriptObject:(WebScriptObject *)obj
{
NSMutableArray *ret = [NSMutableArray array];
NSUInteger count = [[obj valueForKey:@"length"] integerValue]; //exception occurs if it is associative array.
unsigned i;
for (i = 0; i < count; i++) {
[ret addObject:[obj webScriptValueAtIndex:i]];
}
return [[ret retain] autorelease];
}
+ (NSDictionary *)dictionaryWithWebScriptObject:(WebScriptObject *)obj
webScriptObject:(WebScriptObject *)scriptObj
{
NSMutableDictionary *ret= [NSMutableDictionary dictionary];
id keys= [scriptObj callWebScriptMethod:@"_f0_"
withArguments:[NSArray arrayWithObjects:obj, nil]];
NSArray *keyAry= [SampleAppDelegate arrayWithWebScriptObject:keys];
unsigned i;
for(i= 0; i<[keyAry count]; i++) {
NSString *key= [keyAry objectAtIndex:i];
[ret setObject:[obj valueForKey:key] forKey:key];
}
return [[ret retain] autorelease];
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
WebView *webView = [[WebView alloc] init];
[[webView mainFrame] loadHTMLString:@"" baseURL:NULL];
WebScriptObject *scriptObject = [webView windowScriptObject];

NSString *_f0_= @"function _f0_(hash){var ret=[];for(var key in hash){ret.push(key);}return ret;}";
NSString *code= @"function main(){return {'key0':'val0', 'key1':'val1'};}";
NSString *script = [NSString stringWithFormat:@"try { %@ %@ } catch (e) { e.toString() }", code, _f0_];
id ret0= [scriptObject evaluateWebScript:script];
if (![ret0 isMemberOfClass:[WebUndefined class]]) {
NSLog(@"ret(main): %@", ret0);
}

id ret= [scriptObject callWebScriptMethod:@"main" withArguments:nil];
if (ret && [ret isMemberOfClass:[WebScriptObject class]]) {
WebScriptObject *obj= (WebScriptObject *)ret;
NSDictionary *dict= [SampleAppDelegate dictionaryWithWebScriptObject:obj
webScriptObject:scriptObject];
NSLog(@"%@", dict);
}
}
@end


reference: "Notes on Cocoa - Convert a Javascript array to an NSArray"

2010年3月3日水曜日

NSPNGFileTypeの埋込みカラープロファイル

10.6からか10.6.xになってからだと思うがWebViewの[nsBitmapImageRep initWithFocusedViewRect:]の出力にカラープロファイルがディスプレイのカラーの内容で追加されるようになったように思う.そのためかPNGで書き出すとColorSyncプロファイル(iCCPチャンク)が付いてくる.


下記のようにすると自分で指定できるらしい.
PNGフォーマット/iCCPチャンクについてはココをみた.感謝!

前のエントリーを例にwebViewProgressFinished:を変更

- (void)webViewProgressFinished:(NSNotification*)notification
{
[webView lockFocus];
NSBitmapImageRep *viewImageRep= [[NSBitmapImageRep alloc] initWithFocusedViewRect:[webView bounds]];

NSString *pathToProfile= @"/System/Library/ColorSync/Profiles/Generic RGB Profile.icc";
NSData *colorProfile = [NSData dataWithContentsOfFile:pathToProfile];
[viewImageRep setProperty:NSImageColorSyncProfileData withValue:colorProfile];


NSDictionary *properties= [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithFloat:1.0], NSImageCompressionFactor,
nil];
NSData *pngImageData= [viewImageRep representationUsingType:NSPNGFileType
properties:properties];
[pngImageData writeToFile:@"/path/to/output.png"
atomically:YES];
[webView unlockFocus];
}





・propertiesにNSImageColorSyncProfileDataをキーに[NSColorSpace genericRGBColorSpace]とか入れてみたけど見当違いみたいで効果がなかったw.
・ [viewImageRep setProperty:NSImageColorSyncProfileData withValue:nil];にしたらiCCPチャンクが付かなくなる.

2010年3月2日火曜日

CoreLocationを試す

追記 2010/03/03: ScrollViewはいらなかったねw.



動機:
この記事を読んだ.
Snow Leopard で Core Location Framework が使える
MOONGIFT: » Snow Leopard向け。位置情報取得デモ「whereami」:オープンソースを毎日紹介

ここにコードがあるらしい.
victor’s whereami at master - GitHub http://github.com/victor/whereami

ということでやってみる.

やったこと1:
とりあえずまねる.
1. MacPortsでgitをいれる.
$ sudo port install git-core

2. download
$ git clone git://github.com/victor/whereami.git

3. Xcodeプロジェクトを起動
 whereamiフォルダのwhereami.xcodeprojをダブルクリック.
4. ビルドと実行

5. 実行内容について
 こちらを参照のこと.
MOONGIFT: » Snow Leopard向け。位置情報取得デモ「whereami」:オープンソースを毎日紹介


やったこと2:
WebViewと連携させてみよう.
1.CocoaProject(Sample_CoreLocation)を作成.
1.1作成する.
1.2プロジェクトに既存のフレームワークを追加する.
 WebKit.framework,CoreLocation.frameworkを追加する.
 こんな感じになるはず.

2.コード
Sample_CoreLocationAppDelegate.h

#import <Cocoa/Cocoa.h>
#import <WebKit/WebKit.h>
#import <CoreLocation/CoreLocation.h>

@interface Sample_CoreLocationAppDelegate : NSObject <NSApplicationDelegate, CLLocationManagerDelegate>
{
NSWindow *window;
WebView *webView;
CLLocationManager * manager;
}

@property (assign) IBOutlet NSWindow *window;
@property (assign) IBOutlet WebView *webView;

- (void)_requestMapWithLa:(float)la
ln:(float)ln;
@end

Sample_CoreLocationAppDelegate.m

#import "Sample_CoreLocationAppDelegate.h"

@implementation Sample_CoreLocationAppDelegate

@synthesize window;
@synthesize webView;

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(webViewProgressFinished:)
name:WebViewProgressFinishedNotification
object:nil];

manager = [[CLLocationManager alloc] init];
[manager setDelegate:self];
[manager startUpdatingLocation];
}
- (void)webViewProgressFinished:(NSNotification*)notification
{
NSLog(@"finished");
}
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation
{
[self _requestMapWithLa:newLocation.coordinate.latitude
ln:newLocation.coordinate.longitude];
}
- (void)locationManager:(CLLocationManager *)manager
didFailWithError:(NSError *)error
{
NSLog(@"%@: %@",[error localizedDescription],
[error localizedFailureReason]);
[self _requestMapWithLa:35. ln:135.];
}
- (void)_requestMapWithLa:(float)la
ln:(float)ln
{
NSString *format= @"http://maps.google.co.jp/maps?q=%f,%f&output=embed";
NSString *urlString= [NSString stringWithFormat:format,la,ln];
NSURL *URL= [NSURL URLWithString:urlString];
[[webView mainFrame] loadRequest:[NSURLRequest requestWithURL:URL]];
}
@end

3.InterfaceBuilderでMainMenu.xibを料理
3.1WindowイッパイになるようにScrollViewを貼り,その中に同様にWebViewを貼る.
 それぞれInspectorのSizeタブ内のAutosizingで領域イッパイになるようにしておく.
3.2Sample Core Location App DelegateのOutletにWebViewを登録する.
4.実行
4.1ダイアログで利用を聞かれる.

4.2'許可しない'を選ぶ又はエラーなら緯度35,経度135にしてGoogleMapを呼び出す.

4.3'OK'を選ぶと求められた位置でGoogleMapを呼び出す.
format中の'&output=embed'がなければ通常の表示.

2009年4月23日木曜日

WebKit / WebView あれこれ

デフォルトの背景(色)を描かせないならこれ
[aWebView setDrawsBackground:NO];

透明レイヤーを持たせたいならこれ
[aWebView setAlphaValue:1.0];

透明レイヤー付きで画像(NSBitmapImageRep)が欲しいときはこれ
 NSBitmapImageRep *aBitmapImageRep = [aWebView bitmapImageRepForCachingDisplayInRect:[aWebView bounds]];
[aWebView cacheDisplayInRect:[aWebView bounds] toBitmapImageRep:aBitmapImageRep];


アンチエイリアスを切りたい(not-antialiasing, non-antialiasing, no-antialiasing …なんて言えばよいの?)ならこれ(いろいろ条件が付くがそれはもと(?)を読んでね)
@implementation WebFrameView (myextension)
- (void)drawRect:(NSRect)rect
{
[[NSGraphicsContext currentContext] setShouldAntialias:NO];
}
@end


まぁおいらがうまくいったことでしかないので,もっと正しいやり方とか素敵なやり方があるとは思うんですけどね.特に最後のなんかは.

追記(2009/04/25):
[NSBitmapImageRep initWithFocusedViewRect:]は描いた結果をbitmapとして取得,[WebView cacheDisplayInRect:toBitmapImageRep:]だと描く工程をbitmapへ実施って感じかしらね(よくわかってないけど).