2016年1月29日金曜日

スマホで写真を投稿したら・・・ひっくり返って表示された!

「スマホで写真を投稿したら・・・ひっくり返って表示された!」



なんてことに出会ったことはありますか?

写真のデータの中には、写真の情報はもちろんですが、
どういう風に写真を撮ったのか、というデータも持っています。

-スマホを縦にして写真を撮ったのか、横にして写真を撮ったのか。

といった情報です。

この情報を正しく扱ってあげないと、Web上で写真を表示するときに、
ひっくり返ったり、横向きになったりしてしまうのです。

デジカメ画像の規格として、Exif(イグジフ)というものがあります。
※詳しくは、http://e-words.jp/w/Exif.html

この規格を採用しているカメラ(スマホカメラ含む)の場合、
写真以外に様々なデータが、付加情報として記録されます。

この付加情報を持っている写真データの場合は、
その情報を考慮し、写真を保存してあげないと、ひっくり返ったり、横向きになったりしてしまうのです。

iPhoneのカメラで採用されていることもあり、開発する際に遭遇することもあると思うので、
付加情報の確認とその修正のサンプルを載せておきます。

もちろん、C#です。

private void CheckProperties(string _path)
{
 // 対象の写真を開きます
 System.Drawing.Bitmap origin = new System.Drawing.Bitmap(_path);

 // 画像の回転度合の設定用
 System.Drawing.RotateFlipType rotation = System.Drawing.RotateFlipType.RotateNoneFlipNone;
 // 開いた写真の情報を順に確認します。
 foreach (System.Drawing.Imaging.PropertyItem item in origin.PropertyItems) {

  // 写真の向きの情報は、0x0112というIDに割り振られているので、このID以外はすっ飛ばします
  if (item.Id != 0x0112)
  {
   continue;
  }

  // IDが0x0112の時なので、向きの情報が取れる場所
  switch(item.Value[0])
  {
   case 1:// 不要(回転・反転なし)
    break;

   case 2:// 水平方向に反転
    break;

   case 3:// 時計回りに180度回転
    // 時計回りに180度回転しているので、180度回転して戻す
    rotation = System.Drawing.RotateFlipType.Rotate180FlipNone;
    break;

   case 4:// 垂直方向に反転
    break;

   case 5:// 水平方向に反転+時計回りに270度回転
    break;

   case 6:// 時計回りに90度回転
    // 時計回りに270度回転しているので、90度回転して戻す
    rotation = System.Drawing.RotateFlipType.Rotate90FlipNone;

    break;

   case 7:// 水平方向に反転+時計回りに90度回転
    break;

   case 8:// 時計回りに270度回転
    // 時計回りに90度回転しているので、270度回転して戻す

    rotation = System.Drawing.RotateFlipType.Rotate270FlipNone;

    break;

   default:    break;

  }

  // といった感じで、item.Value[0]の値で、どんな状態なのかが分かるのです。
  // あとは、この値を元に処理をしてあげればOK
  // 上記の3、6、8には正しくする処理を記載しましたので、参考にしてみてください

 }



 // 画像を複製して、回転を正す
 System.Drawing.Image rotated_image = (System.Drawing.Image)origin.Clone();

 // 複製する際のフォーマット(元の画像と一緒にする)
 System.Drawing.Imaging.ImageFormat format = origin.RawFormat;

 // オリジナルの画像から、欲しいものは奪えたので、閉じちゃう
 origin.Dispose();

 // 指定された角度だけ画像を回転する
 rotated_image.RotateFlip(rotation);

 // 回転を正したものを、指定のパスに保存
 try
 {
  rotated_image.Save("新たな保存先", format);
 }
 catch(Exception ex)
 {
  rotated_image.Dispose();
 }
 finally
 {
  rotated_image.Dispose();
 }
}

2016年1月28日木曜日

開発初心者がこれだけは知っておいた方が良いこと①

こんにちはSです!

前回、自己紹介でも書きましたが、わたしは7ヶ月前まで本当に何も知らず、
分からない事だらけでした。
(ブラウザって何?アマゾンって本屋さんじゃないの?!という状態でした。
本当にごめんなさい。。。)

そこで今回は「最初にこれを知ってたらもっとラクだったかも」と思うことを思い出しながらまとめます。

基本中の基本なのでベテランの方々は読み飛ばすか、
もしくは次に新人さんが入ってきたときに、こういうところにつまづくんだな~という参考にしてみて下さい。


◆勘違いポイント
わたしがはまった勘違いポイントです。
きっと誰でも最初に一度ははまるのではないでしょうか。。。?わたしだけ??

①JavaとJSは別物・・・
 先輩たちがJSといっているものはJava Scriptという言語のことであり、Javaとつきますが
 Javaとは完全に別物です。

②JSとjQueryも別物・・・
 「jQueryはJSで書くと何十行にもなるものを少ない行数で書けるようにまとめたライブラリだよ」
 と教わったので、わたしは「jQueryはJSの短い版でほとんど一緒なんだ!」
 という拡大解釈をしていましたが、書き方が違います。
 なのでjQueryオブジェクトをJSの書き方で動かそうとしても全く動きません。。。

◆最初のつまづきポイント
①{ }の中で定義した変数は{ }の外で使えない←当たり前

②分からないことがあってもどんなワードで検索すれば良いのか良く分からない
 →「やりたいこと C#」とかで調べてみるけどやりたいことの表現が適格でないと全然欲しい結果が返ってこない
 →もういっそ先輩に「こういうことがやりたいんですけど、なんてググったら良いですか?」と聞いた方が早い

③もともと用意されているメソッドと自分(の会社の人)が作ったメソッドの違いが分からない
 →オリジナルのメソッド名でググるけど何も出てこない。。。
 →オリジナルのメソッドはそのページ内、もしくは継承しているページのどこかで定義しています


◆先に知っておいた方が良いVisual Studioの機能
①Ctrl + スペース で携帯の予測変換みたいなことができます
 →ちょっと意味が分からないと思いますが、とりあえずやってみて下さい

②メソッドの上でF12を押すとそのメソッドを定義しているところに飛べる

③変数やメソッドの上でダブルクリックして少し待つと、同じ名前を使っているところの背景がグレーになります
わたしはせっかちすぎて1ヶ月くらい気づきませんでした



◆番外編(便利なショートカットキー)
営業からシステムに異動になり、色々と教えて頂く中でショートカットキーも教わり
非常に感動しました!
今までなんて非効率なことをしていたんだろう。。。

開発初心者の方はこれからバンバン開発をしていく上で、非常に業務効率があがると思うので
ぜひ使ってみてください♪

ステップ1 ~結構誰でも使ってる?~
Ctrl + C コピー
Ctrl + V ペースト
Ctrl + X 切り取り
Ctrl + A 全選択
Ctrl + S 保存
Ctrl + Z 戻る
Ctrl + Y 進む

ステップ2 ~知らなかったらすごく感動する~
Alt + Tab  画面の切り替え
田 + E   エクスプローラーを表示
田 +  →  画面の右半分に表示
田 +  ↑  最大化
田 +  ↓  最小化

他にも色々あるようですが、このへんがオススメです!
ベテランエンジニアの方々はきっともっと知ってるはずので聞いてみて下さい。





定数の新しい行です エラー

こんにちは山田です。

(ちなみに開発言語:C#の話)

本日もカタカタとプログラミングをしている中 
文字の置き換え(String.Replace)を行おうと思ったら見慣れないエラーが
 

「定数の新しい行です。」

ちょっとわからなくグーグル先生に聞いてみました。
どうやら調べてみると¥の文字に原因があるようでした。
 解決方法としては2パターン見つかりました↓

■解決方法①

 \を直接書かず
System.IO.Path.DirectorySeparatorChar; を使う
tempFileName1.Value.ToString().Replace("/", "System.IO.Path.DirectorySeparatorChar;");
■解決方法②
 "\"の前に@を付ける
tempFileName1Value.ToString().Replace("/", @"\");
■解決方法③

 \\と書く
tempFileName1.Value.ToString().Replace("/", "\\");
結局は方法②を取りました。

【Android】AppIndexingを実装してみた

こんにちは。エンジニアのKです。
アプリへの新しい導線口だけでなく、SEOにも効果があると言われているAppIndexingを
遅ればせながら実装してみました。

AppIndexingについて

ざっくり言うと、Google検索結果にアプリコンテンツへのリンクが表示されるようになります。
Cookpadさんの場合、こんな感じで表示されます。


アプリがインストールされていれば、アプリ内のコンテンツ(この場合「大根」レシピの検索結果画面)が、まるでwebページへの遷移のようにシームレスに行われます。
アプリがインストールされていない場合、Google Playストアのダウンロードページヘ遷移します。便利ですね。

アプリリンクの表示条件は?

実装にあたって、どんな挙動になるか、先駆者様のアプリで見てみようと思ったのですが、
なかなか上手く行かずに苦労しました。
AndroidはGoogleアカウントでログインしていなくても表示されるらしいのですが、なかなか表示されず。。
とりあえず、対象アプリをインストールしたGoogleカウントでログインしたら、表示されるようになりました。
※ Androidバージョンやブラウザアプリのバージョンにもよる違いもあるかもです。


AppIndexingを実装する

公式ドキュメントに従って実装していきますが、試行錯誤した点について補足していければと思います。
 サンプルコードは、公式ドキュメントにも出てくるandroid-deep-linkingプロジェクト(com.recipe-app)を使います。

 

インテントフィルタの追加

まず、アプリ内のコンテンツに直接遷移できるディープリンクをサポートする必要があります。
http://recipe-app.com/recipe/{recipeId}といったwebページでレシピ詳細を表示する機能があった場合、
同等の機能を持ったアプリのActivity(.RecipeActivity)に、以下の様なintent-filterを追加します。(AndroidManifest.xml)
        
            
                
                
                
                
                
            
            
                
                
                
                
                
            
        

HTTPスキームとカスタムスキームどちらかだけでもいいですし、両方設定してももちろん大丈夫です。
要は特定のURLでインテントが飛んだ時に、アプリが反応できるようになっていれば良いということですね。
Googleは実装手順が簡素になるということから、HTTPスキームを推奨しています。

ディープリンクのURIに対応する処理をActivityに実装

 intent-filterを追加したことにより、http://recipe-app.com/recipe/pierogi-poutineといったURLで.RecipeActivityが起動するようになります。
.RecipeActivityはレシピ詳細を表示するアクティビティですので、対象となるレシピIDが必要になります。
アプリ内遷移であれば、前画面から飛ばすintentにputExtraしてレシピIDを渡すのが一般的かと思いますが、
ディープリンクの場合、intent.getDataString()で取得できるURLをパースして、レシピIDを取り出して、後続の処理に渡すようにします。

    protected void onNewIntent(Intent intent) {
        String action = intent.getAction();
        String data = intent.getDataString(); // http://recipe-app.com/recipe/pierogi-poutine
        if (Intent.ACTION_VIEW.equals(action) && data != null) {
            String recipeId = data.substring(data.lastIndexOf("/") + 1); // pierogi-poutine
            // レシピ情報を取得して、表示する処理
            Uri contentUri = RecipeContentProvider.CONTENT_URI.buildUpon().appendPath(recipeId).build();
            showRecipe(contentUri);
        }
    }


ディープリンクをGoogleに知らせる

ここまでで、アプリがディープリンクに対応し、Googleの検索結果から直接アプリへ遷移できるようになりました。
あとは、対応したディープリンクをGoogleに教えて、検索結果に表示するようにしてもらいましょう。
教える方法は、
  1. AppIndexing APIをアプリに実装
  2. 対応するwebページのmetaタグにディープリンクを指定
  3. sitemap.xmlに記述する
があります。2,3はアプリに対応するwebページを持っている前提となります。
できれば全て対応したほうが、インデックスされやすくなりそうですね。

また、Googleにディープリンクを知らせる際のURLは、以下の様なフォーマットで記述します。
android-app://{package_id}/{scheme}/{path}
上記で対応したディープリンクの場合、
android-app://com.recipe-app/http/recipe/pierogi-poutine
android-app://com.recipe-app/recupe-app/recipe/pierogi-poutine
となります。

AppIndexing APIで知らせる

公式ドキュメントにあるとおり、build.gradleとAndroidManifest.xmlに設定を追加し、ActivityのonStart(), onStop()でAPIを実行します。
公式ドキュメントにあるコードでは、タイトルとwebのURL、アプリのURLを設定していますが、
以下のように書くと、概要(description) も合わせて送信できるようになります。
※descriptionがどのように評価され、利用されるかは不明

    mClient.connect();

    String title = "タイトル";
    String description = "概要";
    Thing object = new Thing.Builder()
        .setType("http://schema.org/Thing")
        .setName(title)
        .setDescription(description)
        .setUrl(APP_URL)
        .setId(WEB_URL)
        .build();
    Action viewAction = new Action.Builder(Action.TYPE_VIEW).setObject(object).build();
    AppIndex.AppIndexApi.start(mClient, viewAction);

タイトルや概要にマルチバイト文字が含まれる場合、URLエンコードする必要は無いのかな?と迷いましたが、エンコードは不要でした。
公式ドキュメントのApp Indexing API 呼び出しをテストするで見た時、コンソールに文字化けして表示されますが、
リリース後にSearch ConsoleでFetch as Googleで見たところ、正常に日本語が認識されていました。


Webページのmetaタグで知らせる

http://recipe-app.com/recipe/pierogi-poutineのheadタグ内に、以下のmetaタグを追加します。

<html>
<head>
...


...
</head>
...
</html>

sitemap.xmlで知らせる

http://recipe-app.com/recipe/pierogi-poutineの要素にlink要素を追加します。
...

  http://recipe-app.com/recipe/pierogi-poutine
  
  

...


以上で実装編は完了です(長い)。
次回はGooglePlay DeveloperConsoleやSearchConsoleで必要となる設定についてまとめられたらと思います。

まとめました => 【Android】AppIndexingを設定してみた




2016年1月27日水曜日

GoogleのAMP(Accelerated Mobile Pages)ってすごいの?

AMP(Accelerated Mobile Pages)とは・・・


Z-MENです。
どうも。

昨年夏頃?からモバイルやSEO界隈でAMPの話題がすごく盛り上がっていて、
モバイル担当としてもやはり気になるところなので一度情報を整理してみたいと思います。

自分の勉強がてらではありますが、どなたかの参考になれば幸いです。
AMPとは、からAMPの実装・確認までまとめてみます。

AMP(Accelerated Mobile Pages)とは?

AMPはAccelerated Mobile Pagesの略称です。
GoogleとTwitterが共同で立ち上げたAMPプロジェクトのオープンソースらしいです。
簡単に言うとAMPに対応した記事コンテンツをGoogle側が勝手に読み取り、キャッシュして、
超高速に優先表示してくれます。モバイルの場合のみ出てくるようですが、カルーセル形式でずらっと並べてくれます。

去年末くらいからモバイルで検索した際に、一部記事がカルーセルで表示されるようになりましたが、あんな感じのイメージで、表示が超高速になる、という感じです。

【g.co/ampdemo】でAMPをデモ体験

Googleさん、ちゃんとデモも用意してくれていて、Googleの検索窓に『gco/ampdemo』といれると
AMPのデモ表示モードに切り替わります。ほんと爆速です。


 AMPの実装について

AMPの実装方法を見てみましょう。
GitHubにもあるんですが、全部英語でオエッとなるかたは参考になれば。

AMPは専用のjsライブラリとbilerplate(いけてるテンプレみたいの)で動くとのこと。
超シンプルに書くとこんな感じになりますと。

  
    Hello, AMPs
    
    
    
    
    
  
  
    

Welcome to the mobile web

 

マークアップ上の注意点としては、

    • <html>タグを<html amp>と書く?
    • <head> 内に<style>body {opacity: 0}</style><noscript><style>body {opacity: 1}</style></noscript>をいれる
    • <head>閉じ直前にを<script async src="https://cdn.ampproject.org/v0.js"></script>をいれる
    • 画像を入れるときはこんな感じ<amp-img src="welcome.jpg" alt="Welcome" height="400" width="800"></amp-img>
    とかとか、基本はこんな感じなのですが、普通にHTMLでページ作ればOKというわけでもなさそうです。
    公式のGetStartにいくつか注意事項があるので貼っておきます。
    AMPプロジェクト公式
    AMP GitHub

    日本語版の導入ガイドも発表されたようです。
    AMP日本語版導入ガイド

     AMPの条件・制約 

    AMPには、爆速を得られる代わりにいくつか制約があります。
    この制約がやや影響が大きく、導入できない方も多いかもしれません。

    1. AMPのランタイムはAMPのCDNから固定のURLで配信
    2. Javascriptが使えない(JSON-LDのみ)
    3. 画像・動画は大きさの固定指定が必要
    4. 広告はiframe経由で表示
    5. フォーマットを遵守
    6.  link要素はrel:canonical以外禁止
    7. ほかimgとかformとかinputタグも使えないかも
    とのこと。これ特に②がでかい、トラッキングができない・・・。
    『AMP実装したから効果が楽しみだぜー!』と思っても効果の程がわからない・・・
    そしてどうもレスポンシブにもうまく対応してない模様。。。厳密にはレスポンシブの実装方法による、ということででしょうか。ちゃんとCSSとかでdevicewidthで判別してればいいんでしょうが、jsでUserAgentみて~とかやってるとアウトなんでしょうね。
    レスポンシブを推奨しておきながらレスポンシブでは使えないかもってどうなのよ。
    そしてとどめの⑥⑦・・・まじか。
    とにかく新しいものやっとけ!と飛びつかずにGoogleが修正やら本腰入れた公表をするまでは
    いったんステイが間違いないかも、が現時点でのわたしの見解です。


    2016.02.03追記
     広告とGAについては対応されることが発表されたようですね。
     まずは最低限の機能は揃えてくれた、というかんじでしょうか。他のアクセス解析が
     使えないのは相変わらず痛いんですが・・・。
    AMPが広告とGoogleアナリティクスをサポート開始

     AMPの確認方法

    先日SearchConsoleでAMPが確認できるようになりました、とアナウンスがありました。
    とりあえず実装してみた!というかたはいてみましょう。
    公開しなきゃわからんよ、ってことね・・・。
    Googleウェブマスターブログ:Search Console における AMP エラー レポートのプレビュー 

     終わりに

    GoogleのAMPの説明を直接聞いたり様々な記事に目を通したりしてきましたが、所感として、モバイルフレンドリーの基準として表示スピードがいよいよ本格導入されるか?な話もあり、AMPを通してモバイルでの表示スピードに対するGoogleの本気度みたいなものは感じました。