アラのアラアラしい日記

こっそりかいてます

androidでBitmapを縦横比を維持しながらスケールする方法

こんにちは!メガネ萌えする人です!
今回はandroidネタです。

ビデオのサムネイルをBitmapで取得した時の表示のさせ方について、若干はまったのでメモです。
サムネをレイアウトの中で3:4の比率で表示させようとした時に、思ったように拡大縮小されなかったんですね〜
ただ、調べていると色々な方法があるようなので、その中の一つとして見てもらえればと。

fileName = "***動画ファイル名***"

// サムネイルをBitmapとして取得
Bitmap bmp = ThumbnailUtils.createVideoThumbnail(CommonUtils.getAvailableDirectory() + fileName, MediaStore.Video.Thumbnails.MINI_KIND);

// 作られたサムネイルから横幅とそれに応じた高さを指定
int dispWidth = bmp.getWidth();
int dispHeight = dispWidth * 3 / 4;

// 元のサイズでBitmap作成
bmp = Bitmap.createBitmap(bmp, 0, 0, dispWidth, dispHeight, null, true);

// デバイスの画面サイズを取得
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);

// スケールさせたい大きさを指定
int scaleWidth = size.x / 2;
int scaleHeight = scaleWidth * 3 / 4;

// 上で指定した大きさにする為にLayoutParamsを指定
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(scaleWidth, scaleHeight);

// 指定したparamsをセットしてokomeThumbViewにBitmap表示
okomeThumbView.setLayoutParams(params);
okomeThumbView.setImageBitmap(bmp);

BitmapクラスにはcreateScaledBitmapというメソッドも存在するのですが、
機種によって勝手にトリミングされたりして思ったようにサムネイルが取得出来ない場合がありました。

また、最初からscaleWidthscaleHeightcreateBitmapを実行すると、
今回の場合はscaleWidthをデバイスの画面サイズから作っている為、
元のbmp.widthがscaleWidthよりも小さい場合にエラーが起こります。(これも機種に依存するエラーです。)

それにしても圧倒的javaアレルギーだった私ですが、androidを始めてからjavaアレルギーがなくなった気がします。
個人的にはiOSよりもandroidの方が自由度が高いので開発は楽しかったかなーという感想です。
android studioxcodeがもっと仲良くなって同じ仕様になってくれたら嬉しいですねww (ショートカットとか)

AVAssetImageGeneratorから取得した動画のサムネイル(UIImage)が撮影時とサイズが違ってしまう問題の解決法

こんばんわ!一昨日の晩御飯が思い出せない系エンジニアです。
objective-cを「おぶしー」って呼んでいたらチャラいって言われました。

そんな感じで、今回ハマったのはAVAssetImageGeneratorから動画のサムネイルを取得したあとに、それをUIImageで画像として表示するところで、
なんだか撮影していた時と表示される画像のサイズが違ったのでその解決法を書きます。

私が遭遇した現象としては、以下のような感じです。
f:id:wknar0311:20150531115654p:plain AVFoundation Frameworkを使用しているのですが、この撮影範囲とiOSカメラの撮影範囲が違う為、
画像に変換した時に撮っていた時と違う表示のされ方をします。
見てくださいよこの可哀想なカーネルサンダース。
( というかAVFoundationで撮影している時点で全体の画像を持っているんですね。)

色々調べていたんですがどれも理想通りにいかなかったので、
以下のようにしました。

// サムネイル作成
AVURLAsset *asset = [AVURLAsset URLAssetWithURL:[videoFile toURL] options:nil];
AVAssetImageGenerator *gen = [[AVAssetImageGenerator alloc] initWithAsset:asset];
gen.appliesPreferredTrackTransform = YES;
CGImageRef image = [gen copyCGImageAtTime:CMTimeMakeWithSeconds(0.0, 600) actualTime:nil error:nil];
UIImage *thumb = [[UIImage alloc] initWithCGImage:image];
CGImageRelease(image);

NSString *attr = [[NSString alloc] initWithFormat:@"okomeView%d", i];

// ここでサムネイルの余計な部分を切り取る
[[self valueForKey:attr] setContentMode:UIViewContentModeScaleAspectFill];
[[self valueForKey:attr] setClipsToBounds:YES];
[[self valueForKey:attr] setImage:thumb];

取得したサムネイル画像からUIViewContentModeを利用して見た目を変えてしまうという方法です。

UIViewContentModeScaleAspectFillで元の縦横比を維持したまま、指定した範囲内で最大に画像を表示します。
そのあと、setClipsToBoundsYESにすることではみ出した部分を非表示にします。
これで撮影した部分のみのサムネイルが表示されます。

ただ、切り取り済みの画像を表示するのと違い、表示毎に大きい画像を持ってきてから見た目を変えたり非表示にしているので
メモリ使用量を考えると大量のサムネイルを表示したい時等は向いてないかもしれないです!

UIViewContentModeの使い方は以下から見れます。
UIView Class Reference

それではちゃんと歯磨きして寝てくださいね!

objective-cのループ内での表示とか非表示とか

こんにちは!okomeが好きな人です。

相変わらず仕事でobjective-cを触る毎日ですが、
地味に時間がかかってしまったのでメモです。

Storyboardを使って画像を表示するような場合、

@property (weak, nonatomic) IBOutlet UIImageView *okomeView;

このように変数を定義して、

UIImage *okomeImage = [UIImage imageNamed:@"okome.png"];
self.okomeView.image = okomeImage;

と、指定した変数に対して画像をセットするのがありがちだと思いますが、

例えば3つの画像を並べて表示したい場合、以下のように変数を定義して、

@property (weak, nonatomic) IBOutlet UIImageView *okomeView0;
@property (weak, nonatomic) IBOutlet UIImageView *okomeView1;
@property (weak, nonatomic) IBOutlet UIImageView *okomeView2;

「よしループで表示だ!」と思ったらobjective-cの場合は変数のループってどうやってまわすんだってなってしまったんですよね。。。

そこで、調べてみると表示方法にもいくつか種類があることを知りました。
先程の画像の表示を違う方法で書くと以下のようになります。

  [[self okomeView] setImage:okomeImage];

この表示方法を利用すると、以下のようにループ文を書くことが出来ます。

for (int i=0; i<3; i++) {
  NSString *attr = [[NSString alloc] initWithFormat:@"okomeView%d", i];
  [[self valueForKey:attr] setImage:okomeImage];
}

流れとしては、最初にokomeView{i}になるような文字列をセットして、
それを利用して先程の表示方法を書きます。

この方法を利用すると以下のようなhiddenなども指定することが出来ます。

  [[self okomeView] setHidden:YES];

set系の関数むちゃくちゃ多いので色々出来そうですね。

もっと良い書き方とかを知っている方は教えてください!

objective-cでdelegateを使ってmodalのtextareaつくるよ

こんばんわ!
天一はこってりしか食べない人です。

最近会社でのポジションがウェッブエンジニアからiOSエンジニアになったのですが、
objective-cxcodeの文化ってありますね!初めてpython触った時のインデントみたいな!(雑)

という訳でmodalで出てきたウィンドウからテキストを入力して、
modalを閉じたら元の画面に入力したテキストが表示されてるっていうのを作るコードが
意外と分かりやすいマニュアルとか参考が少なかったのでメモしておきます。

元の画面名がFirstViewController, modal画面名がModalControllerです。

●FirstViewController.h

#import <UIKit/UIKit.h>

@interface FirstViewController : UIViewController {
}
@end

FirstViewController.hに関してはデフォルトのままで大丈夫です。

●FirstViewController.m

#import "FirstViewController.h"
#import "ModalController.h"

@interface FirstViewController ()
@property (weak, nonatomic) IBOutlet UILabel *viewLabel;
@end

@implementation FirstViewController

- (void) viewDidLoad {
    [super viewDidLoad];
}

- (void)sendOkome:(NSString*) str {
    self.viewLabel.text = str;
    [self dismissViewControllerAnimated:YES completion:nil];
}

- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    NSString *genmaiText = self.viewLabel.text;
    ModalController *mCon = [segue destinationViewController];
    mCon.mydelegate = self;
    mCon.genmai = genmaiText;
}
@end

viewLabelはModalInputControllerで入力したテキストを表示する部分です。
ModalControllerに送りたい(ModalControllerインスタンスを使いたい)ので、初めにModalController.hをimportしておく必要があります。 prepareForSeguemethodでボタンが押された時にgenmaiとしてModalControllerにテキストを送ります。

●ModalController.h

#import <UIKit/UIKit.h>

@protocol ModalControllerDelegate
- (void)sendOkome:(NSString*)str;
@end

@interface ModalController : UIViewController <UITextViewDelegate> {
}
@property (nonatomic, weak) IBOutlet UITextView* textOkome;
@property (weak, nonatomic) IBOutlet NSString *genmai;
@property (nonatomic, retain) id mydelegate;

@end

受け取るデータの変数やdelegateの設定を行います。

●ModalController.m

#import "ModalController.h"

@interface ModalController ()
@end

@implementation ModalController
@synthesize textOkome, mydelegate, genmai;

- (void)viewDidLoad {
    [super viewDidLoad];
    textOkome.delegate = self;
    [textOkome becomeFirstResponder];
    textOkome.text = genmai;
}

- (BOOL) textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)textGenmai {
    if ([textGenmai isEqualToString:@"\n"]) {
        [textView resignFirstResponder];
        return NO;
    }
    return YES;
}

- (IBAction)pushBtn:(id)sender {
    if ([self.mydelegate respondsToSelector:@selector(sendOkome:)]) {
        [self.mydelegate sendOkome:textOkome.text];
    }
}
@end

受け取った値をtextview内に表示し、textview内にあるテキストをdelegateで取得しています。
最後にFirstViewController.mのsendOkomeメソッドを呼び出してそこでmodalウィンドウを閉じています。

試行錯誤で出来たものなので美しくないですがつんだら試してみてください。
説明がまじで下手くそなので後日追加するかもしれません。

screenで絵文字が出ない人へメッセージ

Macのターミナルでtmuxは絵文字が出るのにscreenだと出ない!!
screenから抜けると出るのに!!

と言っているみなさん、brew info screenしてみてインストールされてなかったらbrew install screenしてみてください。インストールしてたら、brew update screenしてみてください。
そんで、ターミナル再起動してみてください。

きっと幸せになれます。
私が幸せになりました。

vimを使っている人はみんなctagsで幸せになれる権利を持っている

こんにちは!飲み過ぎてよくお腹を壊す人です。

結構長い間vimを使って開発をしているのですが、じょうよわなのでこの間初めて知りました。

開発中にどこから呼ばれてるのか分からないクラスやモジュールとかをgit grepしてたんですけど、
ctagsが超便利すぎて泣いて喜んだのでメモです。

まずインストールです。macの場合はctagsというコマンド自体は最初から入っていますが、
バージョンが古いのか、なんだか仕様が若干違うのでhomebrewでinstallし直すと良いと思います。

$ brew install ctags

設定ファイルは.ctagsに書きます。

ctagsのインストールが完了したら、"tags"というindexファイルを作成します。
ソースのあるディレクトリで以下のようなコマンドを入力します。

$ ctags -R

tagsというファイルが存在していたら成功です。
また、jsファイルはデフォルトだと

ctags: Warning: ignoring null tag in XXXX.js

っていうエラーが出るので、
gist.github.com
こちらのリンク内の内容を.ctagsに追加すると、jsファイルもtagsに含めてくれると思います。

あとはvimで開いているソースコードの中で、
調べたいワードにカーソルが乗っている状態でCtrl + ]をすると、
対象のファイルが出てきます。(カーソルも名前の一番先頭にあります。)

また、デフォルトの設定だと、今までの開いていたファイルの上に出てきちゃうので(:b#で戻れますが)これがなかなか厄介です。

なので以下の設定を入れると、新しいタブでファイルが出てきます。

map <C-]> :tab split<CR>:exec("tag ".expand("<cword>"))<CR>

gist.github.com
こちらを参考にさせて頂きました。

これでより幸せな開発環境を手に入れることが出来ました。幸せです。

ドキュメントはこちらです。
CTAGS

git statusでsyntax checkをしよう

こんばんわ!
膝に痛みを感じた瞬間に痛風だと思った情弱です!

最近は少しだけPHPを触るようになってファッションPHPヤローみたいな生活をしている訳ですが、
Rubyに体が慣れてしまってどうしてもお昼ご飯を忘れたおばあちゃんのノリでセミコロンを忘れるので、

git statusの時についでにsyntax chackするように.gitconfigにaliasを追加しました。
結構ごりごりです。

gist21c13200bae7d489896b

内容としては、git status --shortで編集済みのファイルパスを取得して、
その中でphp拡張子がついているファイルがあればphp -lで文法チェックをしている流れです。

PHPの場合はphp -lで文法チェックができますが、コマンドを打っているだけなので他の言語でも使えます。
Rubyでもruby -wcとかで同じように表示されると思います。

ただ、.gitconfigにshellscriptを書く場合は記号をエスケープする必要があるので
普通に新しいファイルに同じ内容を書いて、それをaliasで読み込む方が正直やりやすいです。

[alias]
  st = "!f(){ . git_syntax_check.sh };f"

こんな感じ

ただ、設定ファイルをこれ以上増やすのが嫌だったので.bashrcに関数を追加してその関数を
.gitconfigから呼ぼうとして色々試してみたのですがなかなか上手くいかなかったのでこの方法にしました。

.gitconfigのaliasから他のshellscriptファイルの関数を呼ぶナイスな方法を知っている方がいたらぜひ教えてくださいスリスリ