SQLの窓

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月27日


Android 4.2.2(ADT) : class MyDatePicker extends DatePickerDialog

Android : 日付ダイアログをインナーで使う では、その場で処理を記述するのでとりあえずの処理としてならば簡単ですが、きちんと制御したい場合には不向きなので、継承してクラスを作ってみました

ただ、この場合専用のインターフェイスが必要になります。それと、もともとキャンセルした時とそうでない決定ボタンを使った時の処理に汎用性が無かったので、いろいろ面倒な事をする結果となっています。



※ 画面の大きな Nexus 7 でエミュレートしてみました
package com.example.shapetextview;

import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;

import org.w3c.dom.Document;

import jp.winofsql.*;

import android.app.Activity;
import android.app.DatePickerDialog;
import android.app.Dialog;
import android.app.TimePickerDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.FragmentActivity;
import android.text.format.DateFormat;
import android.view.Menu;
import android.view.View;
import android.widget.DatePicker;
import android.widget.TextView;
import android.widget.TimePicker;

public class MainActivity extends Activity {

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		this.setContentView(R.layout.activity_main);
	}
	
	private interface MyClick {
		public void onClick(DialogInterface dialog, int which,int yy,int mm, int dd);
		public void onCancel();
	}

	private class MyDatePicker extends DatePickerDialog {

		private int yy = 0;
		private int mm = 0;
		private int dd = 0;

		private int year = 0;
		private int monthOfYear = 0;
		private int dayOfMonth = 0;
		
		private MyClick clickCallBack;

		public MyDatePicker(Activity context, MyClick callBack,
				int year, int monthOfYear, int dayOfMonth) {
			super(context, null, year, monthOfYear, dayOfMonth);
			this.clickCallBack = callBack;
			this.year = year;
			this.monthOfYear = monthOfYear;
			this.dayOfMonth = dayOfMonth;
		}

		@Override
		public void onClick(DialogInterface dialog, int which) {
			if ( yy == 0 ) {
				yy = this.year;
				mm = this.monthOfYear;
				dd = this.dayOfMonth;
			}
			clickCallBack.onClick(dialog, which,yy,mm+1,dd);
		}

		@Override
		public void onDateChanged(DatePicker view, int year, int month, int day) {
			this.yy = year;
			this.mm = month;
			this.dd = day;
		}
		
		@Override
		protected void onStop() {
			super.onStop();
			if ( yy == 0 ) {
				clickCallBack.onCancel();
			}
		}
		
	}	
	
	public void openDialog(View view) {
		
		final Calendar c = Calendar.getInstance();
		int year = c.get(Calendar.YEAR);
		int month = c.get(Calendar.MONTH);
		int day = c.get(Calendar.DAY_OF_MONTH);

		MyDatePicker mdp = 	new MyDatePicker(this,new MyClick(){

			@Override
			public void onClick(DialogInterface dialog, int which, int yy,
					int mm, int dd) {
				TextView textView = (TextView)MainActivity.this.findViewById(R.id.textView1);
				textView.setText(yy + "/" + mm + "/" + dd);
				
			}
			
			@Override
			public void onCancel() {
				System.out.println("キャンセル");
			}

			
		}, year, month, day);
		mdp.show();

	}
}

onStop は、無条件にダイアログが閉じられた時に発生します。
onDateChanged は、日付を UI で変更しないと発生しません



posted by lightbox at 2013-06-27 19:57 | Android | このブログの読者になる | 更新情報をチェックする

2013年06月26日


Android : 日付ダイアログをインナーで使う( 完了ボタンをクリックした場合としない場合の対応 )







DatePickerDialog の 引数に与える callback では、完了ボタンを押さなくても日付が返って来るので、単純に閉じた時の判断をしています。
package com.example.shapetextview;

import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;

import org.w3c.dom.Document;

import jp.winofsql.*;

import android.app.Activity;
import android.app.DatePickerDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import android.view.View;
import android.widget.DatePicker;
import android.widget.TextView;

public class MainActivity extends Activity {

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		this.setContentView(R.layout.activity_main);
	}

	public void openDialog(View view) {

		final Calendar c = Calendar.getInstance();
		final int year = c.get(Calendar.YEAR);
		final int month = c.get(Calendar.MONTH);
		final int day = c.get(Calendar.DAY_OF_MONTH);

		new DatePickerDialog(this, null, year, month, day) {

			int yy = 0;
			int mm = 0;
			int dd = 0;

			@Override
			public void onDateChanged(DatePicker view, int year, int month,
					int day) {
				this.yy = year;
				this.mm = month;
				this.dd = day;
			}
			
			@Override
			public void onClick(DialogInterface dialog, int which) {

				TextView textView = (TextView)MainActivity.this.findViewById(R.id.textView1);
				if ( this.yy == 0  ) {
					textView.setText(year + "/" + (month+1) + "/" + day);
				}
				else {
					textView.setText(this.yy + "/" + (this.mm+1) + "/" + this.dd);
				}
			}
			
		}.show();
		
	}
}

関連する記事

Android 4.2.2(ADT) : class MyDatePicker extends DatePickerDialog


posted by lightbox at 2013-06-26 21:42 | Android | このブログの読者になる | 更新情報をチェックする

2013年06月22日


Word 2013 : ワードアートを縦書きにして横長の文字で『背表紙』を作成


ワードアート



フォントとサイズ変更



縦書きに変更





文字の縮小

※ 縦書きなので、縦が縮小されます



() を半角に変更



文字間隔を変更



ワードアートの幅を広くして、右クリック

※ 図形の書式設定



レイアウト

文字のオプション => レイアウトとプロパティ



完成




posted by lightbox at 2013-06-22 22:46 | Microsoft Office | このブログの読者になる | 更新情報をチェックする
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 終わり