MOSA Multi-OS Software Artists

MOSAはソフトウェア開発者を支援します

プログラマーに興味がある方なら誰でも入会いただけます。
MOSA Multi-OS Software Artists
===SINCE 1995===

  • iPhone/iPod touch アプリ紹介
  • MOSA掲示板
  • 活動履歴
  • About MOSA(English)

MOSADenバックナンバー 2009年4月発行分

  • MOSA Developer News[MOSADeN=モサ伝]第341号

    2009-04-28

    目次

    • りんご味Ruby         第46回  藤本 尚邦
    • 藤本裕之のプログラミング夜話   #159
    • 高橋真人の「プログラミング指南」  第157回

    りんご味Ruby   第46回  藤本 尚邦

    引き続き、Ruby+RubyCocoaを使って「CoreGraphicsによるPDFの描画」を記述するための簡易言語(DSL)を作っていきます。

    まず、前回までに完成した、CGContextクラスとCGPDFContextクラスの根幹部分のプログラムを確認しておきましょう(本文末尾の cg_context.rb を参照のこと)。この cg_context.rb を使ってPDF描画のプログラムを書くと以下のようになります:

     

    url  = OSX::NSURL.fileURLWithPath("circle.pdf")
     rect = OSX::NSRect.new(0, 0, 612, 792)
     context_ref = CGPDFContextCreateWithURL(url, rect, nil)
    
     pdf = CGPDFContext.new(context_ref)
     pdf.beginPage(nil)
       pdf.setRGBFillColor(1.0, 0.0, 0.0, 1.0)
       pdf.addArc(300, 300, 100, 0, 2 * Math::PI, 1)
       pdf.fillPath
     pdf.endPage
     pdf.flush
     # CFRelease(context_ref)  # (注)
    


    ぱっと見たところ、後半部分にDSL化した効果は見られるものの、これだけであれば、わざわざ DSL にするほどのメリットがあるのかどうか微妙な感じです。さらに DSL的要素を追加していくことにしましょう。

    (注: 今作っているDSLを、変更せずそのまま MacRuby(0.4) で動かすことはできませんが、もし現時点(2009.4.23)の MacRuby 0.4 向けに書き直す場合には、本文のPDF描画プログラム例の最後のところで、CFRelease を使ってcontext_ref で使われたリソースを明示的に解放する必要があります)

    ■ ブロック構文の導入

    beginPage と endPage は、間に挟んだ CGContext 向け関数の呼び出しをページと関連づけるための対になっています:

     pdf.beginPage
       ....    # あるページに対する描画
     pdf.endPage
    


    beginPage と endPage は、組み合わせて使うことによって初めて意味を持ちます。CGContext向けの関数の中には、このように組み合わせて使うことを想定した関数の対がいくつかあります。

    そもそも、CoreGraphicsに限らずとも、C言語向けのライブラリやAPIには、このような関数の組み合わせがよくありますね。Cの標準ライブラリに入っているfopen と fclose がその代表といったところでしょうか。古代からのMacプログラマの方であれば、HLock と HUnlock とか GetPort と SetPort の組み合わせを思い浮かべる方もいらっしゃるかもしれません。

    このタイプのAPIを使ったCプログラミングでは、対の片方(たいがいは後の方)を書き忘れるというのはありがちなバグです。では何故、バグの原因になりやすいこのような関数の組み合わせがC言語用のライブラリやAPIには存在するのでしょうか? それは、C言語には無名の手続きをデータとして扱う手段がなく、1つの安全なAPIとして提供する簡単な手段がなかったから、ということもあるでしょう(名前のついた関数を引数にとるAPIとして作ることはできますが、使い勝手はあまりよくなさそうです)。

    Rubyには、無名手続きをデータとして扱う手段の1つとして、ブロック構文があります。ブロック構文を使って、API関数の対で挟まれる手続きの部分をデータとして扱うことにより、2つのAPI関数が必ず対で呼ばれることを保証する1つのAPIを簡単に作ることができます。

    では、beginPage と endPage を組み合わせて呼び出す1つのDSL構文 page を作り、対の片方を書き忘れるというバグの原因を根元から取り去ってしまいましょう:

     

    class CGPDFContext
       def page(page_info={}, &block)
         beginPage(page_info)
         block.call(self)
       ensure
         endPage     # このメソッドから出るときに必ず呼ばれる
       end
     end
    


    ensureは、ensure と end の間の文式が、スコープ(この場合メソッド全体)の本体から出るときに必ず呼ばれることを保証するRubyの構文です。Javaのfinally、Objective-Cの@finallyに相当します。

    仮引数のblockが、対に挟まれた手続き(あるページに対する描画)になります。beginPageしたあと、block.callにより描画手続きが実行され、その後endPageすることになります。前述の描画プログラム例の後半部分を、page を使って書き直すと以下のようになります:

     

    pdf = CGPDFContext.new(context_ref)
     pdf.page do
       pdf.setRGBFillColor(1.0, 0.0, 0.0, 1.0)
       pdf.addArc(300, 300, 100, 0, 2 * Math::PI, 1)
       pdf.fillPath
     end
     pdf.flush
    


    beginPage と endPage の対ではなく page を使うことにより、beginPageが呼び出されたら、それに対応するendPage が必ず呼び出されるようになります。endPage は書き忘れようがありません。(次回に続きます)

    ■ CGContextクラスとCGPDFContextクラスの根幹部分

    -------------------------- cg_context.rb (未完成) --
    # -*- coding: utf-8 -*-
    require 'osx/cocoa'
    
    class CGContext
     # context_type 宣言構文の定義:
     #   コンテキストの種類(PDFなど)を宣言するとCG(種類)Context関数のイン
     #   スタンスメソッドを生成する
     class << self
       private
       def methodnize(original_name, name)
         method_name = name[0].chr.downcase + name[1..-1]
         define_method(method_name) do |*args|
           OSX.__send__(original_name, @context, *args)
         end
       end
       def context_type(type)
         pattern = / ACG#{type}Context(.*) Z/
         OSX.methods.each do |func_name|
           matched = pattern.match(func_name)
           methodnize(func_name, matched[1]) if matched
         end
       end
     end
    
     # デフォルトの context_type 宣言
     context_type ''
    
     # CGContextクラスのインスタンスオブジェクトの初期化
     def initialize(context)
       @context = context
     end
    end
    
    class CGPDFContext < CGContext
     context_type :PDF
    end
    
    class CGBitmapContext < CGContext
     context_type :Bitmap
    end
    ---

    藤本裕之のプログラミング夜話 #159

     さて、コマかいことを言い出すと、そもそもニホンにおけるインターネットのコト始めは1984年、東京大学、東京工業大学、慶應義塾大学が実験的にネットワークを組んだ JUNET が云々……てな話になるわけだが(またそう書かないと納得しないヒトも多いのだが)、ここでは「インターネット」という言葉が流行語大賞のトップ10に選ばれた1995年をとりあえず「インターネットが一般化した年」として話を進める。

     あ、せっかく調べたので書いておくと、この年の流行語大賞は3つあって「無党派」(受賞者は故・青島幸男)と「NOMO」(同じく野茂英雄)、そして「がんばろうKOBE」(同じく故・仰木彬)である。なんだか懐かしいよねぇ。

     閑話休題。論じたいのはこの「インターネットの普及」とゆーものが、コンピュータ・ソフトウェア業界、特にソフトウェア開発者の状況にどんなインパクトを与えたか、ということである。

     え?「つまりはそれまでのプラットフォームに加えて Web開発というものが加わったとか言いたいのか」って? チッチ、そんな大学の、しかもソフトウェア工学ではなく情報処理史みたいな与太授業を受け持っているセンセイがいいそうなことは言いませんよ。ベクトルが違う。

     つまりね、「インターネットの普及」は、コンピュータ……なかでもパーソナル・コンピュータをものすごい勢いで「フツウのヒトが使うもの」に変えたわけ。

     たとえが適切かどうかわからんが、かつて皇太子(今の天皇)ご成婚や東京オリンピックが一般家庭へカラーテレビを「押し込んだ」ように、「インターネット」という言葉がパソコンの販売台数を劇的に押し上げたのである。ま、ほとんど「Windows95」マシンだったけどさ。

     その結果なにが起きたか。

     ヒトツには「パソコンを純粋に『使う』だけのユーザーが劇的に増加」した。もっとはっきり言えば「コンピュータのことを何も知らず、また勉強するつもりもないユーザーが増えた」のである。

     それから「インターネット」がビジネスの媒体として機能するようになり「コンピュータに関わる仕事」のバリエーションが広がった。それまでは「コンピュータ関係の仕事」といえば,まぁ十中八九はエンジニア(開発者)かセールスマン(営業)だったのが、「サイトプランナー」だとか「ハイパーメディアクリエータ」だとか「スベッタコロンダコンサルタント」だとかそういうちょっと聞いただけではオレでも「具体的になにをやってんだかまったくわからない」肩書きのヒトがやたら増えた。

     で、こっからがオレの問題意識のマトなのだけど、この2つ、つまり「ユーザーがシロウトばっかりになり、クロウトの種類が増えた」ことの相乗効果として、「ソフトウェア技術者」という概念がとっても曖昧なものになってしまったんだよね。

     それまでだって、厳密ということを尊ぶ我々は「SE」と自称する連中が時として「セールス・エンジニア」(なんだそりゃ? と思いました)だったり、「システム・アーキテクト」とか名乗るオトコが実現可能性も考えずにただ大風呂敷を広げるだけのクチサキ小僧だったりすることに苛立ってはいた。が、この時オレ達の足下にクチを開けた地獄はもう一段上……いや下か、とにかく
    ちょっとトンデモナイものだった。

     何を言いたいかわからない? つまりですね、「ツールを使ってWebサイトの体裁を良くする仕事をするだけのヒト」も「高度で専門的な知識や経験を必要とするソフトウェア技術者」ナノだよ、この地獄では。
    (以下次回 2009_04_25)                       

    高橋真人の「プログラミング指南」第157回

    これから始めようとする人へ(8)

     皆さんこんにちは、高橋真人です。
     さて、今回からObjective-Cのメモリ管理のお話をします。Cocoaのフレームワークが持つ高度なメモリ管理の仕組みを見る前に、まずはObjective-Cの一部でもある、Cのメモリ管理について見てみましょう。
     Cには以下の3種類のの変数があります。

    ・ローカル変数(局所変数または自動変数とも呼ばれる)
    ・グローバル変数(大域変数または外部変数とも呼ばれる)
    ・static変数(静的変数とも呼ばれる)

     この中で、ローカル変数は自動変数とも呼ばれるように、メモリの管理が自動的に行われます。それ以外の変数はプログラムの終了時までずっとメモリを保持し続けるので、特にメモリ管理を考える必要はありません。
     このように、Cが元々用意している仕組みを利用するだけならば、メモリ管理ということについていちいち気にする必要はありません。しかし、プログラムに柔軟性を生むために「メモリの動的な確保」ということを行うのが、現実的なCでのプログラミングです。
     この動的なメモリ確保のために使われるのが、ANSI Cライブラリのmalloc()という関数です。この関数を呼び出すと、通常ローカル変数のために利用するスタック領域とは別のヒープ領域というメモリのエリアから、引数に指定されたサイズのメモリを連続的に確保して、その先頭のアドレス値を返してくれます。
     malloc()で確保したメモリは、明示的にfree()という関数を呼び出さない限り解放されることはありませんから、変数のスコープなどとは関係なく確保したままにすることができます。これは逆から見れば、free()を使ってきちんと後始末をしないと、そのメモリ領域は他では使えない状態のままに置かれるこということでもあります。
     もっともヒープ領域と呼ばれる領域も、システムによって割り当てられている、そのプログラムのための専用のメモリ領域の一部ではありますので、プログラム自体が終了すれば自動的にシステムに返されます。
     なので、少しの量のメモリであれば、いちいち後始末など気にしなくても、という考え方があるのも事実です。ただ、それを言い出すとメモリ管理の話から外れてしまうので、今はそれは考えないことにします。

     さて、malloc()で確保したメモリはfree()で解放すると言いましたが、動的に確保されるメモリ領域は1つに限るわけではありません。なので、それぞれを識別するための情報が必要になるわけです。そこでmalloc()が返したアドレス値をポインタと呼ばれる「メモリのアドレスを格納する型」の変数に保管しておき、この値をfree()に渡すことで、解放すべきメモリ領域を伝えます。
     このように、プログラム側から見ると、動的に確保したメモリが不要になった際、きちんとそれを解放するためには、malloc()が返したアドレス値を保持しておくことが必要となります。例えば以下のようなコードを書くとします。

    void foo(size_t memory_size)
    {
       char *ptr = malloc(memory_size);
       if (ptr == NULL) {
           fprintf(stderr, "Memory allocation failed.\n");
       }
       else {
           fprintf(stderr, "Memory allocation suceeded.\n");
       }
    }
    


     malloc()が返した値は、ちゃんとptrという名のポインタ変数に受け取ってはいるものの、この関数が終わったとたんにptrという変数自体は消滅してしまいます。しかしながら、free()はこのメモリ領域に対して呼ばれていませんから、領域自体は確保されたままになっています。
     この関数から抜けた後は、メモリ領域を識別するための情報は失われてしまっていますから、この領域を解放することはもはや不可能です。こういう状態を「メモリリーク」と呼び、確実なメモリ管理のためには避けなければならないこととされています。

    ◇MOSAからのお知らせと編集後記は割愛します◇

     

     MOSA Developer News   略称[MOSADeN=モサ伝]
            配信停止 mailto:mosaden-ml@mosa.gr.jp
     記事内容に関するご意見 mailto:mosaden-toukou@mosa.gr.jp
          記事投稿受付 http://www.mosa.gr.jp/?page_id=850
    Apple、Mac OSは米国アップル社の登録商標です。またそのほかの各製品名等
    はそれぞれ各社の商標ならびに登録商標です。
    このメールの再配信、および掲載された記事の無断転載を禁じます。
    特定非営利活動法人MOSA  http://www.mosa.gr.jp/
    Copyright (C)2009 MOSA. All rights reserved.

  • MOSA Developer News[MOSADeN=モサ伝]第340号

    2009-04-21

    目次

    • 「Wonderful Server Life」    第91回   田畑 英和
    • 小池邦人のCarbon視点でiPhone探求
    • ターミナルの向こうから      第46回  海上 忍 

    「Wonderful Server Life」  第91回  田畑 英和

    〜「Deployment」編〜

     Xserveがモデルチェンジしました。前回のモデルが発表されたのが2008年の1月ですから、1年と数ヶ月でのモデルチェンジとなります。今回の目玉はCPUにIntelのNehalemが搭載されパフォーマンスが向上していることですが、ほかにもオプションでSSDが選択できるなどの特徴があります。ハードディスクはこれまでと同様3基搭載できますが、SSDはこれとは別に追加することができ、SSDにOSをインストールして起動ボリュームとして使用することができます。
    また、サーバ管理ツールの最新版もリリースされています。

    ・ニュースリリース
    http://www.apple.com/jp/news/2009/apr/07xserve.html
    ・Server Admin Tools 10.5.6v1.1
    http://support.apple.com/downloads/Server_Admin_Tools_10_5_6v1_1

    ◇NetBoot/NetInstallの準備
     それでは本題に戻りまして、今回からNetBoot/NetInstallの具体的な設定方法について解説していきます。まず全体的な流れですが、次のようになります。

    1. システムの準備
    2. システムイメージの作成
    3. DHCPのセットアップ
    4. NetBootサービスの設定
    5. クライアントコンピュータの設定

     実際にはシステムの設計や設定後の検証なども必要になります。システムの規模によっても作業の内容は異なってきますが、まずはサーバ1台、クライアント1台という最小限の環境を想定して話を進めていきたいと思います。

    ◇システムの準備
     システムを構築するのに必要な機材を揃えて、個々の機材が動作条件を満たしているかを確認します。最小構成のNetBootシステムを構築するにはサーバおよびクライアントコンピュータとそれらを接続するネットワークが必要になります。
     まずクライアントコンピュータですが、次の条件を満たしている必要があります。

    クライアントコンピュータの動作条件
    ・PowerPC G4またはG5ベースのMac
    ・IntelベースのMac

     つまり、これは10.5が動作するためのシステム条件と同じです。NetBootは10.4以前から存在したサービスなのですが、10.5では10.5のシステムイメージしか作成できなくなりましたので、この場合クライアントの動作条件も10.5の動作条件を満たす必要があるということです。10.4のシステムイメージを作成する方法もあるのですが、これには10.4の環境が必要になりますのでここでは説明を省略します。
     またファームウェアは最新のものを使用し、メモリは最低512MB必要となっています。

     次にネットワークの環境ですが、お勧めの環境はギガビットのスイッチです。マニュアルを読むとクライアントが50台より多い場合はギガビット、50台以下の場合は100-Mbitとなっているのですが、ネットワークはなるべく速い環境を用意しましょう。
     NetBootとNetInstallとではネットワークの使用状況が違いますが、どちらもより高速なネットワークのほうが快適に使用できます。

     最後にサーバですが、サーバのハードディスクの残り容量には注意しましょう。クライアント用のシステムイメージをサーバ上に保存することになりますし、場合によってはイメージを複数使用する場合もあります。さらに、NetBootの場合にはシャドウファイルと呼ばれるデータをサーバ上に保存する場合もあります。具体的に必要となるディスク容量はシステムによっても異なってきま
    すので、事前に検証を行ってシステムに応じた必要なディスク容量を確認しておきましょう。例えば、空き容量が10GB程度しかない場合はディスクを増設するなどサーバ構成を再検討したほうがよいでしょう。
     またNetBootサービスはかなり負荷のかかるサービスですので、NetBootサーバではなるべく他のサービスは使用しないほうがよいです。Open Directoryやファイルサービスなど他のサービスは別サーバを用意して提供するようにしましょう。

    ◇システムイメージの作成
     クライアントコンピュータ用のシステムイメージの作成です。クライアントで使用するシステムをディスクイメージとしてサーバ上に作成します。NetBootとNetInstallとで少し作業手順は異なってきますが、どちらもサーバ管理ツールに含まれている「システムイメージユーティリティ」を使用します。
     システムイメージを作成するときにまず注意が必要なのは、システムのバージョンです。基本的には最新版のシステムを使用するようにしましょう。なぜならば最新の機種は最新のシステムが必要になるからです。10.5がリリースされた時点で出荷されていたMacであればシステム条件さえ満たしていれば10.5.0で起動はできますが、それ以降にリリースされた機種では10.5.0以降のシステムでないと起動できない場合があります。
     それでは次回はシステムイメージの作成方法の続きを解説します。
    次回へつづく

                                 

    小池邦人のCarbon視点でiPhone探求(2009/04/17)

    〜 画像の矩形サイズを調整する 〜

    今回は、ファイルから読み込んだ画像データのサイズ(幅と高さ)を変更する処理を考えてみます。オリジナルの大サイズ画像をメモリーに常駐させておいては、iPhoneのメモリーがいくらあっても足りません。特定のケースではサムネイルサイズに縮小して利用します。

    ところで、iPhoneのDocumentsフォルダ (ディレクトリ)にちゃんと画像ファイルが保存されたかどうかを確認したい場合があります。もしくは、不必要になった画像ファイルを削除した時なども、それが本当に実行されているか不安です。通常では、iPhone自体のディレクトリの内容をのぞき見ることはできませんが、シミュレータの方であれば、その内容を確認することが可能です。シミュレータが管理しているアプリケーション固有のホームディレクトリは、以下のパスに設定されています。

    User Home/ライブラリ/Application Support/iPhone Simulator/User/Applications/

    このパスの下に「1F96CDFA-7EEA-4A1F-B63E-C22E8F825A50」などと暗号(?)のような名称が付いたフォルダが作成されますが、それがシミュレータが管理しているiPhoneアプリケーションのホームディレクトリです。このフォルダ名ですが、XcodeでMakeを実行し、シミュレータ上でアプリケーションを起動する度に逐次変更されます。ご注意ください。

    この名称では何が何だか判断できませんが、作成日付(最新)をヒントにし、確認すべきターゲット・アプリのフォルダを見つけ出します。このフォルダ内に「Documents」というフォルダが作成されて、その中にアプリケーションから保存した画像ファイルなどが置かれることになります。iPhone側でも同様な階層構造でファイル管理されているので、よほどのことがないかぎりは、このフォルダ内容をチェックすることで、ファイル操作の正確さを確認することが可能となります。

    さて、iPhoneアプリケーションで画像を取り扱う場合には、Quartz2DフレームワークのCGImageRefか、UIKitフレームワークのUIImageクラスを使います。処理内容によっては、UIImageよりCGImageRefを用いた方が便利(もしくは高速)な場合もあります。今回は、せっかくですので両方(CGImageRefとUIImage)を対象とした画像の縮小処理を考察してみます。まずは、CGImageRefの方です。

    CGImageRef resizeCGImage( int type,CGImageRef simg,CGFloat width,
                                                           CGFloat height )

    {
       CGRect          srt,frt,drt;
       void            *bitmapData;
       CGImageRef      dimg=NULL;
       CGFloat         ww,hh;
       CGContextRef    ctx;
    
       ww=(CGFloat)CGImageGetWidth( simg );  //  画像の幅を得る
       hh=(CGFloat)CGImageGetHeight( simg );  //  画像の高さを得る
       srt=CGRectMake( 0.0,0.0,ww,hh );
       frt=CGRectMake( 0.0,0.0,width,height );
       fitBounds( 1,&frt,&srt,&drt );  //  矩形の縦横比を合わせる自作ルーチン
       if( type==0 )  //  画像と同じ縦横比
       {
           drt.origin.x=drt.origin.y=0.0;
           ctx=createBitmapContext( drt.size.width,drt.size.height );
       }
       else  //  widthとheightと同じサイズ(背景の余白は白色)
           ctx=createBitmapContext( width,height );
       if( ctx )  //  オフスクリーン用CGContextRefが得られたか?
       {
           CGContextDrawImage( ctx,drt,simg );        //  オリジナル画像を描画
           dimg=CGBitmapContextCreateImage( ctx );  //  CGImageRefを得る
           if( bitmapData=CGBitmapContextGetData( ctx ) )  //  使用メモリを解放
               free( bitmapData );
           CGContextRelease( ctx );  //  CGImageRefを解放 
       }
       return dimg;
    }
    


    縮小させるオリジナルの画像は引数のsimgで与えられます。引数のwidthとheightは、縮小後の(拡大でもOK)幅と高さピクセル数で与えます。引数のtypeがゼロであればオリジナルの縦横比を保持してリサイズすることで背景を作りません。typeが1であれば、リサイズ方法はtypeがゼロの場合と同じですが、フレームの幅と高さは指定通りとなり背景を残します。

    fitBounds()は、srt(オリジナル画像の矩形)をfrt(描画先矩形)に合わせて拡大縮小させたdrt(描画矩形)を得るための自作ルーチンです。そして、createBitmapContext()ルーチンで、オフスクリーン用のCGContextRefを作成し、そこへオリジナル画像を描画します。最後に、そこから目的のCGImageRef(縮小した画像)を得ます。オフスクリーンとして確保したCGContextRefは、それ自体をCGContextRelease()で解放するだけではなく、そこに使用していたメモリ領域もfree()で解放することを忘れないでください。

    以下は、オフスクリーン用のCGContextRefを作成するcreateBitmapContext()ルーチンです。

    CGContextRef createBitmapContext ( int pixelsWide,int pixelsHigh )
    {
       CGContextRef      bitmapContext=NULL;
       void              *bitmapData;
       CGColorSpaceRef   colorSpace;
    
       if( bitmapData=calloc( 1,pixelsWide*pixelsHigh*4 ) )  //  画像用メモリ確保
       {
           colorSpace=CGColorSpaceCreateDeviceRGB();  //  カラースペースを設定
           bitmapContext=CGBitmapContextCreate( bitmapData,pixelsWide,
           pixelsHigh,8,pixelsWide*4,colorSpace,kCGImageAlphaPremultipliedLast );
           if( ! bitmapContext ) )    //  オフスクリーン用CGContextRef作成
               free( bitmapData );  //  失敗した場合にはメモリを解放する
           CGColorSpaceRelease( colorSpace );
       }
       return bitmapContext;
    }
    


    今回の処理で利用しているAPIの詳細については、Quartz2D関連のヘッダーファイルCGBitmapContext.h 、CGGeometry.h、CGImage.hなどを参照してみてください。続いて、UIImageクラスを利用した画像の縮小処理です。

    UIImage *resizeUIImage( int type,UIImage *simg,CGFloat width,CGFloat height )
    {
       CGRect    srt,frt,drt;
       UIImage   *dimg;
       CGSize    size;
    
       srt=CGRectMake( 0.0,0.0,simg.size.width,simg.size.height );
       frt=CGRectMake( 0.0,0.0,width,height );
       fitBounds( 1,&frt,&srt,&drt );  //  矩形の縦横比を合わせる自作ルーチン
       if( type==0 )       //      画像と同じ縦横比    
           UIGraphicsBeginImageContext( drt.size );  //  オフスクリーンContext作成
       else  //  widthとheightと同じサイズ(背景の余白は白色)
       {
           size.width=width;
           size.height=height;
           UIGraphicsBeginImageContext( size );
       }
       [simg drawInRect:drt];   //  画像の描画(UIImageクラスのメソッド)
       dimg=UIGraphicsGetImageFromCurrentImageContext();   //  UIImage作成 
       UIGraphicsEndImageContext();  //  オフスクリーンContext解放
       return dimg;
    }
    


    こちらでは、先ほどのcreateBitmapContext()ルーチンの役割をUIGraphics.hに定義されているUIGraphicsBeginImageContext()ルーチン(メソッドではない)が担います。描画後にUIImageを作成するのは、UIGraphicsGetImageFromCurrentImageContext()です。また、不必要となったImageContextは、UIGraphicsEndImageContext()で解放します。UIGraphics.hには、今回紹介したような便利なCルーチンが多数定義されていますので、ぜひ一度参照してみてください。

    iPhone OS 3.0でコピー&ペーストにより画像を別アプリケーションから持ってくることが可能になりました。しかし、iPhone OS 2.2ではまだそうした操作はできません。主な画像の入手方法は、iPhoneの写真ライブラリから画像を得るか、そのアプリから写真撮影するかです。次回は、そうした操作の実装を考えてみます。

    ターミナルの向こうから      第46回  海上 忍

    〜 リモートでシェルを使う(1) 〜

     MOSAメンバーの中にも、安くて気軽なレンタルサーバを利用している方は多いのではないでしょうか? 今回は、レンタルサーバの管理に欠かせない「ssh」の使い方を解説します。

    ・sshとは
     ssh(Sechure SHell)とは、ネットワーク経由で他のマシンに接続し、コマンドを実行して遠隔操作を行うためのプロトコルです。その名が示すとおりセキュアな性質を持ち、ネットワーク上を流れるデータは公開鍵暗号方式で保護されます。リモートホストを安全に操るための実装系、と言ってもいいでしょう。
     同名のコマンド「ssh」は、このプロトコルに対応したクライアントです(以降、混同を避けるためプロトコルを指す場合「SSH」と表記)。リモートのサーバ(SSHサーバ)に接続し、指定されたコマンドを実行するか、リモートシステム上でシェルの機能を利用するために利用されます。冒頭に挙げたレンタルサーバの場合、ファイル操作などの処理を行うためには連続して複数のコマンドを実行するはずで、後者の役割が期待されているとも言えます。
     SSH登場以前のUNIXでは、rsh(リモートでのコマンドの実行/シェルの起動)とrlogin(リモートホストへのログイン)、そしてtelnet(ベーシックなネットワークログイン)が多く利用されていました。しかしいずれもセキュリティ上の問題があり、特にtelnetは平文がネットワーク上を流れることから敬遠され、デフォルトで1,024bitの暗号鍵が使用されるSSHが急速に普及しまし
    た。Mac OS Xでも、v10.1以降「リモートログイン」にSSHが採用されています。
     ちなみに、ssh以外にもscpやsftpといった「s」から始まるコマンドが収録されていますが、これらはSSHに対応したセキュアな通信を実現します。コマンド名から推測できるように、scpはrcpの、sftpはftpの代替であり、ファイルの安全な転送に役立ちます。

    ・sshの使い方
     前置きが長くなりましたが、クライアントとしてのsshをいう場合、「(レンタルサーバなどの)サーバでシェルの機能を利用するためのコマンド」を意味します。直接的には、前述したrshコマンドのSSH対応版ですが、loginコマンドとしての機能も備えている(sloginコマンドも用意されているが、実体はsshコマンドのシンボリックリンク)ため、ログインもできます。もちろん、「リモートログイン」を有効にしたMacへのログインにも使えます。
     典型的な使い方ですが、以下に示すとおり引数に「サーバのユーザ名@サーバのアドレス」を与え、コマンドを実行します。初めてログインを試みる場合は、サーバの鍵をクライアント(つまりMac)に作成するためyes/noで確認されるので、「yes」と答えます。あとは、サーバのパスワードを入力すれば、リモートへのログインは完了です。

    - - - - -
    $ ssh daresore@abc.dokka.com
    The authenticity of host 'abc.dokka.com (123.45.44.111)' can't be established.
    RSA key fingerprint is a4:f5:91:b3:c2:25:84:d8:ea:28:bb:46:c9:a5:de:2f.
    Are you sure you want to continue connecting (yes/no)? yes
    Warning: Permanently added 'dokka.com' (RSA) to the list of known hosts.
    daresore@abc.dokka.com's password: 
    Last login: Mon Apr 20 13:34:41 2009 from shiranai.ne.jp
    
    daresore@abc:~>
    - - - - -
    


    ・最初に確認すること
     ログインが完了すれば、そこから先はサーバ上の世界です。ふだん利用しているTerminalとはプロンプトが異なるでしょうし、利用できるコマンドにも差があります。当然、サーバのリソースを使用してコマンドが実行されるため(MacのTerminalには結果が表示されるだけ)、処理能力に差があるかもしれません。
     ともあれ、最初に行うべきは動作しているシェルの確認です。レンタルサーバの場合、ログイン直後に起動されるシェル(デフォルトシェル)は企業/サーバによりまちまちで、bashだったりcshだったり、あるいは機能制限付きのシェルだったりしますから、面倒がらずに以下のコマンドを実行しましょう。気に入らなければ、chshコマンドで他のシェルに変更できます(利用するサービスによってはできないかもしれません)。

    - - - - -
    ~> echo $SHELL
    /bin/bash
    - - - - -
    


     契約時に確認済とは思いますが、サーバのOSも確認しておくべきです。商用ベースのサーバはLinuxとFreeBSDが多く採用されていますから、unameコマンドは収録されているはずなので、以下のとおりunameコマンドを実行すればOKです。ここではOSがLinux、カーネルのバージョンが2.6.23.16-smpで、マシンのCPUアーキテクチャはi686だということがわかります。

    - - - - -
    ~> uname -a
    Linux abc 2.6.23.16-smp #2 SMP Sat Feb 16 04:28:23 JST 2008 i686 GNU/Linux
    - - - - -
    


     次回は、scpコマンドを利用したファイル転送について解説する予定です。

    ◇MOSAからのお知らせと編集後記は割愛します◇

     

     MOSA Developer News   略称[MOSADeN=モサ伝]
            配信停止 mailto:mosaden-ml@mosa.gr.jp
     記事内容に関するご意見 mailto:mosaden-toukou@mosa.gr.jp
          記事投稿受付 http://www.mosa.gr.jp/?page_id=850
    Apple、Mac OSは米国アップル社の登録商標です。またそのほかの各製品名等
    はそれぞれ各社の商標ならびに登録商標です。
    このメールの再配信、および掲載された記事の無断転載を禁じます。
    特定非営利活動法人MOSA  http://www.mosa.gr.jp/
    Copyright (C)2009 MOSA. All rights reserved.

  • MOSA Developer News[MOSADeN=モサ伝]第339号

    2009-04-14

    目次

    • りんご味Ruby         第45回  藤本 尚邦
    • 藤本裕之のプログラミング夜話   #158
    • 高橋真人の「プログラミング指南」  第156回

    りんご味Ruby   第45回  藤本 尚邦

    引き続き、Ruby+RubyCocoaを使って「CoreGraphicsによるPDFの描画」を記述するための簡易言語(DSL)を作っていきます。

    前回、正規表現オブジェクトのメソッド Regexp#match を使ったパターンマッチにより、RubyCocoaで使うことのできるObjective-Cの関数名の中から、描画コンテキスト(CGContext または CGPDFContext) を操作する関数の名前を見つけて、それを元にしたメソッド名とともに methodnize に渡す手順を作りました:

    【編集部注:以下バックスラッシュを¥で置き換えて表現します】

     

      def context_type(type)
         pattern = /¥ACG#{type}Context(.*)¥Z/
         OSX.methods.each do |func_name|
           matched = pattern.match(func_name)
           methodnize(func_name, matched[1]) if matched
         end
       end
    


    例えば、”CGContextFillRect” というCoreGraphicsの関数名がマッチしたときには、methodnize(“CGContextFillRect”, “FillRect”) が実行されます。

    methodnize の役割は、引数として渡された名前のCoreGraphicsの関数を呼び出す CGContextクラス(または派生クラスのCGPDFContextクラス) のインスタンスメソッドを生成することです。methodnize の実装を見ていきましょう:

     

      def methodnize(original_name, name)
         method_name = name[0,1].downcase + name[1..-1]
         define_method(method_name) do |*args|
           OSX.__send__(original_name, @context, *args)
         end
       end
    


    ■ メソッド名の生成

    Rubyでは、メソッド名の最初の文字を英語のアルファベット小文字にすることになっています(注: 実際には、Rubyの処理系によりますが、大文字で始まる名前や日本語のメソッド名も定義できてしまいます)。

    methodnize本体の1行目で、引数nameの値から:

       name[0,1].downcase   # 1文字目のみからなる部分文字列を小文字化
       name[1..-1]          # 2文字目から末尾までの部分文字列
    


    を作り、この2つの文字列を + で連結して小文字で始まるメソッド名を作っています。CGContextFillRect の場合には fillRect というメソッド名になります。

    ちなみに Webアプリケーションフレームワークの Ruby on Rails に含まれている ActiveSupport というライブラリでは、文字列クラスを拡張しまくって、よくあるネーミング規約 (CamelCase、”_” でつなぐスタイルなど)や英単語名詞の単数形・複数形などを相互に変換する便利メソッドがたくさん追加されています:

    ◇ (補足) + もメソッド

    部分文字列の連結に使った + は、普通の2項演算子のように見えるかもしれませんが、左辺=レシーバで右辺=実引数なメソッドの呼び出しになります。つまり:

     左辺 + 右辺

     左辺.+(右辺)

    と同じことなのです。もちろん -, *, / についても同様です。methodnizeで使われている + の左辺は文字列ですから、String#+ が呼ばれることになります。

    ■ CoreGraphics関数のインスタンスメソッド化

    メソッド名ができたので、define_method を使ってインスタンスメソッドを動的に定義します。生成するメソッドの本体では渡された関数を呼び出します。

         define_method(method_name) do |*args|
           OSX.__send__(original_name, @context, *args)
         end
    


    RubyCocoaでは、Objective-C の関数を OSXモジュールのメソッドとして呼び出すようになっています(注: MacRubyの場合は、Kernelクラスのメソッドとして、直接呼び出せるようになっています)。例えば CGContextFillRect なら

     OSX.CGContextFillRect(@context, *args)

    という形で呼び出すことになります。ですが、define_method の本体を実装している段階では、どの関数を呼び出すのかが決まっていないので、上記のように直接呼び出すことはできません。そこで Object#__send__ というメソッドを使います。__send__ は、レシーバに対して、第1引数で指定された名前(文字列またはシンボル)のインスタンスメソッドを第2引数以降で渡された実引数とともに呼び出します:

     OSX.__send__("CGContextFillRect", @context, *args)

    Ruby の Object#__send__ は、Objective-C での NSObjectプロトコルのインスタンスメソッドの performSelector: や performSelector:withObject: に近いかもしれません。

    以上で、CGContextクラスとCGPDFContextクラスの根幹部分はほぼ完成しました。もともとの目標は:

    PDFDrawer.file "circle.pdf", [0, 0, 612, 792] do |pdf|
     pdf.page do
       pdf.setRGBFillColor(1.0, 0.0, 0.0, 1.0)
       pdf.addArc(300, 300, 100, 0, 2 * Math::PI, 1)
       pdf.fillPath
     end
    end
    


    のようにPDF描画を記述できる簡易言語を作成することでした(第42回)。ということで次回は、PDFDrawer.file と pdf.page の中身を実装します。

    藤本裕之のプログラミング夜話 #158

     1989年12月、突然東京上空で「パチン」と軽い音がしてバブルが弾けた……てな説明でいいんだったら楽なのだが事実はそう単純ではない。これを読んでいるヒトの中には「何を今更そんな分かりきったことを」とおっしゃる方もおられると思うが、経済に不案内で「バブルっていったい何だったの?」と思ってるヒトも少なくはないと思うので一応基本的なことをおさらいしておく。

     ここでいうバブルとは、単純に言えば「実質的にはそんな価値がないものを皆が高い価格で買うことによって生まれる好景気」のことである。80年代末のバブルの主役は主に土地だった。「土地は値下がりしない」ってな言葉、記憶にあるでしょ? でも、土地であろうがなんであろうが価格のついているものが「値下がりしない」のはつまるところ「もっと高くても買うヒトがいるから」である。従って「もう誰も買えない」ところまで値上がりすると必然的に売買はされなくなっちゃうのね。

     でもそれを買っているヒト達は「土地が好きで好きでたまんなくてとにかく持っていたい」というヒト達ではない。「誰かにもっと高く売るために買った」ヒト達で、しかもそれを買うために借金までしてる。土地は高く売れなくても借金の利子は払わなければならない。百歩譲って自己資金で買ったとしても土地というモノは持っているだけで税金もかかる。その損をぜんぶひっかぶらなければならない。早い話バブル経済というのは莫大な金を賭けてプレイするババ抜きみたいなものなのだ。

     1989年の12月、そういう「借金して買った土地を高く買ってくれるヒト(カモとも言う)」というのを探すのが難しくなってきた時に、日銀が金融の引き締めというのをやった。つまり公定歩合を引き上げて借金の利子を高くしたわけ。これでなおさらカモになるヒトはいなくなり、つまり「そんときババを持ってたヤツの負け」が確定したわけ。

     2007年の映画「バブルへGO! タイムマシンはドラム式」ではこの金融引き締めに続く翌年3月の総量規制(不動産融資の伸び率の抑制)がバブル崩壊を招いた、という解釈をしていたけど、それぢゃあのまま野放図にやってりゃうまくいったかといえばそんなことはありえない。確かにこの政策はハードランディング……というより不時着に近いもんだったけれど、成層圏まで舞い上がってから墜落するよりはナンボかましだったという考え方もあるわけ。

     とまぁこういう経緯でバブルは弾け、明るみに出て皆がオドロイたのは、表立って不動産売買を仕事にしているわけぢゃない企業の多くが土地に投資して大損こいてたこと。有り体に言えば「なんで土地バブルが弾けてお前んとこが傾くんだよ」というような企業がグラグラと傾き、社員の新規採用を控えたり事業規模を縮小したりし、土地バブルではたいしていい目も見なかったソフト
    ウェア・エンジニアたちに悪影響が……つまりは仕事が減ったのである。

     差し障りがあるかも知れないので具体的な企業名は出さないが、当時ある企業の課長級のヒトと交わした以下のような会話を覚えている。

    課長「上が『バブルのときに採用した社員が山ほどいるのに何で外注が要るんだ』って言うんですよ」
    オレ「いるなら彼らにやらせればいいぢゃないですか?」
    課長「やらせて出来るならやらせてますよ。だいたいワタシが採用したわけぢゃないのに、スキルもない連中いきなりあてがわれてこいつら使えって言われてもねぇ」
    オレ「なるほど」

     社内でヒトを育てない、育てる必要がない状況から一転、その育ってない連中を使って仕事をこなさなければならなくなったわけである。でも営業とか経理とかならともかく(そういう業種もそうなのかも知れないけどさ)ソフトウェア開発のスキルは一朝一夕でなんとかなるもんでもない。しかし外の人間を雇う予算もない。当然、開発仕事は必要最小限に絞り込むことになった。

     そんなこんなで90年代の前半、いわゆる「派遣のプログラマ」の地位は目に見えて下がり始める。「高度で専門的な知識を必要とする仕事」でありながらその需要が枯渇しちゃったのね。そして94〜95年、いよいよ「インターネット」がシーンに登場するわけなんだが……。
    (以下次回 2009_04_10)

                           

    高橋真人の「プログラミング指南」第156回

    これから始めようとする人へ(7)

     皆さんこんにちは、高橋真人です。
     さて、前回のObjective-Cについてのお話は、あくまで言語的な側面から見たものです。Objective-Cの言語仕様は確かに見た目においても独特なものなので、そのこと自体にも説明する価値はあるかもしれません。
     ただ、実際のプログラムを書く上においてはCocoaフレームワークの提供する機能を使わないことはまずあり得ないと言えるでしょう。また、Objective-Cの魅力だと多くの人が感じている中にはフレームワークそのものも含まれているように感じますので、これからは両者を併せてお話を進めます。

     Cocoaフレームワークと言われるものは、AppKitフレームワークとFoundationフレームワークから成り立ちます。AppKitは主にGUIアプリケーションを作る際に使われる機能を提供し、Foundationはその下支えをします。
    Foundationフレームワークはその名前通り基盤となる機能を提供しますので、AppKitが使われる場合には同時にFoundationも使われると考えてほぼ間違いないでしょう。
     それに対して、Foundationは単独で使われることも珍しくありません。一般のMacユーザーにはあまり馴染みがないかもしれませんが、UNIXであるMac OS Xには、ターミナルというアプリケーションから起動するいわゆる「UNIXコマンド」と呼ばれるアプリケーションが数多くあります。
     以下のページを見ると(Safariがフリーズする場合があるので開く時は注意!)、とても多くの項目が並んでいますが、この中でsection 1として分類されている項目(ざっと1,200ほどあります)は、それらはすべてターミナルから起動できるGUIを持たないコマンドです。

    http://developer.apple.com/documentation/Darwin/Reference/ManPages/index.html

     これらの1,200余りのコマンドがすべてFoundationフレームワークを使って書かれているというわけではありません(おそらくは、ほとんどがCまたはそれに準ずるもの)。ですがFoundationを利用して、Objective-Cでこのような形態のアプリケーションを書くことができるのです。

     Foundationフレームワークの提供するのは、メモリ管理の機能やString、Array、Dictionaryなどの各種データ構造の基本となる型、Mac OSとやり取りする上で役に立つ様々なユーティリティなどです。
     この中でもメモリ管理はプログラムを書く上できわめて重要なことですからObjective-Cを学ぶ上でかなり優先度の高い事項です。
     ご存知の方も多いと思いますが、Objective-Cは2.0になってからガベージコレクターが使えるようになりました。ガベージコレクターというのは簡単に言えば、メモリの確保だけをプログラマーがやり、後始末に関してはシステムに任せておくことのできる仕組みです。
     プログラミングを学ぶ上で、メモリ管理というのは乗り越えるのが大変な壁のひとつであるため、ガベージコレクターの登場は一時は大きな話題になりました。ですが、iPhoneにおいては残念ながらガベージコレクターがサポートされていないことから、最近では余り話題に上ることもなくなりました。

     賛否両論あるものの、状況をわきまえて使えばガベージコレクターは便利に使える機能ではあるのでしょう。ただ、「ガベージコレクターがあるのだからメモリ管理については学ぶ必要がない」と言う人がいたら、それはちょっと考えが浅いのでは? と私は思います。たとえガベージコレクターが使えても、メモリという資源が有限であり、これをうまく使うことはやはり効率的なプログラミングをするためには欠かすことのできない技術だからです。

     さて、Objective-Cのメモリ管理というと、まずはalloc、そしてrelease、retainという言葉が登場してきます。そしてこれらと連携して使われるautorelease poolというものがCocoaのメモリ管理においては極めて特徴的なものです。
     次回はこの辺をさらに深く探って行きます。

    ◇MOSAからのお知らせと編集後記は割愛します◇

     

     MOSA Developer News   略称[MOSADeN=モサ伝]
            配信停止 mailto:mosaden-ml@mosa.gr.jp
     記事内容に関するご意見 mailto:mosaden-toukou@mosa.gr.jp
          記事投稿受付 http://www.mosa.gr.jp/?page_id=850
    Apple、Mac OSは米国アップル社の登録商標です。またそのほかの各製品名等
    はそれぞれ各社の商標ならびに登録商標です。
    このメールの再配信、および掲載された記事の無断転載を禁じます。
    特定非営利活動法人MOSA  http://www.mosa.gr.jp/
    Copyright (C)2009 MOSA. All rights reserved.

  • MOSA Developer News[MOSADeN=モサ伝]第338号

    2009-04-07

    目次

    • 「Wonderful Server Life」    第90回   田畑 英和
    • 小池邦人のCarbon視点でiPhone探求
    • ターミナルの向こうから      第45回  海上 忍 

    Wonderful Server Life」  第90回  田畑 英和

    〜「Deployment」編〜

     いよいよ新年度がスタートしました。このシーズンになりますと学校では新入生が、会社では新入社員ということになります。学校によっては学生にノートパソコンを配布するようなところもありますし、春休みの期間を利用して学内のパソコンを入れ替えたりします。会社であれば新入社員用のパソコンが必要になりますね。用意する台数は組織の規模によって異なるでしょうが、一般的に複数台のパソコンを一時期にセットアップする必要が出てきます。
     こういった背景をふまえて、今回からクライアントコンピュータの効率的なセットアップについて考えていきたいと思います。

    ◇セットアップの問題点
     複数台のパソコンをセットアップするとなると、なんといっても問題になるのはその手間と時間でしょう。パソコンをセットアップするには次のような作業が考えられます。

    ・OSのインストール
    ・アカウントの登録
    ・ネットワークなどシステムの設定
    ・アプリケーションのインストール
    ・OSやアプリケーションのアップデート

     1台のパソコンをセットアップするだけであれば、1つ1つ手作業で対応していってもよいのですが、例えば100台のパソコンをセットアップするとなるとなんとか作業を効率化したいところです。1台1台異なるセットアップが必要になれば、やはり手作業で対応しなければならない部分も出てくるでしょうが、共通の部分に関してはできるかぎり自動化して効率化をはかりたいところです。
     そこでまずはOSのインストールに注目して、セットアップの効率的な手法について解説していきたいと思います。もっとも新規に購入したパソコンでしたら、その時点での最新のOSがプレインストールされていてそのまま使用する場合もあるでしょうが、今回はOSのインストールから実施することを前提とします。

    ◇OSのインストール
     OSのインストール方法を考えてみますと、通常のやり方ではOSのインストールディスクから起動して、インストールを行います。このやり方では1台1台セットアップするのにかなり手間がかかってしまいます。この問題を解決する方法はいくつかあるのですが、Mac OS X Serverに標準で用意されている機能を活用してみましょう。
     Mac OS X Serverには「NetBoot/NetInstall」という機能が搭載されています。まずNetBootですが、これはサーバ上にあらかじめ準備しておいたOSのディスクイメージから、ネットワーク経由でクライアントコンピュータを起動するサービスです。この方法ですとそもそもクライアント側に直接OSをインストールする必要がなくなります。
     次にNetInstallですが、これはNetBootと共通のテクノロジーを使用しています。NetBootではクライアントを起動するたびに、ネットワーク経由でサーバ上のディスクイメージにアクセスしますが、NetInstallではネットワーク経由でクライアントのハードディスクにインストールを行います。
     つまりNetBootもNetInstallも、あらかじめサーバ上にクライアントに必要なものを用意しておき、ネットワーク経由で配布することになります。このような仕組みを利用すれば、ネットワークの準備さえできれば、あとはサーバを用意するだけでクライアントのセットアップができてしまうということになります。

    ◇NetBootとNetInstall
     ではNetBootとNetInstallはどのように使い分ければよいのでしょうか。これは環境によって変わってきます。例えばノートパソコンのように持ち運んで利用するような場合には、常時ネットワークに接続しているわけではありませんので、起動のたびにサーバへのアクセスが必要となるNetBootは利用できないということになります。またNetBootでは毎回サーバへのアクセスが必要になりますので、サーバやネットワークへの負荷は高まりますし、通常はディレクトリサービスやネットワークホームを組み合わせたユーザ管理が必要になってきます。
     一方NetInstallの場合は、インストールさえ完了してしまえばあとはクライアントコンピュータを単独で利用できることになります。
     このようにそれぞれ特徴がありますので、システムの環境や目的によってどちらかを使い分けるということになります。

     というわけでまずは概要を解説したわけですが、次回からは具体的な設定方法について解説していく予定です。また、機会があればNetBoot/NetInstall以外のソリューションについても紹介していければと思います。
    次回へつづく

                                 

    小池邦人のCarbon視点でiPhone探求(2009/04/03)

    〜 画像ファイルの取り扱いを考える 〜

    今回は、画像ファイルの話です。画像ファイルは、Modelオブジェクトのドキュメントからは分離して別に保存します。登録一覧(UITableView)に画像を表示するためには、画像ファイルから小サイズ画像(UIImage)を作る必要もあります。

    iPhoneアプリケーションで画像を取り扱う場合には、Quartz2DフレームワークのCGImageRefやUIKitフレームワークのUIImageクラスを利用します。片方からもう片方への変換は簡単です。UIImageからCGImageRefを得るには、UIImageのCGImageプロパティを参照します。

    UIImage      *uiimage;
    CGImageRef   cgimage;
    
    cgimage=uiimage.CGImage  //  プロパティを参照する
    


    逆に、CGImageRefからUIImageを得るには、UIImageクラスのimageWithCGImage:メソッドを利用します。

    uiimage=[UIImage imageWithCGImage:cgimage];  //  メソッドを利用する
    


    UIImageクラスには色々と便利なメソッドが用意されていますが、Quartz2Dの強力な機能を利用したいケースも出てきます。そうした場合には、上記に示したオブジェクトの変換が必要ですので注意してください。

    さて、次は画像ファイルの読み込みです。XcodeプロジェクトのResourcesグループに登録した画像やサウンドファイル(内部利用)は、各アプリケーションパッケージ内に保存されています。そこに保存されている画像ファイル(ボタンなどのユーザインターフェースなどに使う)については、UIImageクラスのImageNamed:メソッドを利用することで簡単に読み込むことが可能です。以下は、与えたフラグの内容により異なる画像(PNGファイル)を読み込むサンプルルーチンです。

    UIImage *getLockImag (BOOL flag )
    {
       UIImage    *image;
       NSString   *str;
    
       if( flag&LOK_FLAG )    //  ロックフラグON/OFF
           str=@"Lock.png";   //  画像ファイル名
       else
           str=@"Unlock.png";
       image=[UIImage imageNamed:str];    //  画像(UIImage)を得る
       return image;
    }
    


    imageNamed:メソッドで読み込まれた画像はシステムでキャッシュされるため、再描画される時には高速に処理されます。つまり、Cocoaのルールとは異なり、このメソッドで得られたUIImageオブジェクトはAutoReleaseされません。このメソッドを使うと画像は例外なくキャッシュに入ってしまいますので、大容量の画像ファイルを読み込むことは厳禁です。間違いなくアプリケーションの使用可能メモリを圧迫します。

    以下は、iPhone OSで描画できる画像フォーマットです。ただし、iPhone OSの場合は、描画システムがPNG形式の画像に最適化されているので、頻繁に描画するUIImageには、そのソースとしてPNG形式の画像を使うことが推奨されています。

    ・PortableNetworkGraphic(PNG)  .png
    ・TaggedImageFileFormat(TIFF)  .tiff, .tif
    ・JointPhotographicExpertsGroup(JPEG)  .jpeg, .jpg
    ・GraphicInterchangeFormat(GIF)  .gif
    ・WindowsBitmapFormat(DIB)  .bmp, .BMPf
    ・Windowsアイコン形式  .ico
    ・Windowsカーソル  .cur
    ・XWindowビットマップ  .xbm

    続いて、アプリケーションのDocumentsフォルダに保存されている画像ファイルの読み込みです。アプリケーション内部の作業で入手した(例えばカメラ撮影した画像など)については、もし継続して使うなら、そのままDocumentsフォルダに保存しておくことになります。以下は、拡張子を外したファイル名を与えることで、UIImageをJPEG画像ファイルとして保存するメソッドの一例です。

    - (BOOL)saveJPEGImage:(UIImage *)image name: (NSString *)name
    {
       NSString    *name,*path;
       BOOL        ret=NO;
       NSData      *data;
    
       if( data=UIImageJPEGRepresentation( image,0.5 ) ) // 圧縮率設定しデータ作成
       {
           name=[name stringByAppendingString:@".jpg"];    
           path=getDocumentPath( name );      //  保存ファイルのパスを得る
           ret=[[NSFileManager defaultManager] createFileAtPath:path
                                                contents:data attributes:nil];
       }                                      //  指定パスにファイルを作成する
       return ret;
    }
    


    ここで、画像ファイルのパス(保存場所)を得るためにgetDocumentPath()というルーチンを利用していますが、これはDocumentsフォルダ経由のファイルパスを得るための自作ルーチンです。リソースとして保存されている画像ファイルのパスについては、以前作成したsysBeep()ルーチン同様に、NSBundleクラスのpathForResource:メソッドを使えば簡単に得ることができます。

    path=[[NSBundle mainBundle] pathForResource:name ofType:@"jpg"];

    しかし、アプリケーションのDocumentsフォルダのパスを得るには、以下の様に少し複雑な処理が必要となります。次期バージョンのiPhone OSでは、CarbonのFindFolder()ルーチンのような便利なメソッドを用意してもらいたところですね。

    NSString *getDocumentPath( NSString *name )
    {
       NSString    *path=nil;
       NSArray     *paths;
       NSString    *dir;
    
       paths=NSSearchPathForDirectoriesInDomains( 
                           NSDocumentDirectory,NSUserDomainMask,YES );
                                 //  ドキュメントディレクトリーを含むリスト
       if( [paths count] > 0 )   //  得られた項目が配列(NSArray)に格納される
       {
           dir=[paths objectAtIndex:0];      //  ドキュメントディレクトリのパス
           path=[dir stringByAppendingPathComponent:name];         
                                         //  画像ファイルのパスを得る
       }
       return path;
    }
    


    次は、拡張子を外したJPEGファイルの名前を与えることで、Documentsフォルダに保存されている画像ファイルを読み込むメソッドの一例です。

    - (UIImage *)loadJPEGImage:(NSString *)name
    {
       NSString    *str,*path;
       UIImage     *image;
    
       str=[name stringByAppendingString:@".jpg"];    //  拡張子を追加する
       path=getDocumentPath( str );                   //  保存ファイルのパスを得る
       image=[[UIImage alloc] initWithContentsOfFile:path];  //  UIImageの読み込み
       return image;
    }
    


    次回は、こうしてファイルから読み込んだ画像の矩形サイズを変更する処理を考えてみます。 大きなオリジナルサイズの画像をメモリーに常駐させておいては、iPhoneのメモリーがいくらあっても足りません。サムネイルサイズに小さくして活用します。

    ターミナルの向こうから      第45回  海上 忍

    〜 いま敢えて学ぶTerminalのイロハ(12) 〜

     前回、chmodコマンドとパーミッションのお話をしましたが、後から読み返してみると説明不足だった気がしてなりません。今回は補足情報として、chmodコマンドで使う8進数の話と、Tigerから導入されたACLの話をしてみます。

    ・「r」と「w」、「x」
     前回、chmodコマンドに「+x」オプションを指定することで、ファイルに実行権限を付与できることを説明しました。このオプションは、実行権限を意味する記号(x)をファイルに与える(+)という意味で、反対に実行権限を取り去る場合は「-x」です。読み取り権限(r)、書き込み権限(w)についても同様で、権限を与える場合は「+r」および「+w」、取り去る場合は「-r」および「-w」となります。
     「r」と「w」、「x」の3要素は、所有者とグループ、その他ユーザという3種類のフィールドで分けて管理されます。Mac OS Xのファイルシステム(HFS+)では、1つのファイル/フォルダに対して3要素が3種類、すなわち3×3で9の情報が必ず与えられます。
     この記号は、ファインダーの情報ウインドウ下部に表示される「共有とアクセス権」、およびターミナルで「ls」コマンドを「-l」オプション付きで実行したときに表示される情報と連動しています。ただし、情報ウインドウでは「x」の情報が無視されるため、シェルスクリプトに実行権限を与える場合にはUNIXコマンドを使わざるを得ません。

    ・lsコマンドで確認する
     実際に「ls -l」で確認してみましょう。適当なファイルを引数に与えコマンドを実行すると、以下のような情報が表示されるはずです。前述したパーミッション情報は2文字目以降に表示されるので、この場合所有者は「rw-」で読み書き可だが実行は不可、グループとその他ユーザは「r–」で読み取り以外は不可ということがわかります。ちなみに、先頭の文字は種類を意味し、「-」が通常のファイルで「d」がディレクトリ(フォルダ)、「l」がシンボリックリンクです。

    - - - - -
    $ ls -l 43.txt
    -rw-r--r--   1 shinobu  staff   4459  3 21 15:55 43.txt
    - - - - -
    


     なお、Mac OS X 10.5ではこのパーミッション情報が拡張され、「ls -l」を実行すると11文字のパーミッションフィールドが表示されます(末尾に「@」がある場合は拡張属性付きのファイル/フォルダ)。

    ・謎の8進数
     パーミッション情報は、人間が直感的に理解しやすい記号(r、w、x)のほかに、8進数でも表現されます。冒頭にレンタルサーバが云々と書きましたが、パーミッションに関する情報を収集していると、「パーミッションを666にせよ」といった記述を目にすることがあるかと思います。この666は悪魔の数字ではなく、その「rwx」を8進数で表現しているに過ぎません。
     この8進数は、許可を「1」、拒否を「0」とした2進数で表現できます。たとえば、「rwx」は2進数で「111」、8進数に置き換えると「7」ということになります。同様に「rw-」は「6」、「r–」は「4」となります。前述した「パーミッションを666にせよ」は、「rw-rw-rw-」、つまりファイルを読み書き(実行は不可)の権限を所有者・グループ・その他ユーザに対し与える、という意味であることがわかります。

    ・ここでようやくACLの話
     Tiger以降に収録されているchmodコマンドとlsコマンドは、ACL(Access Control List)に対応しています。ACLとは、詳細なアクセス権限管理を可能とする拡張であり、chmodコマンドでは「+a」オプション、lsコマンドでは「-e」オプションで利用できます。なお、TigerのときはfsaclctlコマンドでACLを有効にする必要がありましたが、Leopardではデフォルトで有効になっています。

    - - - - -
    $ chmod +a "admin allow delete" iroha.tex
    $ ls -le iroha.tex 
    -rw-r--r--@ 1 shinobu  staff  1029  5 18  2006 iroha.tex
    0: group:admin allow delete
    - - - - -
    


     HFS+に限定していえば、ACLの設定はPOSIXのパーミッション情報に優先します。たとえば、管理者のみ書き込みできるファイル(所有者がroot)に対し、一般ユーザに書き込み権限を与えるACLの設定を行うことも可能です。以下の例では、管理者権限がないかぎり上書きできなかったファイルを、「shinobu」というユーザにかぎり上書きできる設定にしています。

    - - - - -
    $ sudo chmod +a "shinobu allow write" hostconfig
    Password:
    $ ls -le hostconfig
    -rw-r--r--@ 1 root  wheel  202  4  5 00:36 hostconfig
    0: user:shinobu allow write
    - - - - -
    
    

    ◇MOSAからのお知らせと編集後記は割愛します◇

     

     MOSA Developer News   略称[MOSADeN=モサ伝]
            配信停止 mailto:mosaden-ml@mosa.gr.jp
     記事内容に関するご意見 mailto:mosaden-toukou@mosa.gr.jp
          記事投稿受付 http://www.mosa.gr.jp/?page_id=850
    Apple、Mac OSは米国アップル社の登録商標です。またそのほかの各製品名等
    はそれぞれ各社の商標ならびに登録商標です。
    このメールの再配信、および掲載された記事の無断転載を禁じます。
    特定非営利活動法人MOSA  http://www.mosa.gr.jp/
    Copyright (C)2009 MOSA. All rights reserved.