カテゴリーアーカイブ Java

asaba 著者:asaba

【anadroidJava】続・ExifInterfaceで画像の向きを変える

ExifInterface記事の三回目になります。

前回はExifInterfaceクラスを使って画像の向きを取得していたと思いますが、今回はその画像の向き情報を使って

実際に向きを正しい位置に変えて表示するコードを書いてみようと思います。

まず、通常通りメソッドを書きますが、ここでの引数は前回取得した画像の向き情報が入っている変数locatateになります。

<pre>public void replace(int locatate,Bitmap bitmap){
//ここに処理を書きます
}</pre>

二つ目の引数は、このメソッドを叩く前に取得したBitmapのデータになります。

つまり、まだ正しい向きに修正されていない画像が変数に入っている状態ですね。

ここで実際に向きを変える工程に入りますが、まず最初にMatrixクラスをnewします。

画像を動的に編集する手段は枚挙に暇がありませんが、このMatrix拡大・縮小・回転など画像に関するアクションを全て揃えており

androidで画像をいじるときはよく重宝して使っています。

このmatrixを使う前にswitch文を使って角度別に処理を分けていきたいと思います。

case別で90,180,270とありますが、これは前回のORIENTATION_ROTATE_〇〇に合わせて指定した角度に修正するように

制御しており、引数のlocatateが90ならば一番最初のcase90で処理を受けて加工されていきます。

ORIENTATION_ROTATE_〇〇なんてわかりにくいという方も見受けられますが、慣れてくれば「ああこの角度に修正すればいいのね。」

みたいに感覚で慣れてくると思います。

public void replace(int locatate,Bitmap bitmap){
<pre>    int imageWidth = bitmap.getWidth();
    int imageHeight = bitmap.getHeight();
    Bitmap bitmap2;
    // Matrix インスタンス生成
    Matrix matrix = new Matrix();</pre>
<pre>     switch (locatate) {
        case 90:
            matrix.setRotate(90, imageWidth/2, imageHeight/2);
            // 90度回転したBitmap画像を生成
            matrix.postScale(0.3f, 0.3f);// 0.5倍調整
            bitmap2 = Bitmap.createBitmap(bitmap, 0, 0,
                    imageWidth, imageHeight, matrix, true);
            imageView.setImageBitmap(bitmap2);
            break;
        case 180:
            matrix.setRotate(180, imageWidth/2, imageHeight/2);
            // 90度回転したBitmap画像を生成
            matrix.postScale(0.3f, 0.3f);// 0.5倍調整
            bitmap2 = Bitmap.createBitmap(bitmap, 0, 0,
                    imageWidth, imageHeight, matrix, true);
            imageView.setImageBitmap(bitmap2);
            break;
        case 270:
            matrix.setRotate(270, imageWidth/2, imageHeight/2);
            // 90度回転したBitmap画像を生成
            matrix.postScale(0.3f, 0.3f);// 0.5倍調整
            bitmap2 = Bitmap.createBitmap(bitmap, 0, 0,
                    imageWidth, imageHeight, matrix, true);
            imageView.setImageBitmap(bitmap2);
            break;
            default:
                matrix.postScale(0.3f, 0.3f);// 0.5倍調整
                bitmap2 = Bitmap.createBitmap(bitmap, 0, 0,
                        imageWidth, imageHeight, matrix, true);
                imageView.setImageBitmap(bitmap2);
    }
}</pre>
}

三日間ExifInterfaceのお話をしましたがまだまだ作っているアプリにも改善の余地があるのでまた画像周りを

いじることがあれば記事に載せるかもしれません。

あと前にも書きましたが、androidStudioのgradleや実機のスペックが人によって違ってくるのでここで紹介した

設定に合わせる必要は全くないのでそこは皆さんの環境に合わせてください。
 

  • この記事いいね! (0)
asaba 著者:asaba

【androidJava】exifInterface:exif情報の取得

前回はexifInterfaceを使うためのgradleの設定をしたので、今回いよいよ実際にコードを書いて説明していきたいと思います。

 

前述のサポートにより、画像を扱うアプリではInputstreamを使うことでExifInterfaceがぐっと使いやすくなりました。

これにより、受け取ったURIから直接画像のexif情報を取得できるようになりました。

exifInterfaceをnewする前にInputStreamを初期化しておきましょう。

<pre>InputStream in = null;</pre>

ここでようやくexifInterfaceクラスを使うことが出来ます。次に向き(orientation)の取得ですが、ここではexifInterfaceクラスの

メソッドgetAttributeIntを使って向きを取得します。getAttributeIntの使い方ですが、取得する情報のタグを指定して値を取得する.

だけで使うことができます。例えば、何の変哲もない修正していない画像を取得する場合はExifInterface.ORIENTATION_NORMALを

指定します。

<pre>int orientation = exifInterface.getAttributeInt(
        ExifInterface.TAG_ORIENTATION,
        ExifInterface.ORIENTATION_NORMAL);</pre>

無事に取得できれば後はこのorientationを変更したい角度に合わせてswitch文にセットすれば対象の画像のexif情報を

取ってくることができますね。

<pre>switch (orientation) {
    case ExifInterface.ORIENTATION_ROTATE_90:
        rotation = 90;
        break;
    case ExifInterface.ORIENTATION_ROTATE_180:
        rotation = 180;
        break;
    case ExifInterface.ORIENTATION_ROTATE_270:
        rotation = 270;
        break;
}</pre>

ExifInterface.ORIENTATION_ROTATE_〇〇はぱっと見分かりづらいですが、ものすごくかみ砕いて「この角度にすれば正しい位置になるよ」

と解釈しておけばその内慣れてくると思います。

次回はこのメソッドで取得したrotation変数を使って実際に向きを変えて表示してみましょう。

断片的なコードだけでは戸惑うかたもいると思うのでメソッド含めた全コードを載せておきます。


public class sample extends AppCompatActivity {

private ImageView imageView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sample);
imageView = findViewById(R.id.image_view);
int locatate;
int rotation = 0;
Bitmap bitmap;
Uri uri;
Intent intent = getIntent();
uri = intent.getParcelableExtra("imageUri");
try {
bitmap = MediaStore.Images.Media.getBitmap(getContentResolver(), uri);
//画像の向きを取得
getBmp(uri,rotation);
} catch (IOException e) {
e.printStackTrace();
}
}
public int getBmp(Uri uri,int rotation) {
  InputStream in = null;
  try {
    in = getContentResolver().openInputStream(uri);
    ExifInterface exifInterface = new ExifInterface(in);
    //緯度経度を取得
    getLatlong(exifInterface);
   //画像の向きを取得
    int orientation = exifInterface.getAttributeInt(
    ExifInterface.TAG_ORIENTATION,
    ExifInterface.ORIENTATION_NORMAL);
   switch (orientation) {
     case ExifInterface.ORIENTATION_ROTATE_90:
     rotation = 90;
     break;
     case ExifInterface.ORIENTATION_ROTATE_180:
     rotation = 180;
     break;
     case ExifInterface.ORIENTATION_ROTATE_270:
     rotation = 270;
     break;
  }
    System.out.println(rotation);
  } catch (IOException e) {
    e.printStackTrace();
  } finally {
    if (in != null) {
      try {
        in.close();
      } catch (IOException ignored) {
    }
  }
}
     return rotation;
}
}

 

 

  • この記事いいね! (0)
asaba 著者:asaba

【androidJava】exifInterfaceの初期化

長い間exifInterfaceの使い方がおぼろげだったのですが、理解が深まってきたところで小出しで記事をかくことにしました。

今回はチュートリアルみたいな感じでいきなり実践はせず設定の部分だけアウトプットすることにしました。

 

本題ですが、このexifInterfaceというのは1994年に富士フィルムが開発した画像のデータを含んだ形式のことを指します。

このデータを使うことで、角度を修正したりリサイズをしたり写真を撮った位置所法を取得できたりと画像を扱うプログラム

ならほぼ網羅することができます。

 

このExifInterfaceはapiレベルが24以上と推奨されていましたが

Support Library 25.1.0 のリリースに合わせて新たに ExifInterface Support Library が追加されたので、

apiが24以下の端末でも利用できるようになりました。

 

まずはgradleでminSDKVersionが実機より高くないか確認して、高かった場合はその実機のAPIより低くする必要

があります。

例えば、使用している実機のapiが22で、minSdkVersionが24だった場合はこのままでは怒られて使用できないので

minSdkVersionのapiレベルを下げましょう。

 

しかしminSDKVersionが低すぎても警告を受ける場合があるので今実機として使っているandroidのapiレベルが同じになるように

合わせてgradleのminSDKVersionを調整してみてください。

例えば実機のapiレベルが22の場合は


<span style="font-size: 14pt;">minSDKVersion 16 ×</span>

 


<span style="font-size: 14pt;">minSDKVersion 22 〇</span>

 

念のためにぴったりにしておいたほうが間違いないのでw

 

マニフェスト部分にもしっかりとパーミッションを書いておきましょう。

<pre><uses-sdk android:minSdkVersion="22" /></pre>

 

これでexifIterfaceを使う下準備は終わりました。次回は実際にexifInterfaceを使って向きを取得してみましょう。

 

 

 

 

  • この記事いいね! (0)
asaba 著者:asaba

【androidJava】カメラ・ギャラリーを同じダイアログに入れて選択させる方法

javascriptでできなかったカメラとギャラリーが同じダイアログに入った機能があっさりできてしまいました。

この場合はコードを先にみてしまった方が早いと思うので端折ります。

//一番最初にカメラ・ギャラりーを識別するための定数を記述しておく
private static final int REQUEST_CHOOSER = 1000;
private void showGallery() {

    //カメラの起動Intentの用意
    String photoName = System.currentTimeMillis() + ".jpg";
    ContentValues contentValues = new ContentValues();
    contentValues.put(MediaStore.Images.Media.TITLE, photoName);
    contentValues.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
    m_uri = getContentResolver()
            .insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues);

    Intent intentCamera = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    if (intentCamera.resolveActivity(getPackageManager()) != null) {
        // Create the File where the photo should go
        File photoFile = null;
        try {
            photoFile = createImageFile();
            System.out.println(photoFile);
        } catch (IOException ex) {
            // Error occurred while creating the File
            Log.d("Error", ex.getMessage());
            Toast.makeText(getBaseContext(), ex.getMessage(), Toast.LENGTH_SHORT).show();
        }
    }
    // ギャラリー用のIntent作成
    Intent intentGallery;
    if (Build.VERSION.SDK_INT &amp;amp;amp;lt; 19) {
        intentGallery = new Intent(Intent.ACTION_GET_CONTENT);
        intentGallery.setType("image/*");
    } else {
        intentGallery = new Intent(Intent.ACTION_OPEN_DOCUMENT);
        intentGallery.addCategory(Intent.CATEGORY_OPENABLE);
        intentGallery.setType("image/jpeg");
    }
    Intent intent = Intent.createChooser(intentCamera, "画像の選択");
    intent.putExtra(Intent.EXTRA_INITIAL_INTENTS, new Intent[] {intentGallery});
    startActivityForResult(intent, REQUEST_CHOOSER);
}
</pre>
<pre>private File createImageFile() throws IOException {
    // Create an image file name
    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
    String imageFileName = "PNG_" + timeStamp + "_";
    File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
    File image = File.createTempFile(
            imageFileName,  /* prefix */
            ".png",         /* suffix */
            storageDir      /* directory */
    );
    // Save a file: path for use with ACTION_VIEW intents
    mCurrentPhotoPath = Uri.parse(image.getAbsolutePath());
    return image;
}</pre>
<pre>

カメラ・ギャラリーから取得した画像をonActivityResultで受け取って処理をします。

 

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);

    if(requestCode == REQUEST_CHOOSER) {
  //ここに書きたい処理を書く</pre>
<pre>  resultUri = (data != null ? data.getData() : m_uri);</pre>
<pre>  } 
} 

二番目の引数と定数REQUEST_CHOOSERが同じ値なので、if内に処理をしていきます。

上記の例のようにgetDataでuriを取得をすればもうご自由にuriを使うことが出来ますね。

  • この記事いいね! (0)
村上 著者:村上

【Android】ActivityのメソッドをAdapterで呼び出す方法

ちょっと悩んだので、今後のためにまとめ。
Adapter内で、Activity に記述したメソッドを呼び出す方法です。
Interface を使用しています。

なお、今回参考にしたのはこちらのサイトです。

Android – Call Activity method from adapter – Stack Overflow
https://stackoverflow.com/questions/12142255/call-activity-method-from-adapter

2つ目のアンサーに書かれている内容を参考にしました。

 

では早速コードを書いていきます。
まず、インターフェースを作成します。
で、Adapter で呼び出したい& Activity に追加するメソッドを定義します。

public interface [インターフェース名] {
    void test();
}

なお、この時指定するのは、メソッド名・引数・戻り値のみで、処理内容は記述しません。

次に、Activityに、上で作成したインターフェースを、下記のように implements で実装します。

public class [アクティビティ名] extends AppCompatActivity implements [インターフェース名] {

Android Studioを使用している場合、上記のようにインターフェースを追加すると、メソッドをオーバーライドして!というエラーになるので、Alt+Enter で言われるがままにメソッドを追加します。
なお、追加するメソッドは下記のとおりです。
最初に @Override が付くのにお気を付けください。

@Override
public void test() {
    // メソッド内で行いたい処理
}

そして Adapterに、下記を追加します。

public [アダプター名] extends BaseAdater{
    private [インターフェース名] listener;

    public [アダプター名]([インターフェース名] listener){
        this.listener = listener;
    }
}

で、あとは下記のように使いたいタイミングでメソッドを呼び出すだけです。

listener.test();

 

で、私がハマったのが、Adapterでの定義で、継承しているのが BaseAdapter ではなかったので、上記の記述では動かなかったんですよね…。
なので、下記のように修正。
まず、Adapter。

private int mResource;
private List<EntryListItem> mItems;
private LayoutInflater mInflater;
private Context mContext;
private ListViewInterface listener;

public [アダプター名](Context context, int resource, List<EntryListItem> items, [インターフェース名] listener) {
    super(context, resource, items);

    this.mContext = context;
    mResource = resource;
    mItems = items;
    mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    this.listener = listener;
}

一部必要ないものも混じっていますが、それはスルーしてください。

次は、このままでは、Activitiy でエラーになるので Adapter を new している所を修正します。

[アダプター名] adapter = new [アダプター名](getBaseContext(), R.layout.[レイアウトファイル名], item, this);

最後の this がインターフェースを指しています。
ここが分からず、少し悩みました…。

 

以上、Activity内のメソッドをAdapterで呼び出す方法でした。
もしかしたら、ListViewを扱うときなどに使うことがあるかもしれませんので、その際は是非ご活用ください。

  • この記事いいね! (0)
asaba 著者:asaba

【androidJava】intentでbitmapを遷移させる方法

androidではintent機能を必ずといっていいほど使います。

値を遷移させたりカメラで撮影画面に映ったりなど様々な場面で使うことが出来ます。

今回は画像をintentに持たせて遷移先でやり取りをしたかったのですが!!! FAILED BINDER TRANSACTION !!!というエラーに

ひっかかり見事に怒られてしまいました。

 

どうやらiphoneやandroidで撮影した写真や画像は加工せずに送ると重すぎるためにファイルとして扱うには不適切と見なされ

拒否されてしまうみたいです・・・。

 

少しまわりくどいですが、uriでintentに持たせbitmapに加工するという手段に落ち着きました。

とりあえず遷移先でuriを宣言していればどれだけ重い画像でも持ってこれるので同じような内容でハマっている

方は試してみてください。

 

最後にコードを掲示しておきます。

 

遷移前

<pre>Intent intent = new Intent(this, EditActivity.class);
intent.putExtra("imageUri", uri);
startActivity(intent);</pre>

 

遷移先

<pre>public void getBmp(){
    Intent intent = getIntent();
    Uri uri = intent.getParcelableExtra("imageUri");
    System.out.println(uri);
    try {
        Bitmap bitmap = MediaStore.Images.Media.getBitmap(getContentResolver(), uri);
        imageView.setImageBitmap(bitmap);
    } catch (IOException e) {
        e.printStackTrace();
    }
}</pre>

 

遷移先で変数uriに“imageUri”キーを持つ値を持ってきています。

tryの中ではMediaStoreに問い合わせてuriをBitmapに変換しているところです。(ざっくりですみません)

 

  • この記事いいね! (0)
村上 著者:村上

【Android】ListView要素にボタンを追加すると要素自体のクリックイベントが呼ばれない

長いタイトルですみません。
Android アプリでカスタム ListView を利用しているとき、List の要素に Button(ImageButton)を追加したところ、要素自体のクリックイベントが呼ばれなくなったので、その対処法について。
実はこれ、以前も経験していて対処法があることは覚えていたのですが、その内容は失念していたので、備忘録としてまとめ。

なお、参考にさせていただいたサイトはこちらから。

ボタン付きのListViewを実装してみる – Qiita
https://qiita.com/maromaro3721/items/6ac3cba4f090662adabf

 

で、対処法ですが、ListViewItem のレイアウトを記述しているXMLファイルに、下記の一行を追加するだけ。

android:descendantFocusability="blocksDescendants"

具体的には下記のとおりです。

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:descendantFocusability="blocksDescendants">

    <TextView
        android:id="@+id/title"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
    <ImageButton
        android:layout_width="50dp"
        android:layout_height="match_parent"
        android:src="@drawable/icon"
        android:scaleType="fitCenter"
        android:id="@+id/btn"
        android:layout_alignParentRight="true"/>
</RelativeLayout>

5行目に記述しています。
これを指定し忘れると、ListViewItem のボタンは反応するのに、ListViewItem 自体がクリックできなくなるのでご注意ください。
ちなみに、それ以外の指定等はなにもなく、これだけです。

なお、ListViewItemに指定したボタンのクリック検知は、ListAdapter の getView関数内で行います。
抜粋するとこんな感じ。

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    View view;

    if (convertView != null) {
        view = convertView;
    } else {
        view = mInflater.inflate(mResource, null);
    }

    // ボタンのクリックイベント
    ImageButton btn = view.findViewById(R.id.btn);
    btn.setOnClickListener(view1 -> {
        // ボタンクリック時に行いたいたい処理
     });

     return view;
}

 

以上、カスタムしたListView にボタンを追加した際、ListViewItem自体のクリックイベントが呼ばれなくなる現象とその対処法についてでした。
同じことでお困りの方は、是非お試しください。

  • この記事いいね! (0)
村上 著者:村上

【Android】文字列をMD5でハッシュ化する方法

使用される場所が大分限定的かもしれませんが…今回、分け合って調べたので備忘録としてまとめ。
JavaでMD5ハッシュを行う方法です。

今回参考に…というか、コードをまるっとコピーさせていただいたサイトはこちらから。

後ろ向きに全力疾走: AndroidでMD5ハッシュを使う
http://taiwanology.blogspot.com/2012/06/androidmd5.html

参考にさせていただいた記事って、こうでもしないとすぐにどこかにやってしまうので…ご紹介という形で保存します。

 

コード自体はこちら。

public String md5(String s) {
    try {
        // Create MD5 Hash
        MessageDigest digest = java.security.MessageDigest.getInstance("MD5");
        digest.update(s.getBytes());
        byte messageDigest[] = digest.digest();

        // Create Hex String
        StringBuffer hexString = new StringBuffer();
        for (int i=0; i<messageDigest.length; i++)
            hexString.append(String.format("%02x", messageDigest[i] & 0xff));
        return hexString.toString();

    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    }
    return "";
}

関数化されているので、そのままコピーして使うことができました。
なお、上で紹介した記事内では、11行目が

hexString.append(Integer.toHexString(0xFF &amp; messageDigest[i]));

になっていますが、コメント欄で、「この書き方では0埋めされない」とのことで、

hexString.append(String.format("%02x", messageDigest[i] & 0xff));

上記の記述があったので、こちらに書き換えました。
記事のコードをコピーした時は、11行目でエラーが発生していましたが、こちらに修正したところ、エラーもなく動作しました。

 

以上、Javaで文字列をMD5ハッシュ化する方法でした。
今回はマルコピしたコードの紹介でした…。
が、私としては凄く便利で助かったので、是非ご活用ください。

  • この記事いいね! (0)
asaba 著者:asaba

【androidJava】READ_EXETERNAL_STORAGEは必要なかった

ギャラリーから画像を読み込む機能を開発していてパーミッション関係のエラーで躓いたのでメモします。

ペイントの動きが悪かったのでそのまま抜粋してきました。

java.lang.SecurityException: Permission Denial:

writing com.android.providers.media.MediaProvider uri content://media/external/images/media from pid=19325, uid=10589

requires android.permission.WRITE_EXTERNAL_STORAGE, or grantUriPermission()

 

ストレージを読み込むにはREADだけでなくWRITE_EXETERNAL_STORAGEのほうも必要だったみたいなので追加して解決。

<pre><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /></pre>

このWRITE_EXETERNALSTORAGEは、READ_EXETERNAL_STORAGEの役割である読み込みも兼業しているので、実際に

マニフェストに書くのはこのWRITEのほうだけでも問題ないみたいですね。

このエラー、というかただ追加するだけの作業だったのですが、自分の備忘録を兼ねての投稿なのでそんなの知ってるよっていう

かたも多いかもしれませんがご容赦ください。

 

これでパーミッションの設定も無事にできたことなので近日にギャラリーから画像の名前を取得するコードを

載せようかと考えています。

画像を扱ったコードを正しく書ければ大分できることが増えますね~。

 

以下、参考にさせていただいたサイトです。

[Android] 外部ストレージにファイルを保存する WRITE_EXTERNAL_STORAGE

Android:KitkatのREAD_EXTERNAL_STORAGEと外部記憶領域

Androidアプリ開発「外部ストレージアクセスのパーミッション」

  • この記事いいね! (0)
asaba 著者:asaba

【androidJava】EditTextの内容を取得する

グーグル先生で探してもありそうでなかったEditTextの中身の取得方法です。

 


String before_text,new_text;
EditText entry_text


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

  //EditTextを紐付け
  entry_text = findViewById(R.id.getText);

  upLoadBtn.setOnClickListener(new View.OnClickListener() {
      public void onClick(View view) {
        edit();
      }
   });
}

  //edit関数定義
  public void edit(){
    new_text = entry_title.getText().toString();
  }

androidの記事は乱雑していて、しかも古い情報が多いので一つ一つ今風な書き方に合わせるのが面倒で苦労しています。

editTextは上記の書き方で問題なく取得できます。

  • この記事いいね! (0)