SQLの窓

2014年02月05日


Win8.1 ストアアプリ(JS) : Visual Studio 2013 で Three.js(v65) の WebGLRenderer の動作を確認しました

Visual Studio 2013 Professional の 90 日間の無償評価版をダウンロードしてインストールし、動作確認しました。


<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <meta charset="utf-8" />
    <title>App1</title>

    <!-- WinJS 参照 -->
    <link href="//Microsoft.WinJS.2.0/css/ui-dark.css" rel="stylesheet" />
    <script src="//Microsoft.WinJS.2.0/js/base.js"></script>
    <script src="//Microsoft.WinJS.2.0/js/ui.js"></script>

    <!-- App1 参照 -->
    <link href="/css/default.css" rel="stylesheet" />
    <script src="/js/default.js"></script>
    <script src="/js/three.min65.js"></script>
    <script src="/js/OrbitControls.js"></script>
    <script src="/js/user_three.js"></script>

    <style>
        #three_area {
            margin: 20px 0px 0px 190px;
            width: 850px;
            height: 400px;
            border: solid #ffffff 1px;
        }

        #title_area {
            margin: 150px 0px 0px 190px;
            width: 820px;
            height: 60px;
            border: solid #ffffff 1px;
            font-size: 25px;
            padding: 15px;
        }

    </style>
</head>
<body>

    <div id="title_area">Windows 8.1 + Visual Studio 2013 + WebGL + Three.js v65</div>

    <div id="three_area"></div>

    <script>

        var cameraCube, sceneCube;

        var w = 850;
        var h = 400;

        // カメラ作成
        USER.camera = new THREE.PerspectiveCamera(70, w / h, 1, 10000);
        USER.camera.position.set(0, 0, 1);

        USER.camera2 = new THREE.PerspectiveCamera(50, w / h, 1, 500);
        USER.camera2.position.z = 0;

        // シーン作成
        USER.scene = new THREE.Scene();
        USER.scene2 = new THREE.Scene();

        // テクスチャの準備
        var path = "/images/";
        var format = '.jpg';
        var urls = [
                path + 'px' + format, path + 'nx' + format,
                path + 'py' + format, path + 'ny' + format,
                path + 'pz' + format, path + 'nz' + format
        ];

        // テクスチャの実装
        mesh = USER.meshPanorama(urls);
        USER.scene2.add(mesh);

        // レンダラー作成
        USER.renderer = new THREE.WebGLRenderer();
        USER.renderer.setSize(w, h);

        // 表示エリア設定
        document.getElementById("three_area").appendChild(USER.renderer.domElement);

        // コントロール作成
        USER.orbit();
        USER.controls.autoRotate = true;
        USER.controls.autoRotateSpeed = 0.5; //default 2.0

        // アニメーション開始
        USER.animate();

        // オーバーライド
        USER.animate = function () {

            requestAnimationFrame(USER.animate);

            USER.camera2.rotation.copy(USER.camera.rotation);
            USER.camera2.position.copy(USER.camera.position);
            USER.controls.update();
            USER.renderer.render(USER.scene2, USER.camera2);

        }


    </script>

</body>
</html>

▼ このコードは、実際 WEB 上で動作しているものです。

Three.js : WebGL限定の Cube テクスチャによる『パノラマ背景』

この時の Three.js は v57 で、Windows8.1 で動作確認するにあたり、最新版は v65 でした。しかし、v65 のほうでは OrbitControls.js の内部処理がかなり変更された結果、Windows8.1 上では画面がちらつくので元のコードに近い状態に変更して動作させました。( 373 行目の scope.update(); をコメントにしました )

以下は、メインコードを簡潔にする為のユーザコードです( user_three.js )
USER = {};
USER.camera = null;
USER.scene = null;
USER.camera2 = null;
USER.scene2 = null;
USER.renderer = null;
USER.controls = null;

USER.animate = function () {
	requestAnimationFrame( USER.animate );
	USER.controls.update();
}

USER.render = function() {
	USER.renderer.render( USER.scene, USER.camera );
}

USER.orbit = function() {

	USER.controls = new THREE.OrbitControls( USER.camera );
	USER.controls.addEventListener( 'change', USER.render );

}

USER.meshPanorama = function(urls) {

	var reflectionCube = THREE.ImageUtils.loadTextureCube( urls );
	reflectionCube.format = THREE.RGBFormat;

	// Skybox
	var shader = THREE.ShaderLib[ "cube" ];
	shader.uniforms[ "tCube" ].value = reflectionCube;

	var material = new THREE.ShaderMaterial( {

		fragmentShader: shader.fragmentShader,
		vertexShader: shader.vertexShader,
		uniforms: shader.uniforms,
		depthWrite: false,
		side: THREE.BackSide

	} );

	return new THREE.Mesh( new THREE.CubeGeometry( 100, 100, 100 ), material );

}




posted by lightbox at 2014-02-05 17:38 | Win8 ストアアプリ | このブログの読者になる | 更新情報をチェックする

2013年11月11日


WinJS ストア : Three.js を組み込んで、『画像を飛ばす』テンプレート( Bird.js を利用 )

SkyDrive へ移動




WinJS ストア : 『背景画像をチェンジする2画面アプリ』のテンプレート を元に、2画面目で Three.js の canvas_geometry_birds を組み込んで通常の Bird をテスト飛行させてから、平面画像で飛ばすように変更しています。元々、WEB ベースの Three.js で実装済だったものを、Windows ストアの JavaScript で実装しました。製品版になる前より、Three.js の Canvas バージョンは動作する事が解っていましたが、今回あらためて動作確認しました。但し、飛ばせる数は WEBブラウザよりはかなり少なくなります。

▼ 飛ばす画像( 背景透過 )


もともと、Bird(3Dデータ) は簡単なアニメーションで成り立っています。その羽ばたき部分を平面画像の各頂点の移動に変えて実現しています。

ですから、ソースコード上の Bird オプジェクトは使用せずに、THREE.PlaneGeometry を使用しており、マテリアルとして画像をテクスチャ使用しています。また、さらに material.side = 2 なので両面仕様です。
( THREE.FrontSide=0;THREE.BackSide=1;THREE.DoubleSide=2 )
			texture = new THREE.Texture(this);
			texture.needsUpdate = true;
			material = new THREE.MeshBasicMaterial({ map: texture, overdraw: true });
			material.side = 2


var SCREEN_WIDTH = window.innerWidth,
SCREEN_HEIGHT = window.innerHeight,
SCREEN_WIDTH_HALF = SCREEN_WIDTH / 2,
SCREEN_HEIGHT_HALF = SCREEN_HEIGHT / 2;

var camera, scene, renderer = null,
birds, bird;

var boid, boids;



var Bird = function () {

	var scope = this;

	THREE.Geometry.call( this );

	v(   5,   0,   0 );
	v( - 5, - 2,   1 );
	v( - 5,   0,   0 );
	v( - 5, - 2, - 1 );

	v(   0,   2, - 6 );
	v(   0,   2,   6 );
	v(   2,   0,   0 );
	v( - 3,   0,   0 );

	f3( 0, 2, 1 );
	// f3( 0, 3, 2 );

	f3( 4, 7, 6 );
	f3( 5, 6, 7 );

	this.computeCentroids();
	this.computeFaceNormals();

	function v( x, y, z ) {

		scope.vertices.push( new THREE.Vector3( x, y, z ) );

	}

	function f3( a, b, c ) {

		scope.faces.push( new THREE.Face3( a, b, c ) );

	}

}

Bird.prototype = Object.create( THREE.Geometry.prototype );


var Boid = function () {

	var vector = new THREE.Vector3(),
	_acceleration, _width = 500, _height = 500, _depth = 200, _goal, _neighborhoodRadius = 100,
	_maxSpeed = 4, _maxSteerForce = 0.1, _avoidWalls = false;

	this.position = new THREE.Vector3();
	this.velocity = new THREE.Vector3();
	_acceleration = new THREE.Vector3();

	this.setGoal = function (target) {

		_goal = target;

	}

	this.setAvoidWalls = function (value) {

		_avoidWalls = value;

	}

	this.setWorldSize = function (width, height, depth) {

		_width = width;
		_height = height;
		_depth = depth;

	}

	this.run = function (boids) {

		if (_avoidWalls) {

			vector.set(-_width, this.position.y, this.position.z);
			vector = this.avoid(vector);
			vector.multiplyScalar(5);
			_acceleration.add(vector);

			vector.set(_width, this.position.y, this.position.z);
			vector = this.avoid(vector);
			vector.multiplyScalar(5);
			_acceleration.add(vector);

			vector.set(this.position.x, -_height, this.position.z);
			vector = this.avoid(vector);
			vector.multiplyScalar(5);
			_acceleration.add(vector);

			vector.set(this.position.x, _height, this.position.z);
			vector = this.avoid(vector);
			vector.multiplyScalar(5);
			_acceleration.add(vector);

			vector.set(this.position.x, this.position.y, -_depth);
			vector = this.avoid(vector);
			vector.multiplyScalar(5);
			_acceleration.add(vector);

			vector.set(this.position.x, this.position.y, _depth);
			vector = this.avoid(vector);
			vector.multiplyScalar(5);
			_acceleration.add(vector);

		}/* else {

						this.checkBounds();

					}
					*/

		if (Math.random() > 0.5) {

			this.flock(boids);

		}

		this.move();

	}

	this.flock = function (boids) {

		if (_goal) {

			_acceleration.add(this.reach(_goal, 0.005));

		}

		_acceleration.add(this.alignment(boids));
		_acceleration.add(this.cohesion(boids));
		_acceleration.add(this.separation(boids));

	}

	this.move = function () {

		this.velocity.add(_acceleration);

		var l = this.velocity.length();

		if (l > _maxSpeed) {

			this.velocity.divideScalar(l / _maxSpeed);

		}

		this.position.add(this.velocity);
		_acceleration.set(0, 0, 0);

	}

	this.checkBounds = function () {

		if (this.position.x > _width) this.position.x = -_width;
		if (this.position.x < -_width) this.position.x = _width;
		if (this.position.y > _height) this.position.y = -_height;
		if (this.position.y < -_height) this.position.y = _height;
		if (this.position.z > _depth) this.position.z = -_depth;
		if (this.position.z < -_depth) this.position.z = _depth;

	}

	//

	this.avoid = function (target) {

		var steer = new THREE.Vector3();

		steer.copy(this.position);
		steer.sub(target);

		steer.multiplyScalar(1 / this.position.distanceToSquared(target));

		return steer;

	}

	this.repulse = function (target) {

		var distance = this.position.distanceTo(target);

		if (distance < 150) {

			var steer = new THREE.Vector3();

			steer.subVectors(this.position, target);
			steer.multiplyScalar(0.5 / distance);

			_acceleration.add(steer);

		}

	}

	this.reach = function (target, amount) {

		var steer = new THREE.Vector3();

		steer.subVectors(target, this.position);
		steer.multiplyScalar(amount);

		return steer;

	}

	this.alignment = function (boids) {

		var boid, velSum = new THREE.Vector3(),
		count = 0;

		for (var i = 0, il = boids.length; i < il; i++) {

			if (Math.random() > 0.6) continue;

			boid = boids[i];

			distance = boid.position.distanceTo(this.position);

			if (distance > 0 && distance <= _neighborhoodRadius) {

				velSum.add(boid.velocity);
				count++;

			}

		}

		if (count > 0) {

			velSum.divideScalar(count);

			var l = velSum.length();

			if (l > _maxSteerForce) {

				velSum.divideScalar(l / _maxSteerForce);

			}

		}

		return velSum;

	}

	this.cohesion = function (boids) {

		var boid, distance,
		posSum = new THREE.Vector3(),
		steer = new THREE.Vector3(),
		count = 0;

		for (var i = 0, il = boids.length; i < il; i++) {

			if (Math.random() > 0.6) continue;

			boid = boids[i];
			distance = boid.position.distanceTo(this.position);

			if (distance > 0 && distance <= _neighborhoodRadius) {

				posSum.add(boid.position);
				count++;

			}

		}

		if (count > 0) {

			posSum.divideScalar(count);

		}

		steer.subVectors(posSum, this.position);

		var l = steer.length();

		if (l > _maxSteerForce) {

			steer.divideScalar(l / _maxSteerForce);

		}

		return steer;

	}

	this.separation = function (boids) {

		var boid, distance,
		posSum = new THREE.Vector3(),
		repulse = new THREE.Vector3();

		for (var i = 0, il = boids.length; i < il; i++) {

			if (Math.random() > 0.6) continue;

			boid = boids[i];
			distance = boid.position.distanceTo(this.position);

			if (distance > 0 && distance <= _neighborhoodRadius) {

				repulse.subVectors(this.position, boid.position);
				repulse.normalize();
				repulse.divideScalar(distance);
				posSum.add(repulse);

			}

		}

		return posSum;

	}

}


function init() {

	if (renderer == null) {
		camera = new THREE.PerspectiveCamera(75, SCREEN_WIDTH / SCREEN_HEIGHT, 1, 10000);
		// エリアの中に視点を置く
		camera.position.z = 300;

		scene = new THREE.Scene();

		birds = [];
		boids = [];

		//for (var i = 0; i < 30; i++) {

		//	boid = boids[i] = new Boid();
		//	boid.position.x = Math.random() * 400 - 200;
		//	boid.position.y = Math.random() * 400 - 200;
		//	boid.position.z = Math.random() * 400 - 200;
		//	boid.velocity.x = Math.random() * 2 - 1;
		//	boid.velocity.y = Math.random() * 2 - 1;
		//	boid.velocity.z = Math.random() * 2 - 1;
		//	boid.setAvoidWalls(true);
		//	boid.setWorldSize(500, 500, 400);

		//	bird = birds[i] = new THREE.Mesh(new Bird(), new THREE.MeshBasicMaterial({ color: Math.random() * 0xffffff, side: THREE.DoubleSide }));
		//	bird.phase = Math.floor(Math.random() * 62.83);
		//	bird.position = boids[i].position;
		//	scene.add(bird);

		//}

		var image = new Image()
		image.onload = function () {

			texture = new THREE.Texture(this);
			texture.needsUpdate = true;
			material = new THREE.MeshBasicMaterial({ map: texture, overdraw: true });
			material.side = 2

			for (var i = 0; i < 30; i++) {

				boid = boids[i] = new Boid();
				boid.position.x = Math.random() * 400 - 200;
				boid.position.y = Math.random() * 400 - 200;
				boid.position.z = Math.random() * 400 - 200;
				boid.velocity.x = Math.random() * 2 - 1;
				boid.velocity.y = Math.random() * 2 - 1;
				boid.velocity.z = Math.random() * 2 - 1;
				boid.setAvoidWalls(true);
				boid.setWorldSize(500, 500, 400);

				birds[i] = new THREE.Mesh(new THREE.PlaneGeometry(30, 30, 2, 1), material);
				bird = birds[i]
				bird.phase = Math.floor(Math.random() * 62.83);
				bird.position = boids[i].position;
				scene.add(bird);

			}

		};
		image.src = "/images/Black_Eagle_Miku_Elf4.png";


		renderer = new THREE.CanvasRenderer();
		Debug.writeln("new THREE.CanvasRenderer()");
		// renderer.autoClear = false;
		renderer.setSize(SCREEN_WIDTH, SCREEN_HEIGHT);

		document.addEventListener('mousemove', onDocumentMouseMove, false);
	}
	var target = document.querySelector("#contentHost");
	target.appendChild(renderer.domElement);
//	document.body.appendChild(renderer.domElement);

	if (renderer == null) {
		window.addEventListener('resize', onWindowResize, false);
	}

}

function onWindowResize() {

	camera.aspect = window.innerWidth / window.innerHeight;
	camera.updateProjectionMatrix();

	renderer.setSize(window.innerWidth, window.innerHeight);

}

function onDocumentMouseMove(event) {

	var vector = new THREE.Vector3(event.clientX - SCREEN_WIDTH_HALF, - event.clientY + SCREEN_HEIGHT_HALF, 0);

	for (var i = 0, il = boids.length; i < il; i++) {

		boid = boids[i];

		vector.z = boid.position.z;

		boid.repulse(vector);

	}

}

//

function animate() {

	requestAnimationFrame(animate);
	render();

}

function render() {

	for (var i = 0, il = birds.length; i < il; i++) {

		boid = boids[i];
		boid.run(boids);

		bird = birds[i];

		bird.rotation.y = Math.atan2(-boid.velocity.z, boid.velocity.x);
		bird.rotation.z = Math.asin(boid.velocity.y / boid.velocity.length());
		bird.rotation.x = (180 * Math.PI / 180) / 2;
		bird.phase = (bird.phase + (Math.max(0, bird.rotation.z) + 0.1)) % 62.83;

		bird.geometry.vertices[0].z = bird.geometry.vertices[2].z = Math.sin(bird.phase) * 15;

		//color = bird.material.color;
		//color.r = color.g = color.b = (500 - bird.position.z) / 1000;

		//bird.rotation.y = Math.atan2(-boid.velocity.z, boid.velocity.x);
		//bird.rotation.z = Math.asin(boid.velocity.y / boid.velocity.length());

		//bird.phase = (bird.phase + (Math.max(0, bird.rotation.z) + 0.1)) % 62.83;
		//bird.geometry.vertices[5].y = bird.geometry.vertices[4].y = Math.sin(bird.phase) * 5;

	}

	renderer.render(scene, camera);

}

Windows JS ストアとしての改造のキモは、default.html の contentHost をうまく使うところです。



posted by lightbox at 2013-11-11 19:35 | Win8 ストアアプリ | このブログの読者になる | 更新情報をチェックする

2013年11月01日


WinJS ストア : 『背景画像をチェンジする2画面アプリ』のテンプレート

SkyDrive へ移動



( 自作のイラストを背景画像として使用しています )

製品になる前のサンプルコードから様変わりし、以前のままでは動作しなかったものを修正しました。以前から比べて、アプリバーのボタンの作成方法が変わり、画面定義にイベント記述ができないようになっていました。しかし、その他の大きな骨格は基本的に以前と変わっていませんでした。
default.js
(function () {
    "use strict";

    WinJS.Binding.optimizeBindingReferences = true;

    var app = WinJS.Application;
    var nav = WinJS.Navigation;
    var activation = Windows.ApplicationModel.Activation;

	// ************************************************
	// 開始処理
	// ************************************************
    app.onactivated = function (args) {
        if (args.detail.kind === activation.ActivationKind.launch) {
        	if (args.detail.previousExecutionState !== activation.ApplicationExecutionState.terminated) {

        		nav.navigate("/HomePage.html");

            } else {
                // TODO: このアプリケーションは中断状態から再度アクティブ化されました。
                // ここでアプリケーションの状態を復元します。
            }
            args.setPromise(WinJS.UI.processAll());
        }
    };

	// ************************************************
	// Navigate された時の処理( 画面変更 )
	// ************************************************
    WinJS.Navigation.addEventListener("navigated", function (ev) {
    	Debug.writeln("navigated");
    	Debug.writeln(ev.detail.location);
		// 画面を切り替えるコンテンツエリア
    	var target = document.querySelector("#contentHost");
    	WinJS.Utilities.empty(target);
		// 画面の初期処理
    	WinJS.UI.Fragments.render(ev.detail.location, target).then(function () {

    		// ************************************************
    		// 戻るボタンがあった場合の処理
    		// ************************************************
    		var backButton = document.querySelector(".win-backbutton");
    		if (backButton) {
    			backButton.addEventListener('click', function () {
    				WinJS.Navigation.back();

    			}, false);
    			if (WinJS.Navigation.canGoBack) {
    				backButton.removeAttribute('disabled');
    			}
    			else {
    				backButton.setAttribute('disabled', 'true');
    			}
    		}

    		// ************************************************
    		// 画面が切り替わった時の処理
    		// ************************************************
    		if (ev.detail.location == "/HomePage.html") {
    			var body = document.getElementsByTagName("body")[0];
    			body.style.backgroundImage = "url(/images/back_001.jpg)";
    		}
    		if (ev.detail.location == "/NextPage.html") {
    			var body = document.getElementsByTagName("body")[0];
    			body.style.backgroundImage = "url(/images/back_002.jpg)";
    		}

    	});

    }, false);

	// ************************************************
	// イベント処理の登録
	// ************************************************
    var page = WinJS.UI.Pages.define("/default.html", {
    	ready: function (element, options) {
    		document.getElementById("home")
                .addEventListener("click", EVENT.navigateHome, false);
    		document.getElementById("play")
                .addEventListener("click", EVENT.navigateGame, false);
    		document.getElementById("rules")
				.addEventListener("click", EVENT.navigateRules, false);
    		document.getElementById("scores")
				.addEventListener("click", EVENT.navigateScores, false);
    		document.getElementById("credits")
				.addEventListener("click", EVENT.navigateCredits, false);
    	},
    });

	// ************************************************
	// 実際のイベント処理
	// ************************************************
    function navigateHome() {
    	Debug.writeln("メニュー");
    	document.getElementById("appbar").winControl.hide();
    	nav.navigate("/HomePage.html");
	}
    function navigateGame() {
    	Debug.writeln("ゲーム");
    	document.getElementById("appbar").winControl.hide();
    	nav.navigate("/NextPage.html");
    }
    function navigateRules() {
    	Debug.writeln("ルール");
    	document.getElementById("appbar").winControl.hide();
    }
    function navigateScores() {
    	Debug.writeln("スコア");
    	document.getElementById("appbar").winControl.hide();
    }
    function navigateCredits() {
    	Debug.writeln("クレジット");
    	document.getElementById("appbar").winControl.hide();
    }

    app.oncheckpoint = function (args) {
    };

    app.start();

	// ************************************************
	// 各ページから参照可能な名前空間の定義
	// ************************************************
    WinJS.Namespace.define("EVENT", {
    	navigateHome: navigateHome,
    	navigateGame: navigateGame,
    	navigateRules: navigateRules,
    	navigateScores: navigateScores,
    	navigateCredits: navigateCredits
    });


})();



default.html
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>JSBasic</title>

    <!-- WinJS 参照 -->
    <link href="//Microsoft.WinJS.1.0/css/ui-dark.css" rel="stylesheet" />
    <script src="//Microsoft.WinJS.1.0/js/base.js"></script>
    <script src="//Microsoft.WinJS.1.0/js/ui.js"></script>

    <!-- JSBasic 参照 -->
    <link href="/css/default.css" rel="stylesheet" />
    <script src="/js/default.js"></script>

</head>
<body>
	<!-- 画面切り替え用エリア -->
    <div id="contentHost"></div>

	<!-- アプリケーションバー -->
    <div
        id="appbar"
        data-win-control="WinJS.UI.AppBar"
        aria-label="Command Bar">

        <button 
            data-win-control="WinJS.UI.AppBarCommand" 
            data-win-options="{id:'home', label:'メニュー', icon:'&#xE10F;', section: 'global'}">
        </button>

        <button 
            data-win-control="WinJS.UI.AppBarCommand" 
            data-win-options="{id:'play', label:'ゲーム', icon:'&#xE102;', section: 'global'}">
        </button>

        <button 
            data-win-control="WinJS.UI.AppBarCommand" 
            data-win-options="{id:'rules', label:'ルール', icon:'&#xE104;', section: 'global'}">
        </button>

        <button 
            data-win-control="WinJS.UI.AppBarCommand" 
            data-win-options="{id:'scores', label:'スコア', icon:'&#xE113;', section: 'global'}">
        </button>

        <button 
            data-win-control="WinJS.UI.AppBarCommand" 
            data-win-options="{id:'credits', label:'クレジット', icon:'&#xE10C;', section: 'global'}">
        </button>

    </div>
</body>
</html>

第二画面にコンテンツは無く、背景画像のみ変更するようにしています。



※ アプリバーは動作します


posted by lightbox at 2013-11-01 21:05 | Win8 ストアアプリ | このブログの読者になる | 更新情報をチェックする

2013年10月29日


Framework4.5(C#)ストア : HttpClient で Post と Get する汎用 static クラス

UrlEncode をキャラクタセットを指定して送れるようになっています。受信データは、Content-Type でキャラクタセットが指定されておれば、自動的に変換されています。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;

namespace winofsql {

	class Tool {

		// 戻される文字列は、サーバー側で Content-Type に Charset が
		// 指定されておれば自動変換されます

		// *********************************************
		// UTF-8 POST
		// *********************************************
		public static async Task<string> Post(string url, Dictionary<string, string> param) {
			string result = "";

			try {
				HttpClient httpClient = new HttpClient();
				httpClient.MaxResponseContentBufferSize = int.MaxValue;
				HttpContent content = new FormUrlEncodedContent(param);
				var response = await httpClient.PostAsync(url, content);
				String text = await response.Content.ReadAsStringAsync();

				result = text;
			}
			catch (Exception Err) {
				result = "ERROR: " + Err.Message;
			}

			return result;

		}

		// *********************************************
		// エンコード指定 POST
		// *********************************************
		public static async Task<string> Post(string url, string encoding, Dictionary<string, string> param) {
			string result = "";
			string query_string = "";
			byte[] data1 = null;
			byte[] data2 = null;
			string data3 = null;

			foreach (KeyValuePair<string, string> kvp in param) {
				if (query_string == "") {
					query_string += "";
				}
				else {
					query_string += "&";
				}

				data1 = Encoding.GetEncoding(encoding).GetBytes(kvp.Value);
				data2 = WebUtility.UrlEncodeToBytes(data1, 0, data1.Length);
				data3 = Encoding.GetEncoding(encoding).GetString(data2, 0, data2.Length);
				query_string += kvp.Key + "=" + data3;
			}

			try {

				HttpClient httpClient = new HttpClient();
				HttpContent content = new StringContent(query_string);
				content.Headers.ContentType = new MediaTypeHeaderValue("application/x-www-form-urlencoded");
				var response = await httpClient.PostAsync(url, content);
				String text = await response.Content.ReadAsStringAsync();

				result = text;
			}
			catch (Exception Err) {
				result = "ERROR: " + Err.Message;
			}

			return result;

		}

		// *********************************************
		// URL のみ呼び出し GET
		// *********************************************
		public static async Task<string> Get(string url) {
			string result = "";

			HttpClient httpClient = new HttpClient();

			HttpResponseMessage response = null;
			try {
				response = await httpClient.GetAsync(url);
			}
			catch (Exception Err) {
				result = "ERROR: " + Err.Message;
			}
			// 接続に失敗
			if (response == null) {
				return result;
			}

			try {
				response.EnsureSuccessStatusCode();
			}
			catch (Exception Err) {
				result = "ERROR: " + Err.Message;
			}
			// HTTP 応答の失敗
			if (!response.IsSuccessStatusCode) {
				return result;
			}

			// 内容を文字列として取得
			try {
				String text = await response.Content.ReadAsStringAsync();

				result = text;
			}
			catch (Exception Err) {
				result = "ERROR: " + Err.Message;
			}

			return result;

		}

		// *********************************************
		// データ呼び出し( UTF-8 ) GET
		// *********************************************
		public static async Task<string> Get(string url, Dictionary<string, string> param) {

			string query_string = "";

			foreach (KeyValuePair<string, string> kvp in param) {
				if (query_string == "") {
					query_string += "?";
				}
				else {
					query_string += "&";
				}
				query_string += kvp.Key + "=" + WebUtility.UrlEncode(kvp.Value);
			}

			return await Get(url + query_string);

		}

		// *********************************************
		// データ呼び出し( エンコード指定 ) GET
		// *********************************************
		public static async Task<string> Get(string url, string encoding, Dictionary<string, string> param) {

			string query_string = "";
			byte[] data1 = null;
			byte[] data2 = null;
			string data3 = null;

			foreach (KeyValuePair<string, string> kvp in param) {
				if (query_string == "") {
					query_string += "?";
				}
				else {
					query_string += "&";
				}
				data1 = Encoding.GetEncoding(encoding).GetBytes(kvp.Value);
				data2 = WebUtility.UrlEncodeToBytes(data1, 0, data1.Length);
				data3 = Encoding.GetEncoding(encoding).GetString(data2, 0, data2.Length);

				query_string += kvp.Key + "=" + data3;
			}

			return await Get(url + query_string);

		}

	}
}


呼び出し
string result = await winofsql.Tool.Post(
	"http://localhost/lightbox/sample/test.php",
	"shift_jis",
	new Dictionary<string, string>() { { "field1", "日本語" }, { "field2", "表示" } });

if (result.PadRight(5).Substring(0, 5) == "ERROR") {
	Debug.WriteLine(result);
}

関連する記事

Framework4(C#) : WebClient で Post と Get する汎用 static クラス
Framework4(C#) : Windows Phone OS 7.1 : WebClient で Post と Get する汎用 static クラス
Android で Post と Get


posted by lightbox at 2013-10-29 21:02 | Win8 ストアアプリ | このブログの読者になる | 更新情報をチェックする

2013年10月26日


VS2012ストア(C#) : WebView テンプレート

きちんとした、WebView の利用は Windows 8.1 + VS2013 で行ったほうがよさそうですが、API を使用したWEB アプリ関連のログイン処理はこれを使うしかありません。ほとんどたいした事はできませんが、テンプレートを作ってみました。

Windows ストア用に作ったイラストを 5 枚同梱しています。以下はそのうちの一つを使ったものです





イベントは、LoadCompleted で Navigate 後の処理を行う事ができます。

ページ内で JavaScript を実行するには、以下のようにすれば大抵は実行可能のようです。
this.webView.InvokeScript("eval", new[] { "history.back()" });



posted by lightbox at 2013-10-26 00:22 | Win8 ストアアプリ | このブログの読者になる | 更新情報をチェックする

2013年10月11日


VS2012(C#)ストア : ListView Twitter 検索テンプレート

SkyDrive へ移動




インターネットから取得した JSON のデータをいかに ListView にバインドするかをまとめたテンプレートです。

Twitter_Search.cs

Twitter API の GET のテンプレートでもあります。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Diagnostics;
using System.Net.Http;
using System.IO;
using System.Threading.Tasks;
using Windows.Security.Cryptography;
using Windows.Storage.Streams;
using Windows.Security.Cryptography.Core;

namespace VS2012_Twitter {
	class Twitter_Search {
		private string _consumer_key;
		private string _consumer_secret;
		private string _token;
		private string _secret;

		private string _tweet_api = "https://api.twitter.com/1.1/search/tweets.json";

		public Twitter_Search(
			string consumer_key,
			string consumer_secret,
			string token,
			string secret
			) {
			_consumer_key = consumer_key;
			_consumer_secret = consumer_secret;
			_token = token;
			_secret = secret;
		}

		public async Task<string> Tweet(string text, int count) {

			HttpClient hc = new HttpClient();

			// ソートされるリスト
			SortedDictionary<string, string> sl = new SortedDictionary<string, string>();
			sl.Add("count", count.ToString());
			sl.Add("oauth_consumer_key", _consumer_key);
			sl.Add("oauth_nonce", Nonce());
			sl.Add("oauth_signature_method", "HMAC-SHA1");
			sl.Add("oauth_timestamp", TimeStamp());
			sl.Add("oauth_token", _token);
			sl.Add("oauth_version", "1.0");
			sl.Add("q", Uri.EscapeDataString(text));

			// http ヘッダ用シグネチャ作成
			string work = "";
			foreach (KeyValuePair<string, string> kvp in sl) {
				if (work != "") {
					work += "&";
				}
				work += kvp.Key + "=" + kvp.Value;
			}

			string work2 = "";
			// メソッド
			work2 += "GET" + "&";
			// API URL
			work2 += Uri.EscapeDataString(_tweet_api) + "&";
			// Oauth + データ
			work2 += Uri.EscapeDataString(work);

			// OAuth tool チェック用
			Debug.WriteLine(work2);

			string oauth_signature = Signature(work2);

			// ヘッダ情報を作成
			work = "";
			foreach (KeyValuePair<string, string> kvp in sl) {
				// oauth_* のみを使用する
				if (work != "") {
					if ((kvp.Key + "      ").Substring(0, 6) == "oauth_") {
						work += ", ";
					}
				}
				if ((kvp.Key + "      ").Substring(0, 6) == "oauth_") {
					work += kvp.Key + "=" + Dd(kvp.Value);
				}
			}
			// シグネチャを追加( ヘッダーはソートの必要は無い )
			work += ", oauth_signature=" + Dd(Uri.EscapeDataString(oauth_signature));

			// OAuth tool チェック用
			Debug.WriteLine(work);

			string result = null;
			try {
				// フォーマットは、 OAuth tool で確認。
				hc.DefaultRequestHeaders.Add("Authorization", "OAuth " + work);

				// 投稿
				result = await hc.GetStringAsync(new Uri(
					_tweet_api +
					"?" +
					"q=" + sl["q"] +
					"&count=" + sl["count"]
				));
			}
			catch (Exception ex) {
				result = "{\"error\", \"" + ex.Message + "\" }";
			}

			return result;

		}

		// Framework 4.5 では必要無い
		private string rfc3986(string base_string) {
			string result = base_string.Replace("!", "%21");
			result = result.Replace("'", "%27");
			result = result.Replace("(", "%28");
			result = result.Replace(")", "%29");
			result = result.Replace("*", "%2A");
			return result;
		}

		// ダブルクォートで挟む
		private string Dd(string base_string) {
			return "\"" + base_string + "\"";
		}

		private string Nonce() {
			Random rand = new Random();
			int nonce = rand.Next(1000000000);
			return nonce.ToString();
		}

		// タイムスタンプ
		private string TimeStamp() {
			TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
			return Convert.ToInt64(ts.TotalSeconds).ToString();
		}

		// シグネチャ
		private string Signature(string target) {
			String signingKey = _consumer_secret + "&";
			signingKey += _secret;

			IBuffer keyMaterial = CryptographicBuffer.ConvertStringToBinary(signingKey, BinaryStringEncoding.Utf8);
			MacAlgorithmProvider hmacSha1Provider = MacAlgorithmProvider.OpenAlgorithm("HMAC_SHA1");
			CryptographicKey macKey = hmacSha1Provider.CreateKey(keyMaterial);
			IBuffer dataToBeSigned = CryptographicBuffer.ConvertStringToBinary(target, BinaryStringEncoding.Utf8);
			IBuffer signatureBuffer = CryptographicEngine.Sign(macKey, dataToBeSigned);
			String signature = CryptographicBuffer.EncodeToBase64String(signatureBuffer);
			return signature;
		}
	}
}



posted by lightbox at 2013-10-11 11:34 | Win8 ストアアプリ | このブログの読者になる | 更新情報をチェックする

2013年10月10日


イラストを背景にして2ページの画面遷移を解りやすくした Windows Store テンプレート

SkyDrive へ移動


MainPage

メイン画面の背景に大きなイラストを設定しました。ファイルは、『Assets フォルダ』に保存して参照しています



NextPage

次画面は、LinearGradientBrush でグラデーションにしました。



App.xaml.cs

ページの設定は、Microsoft のテンプレートを無視しました。本来の WPF と同じような形でフレーム内のコンテンツを複数ページで切り替える形にしています。
using System;
using System.Diagnostics;
using Windows.ApplicationModel;
using Windows.ApplicationModel.Activation;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

namespace Simple_Pages {

	// *************************************************
	// クラス
	// *************************************************
	sealed partial class App : Application {

		public static Frame rootFrame = null;
		public static MainPage mainPage;
		public static NextPage nextPage;

		// *************************************************
		// コンストラクタ
		// *************************************************
		public App() {
			this.InitializeComponent();
			this.Suspending += OnSuspending;
		}

		// *************************************************
		// アプリケーションがエンド ユーザーによって正常に起動された
		// *************************************************
		protected override void OnLaunched(LaunchActivatedEventArgs args) {

			// ***********************************************
			// Window => Current => Content
			// Content( Frame => Content(MainPage) )
			// ***********************************************
			// 初回は Windows 内に置く フレームを作成
			if (rootFrame == null) {
				rootFrame = new Frame();
				Window.Current.Content = rootFrame;
			}

			if (rootFrame.Content == null) {
				// メインページの初回ロード
				rootFrame.Content = new MainPage();
				// 次ページを最初に作成しておく
				nextPage = new NextPage();
			}

			// 現在のウィンドウをアクティブにします
			Window.Current.Activate();
		}

		// *************************************************
		// アプリケーションの実行が中断されたときに呼び出されます
		// *************************************************
		private void OnSuspending(object sender, SuspendingEventArgs e) {
			Debug.WriteLine("アプリケーションの実行が中断されました");

			var deferral = e.SuspendingOperation.GetDeferral();
			// アプリケーションの状態を保存してバックグラウンドの動作があれば停止します
			deferral.Complete();
		}
	}
}


MainPage.xaml

MainPage と NextPage を用意していますが、NextPage は、MainPage をコピーしてリネームしたものです。
<Page
	x:Class="Simple_Pages.MainPage"
	xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
	xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
	xmlns:local="using:Simple_Pages"
	xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
	xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
	mc:Ignorable="d"
	Loaded="Page_Loaded">

	<!--画面定義-->
	<Grid>
		<Grid.Background>
			<ImageBrush
				ImageSource="Assets/1378650512243910.jpeg"
				Stretch="None" />
		</Grid.Background>
		<Button
			Content="次ページ"
			HorizontalAlignment="Left"
			Height="41"
			Margin="34,30,0,0"
			VerticalAlignment="Top"
			Width="136"
			Click="Button_Click_1" />
	</Grid>
	
</Page>


MainPage.xaml.cs

ページの切り替えは、Navigate メソッドを使わずに直接ページのインスタンスをセットしています。そうする為に、App クラスに参照用に static な変数を作成して、インスタンスを保存しています。
App.rootFrame.Content = App.nextPage;
※ よって、Page.OnNavigatedTo イベントは発生しません
using System;
using System.Diagnostics;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

namespace Simple_Pages {

	// *************************************************
	// クラス
	// *************************************************
	public sealed partial class MainPage : Page {

		// *************************************************
		// コンストラクタ
		// *************************************************
		public MainPage() {
			this.InitializeComponent();
			App.mainPage = this;
		}

		// *************************************************
		// ページが Frame にロードされた時に実行
		// ( アプリケーション中でページ遷移する毎 )
		// *************************************************
		private void Page_Loaded(object sender, RoutedEventArgs e) {
			Debug.WriteLine("Main Page_Loaded");
		}

		// *************************************************
		// フレームに NextPage をセット
		// *************************************************
		private void Button_Click_1(object sender, RoutedEventArgs e) {
			App.rootFrame.Content = App.nextPage;
		}


	}
}



posted by lightbox at 2013-10-10 21:05 | Win8 ストアアプリ | このブログの読者になる | 更新情報をチェックする

2013年08月22日


Twitter API の自分のアプリのトークンを使って投稿するだけの class VS2012_Twitter

SkyDrive に移動( Windows8 用テンプレート )

テンプレートの主な機能
❶ Twitter 投稿
❷ ダイアログボックス用クラス
❸ Http 用クラス( Twitter では無く一般的なもの )
❹ 新しいページをメモリ上に保持する為の実装( App.xaml.css )
Twitter API の自分のアプリのトークンを使って投稿するだけの class VS2010_Twitter とは、微妙に違います。 VS2012_Twitter.cs
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using Windows.Security.Cryptography;
using Windows.Security.Cryptography.Core;
using Windows.Storage.Streams;

namespace LBOX_Tool
{
	class VS2012_Twitter
	{
        private string _consumer_key;
        private string _consumer_secret;
        private string _token;
        private string _secret;

        private string _tweet_api = "https://api.twitter.com/1.1/statuses/update.json";

        public VS2012_Twitter (
            string consumer_key,
            string consumer_secret,
            string token,
            string secret
            ) {
                _consumer_key = consumer_key;
                _consumer_secret = consumer_secret;
                _token = token;
                _secret = secret;
        }

        public async Task<string> TweetAsync(string text)
        {

            // ソートされるリスト
			SortedDictionary<string, string> sd = new SortedDictionary<string, string>();
            sd.Add("oauth_consumer_key", _consumer_key);
            sd.Add("oauth_nonce", Nonce());
            sd.Add("oauth_signature_method", "HMAC-SHA1");
            sd.Add("oauth_timestamp", TimeStamp());
            sd.Add("oauth_token", _token);
            sd.Add("oauth_version", "1.0");
            sd.Add("status",  Uri.EscapeDataString(text));

            // http ヘッダ用シグネチャ作成
            string work = "";
            foreach (KeyValuePair<string, string> kvp in sd)
            {
                if (work != "")
                {
                    work += "&";
                }
                work += kvp.Key + "=" + kvp.Value;
            }

            string work2 = "";
            // メソッド
            work2 += "POST" + "&";
            // API URL
            work2 += Uri.EscapeDataString(_tweet_api) + "&";
            // Oauth + データ
            work2 += Uri.EscapeDataString(work);

            // OAuth tool チェック用
            Debug.WriteLine(work2);

            string oauth_signature = Signature(work2);

            // ヘッダ情報を作成
            work = "";
            foreach (KeyValuePair<string, string> kvp in sd)
            {
                // oauth_* のみを使用する
                if (work != "")
                {
                    if (kvp.Key.Substring(0, 6) == "oauth_") {
                        work += ", ";
                    }
                }
                if (kvp.Key.Substring(0, 6) == "oauth_")
                {
                    work += kvp.Key + "=" + Dd(kvp.Value);
                }
            }
            // シグネチャを追加( ヘッダーはソートの必要は無い )
            work += ", oauth_signature=" + Dd(Uri.EscapeDataString(oauth_signature));

            // OAuth tool チェック用
            Debug.WriteLine(work);

			string result = "";
			HttpResponseMessage response = null;
			HttpClient hc = new HttpClient();
			try
			{
				hc.MaxResponseContentBufferSize = int.MaxValue;
				hc.DefaultRequestHeaders.ExpectContinue = false;
				hc.DefaultRequestHeaders.Add("Authorization", "OAuth " + work);

				// 送信処理の準備
				HttpContent content = new FormUrlEncodedContent(new Dictionary<string, string>
                {
                    { "status",  text }
                });

				response = await hc.PostAsync( _tweet_api, content );
				result = await response.Content.ReadAsStringAsync();
				if (response.IsSuccessStatusCode)
				{
					if (result.Substring(0, 10) == "{\"errors\":")
					{
						result = "ERROR:" + response.StatusCode + ":" + result;
					}
				}
				else
				{
					result = "ERROR:" + response.StatusCode + ":2XX以外:" + result;
				}
			}
			catch (Exception ex)
			{
				result = "ERROR:" + ex.Message;
			}

			return result;

        }

        // ダブルクォートで挟む
        private string Dd(string base_string)
        {
            return "\"" + base_string + "\"";
        }

        private string Nonce()
        {
            Random rand = new Random();
            int nonce = rand.Next(1000000000);
            return nonce.ToString();
        }

        // タイムスタンプ
        private string TimeStamp()
        {
            TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
            return Convert.ToInt64(ts.TotalSeconds).ToString();
        }

        // シグネチャ
        private string Signature(string target)
        {
			String signingKey = _consumer_secret + "&";
			signingKey += _secret;

			IBuffer keyMaterial = CryptographicBuffer.ConvertStringToBinary(signingKey, BinaryStringEncoding.Utf8);
			MacAlgorithmProvider hmacSha1Provider = MacAlgorithmProvider.OpenAlgorithm("HMAC_SHA1");
			CryptographicKey macKey = hmacSha1Provider.CreateKey(keyMaterial);
			IBuffer dataToBeSigned = CryptographicBuffer.ConvertStringToBinary(target, BinaryStringEncoding.Utf8);
			IBuffer signatureBuffer = CryptographicEngine.Sign(macKey, dataToBeSigned);
			String signature = CryptographicBuffer.EncodeToBase64String(signatureBuffer);
			return signature;
		}
	}
}


MainPage.xaml.cs
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Diagnostics;
using System.Threading.Tasks;
using LBOX_Tool;

namespace C_Sharp_Twitter1
{
	public sealed partial class MainPage : Page
	{
		public MainPage()
		{
			this.InitializeComponent();
		}

		protected override void OnNavigatedTo(NavigationEventArgs e)
		{
		}

		private async void  Button_Click_1(object sender, RoutedEventArgs e)
		{
			VS2012_Twitter twitter =
				new VS2012_Twitter(
		                    "Consumer key",
		                    "Consumer secret",
		                    "Access token",
		                    "Access token secret"
				);

			string result = await twitter.TweetAsync(this.tweet.Text);
			if (result.Substring(0, 6) != "ERROR:")
			{
				this.Response.Text = result;
			}
			else
			{
				Debug.WriteLine(result);
			}

		}
	}
}

関連する記事Twitter API の自分のアプリのトークンを使って投稿するだけの class VS2010_TwitterTwitter API の自分のアプリのトークンを使って投稿するだけの class Android_TwitterWSH : VBScript と JavaScript で Twitter に投稿するTwitter アプリの登録方法と、API キーの利用PHP : Twitter 投稿関数( twitter_update ) / cURL 関数

変更履歴
2013-07-09 : 初回投稿
2013-08-22 : ダウンロード(テンプレート追加)


タグ:twitter API
posted by lightbox at 2013-08-22 15:45 | Win8 ストアアプリ | このブログの読者になる | 更新情報をチェックする

2013年06月30日


Win8 ストア(C#) / PDF viewer sample (Windows 8.1)

PDF viewer sample (Windows 8.1)

実行できる環境はまだ無いですが、内容は単純だったのでコメントを付けてみました。
//*********************************************************
//
// Copyright (c) Microsoft. All rights reserved.
//
//*********************************************************

using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;
using SDKTemplate;
using System;
using Windows.Foundation;
using Windows.Storage;
using Windows.Storage.Streams;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Automation;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Media.Imaging;
using Windows.UI.Xaml.Navigation;
using Windows.UI.Xaml.Controls.Primitives;
using System.Threading.Tasks;
using Windows.Data.Pdf;

namespace PDFAPI
{	
	public sealed partial class Scenario1 : SDKTemplate.Common.LayoutAwarePage
	{
		// A pointer back to the main page.  This is needed if you want to call methods in MainPage such
		// as NotifyUser()
		// ***************************************************
		// 通知に使っていますが、機能とは関係ありません
		// ***************************************************
		MainPage rootPage = MainPage.Current;

		// ***************************************************
		// PDF を扱うクラス。インスタンスは、PdfDocument の 
		// static メソッドで取得
		// ***************************************************
		private PdfDocument _pdfDocument;   

		enum RENDEROPTIONS
		{
			NORMAL,
			ZOOM,
			PORTION
		}

		uint PDF_PAGE_INDEX = 0; //first page
		uint ZOOM_FACTOR = 3; //300% zoom
		Rect PDF_PORTION_RECT = new Rect(100, 100, 300, 400); //portion of a page
		string PDFFILENAME = "Assets\\Windows_7_Product_Guide.pdf"; //Pdf file

		public Scenario1()
		{
			this.InitializeComponent();
		}

		// ***************************************************
		// 未使用
		// ***************************************************
		protected override void OnNavigatedTo(NavigationEventArgs e)
		{
		}

		// ***************************************************
		// ボタン毎に PDF を読み込んで簡単な加工してから表示
		// ***************************************************
		public async Task DisplayImageFileAsync(StorageFile file)
		{			
			// Display the image in the UI.
			BitmapImage src = new BitmapImage();
			src.SetSource(await file.OpenAsync(FileAccessMode.Read));
			// Image1 に表示
			Image1.Source = src;
		}

		// ***************************************************
		/// PDF ページを読み込んで、png ファイルに書き出して
		/// 加工してイメージコントロールに表示
		/// ■何故か変数名が jpgFile なのかは謎■
		// ***************************************************
		private async Task RenderPDFPage(string pdfFileName,RENDEROPTIONS renderOptions)
		{
			try
			{
				// ***************************************************
				// まずファイルとして読み込み
				// ***************************************************
				 StorageFile pdfFile = await Windows.ApplicationModel.Package.Current.InstalledLocation.GetFileAsync(pdfFileName);
				 
				// ***************************************************
				// インスタンスを取得
				// ***************************************************
				 _pdfDocument = await PdfDocument.LoadFromFileAsync(pdfFile); ;

				if (_pdfDocument != null && _pdfDocument.PageCount > 0)
				{
					// ***************************************************
					// 最初のページを取得
					// ***************************************************
					var pdfPage = _pdfDocument.GetPage(PDF_PAGE_INDEX);					

					if (pdfPage != null)
					{
						// ***************************************************
						// 書き込み用のフォルダ
						// ***************************************************
						StorageFolder tempFolder = ApplicationData.Current.TemporaryFolder;
										 
						// ***************************************************
						// 書き込み用のファイル
						// ***************************************************
						StorageFile jpgFile = await tempFolder.CreateFileAsync(Guid.NewGuid().ToString() + ".png", CreationCollisionOption.ReplaceExisting);
						
						if (jpgFile != null)
						{
							// ***************************************************
							// 書き込み用のファイルのストリーム( ReadWrite )
							// ***************************************************
							IRandomAccessStream randomStream = await jpgFile.OpenAsync(FileAccessMode.ReadWrite);
							
							// ***************************************************
							// 書き込み用のオプション
							// ***************************************************
							PdfPageRenderOptions pdfPageRenderOptions = new PdfPageRenderOptions();
							switch (renderOptions)
							{
								case RENDEROPTIONS.NORMAL:
									//Render Pdf page with default options
									// ***************************************************
									// 書き込み
									// ***************************************************
									await pdfPage.RenderToStreamAsync(randomStream);									
									break;
								case RENDEROPTIONS.ZOOM:
									//set PDFPageRenderOptions.DestinationWidth or DestinationHeight with expected zoom value
									Size pdfPageSize = pdfPage.Size;
									pdfPageRenderOptions.DestinationHeight = (uint)pdfPageSize.Height * ZOOM_FACTOR;
									//Render pdf page at a zoom level by passing pdfpageRenderOptions with DestinationLength set to the zoomed in length 
									// ***************************************************
									// 書き込み
									// ***************************************************
									await pdfPage.RenderToStreamAsync(randomStream, pdfPageRenderOptions);
									break;
								case RENDEROPTIONS.PORTION:
									//Set PDFPageRenderOptions.SourceRect to render portion of a page
									pdfPageRenderOptions.SourceRect = PDF_PORTION_RECT;																	 
									//Render portion of a page
									// ***************************************************
									// 書き込み
									// ***************************************************
									await pdfPage.RenderToStreamAsync(randomStream, pdfPageRenderOptions);
									break;
							}
							// ***************************************************
							// 書き込み完了
							// ***************************************************
							await randomStream.FlushAsync();
							
							// ***************************************************
							// 後始末
							// ***************************************************
							randomStream.Dispose();
							pdfPage.Dispose();

							// ***************************************************
							// 表示
							// ***************************************************
							await DisplayImageFileAsync(jpgFile);
						}
					}
				}
			}
			catch (Exception err)
			{
				rootPage.NotifyUser("Error: " + err.Message, NotifyType.ErrorMessage);

			}
		}

		// ***************************************************
		// 表示ボタン1
		// ***************************************************
		private  async void RenderPage_Click(object sender, RoutedEventArgs e)
		{

			try
			{
				rootPage.NotifyUser("Rendering page...", NotifyType.StatusMessage);
			   
				await RenderPDFPage(PDFFILENAME, RENDEROPTIONS.NORMAL); 
			   
				rootPage.NotifyUser("Rendered page ", NotifyType.StatusMessage);
			}
			catch (Exception err)
			{
				rootPage.NotifyUser("Error: " + err.Message, NotifyType.ErrorMessage);				
			}
		}

		// ***************************************************
		// 表示ボタン2
		// ***************************************************
		private  async void RenderPageZoom_Click(object sender, RoutedEventArgs e)
		{
			try
			{
				rootPage.NotifyUser("Rendering page at zoom level...", NotifyType.StatusMessage);

				await RenderPDFPage(PDFFILENAME, RENDEROPTIONS.ZOOM);

				rootPage.NotifyUser("Rendered page at zoom level", NotifyType.StatusMessage);
			}
			catch (Exception err)
			{
				rootPage.NotifyUser("Error: " + err.Message, NotifyType.ErrorMessage);			 
			}				
		}

		// ***************************************************
		// 表示ボタン3
		// ***************************************************
		private async void RenderPagePortion_Click(object sender, RoutedEventArgs e)
		{
			try
			{
				rootPage.NotifyUser("Rendering portion of a page...", NotifyType.StatusMessage);

				await RenderPDFPage(PDFFILENAME, RENDEROPTIONS.PORTION);

				rootPage.NotifyUser("Rendered portion of a page ", NotifyType.StatusMessage);
			}
			catch (Exception err)
			{
				rootPage.NotifyUser("Error: " + err.Message, NotifyType.ErrorMessage);
			}					   
		 }	 
	  
	}
}




posted by lightbox at 2013-06-30 00:07 | Win8 ストアアプリ | このブログの読者になる | 更新情報をチェックする

2013年06月29日


ストアアプリの TextBox のスクロールバー



Metro Apps - TextBox, Scrolling

一年前の記事ですが、他にこれに相当する記事をみつけられませんでした。この記事では、コードで設定する場合、object.SetValue(ScrollViewer.VerticalScrollBarVisibilityProperty, ScrollBarVisibility.Auto); とあるので、DependencyObject と関連すると思いますが、Microsoft の DependencyObject の説明もあまり要領を得ません。ページ遷移にしても、Navigate では元のページが破棄されてしまいますし、とても作るのが大変です。
<Page
	x:Class="App1.MainPage"
	xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:App1"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
	Loaded="Page_Loaded">

    <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
		<Button
			x:FieldModifier="public"
			x:Name="MoveButton"
			Content="このボタンは x:FieldModifier=&quot;public&quot; です"
			HorizontalAlignment="Left"
			Height="61"
			Margin="66,64,0,0"
			VerticalAlignment="Top"
			Width="379"
			Click="MoveButton_Click" />
		<TextBox
			AcceptsReturn="True"
			Margin="66,156,729,330"
			ScrollViewer.VerticalScrollBarVisibility="Auto"
			Grid.Row="1"
			FontSize="40" />
	</Grid>
</Page>

※ ScrollViewer を親にする方法は他にいくつか見つける事ができますが、この方法を発言しているのが 
Affiliations
Microsoft Employee
となっていて、Rob Caplan さんは、Microsoft の社員さんみたいです。
posted by lightbox at 2013-06-29 14:28 | Win8 ストアアプリ | このブログの読者になる | 更新情報をチェックする

Win8 ストアアプリの、メモリ上にページを残す画面遷移と、前画面のコントロールの参照


▲ この画面は シミュレータの画面です

デフォルトでは、画面のコントロールは private になっているようで、x:FieldModifier="public" を設定する事によって、他のページのコードから参照可能になります( デザイナ時点で可 )
<Page
	x:Class="App1.MainPage"
	xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:App1"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
	Loaded="Page_Loaded">

    <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
		<Button
			x:FieldModifier="public"
			x:Name="MoveButton"
			Content="このボタンは x:FieldModifier=&quot;public&quot; です"
			HorizontalAlignment="Left"
			Height="61"
			Margin="66,64,0,0"
			VerticalAlignment="Top"
			Width="379"
			Click="MoveButton_Click" />

	</Grid>
</Page>

App.xaml.cs に、ページ移動や参照用のメソッドや変数を作成しています。

❶ public static Dictionary AppPage
※ ページの実体保存用
❷ public static Frame rootFrame
※ ページの格納用( 元々ローカル変数だったものを public static に変更 )
❸ public static void PageOpen(Type name)
※ ページ移動用
❹ public static T GetPage(Type name)
※ ページ参照用

App.xaml.cs
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Windows.ApplicationModel;
using Windows.ApplicationModel.Activation;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;

namespace App1
{
    sealed partial class App : Application
    {
		public static Dictionary<Type , Page> AppPage = new Dictionary<Type , Page>();
        public static Frame rootFrame = Window.Current.Content as Frame;
		public static void PageOpen(Type name)
		{
			Page page = null;
			if (!App.AppPage.TryGetValue(name, out page))
			{
				App.rootFrame.Navigate(name);
			}
			// 2回目以降の次ページへの移動
			else
			{
				App.rootFrame.Content = App.AppPage[name];
			}
		}
		public static T GetPage<T>(Type name)
		{
			return (T)(object)App.AppPage[name];
		}

        public App()
        {
            this.InitializeComponent();
            this.Suspending += OnSuspending;
        }

        protected override void OnLaunched(LaunchActivatedEventArgs args)
        {
            if (rootFrame == null)
            {
                rootFrame = new Frame();

                if (args.PreviousExecutionState == ApplicationExecutionState.Terminated)
                {
                    //TODO: 以前中断したアプリケーションから状態を読み込みます。
                }

                Window.Current.Content = rootFrame;
            }

            if (rootFrame.Content == null)
            {
                if (!rootFrame.Navigate(typeof(MainPage), args.Arguments))
                {
                    throw new Exception("Failed to create initial page");
                }
            }
            // 現在のウィンドウがアクティブであることを確認します
            Window.Current.Activate();
        }

        private void OnSuspending(object sender, SuspendingEventArgs e)
        {
            var deferral = e.SuspendingOperation.GetDeferral();
            //TODO: アプリケーションの状態を保存してバックグラウンドの動作があれば停止します
            deferral.Complete();
        }
    }
}


MainPage.xaml.cs
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;

namespace App1
{
	public sealed partial class MainPage : Page
	{
		public MainPage()
		{
			this.InitializeComponent();

			App.AppPage.Add(typeof(MainPage), this);
		}

		protected override void OnNavigatedTo(NavigationEventArgs e)
		{
			// 画面が表示される初回だけ実行されます
			Debug.WriteLine("OnNavigatedTo");
		}

		private void MoveButton_Click(object sender, RoutedEventArgs e)
		{
			App.PageOpen(typeof(BlankPage1));
		}

		private void Page_Loaded(object sender, RoutedEventArgs e)
		{
			// 画面が表示される毎に実行されます
			Debug.WriteLine("Page_Loaded");

		}

	}
}



画面移動のたびに、画面が表示された時の処理を行うには、loaded イベント を使用します。protected override void OnNavigatedTo は、Navigate メソッド(ここでは、App.rootFrame.Navigate)が実行される最初だけ処理されます。

BlankPage1.xaml.cs
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;

namespace App1
{
	public sealed partial class BlankPage1 : Page
	{
		public BlankPage1()
		{
			this.InitializeComponent();

			App.AppPage.Add(typeof(BlankPage1), this);
		}

		protected override void OnNavigatedTo(NavigationEventArgs e)
		{
			// 画面が表示される初回だけ実行されます
			Debug.WriteLine("OnNavigatedTo");
		}

		private void Button_Click_1(object sender, RoutedEventArgs e)
		{

			App.PageOpen(typeof(MainPage));

			MainPage mp = null;

			// 変数を使った参照
			mp = App.AppPage[typeof(MainPage)] as MainPage;
			Debug.WriteLine(mp.MoveButton.Content.ToString());

			// メソッドを使った参照
			mp = App.GetPage<MainPage>(typeof(MainPage));
			Debug.WriteLine(mp.MoveButton.Content.ToString());

		}

		private void Page_Loaded(object sender, RoutedEventArgs e)
		{
			// 画面が表示される毎に実行されます
			Debug.WriteLine("Page_Loaded");
		}
	}
}

関連する記事

XAML の 各属性を別の行に配置する Visual Studio の設定



posted by lightbox at 2013-06-29 13:04 | Win8 ストアアプリ | このブログの読者になる | 更新情報をチェックする

2013年06月10日


Win8 ストアアプリで、『選択肢を応答するダイアログ』を簡単に使うための MessageBox クラス

MessageBox に馴染んでいる人も多いと思うので、とりあえず使うために。( MessageDialog を使うと結構面倒なので )



using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.UI.Popups;

namespace LBOX_Http
{
	class MessageBox
	{
		// **********************************************************
		// 選択肢を応答するダイアログ
		// **********************************************************
		public static async Task<bool> ShowAsync(string title, string message, UICommandInvokedHandler handler)
		{
			var messageDialog = new MessageDialog(message, title);

			// イベントを定義する
			var OK_Handler = new UICommandInvokedHandler(handler);
			var OK_Command = new UICommand("YES", OK_Handler) { Id = 0 };
			messageDialog.Commands.Add(OK_Command);

			// イベントを定義する
			var CANCEL_Handler = new UICommandInvokedHandler(handler);
			var CANCEL_Command = new UICommand("NO", CANCEL_Handler) { Id = 1 };
			messageDialog.Commands.Add(CANCEL_Command);

			// Enter キーで反応するデフォルトボタン
			messageDialog.DefaultCommandIndex = 1;
			// ESC キーで反応するキャンセルボタン
			messageDialog.CancelCommandIndex = 1;

			await messageDialog.ShowAsync();

			return true;

		}

		// **********************************************************
		// 確認をするだけのダイアログ
		// **********************************************************
		public static async Task<bool> ShowAsync(string title, string message)
		{
			var messageDialog = new MessageDialog(message, title);

			// OK ボタンのイベントを定義する
			var OK_Command = new UICommand("OK", (command) => { });
			messageDialog.Commands.Add(OK_Command);

			// Enter キーで反応するデフォルトボタン
			messageDialog.DefaultCommandIndex = 0;
			// ESC キーで反応するキャンセルボタン
			messageDialog.CancelCommandIndex = 0;

			await messageDialog.ShowAsync();

			return true;

		}

	}
}



▼ 使用方法
// *************************************************
// 保存ボタン
// *************************************************
private async void SaveButton_Click(object sender, RoutedEventArgs e)
{
	if (MyCode.Text.Trim() == "")
	{
		await MessageBox.ShowAsync("入力確認","データが入力されていません");
		return;
	}

	await MessageBox.ShowAsync("処理確認","データを保存しますか?", (IUICommand command) =>
	{
		// ボタンの応答
		if (command.Id.Equals(0))
		{
			Debug.WriteLine("YES");
		}
		if (command.Id.Equals(1))
		{
			Debug.WriteLine("NO");
		}
	});
}

ラムダ式で使用しています



posted by lightbox at 2013-06-10 20:00 | Win8 ストアアプリ | このブログの読者になる | 更新情報をチェックする

2013年06月09日


Win8 ストアから Post 投稿

Get 部分を追加しました

Windows8(C#) ストアアプリ : HttpClient で Get と Post する簡易クラス


非同期のメソッドを定義する場合は、async Task<T> とします。大抵の場合、メソッド化しておいたほうが使いやすいものとなります。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;

namespace LBOX_Http
{
	public class Lbox
	{
		public static async Task<string> Post(string url, Dictionary<string, string> param )
		{
			string result = "";

			try
			{
				HttpClient httpClient = new HttpClient();
				httpClient.MaxResponseContentBufferSize = int.MaxValue;
				HttpContent content = new FormUrlEncodedContent(param);
				var response = await httpClient.PostAsync(url, content);
				String text = await response.Content.ReadAsStringAsync();

				result = text;
			}
			catch (Exception Err)
			{
				result = "ERROR:" + Err.Message;
			}

			return result;

		}
	}
}


▼ 呼び出し方法
String url = "投稿先の URL";
var param = new Dictionary<string, string>();
param.Add("u", "入力文字列");
Response.Text = await Lbox.Post(url, param);

u は、HTML 定義で FORM 内の INPUT の name 属性に割り当てられた文字列です。

関連する記事

Win8 ストア : HttpClient + XDocument で RSS の取得
Win8 ストア : UrlEncode と UrlDecode


posted by lightbox at 2013-06-09 22:08 | Win8 ストアアプリ | このブログの読者になる | 更新情報をチェックする

2013年06月07日


Win8ストア XAML の AppBarButtonStyle のContent に指定する 16進数 Unicode の取得





インターネットで使う特殊文字一覧 ♔ ♕ ♖ ♗ ♘ ♙ ♚ ♛ ♜ ♝ ♞ ♟ より適当に文字列をコピーして以下の大きなフィールドに貼り付けて変換して下さい。

※ そのまま貼ってもいいんですが、StandardStyles.xaml での定義ではコードを使っているので。
※ 通常の Content でも使えますが、AppBarButtonStyle で使うと良いと思います。


posted by lightbox at 2013-06-07 02:43 | Win8 ストアアプリ | このブログの読者になる | 更新情報をチェックする

2013年05月30日


Win8 ストア : UrlEncode と UrlDecode

System.Net.WebUtility を使用します。( Windows8 のサンプルコードの 『Push and periodic notifications client-side sample』内にある Helper.cs に使用例が少しあります ) 

内部コードにあわせて、UTF8 のみ文字列のまま変換できますが、他のキャラクタセットではいったんバイト配列に変換して処理する必要があります。
// Shift_JIS で UrlEncode された文字列
string str_sjis_urlencode = "%93%FA%96%7B%8C%EA%95%5C%8E%A6";
// バイト配列に変換
byte[] sjis_data1 = Encoding.GetEncoding("SHIFT_JIS").GetBytes(str_sjis_urlencode);
// バイト配列状態で UrlDecode
byte[] sjis_data2 = WebUtility.UrlDecodeToBytes(sjis_data1, 0, sjis_data1.Length);
// バイト配列を内部コード表現の文字列に戻す
string sjis_data3 = Encoding.GetEncoding("SHIFT_JIS").GetString(sjis_data2, 0, sjis_data2.Length);
Debug.WriteLine("Shift_JIS:" + sjis_data3);

// Shift_JIS の UrlEncode に変換したい文字列
str_sjis_urlencode = "日本語表示";
// バイト配列に変換
sjis_data1 = Encoding.GetEncoding("SHIFT_JIS").GetBytes(str_sjis_urlencode);
// バイト配列状態で UrlEncode
sjis_data2 = WebUtility.UrlEncodeToBytes(sjis_data1, 0, sjis_data1.Length);
// バイト配列を内部コード表現の文字列に戻す
sjis_data3 = Encoding.GetEncoding("SHIFT_JIS").GetString(sjis_data2, 0, sjis_data2.Length);
Debug.WriteLine("Shift_JIS:" + sjis_data3);

// UTF8 で UrlEncode された文字列
string str_utf8_urlencode = "%E6%97%A5%E6%9C%AC%E8%AA%9E%E8%A1%A8%E7%A4%BA";
string str_urldecode = WebUtility.UrlDecode(str_utf8_urlencode);
Debug.WriteLine("UTF8:" + str_urldecode);

// UTF8 で UrlEncode したい文字列
str_urldecode = "日本語表示";
str_utf8_urlencode = WebUtility.UrlEncode(str_urldecode);
Debug.WriteLine("UTF8:" + str_utf8_urlencode);


以下定義の表示
#region アセンブリ System.Runtime.Extensions.dll, v4.0.0.0
// C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETCore\v4.5\System.Runtime.Extensions.dll
#endregion

using System;

namespace System.Net
{
	// 概要:
	//     Web 要求の処理時に URL をエンコードおよびデコードするためのメソッドを提供します。
	public static class WebUtility
	{
		// 概要:
		//     HTTP 伝送用に HTML エンコードされている文字列を、デコードされた文字列に変換します。
		//
		// パラメーター:
		//   value:
		//     デコードする文字列。
		//
		// 戻り値:
		//     デコードされた文字列。
		public static string HtmlDecode(string value);
		//
		// 概要:
		//     文字列を、HTML エンコードされた文字列に変換します。
		//
		// パラメーター:
		//   value:
		//     エンコードする文字列。
		//
		// 戻り値:
		//     エンコードされた文字列。
		public static string HtmlEncode(string value);
		//
		public static string UrlDecode(string encodedValue);
		//
		public static byte[] UrlDecodeToBytes(byte[] encodedValue, int offset, int count);
		//
		public static string UrlEncode(string value);
		//
		public static byte[] UrlEncodeToBytes(byte[] value, int offset, int count);
	}
}


posted by lightbox at 2013-05-30 20:37 | Win8 ストアアプリ | このブログの読者になる | 更新情報をチェックする
Seesaa の各ページの表示について
Seesaa の 記事がたまに全く表示されない場合があります。その場合は、設定> 詳細設定> ブログ設定 で 最新の情報に更新の『実行ボタン』で記事やアーカイブが最新にビルドされます。

Seesaa のページで、アーカイブとタグページは要注意です。タグページはコンテンツが全く無い状態になりますし、アーカイブページも歯抜けページはコンテンツが存在しないのにページが表示されてしまいます。

また、カテゴリページもそういう意味では完全ではありません。『カテゴリID-番号』というフォーマットで表示されるページですが、実際存在するより大きな番号でも表示されてしまいます。

※ インデックスページのみ、実際の記事数を超えたページを指定しても最後のページが表示されるようです

対処としては、このようなヘルプ的な情報を固定でページの最後に表示するようにするといいでしょう。具体的には、メインの記事コンテンツの下に『自由形式』を追加し、アーカイブとカテゴリページでのみ表示するように設定し、コンテンツを用意するといいと思います。


※ エキスパートモードで表示しています

アーカイブとカテゴリページはこのように簡単に設定できますが、タグページは HTML 設定を直接変更して、以下の『タグページでのみ表示される内容』の記述方法で設定する必要があります

<% if:page_name eq 'archive' -%>
アーカイブページでのみ表示される内容
<% /if %>

<% if:page_name eq 'category' -%>
カテゴリページでのみ表示される内容
<% /if %>

<% if:page_name eq 'tag' -%>
タグページでのみ表示される内容
<% /if %>
この記述は、以下の場所で使用します


Windows
container 終わり

フリーフォントで簡単ロゴ作成
フリーフォントでボタン素材作成
フリーフォントで吹き出し画像作成
フリーフォントではんこ画像作成
ほぼ自由に利用できるフリーフォント
フリーフォントの書体見本とサンプル
画像を大きく見る為のウインドウを開くボタンの作成

Android SDK ポケットリファレンス
改訂版 Webデザイナーのための jQuery入門
今すぐ使えるかんたん ホームページ HTML&CSS入門
CSS ドロップシャドウの参考デモ
PHP正規表現チェッカー
Google Hosted Libraries
cdnjs
BUTTONS (CSS でボタン)
イラストAC
ぱくたそ
写真素材 足成
フリーフォント一覧
utf8 文字ツール
右サイド 終わり
base 終わり