SQLの窓

2013年08月31日


Android : Google Spreadsheets API version 3.0でGoogleスプレッドシートを参照

SkyDrive へ移動



Google のライブラリのダウンロード

gdata-java-client

かなり多くのライブラリが中に入っていますが、実際使うのは 5つです。

1) gdata-client-1.0.jar
2) gdata-core-1.0.jar
3) gdata-spreadsheet-3.0.jar
4) guava-11.0.2.jar
5) jsr305.jar

1〜3 は、lib ディレクトリ内で、4〜5 は、deps 内です。Google 的には、gdata を使うのは spreadsheet のみのようで、他の機能( 例えばカレンダー ) は他の API を使うようになっています。また、認証も本来は OAuth を推奨しているようですが、機能の説明に重点を置くために、簡単にユーザーとパスワードのログインで処理しています。


package com.example.posttest;

import java.net.URL;
import java.util.List;

import com.google.gdata.client.spreadsheet.*;
import com.google.gdata.data.spreadsheet.*;
import com.google.gdata.util.*;

import android.os.AsyncTask;
import android.widget.EditText;

public class Android_Spreadsheet {

	// AsyncTask のインラインで参照する為の final
	private final String _userid;
	private final String _password;

	// **************************************************************
	// コンストラクタ
	// **************************************************************
	public Android_Spreadsheet(String _userid, String _password) {
		this._userid = _userid;
		this._password = _password;
	}

	// **************************************************************
	// AsyncTask の onPostExecute から外部イベントとして呼び出す為のインターフェイス
	// **************************************************************
	public interface SendMailed {
		public void onTweetResult(List<CellEntry> result);
   	}
	
	// **************************************************************
	// 通信処理
	// **************************************************************
	public void GetCells(String FileName, String SheetName,final SendMailed OnTweetResult) {
		
		new AsyncTask<String, Void, List<CellEntry>>() {

			// **************************************************************
			// 非同期処理
			// **************************************************************
			@Override
			protected List<CellEntry> doInBackground(String... params) {
				
				List<CellEntry> cells = null;

				String result_string = "";
				try {
					
					// *************************************************
					// ClientLogin
					// *************************************************
				    String USERNAME = _userid;
				    String PASSWORD = _password;

				    SpreadsheetService service = new SpreadsheetService("MySpreadsheetIntegration-v1");
				    service.setUserCredentials(USERNAME, PASSWORD);
				    
					// *************************************************
				    // バージョン3
					// *************************************************
				    SpreadsheetService sss = new SpreadsheetService("MySpreadsheetIntegration");
				    sss.setProtocolVersion(SpreadsheetService.Versions.V3);
				    
					// *************************************************
				    // 一覧を取得
					// *************************************************
				    URL SPREADSHEET_FEED_URL = new URL(
				        "https://spreadsheets.google.com/feeds/spreadsheets/private/full");
				    SpreadsheetFeed feed = service.getFeed(SPREADSHEET_FEED_URL, SpreadsheetFeed.class);
				    // 一覧用のリスト
				    List<SpreadsheetEntry> spreadsheets = feed.getEntries();
				    
				    // スプレッドシート一覧より目的のインデックスを取得
				    int target = 0;
				    for (SpreadsheetEntry Spreadsheet : spreadsheets) {

				    	System.out.println( Spreadsheet.getTitle().getPlainText() );
				    	
				    	if ( Spreadsheet.getTitle().getPlainText().equals(params[0]) ) {
				    		break; 
				    	}
				    	
				    	target++;
				    	
				    }				    
				    

				    SpreadsheetEntry spreadsheet = spreadsheets.get(target);
				    WorksheetFeed worksheetFeed = service.getFeed(
					        spreadsheet.getWorksheetFeedUrl(), WorksheetFeed.class);
				    List<WorksheetEntry> worksheets = worksheetFeed.getEntries();

				    target = 0;
				    for (WorksheetEntry worksheet : worksheets) {

				    	System.out.println( worksheet.getTitle().getPlainText() );
				    	
				    	if ( worksheet.getTitle().getPlainText().equals(params[1]) ) {
				    		break; 
				    	}
				    	
				    	target++;
				    	
				    }				    
				    
				    WorksheetEntry worksheet = worksheets.get(target);

				    URL cellFeedUrl = worksheet.getCellFeedUrl();
				    CellFeed cellFeed = service.getFeed(cellFeedUrl, CellFeed.class);
				    cells = cellFeed.getEntries();
					
				}
				catch( Exception e ) {
					System.out.println(e.getMessage());
				}
				
				return cells;
			}

			// **************************************************************
			// 非同期処理終了後の処理( 画面へのアクセスが可能 )
			// **************************************************************
			@Override
			protected void onPostExecute(List<CellEntry> result) {
				// 引数のインターフェイス内のメソッドを呼び出す
				OnTweetResult.onTweetResult(result);
			}
			
		}.execute(FileName,SheetName);
	
	}

}

スプレッドシートの一覧や、シートの一覧等、それぞれで通信処理をするので、Android では AsyncTask を用いて全て一括で処理を行って、最後の一覧のみを終了イベントとして処理するようにしています。

package com.example.posttest;

import java.net.URL;
import java.util.List;

import com.example.posttest.Android_Spreadsheet;
import com.google.gdata.data.spreadsheet.CellEntry;
import com.google.gdata.data.spreadsheet.CellFeed;
import com.google.gdata.data.spreadsheet.SpreadsheetEntry;
import com.google.gdata.data.spreadsheet.WorksheetEntry;
import com.google.gdata.data.spreadsheet.WorksheetFeed;

import android.os.Bundle;
import android.app.Activity;
import android.content.DialogInterface;
import android.content.Intent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.ListView;

public class MainActivity extends Activity {

	private Android_Spreadsheet as = null;
	private ArrayAdapter<String> adapter = null;
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
		as = new Android_Spreadsheet(
			"", // アカウント
			"" // パスワード
			);
		
		adapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1);
		
	}

	public void postAction(View view) {
		
	    
	    new MessageBox(this,"確認","送信しますか?") {

			@Override
			void onYesClick(DialogInterface dialog, int which) {

				System.out.println("onYesClick");
				
				as.GetCells( "In Googleドライブ", "シート2" ,new Android_Spreadsheet.SendMailed() {
					
						@Override
						public void onTweetResult(List<CellEntry> result) {
							
							ListView listView = (ListView)MainActivity.this.findViewById(R.id.listView1);
							listView.setAdapter(adapter);
							
						    for (CellEntry cell : result) {
						    	
						    	adapter.add( cell.getCell().getValue().toString() );
						    	// System.out.println( cell.getCell().getValue().toString() );
						    	
						    }				    
						    
						}
				});
				
			}
			
		}.show();
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		getMenuInflater().inflate(R.menu.main, menu);
		return true;
	}
	
	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		
		// 選択されたメニュー項目の ID
		int menuId = item.getItemId();
		
		switch(menuId){
		case R.id.action_settings:
			System.out.println("action_settings が選択されました");
			break;
		case R.id.menu_action1:
			System.out.println("menu_action1  が選択されました");
			
			Intent intent = new Intent();
			intent.putExtra("data", "メッセージを別のページに引き渡します");
			intent.setClassName("com.example.posttest", "com.example.posttest.NextPage");
			startActivity(intent);		
			
			break;
		}

		return true;
	}		
	
}




posted by lightbox at 2013-08-31 01:10 | Android | このブログの読者になる | 更新情報をチェックする

2013年08月29日


C#(.NET) : Google Spreadsheets API version 3.0でGoogleスプレッドシートを参照

Google Spreadsheet は、Google ドライブに作成する事ができる Excel のような仕様の WEB アプリケーションです。WEB 上でデータを保存しておいて、インターネット経由で参照や更新が可能なのが Google Spreadsheets API です。( 他の API では、JavaScript より参照できるものもあます )

Google Spreadsheets API version 3.0

.NET ライブラリのダウンロード
( その他全てへのリンク )



ダウンロードしたライブラリは、直接参照する必要があります。本来 XML データでやりとりするものをライブラリ化しているので、あまり便利なものにはなっていませんが、『スプレッドシート』『ワークシート』を順々に一覧より取得するようにはなっていますので、後から解りやすい仕様ではあります。

ここでは、Dictionary を使って保存する手順を行っていますが、使いやすくするには最初に全てのワークシートまでを Dictionary に保存しておいて、名前で取得できるクラスを作成するといいと思います。

▼ で使った『In Googleドライブ』を公開したもの ( 取引先名は VLOOKUP を シート2から行っています )
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

using Google.GData.Client;
using Google.GData.Spreadsheets;
using System.Diagnostics;

namespace WindowsFormsApplication3
{
    public partial class Form1 : Form
    {

        public SpreadsheetsService service = null;
        public Dictionary<string, SpreadsheetEntry> db_Spread = new Dictionary<string, SpreadsheetEntry>();
        public Dictionary<string, WorksheetEntry> table_Spread = null;

        public Form1()
        {
            InitializeComponent();
        }

        // ********************************************************
        // ログインデータを設定
        // ********************************************************
        private void button1_Click(object sender, EventArgs e)
        {
            service = new SpreadsheetsService("MySpreadsheetIntegration-v1");
            service.setUserCredentials(this.textBox1.Text, this.textBox2.Text);

            Debug.WriteLine(service.ServiceIdentifier.ToString());
            
        }

        // ********************************************************
        // Google Spreadsheet 一覧をディクショナリに保存
        // ********************************************************
        private void button2_Click(object sender, EventArgs e)
        {
            this.listBox1.Items.Clear();

            SpreadsheetQuery query = new SpreadsheetQuery();

            try
            {
                SpreadsheetFeed feed = service.Query(query);
                foreach (SpreadsheetEntry entry in feed.Entries)
                {
                    Debug.WriteLine(entry.Title.Text);
                    this.listBox1.Items.Add(entry.Title.Text);
                    db_Spread.Add(entry.Title.Text, entry);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        // ********************************************************
        // ListBox の対象行をダブルクリックしてディクショナリにシートを保存
        // ********************************************************
        private void listBox1_DoubleClick(object sender, EventArgs e)
        {
            string target = this.listBox1.SelectedItem.ToString();
            Debug.WriteLine(target);

            try
            {
                SpreadsheetEntry target_Spread = db_Spread[target];

                table_Spread = new Dictionary<string, WorksheetEntry>();
                WorksheetFeed wsFeed = target_Spread.Worksheets;
                foreach (WorksheetEntry entry in wsFeed.Entries)
                {
                    table_Spread.Add(entry.Title.Text, entry);
                    Debug.WriteLine(entry.Title.Text);
                }

                // 先頭シートからデータを取得
                CellQuery cellQuery = new CellQuery(((WorksheetEntry)wsFeed.Entries[0]).CellFeedLink);
                CellFeed cellFeed = service.Query(cellQuery);

                uint nRow = 1;
                string strResult = "";
                foreach (CellEntry cell in cellFeed.Entries)
                {
                    if (nRow == cell.Row)
                    {
                        if (strResult == "")
                        {
                            strResult += cell.Value;
                        }
                        else
                        {
                            strResult += "," + cell.Value;
                        }
                    }
                    else
                    {
                        strResult += "\r\n" + cell.Value;
                    }
                    Debug.WriteLine(cell.Value);

                    nRow = cell.Row;
                }

                this.textBox3.Text = strResult;

            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }

        }
    }
}




posted by lightbox at 2013-08-29 01:18 | API | このブログの読者になる | 更新情報をチェックする

2013年08月24日


PHP : メール送信(unix : パスワード不要)

sendmail は使用できません。sakura 等、自分で借りているサーバーで動くはずです。また、このような URL を用意しておけば、Android 等のメール送信用の API としてテストに使う事ができます。
さくらインターネット、サーバコントロールパネル ( 作成直後は、容量制限が 200M なので 2M 程度に変更しておきます ) ❷ Gmail の GUI( メールヘッダ等を確認するのに役立ちます ) ❸ メーセージソースの一部
To: =?ISO-2022-JP?B?GyRCMDhAaBsoQg==?= <??????????@gmail.com>
Subject: =?ISO-2022-JP?B?GyRCJWEhPCVrJE4lPyUkJUgbKEI=?=
 =?ISO-2022-JP?B?GyRCJWskSCRKJGokXiQ5GyhCKGxpZ2h0Ym94KQ==?=
From: =?ISO-2022-JP?B?GyRCO2QbKEI=?= <phpuser@??????????.sakura.ne.jp>
Mime-Version: 1.0
Content-Type: text/plain; charset=ISO-2022-JP
Content-Transfer-Encoding: 7bit

$BK\J8$r(B
$BAw?.$7$^$9(B
$B%+%J(B
$B%+%J(B

▼ ここからが本題です

PHP でメール処理をする場合、いろいろなキャラクタセットが入り組んで来るので注意が必要です。

ここではだいたいですが、このようになっています。

❶ 入力 HTML : EUC-JP
❷ PHP のソース : UTF-8
❸ PHP の内部エンコーディング : UTF-8
❹ メール内 : iso-2022-jp( 但しヘッダ内はBASE64変換 )

▼ mailtest.php
<?
header( "Content-Type: text/html; Charset=utf-8" );
header( "Expires: Wed, 31 May 2000 14:59:58 GMT" );

foreach( $_POST as $Key => $Value ) {
	$_POST[$Key] = str_replace("\\\\", "\\", $Value );
	$_POST[$Key] = str_replace("\\'", "'", $_POST[$Key] );
	$_POST[$Key] = str_replace("\\\"", "\"", $_POST[$Key] );
}

// ************************************************************************
// unix では、sendmail を使用します。
// 通常、この URL から信頼されているメールアドレス前提にしているので、
// セキュリティ情報は送る事ができません
// window 環境でもそれは同様なので、同一サーバーにメールサーバー
// を用意するか、COM+basp21でセキュリティ情報を使って送信する必要があります
// ************************************************************************

// mb_send_mail() は、e-mail をエンコードする際にこの設定を使用します
// ※ subject と body のみ
mb_language( "ja" );
mb_internal_encoding("utf-8");

// *********************************************************
// 使用するメールアドレス
// ※ $from_address は、この PHP があるサーバが
// ※ 管理しているメールサーバーのアドレスです
// ※ gmail に送ると、ヘッダーのソースを簡単に確認できます
// *********************************************************
$from_address = "phpuser@????????.sakura.ne.jp";
$to_address = "???????@gmail.com";

// *********************************************************
// 入力データが EUC-JP であると言う前提です
// ※ $subj はこの内部で設定しているので UTF-8 です。
// *********************************************************
$subj	= "メールのタイトルとなります(lightbox)";
$body	= mb_convert_encoding( $_POST['text'], mb_internal_encoding(), "EUC-JP" );
// *********************************************************
// 「半角カタカナ」を「全角カタカナ」に変換します
// *********************************************************
$body = mb_convert_kana($body,'K',mb_internal_encoding());


// *********************************************************
// 宛先と差出人は自分でエンコードする必要があります
// *********************************************************
$to	= mb_encode_mimeheader( mb_convert_encoding("宛先","iso-2022-jp", mb_internal_encoding()) ) . " <{$to_address}>";

// *********************************************************
// From: は追加ヘッダーとして設定しています
// *********************************************************
$from	= "From: " . mb_encode_mimeheader( mb_convert_encoding("私","iso-2022-jp", mb_internal_encoding()) ) . " <{$from_address}>";

$result = mb_send_mail($to, $subj, $body, $from );
if ( $result ) {
	$result = "成功";
}
else {
	$result = "失敗";
}

// ▼ この文字列は UTF-8 です
?>
メール送信が終了しました。<?= $result ?>


▼ 送信テスト用の HTML
<!doctype html>
<html lang="ja">
<head>
<title>sendmail</title>
<meta charset="euc-jp">
<style>
body {
	margin: 0px;
}
textarea {
	width:400px;
	height:200px;
}
</style>
</head>

<body>

<form method="post" action="mailtest.php">
<textarea name="text"></textarea>
<br>
<input type="submit" name="send" value="送信">
</form>

</body>
</html>



関連する記事 ( SQLの窓 )Windows PHP(Pear)で、Gmail(SSL/465)を使ってメールを送るPEAR の Mail パッケージによるメール送信IE 拡張メニューで取得したテキストをメールで送る


更新履歴
2009-05-06 : 初回投稿
2013-08-24 : WEB 経由の API として使う為に内容をチェック、整備




タグ:メール PHP
posted by lightbox at 2013-08-24 16:03 | PHP + 通信 | このブログの読者になる | 更新情報をチェックする

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年08月17日


SkyDrive の PowerPoint のアニメーションが3つしかありませんでした

ユーザからすれば、これは結構『トラブルレベル』だと思うのですが。ただ、ちょっとだけいい事もあるにはあって、Excel や Word に無い『図形描画』が用意されてました。と言っても、Google ドライブには全く及ばない現状ではあります。



ですが、WEB 上で公開するにあたって、複雑なアニメーションがはたして必要かどうかという事を切り口にすると、Office に馴染みの無い一般ユーザでもすぐ使えるようには成っているという考え方もあります。事実、Excel や Word でも同様の実装具合で、Word にいたっては、ルーラが無いのでそれに関する機能は無く、見たままでなんとかするようになっています。

そういう意味で、表の扱いは Word としては簡単になっていると思います。Excel は、グラフ作成に力が入っているようですが、WEB アプリとしてはかなりハイレベルなアプリとなっています。

▼ クリックするとオブジェクトのアニメーション



関連する記事

Google プレゼンテーションが結構ふつうに使えるという事の確認
NAVER での簡単な操作手順



posted by lightbox at 2013-08-17 17:22 | Microsoft Office | このブログの読者になる | 更新情報をチェックする

Google+ から見た『アルバム』と Picasa ウェブアルバム

もともと、Picasa ウェブアルバムが先に運営されていたサービスで、Google+ を立ち上げるにあたって統合されたようになっていますが、『画像』を WEB 上で再利用したい人にとっては、Picasa ウェブアルバム から管理したほうが優れています。ただ、現在、Picasa ウェブアルバムのドメイン(https://picasaweb.google.com/)にアクセスしようとすると、Google+ の UI へ飛ばされてしまいます。



ただ、ほんの少し待っていると画面中央に Picasa へ移動する為のリンクが浮き上がって来ます。常時 Picasa を使っているとそうでもありませんが、普通はこのような状態になります。

もちろん、元は同じなのでわざわざ Picasa へ移動する必要は無いように見えますが、実際は少し違います。Google+ から画像をアップロードしようとすると、毎回『共有(投稿)』作業用のポップアップウインドウが表示されてしまいます。



画像をアップロードして、他の WEB上で参照する事を目的としている場合、この UI の動きは邪魔でしかありません。しかも、Google+では、他の WEB上で参照する為の画像に対する URL が UI 上で公開されていません。つまりこれは、画像の URL を直接取り出して使用していると、いつ突然に仕様変更でその URL がリンク切れになるか解らない危険性を帯びている事になるわけです。

事実、Google+ から見た画像の URL と、Picasa から見た URL の仕様は違うのです。

その点、Picasa では、アルバムのプロパティを公開レベルにすると、画像に対する URL を使用する為の埋め込みコードが取得できるようになるので、そう簡単に仕様変更でリンク切れになる事は無いと考えられます。



実際は、このようなアルバムレベルの公開をしなくても、画像の URL は有効で外部から参照可能です。ただ、サービスとしてユーザが UI で画像 URL 正式に見れるかどうかという設定です(もちろん本来はアルバムを他の人が見れる設定ですが)

▼ 画像 URL の取得


★ この写真へのリンクは違うものです。このページの URL です。
★ 画像埋め込みから取得した IMG 要素の中の SRC 属性がそれですが、画像を右クリックしても基本同じ

▼ サイズ別に並べたもの


サイズは、URL の中の階層の一部で表現されます。最大、アップロード時のサイズまで指定可能で、そのサイズは右上に『写真の情報』として表示されています。但し、注意するべきは、このサイズは長辺側のサイズであるという事です。

その他の情報

Google+ に無制限で画像を保存できる事の説明
Picasa のサムネイルの使い方
Shadowbox 埋め込みコード作成 : 画像・WEBページ用


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

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

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

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

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


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

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

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

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

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



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

CSS ドロップシャドウの参考デモ
イラストAC
ぱくたそ
写真素材 足成
フリーフォント一覧
utf8 文字ツール
右サイド 終わり
base 終わり