OSDN Git Service

Roundの機種で、左側のグリッドが消えるものを対策。
[gokigen/A01c.git] / wear / src / main / java / jp / sfjp / gokigen / a01c / liveview / CameraLiveImageView.java
1 package jp.sfjp.gokigen.a01c.liveview;
2
3 import android.content.Context;
4 import android.content.SharedPreferences;
5 import android.graphics.Bitmap;
6 import android.graphics.BitmapFactory;
7 import android.graphics.Canvas;
8 import android.graphics.Color;
9 import android.graphics.Paint;
10 import android.graphics.PointF;
11 import android.graphics.Rect;
12 import android.graphics.RectF;
13 import android.media.ExifInterface;
14 import android.os.Looper;
15 import android.preference.PreferenceManager;
16 import android.util.AttributeSet;
17 import android.util.DisplayMetrics;
18 import android.util.Log;
19 import android.util.TypedValue;
20 import android.view.MotionEvent;
21 import android.view.View;
22 import android.widget.ImageView;
23
24 import java.util.Map;
25 import java.util.Timer;
26 import java.util.TimerTask;
27
28 import jp.co.olympus.camerakit.OLYCamera;
29
30 import jp.sfjp.gokigen.a01c.R;
31 import jp.sfjp.gokigen.a01c.liveview.gridframe.GridFrameFactory;
32 import jp.sfjp.gokigen.a01c.liveview.gridframe.IGridFrameDrawer;
33 import jp.sfjp.gokigen.a01c.olycamerawrapper.ILevelGauge;
34 import jp.sfjp.gokigen.a01c.preference.ICameraPropertyAccessor;
35
36 /**
37  *   CameraLiveImageView :
38  *    (OLYMPUS の ImageCaptureSample をカスタマイズ)
39  *
40  */
41 public class CameraLiveImageView extends View implements CameraLiveViewListenerImpl.IImageDataReceiver, IAutoFocusFrameDisplay, ILiveImageStatusNotify
42 {
43     private final String TAG = toString();
44
45     private static final String EXIF_ORIENTATION = "Orientation";
46
47     private boolean showGridFeature = false;
48     private boolean showLevelGaugeFeature = false;
49     private ImageView.ScaleType imageScaleType;
50     private Bitmap imageBitmap;
51     private int imageRotationDegrees;
52     private boolean showingFocusFrame = false;
53     private IAutoFocusFrameDisplay.FocusFrameStatus focusFrameStatus;
54     private RectF focusFrameRect;
55     private Timer focusFrameHideTimer;
56
57     private IGridFrameDrawer gridFrameDrawer = null;
58     private ShowMessageHolder messageHolder;
59
60     /**
61      *   コンストラクタ
62      *
63      */
64     public CameraLiveImageView(Context context)
65     {
66         super(context);
67         initComponent(context);
68     }
69
70     /**
71      *   コンストラクタ
72      *
73      */
74     public CameraLiveImageView(Context context, AttributeSet attrs)
75     {
76         super(context, attrs);
77         initComponent(context);
78     }
79
80     /**
81      *   コンストラクタ
82      *
83      */
84     public CameraLiveImageView(Context context, AttributeSet attrs, int defStyleAttr)
85     {
86         super(context, attrs, defStyleAttr);
87         initComponent(context);
88     }
89
90     /**
91      * 初期化ロジック (preferenceからデータを読み出す)
92      */
93     private void initComponent(Context context)
94     {
95         messageHolder = new ShowMessageHolder();
96
97         imageScaleType = ImageView.ScaleType.FIT_CENTER;
98         SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
99
100         showGridFeature = preferences.getBoolean(ICameraPropertyAccessor.SHOW_GRID_STATUS, true);
101         showLevelGaugeFeature = preferences.getBoolean(ICameraPropertyAccessor.SHOW_LEVEL_GAUGE_STATUS, false);
102
103         int framingGridStatus = Integer.parseInt(preferences.getString(ICameraPropertyAccessor.FRAME_GRID, ICameraPropertyAccessor.FRAME_GRID_DEFAULT_VALUE));
104         gridFrameDrawer = GridFrameFactory.getGridFrameDrawer(framingGridStatus);
105
106         // ダミーのビットマップデータ読み込み...画面表示のテスト用ロジック
107         try
108         {
109             imageBitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.momonga);
110         }
111         catch (Throwable t)
112         {
113             t.printStackTrace();
114             imageBitmap = null;
115         }
116     }
117
118     /**
119      *
120      *
121      */
122     @Override
123     protected void onAttachedToWindow()
124     {
125         super.onAttachedToWindow();
126     }
127
128     /**
129      *
130      *
131      */
132     @Override
133     protected void onDetachedFromWindow()
134     {
135         super.onDetachedFromWindow();
136
137         imageBitmap = null;
138         if (focusFrameHideTimer != null)
139         {
140             focusFrameHideTimer.cancel();
141             focusFrameHideTimer = null;
142         }
143     }
144
145     /**
146      *
147      *
148      */
149     @Override
150     protected void onDraw(Canvas canvas)
151     {
152         super.onDraw(canvas);
153
154         // 画像の表示
155         drawCanvas(canvas);
156
157         // メッセージの表示 (Overwrite)
158         drawInformationMessages(canvas);
159     }
160
161     /**
162      *
163      *
164      */
165     @Override
166     public float getContentSizeWidth() {
167         return getIntrinsicContentSizeWidth();
168     }
169
170     /**
171      *
172      *
173      */
174     @Override
175     public float getContentSizeHeight() {
176         return getIntrinsicContentSizeHeight();
177     }
178
179     /**
180      *
181      *
182      */
183     private float getIntrinsicContentSizeWidth()
184     {
185         if (imageBitmap == null)
186         {
187             return (1.0f);
188         }
189         return (imageBitmap.getWidth());
190     }
191
192     /**
193      *
194      *
195      */
196     private float getIntrinsicContentSizeHeight()
197     {
198         if (imageBitmap == null)
199         {
200             return (1.0f);
201         }
202         return (imageBitmap.getHeight());
203     }
204
205     /**
206      * Sets a image to view.
207      * (CameraLiveViewListenerImpl.IImageDataReceiver の実装)
208      *
209      * @param data     A image of live-view.
210      * @param metadata A metadata of the image.
211      */
212     public void setImageData(byte[] data, Map<String, Object> metadata)
213     {
214         Bitmap bitmap;
215         int rotationDegrees;
216
217         if (data != null && metadata != null)
218         {
219             // Create a bitmap.
220             try
221             {
222                 bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
223             }
224             catch (OutOfMemoryError e)
225             {
226                 e.printStackTrace();
227                 return;
228             }
229
230             // Acquire a rotation degree of image.
231             int orientation = ExifInterface.ORIENTATION_UNDEFINED;
232             if (metadata.containsKey(EXIF_ORIENTATION))
233             {
234                 orientation = Integer.parseInt((String) metadata.get(EXIF_ORIENTATION));
235             }
236             switch (orientation)
237             {
238                 case ExifInterface.ORIENTATION_NORMAL:
239                     rotationDegrees = 0;
240                     break;
241                 case ExifInterface.ORIENTATION_ROTATE_90:
242                     rotationDegrees = 90;
243                     break;
244                 case ExifInterface.ORIENTATION_ROTATE_180:
245                     rotationDegrees = 180;
246                     break;
247                 case ExifInterface.ORIENTATION_ROTATE_270:
248                     rotationDegrees = 270;
249                     break;
250                 default:
251                     rotationDegrees = 0;
252                     break;
253             }
254             imageBitmap = bitmap;
255             imageRotationDegrees = rotationDegrees;
256         }
257         refreshCanvas();
258     }
259
260     /**
261      * Returns a point which is detected by a motion event.
262      *
263      * @param event A motion event.
264      * @return A point in the view finder. if a point is equal to null, the point is out of the view finder.
265      */
266     public PointF getPointWithEvent(MotionEvent event)
267     {
268         if (event == null || imageBitmap == null)
269         {
270             return null;
271         }
272
273         PointF pointOnView = new PointF(event.getX(), event.getY());
274         PointF pointOnImage = convertPointFromViewArea(pointOnView);
275         float imageWidth;
276         float imageHeight;
277         if (imageRotationDegrees == 0 || imageRotationDegrees == 180) {
278             imageWidth = imageBitmap.getWidth();
279             imageHeight = imageBitmap.getHeight();
280         } else {
281             imageWidth = imageBitmap.getHeight();
282             imageHeight = imageBitmap.getWidth();
283         }
284         return (OLYCamera.convertPointOnLiveImageIntoViewfinder(pointOnImage, imageWidth, imageHeight, imageRotationDegrees));
285     }
286
287     /**
288      * Returns whether a image area contains a specified point.
289      *
290      * @param point The point to examine.
291      * @return true if the image is not null or empty and the point is located within the rectangle; otherwise, false.
292      */
293     public boolean isContainsPoint(PointF point)
294     {
295         return ((point != null) && (new RectF(0, 0, 1, 1)).contains(point.x, point.y));
296     }
297
298     /**
299      * Hides the forcus frame.
300      */
301     public void hideFocusFrame()
302     {
303         if (focusFrameHideTimer != null)
304         {
305             focusFrameHideTimer.cancel();
306             focusFrameHideTimer = null;
307         }
308         showingFocusFrame = false;
309         refreshCanvas();
310     }
311
312     /**
313      * Shows the focus frame.
314      *
315      * @param rect     A rectangle of the focus frame on view area.
316      * @param status   A status of the focus frame.
317      * @param duration A duration of the focus frame showing.
318      */
319     @Override
320     public void showFocusFrame(RectF rect, FocusFrameStatus status, double duration)
321     {
322         if (focusFrameHideTimer != null) {
323             focusFrameHideTimer.cancel();
324             focusFrameHideTimer = null;
325         }
326
327         showingFocusFrame = true;
328         focusFrameStatus = status;
329         focusFrameRect = rect;
330
331         refreshCanvas();
332
333         if (duration > 0) {
334             focusFrameHideTimer = new Timer();
335             focusFrameHideTimer.schedule(new TimerTask() {
336                 @Override
337                 public void run() {
338                     hideFocusFrame();
339                 }
340             }, (long) (duration * 1000));
341         }
342     }
343
344     /**
345      *
346      *
347      */
348     private void refreshCanvas()
349     {
350         if (Looper.getMainLooper().getThread() == Thread.currentThread()) {
351             invalidate();
352         } else {
353             postInvalidate();
354         }
355     }
356
357     /**
358      * ビットマップの表示・画面表示の更新
359      *
360      * @param canvas キャンバス
361      */
362     private void drawCanvas(Canvas canvas)
363     {
364         // Clears the canvas.
365         canvas.drawARGB(255, 0, 0, 0);
366
367         // ビットマップの取得
368         Bitmap bitmapToShow = imageBitmap;
369         if (bitmapToShow == null)
370         {
371             // 表示するビットマップがないとき
372             return;
373         }
374
375         // Rotates the image.
376         int centerX = canvas.getWidth() / 2;
377         int centerY = canvas.getHeight() / 2;
378         canvas.rotate(imageRotationDegrees, centerX, centerY);
379
380         RectF viewRect = null;
381
382         //  Calculate the viewport of bitmap.
383         if (imageScaleType == ImageView.ScaleType.FIT_CENTER)
384         {
385             viewRect = decideViewRect(canvas, bitmapToShow, imageRotationDegrees);
386
387             // Draws the bitmap.
388             Rect imageRect = new Rect(0, 0, bitmapToShow.getWidth(), bitmapToShow.getHeight());
389             canvas.drawBitmap(bitmapToShow, imageRect, viewRect, null);
390         }
391         else
392         {
393             // Sorry, other scale types are not supported.
394             Log.v(TAG, "Sorry, other scale types are not supported. " + imageScaleType);
395         }
396
397         // Cancels rotation of the canvas.
398         canvas.rotate(-imageRotationDegrees, centerX, centerY);
399
400
401         // フォーカスフレームを表示する
402         if ((focusFrameRect != null) && (showingFocusFrame)) {
403             if (imageRotationDegrees == 0 || imageRotationDegrees == 180) {
404                 drawFocusFrame(canvas, bitmapToShow.getWidth(), bitmapToShow.getHeight());
405             } else {
406                 drawFocusFrame(canvas, bitmapToShow.getHeight(), bitmapToShow.getWidth());
407             }
408         }
409
410         if (viewRect != null)
411         {
412             // グリッド(撮影補助線)の表示
413             if ((showGridFeature) && (gridFrameDrawer != null))
414             {
415                 drawGridFrame(canvas, viewRect);
416             }
417
418             // レベルゲージ(デジタル水準器)の表示
419             if (showLevelGaugeFeature)
420             {
421                 drawLevelGauge(canvas, viewRect);
422             }
423         }
424     }
425
426     /**
427      *
428      *
429      */
430     private RectF decideViewRect(Canvas canvas, Bitmap bitmapToShow, int degree)
431     {
432         final int srcWidth;
433         final int srcHeight;
434         if ((degree == 0) || (degree == 180))
435         {
436             srcWidth = bitmapToShow.getWidth();
437             srcHeight = bitmapToShow.getHeight();
438         }
439         else
440         {
441             // Replaces width and height.
442             srcWidth = bitmapToShow.getHeight();
443             srcHeight = bitmapToShow.getWidth();
444         }
445
446         int maxWidth = canvas.getWidth();
447         int maxHeight = canvas.getHeight();
448
449         int centerX = canvas.getWidth() / 2;
450         int centerY = canvas.getHeight() / 2;
451
452         float widthRatio = maxWidth / (float) srcWidth;
453         float heightRatio = maxHeight / (float) srcHeight;
454         float smallRatio = Math.min(widthRatio, heightRatio);
455
456         final int dstWidth;
457         final int dstHeight;
458         if (widthRatio < heightRatio)
459         {
460             // Fits to maxWidth with keeping aspect ratio.
461             dstWidth = maxWidth;
462             dstHeight = (int) (smallRatio * srcHeight);
463         }
464         else
465         {
466             // Fits to maxHeight with keeping aspect ratio.
467             dstHeight = maxHeight;
468             dstWidth = (int) (smallRatio * srcWidth);
469         }
470
471         final float halfWidth = dstWidth * 0.5f;
472         final float halfHeight = dstHeight * 0.5f;
473         if ((degree == 0) || (degree == 180))
474         {
475             return (new RectF(
476                     centerX - halfWidth,
477                     centerY - halfHeight,
478                     centerX - halfWidth + dstWidth,
479                     centerY - halfHeight + dstHeight));
480         }
481
482         // Replaces the width and height.
483         return (new RectF(
484                 centerX - halfHeight,
485                 centerY - halfWidth,
486                 centerX - halfHeight + dstHeight,
487                 centerY - halfWidth + dstWidth));
488     }
489
490     /**
491      * AF枠の表示
492      *
493      * @param canvas      キャンバス
494      * @param imageWidth  幅
495      * @param imageHeight 高さ
496      */
497     private void drawFocusFrame(Canvas canvas, float imageWidth, float imageHeight)
498     {
499         //Log.v(TAG, "drawFocusFrame() :" + focusFrameStatus);
500
501         //  Calculate the rectangle of focus.
502         RectF focusRectOnImage = OLYCamera.convertRectOnViewfinderIntoLiveImage(focusFrameRect, imageWidth, imageHeight, imageRotationDegrees);
503         RectF focusRectOnView = convertRectFromImageArea(focusRectOnImage);
504
505         // Draw a rectangle to the canvas.
506         Paint focusFramePaint = new Paint();
507         focusFramePaint.setStyle(Paint.Style.STROKE);
508         switch (focusFrameStatus) {
509             case Running:
510                 focusFramePaint.setColor(Color.WHITE);
511                 break;
512
513             case Focused:
514                 focusFramePaint.setColor(Color.GREEN);
515                 break;
516
517             case Failed:
518                 focusFramePaint.setColor(Color.RED);
519                 break;
520
521             case Errored:
522                 focusFramePaint.setColor(Color.YELLOW);
523                 break;
524         }
525         float focusFrameStrokeWidth = 2.0f;
526         DisplayMetrics dm = getResources().getDisplayMetrics();
527         float strokeWidth = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, focusFrameStrokeWidth, dm);
528         focusFramePaint.setStrokeWidth(strokeWidth);
529         canvas.drawRect(focusRectOnView, focusFramePaint);
530     }
531
532     /**
533      * グリッドの表示
534      *
535      * @param canvas   キャンバスエリア
536      * @param viewRect 表示領域
537      */
538     private void drawGridFrame(Canvas canvas, RectF viewRect)
539     {
540         RectF gridRect;
541         if ((imageRotationDegrees == 0) || (imageRotationDegrees == 180)) {
542             gridRect = new RectF(viewRect);
543         } else {
544             float height = viewRect.right - viewRect.left;
545             float width = viewRect.bottom - viewRect.top;
546             float left = (canvas.getWidth() / 2.0f) - (width / 2.0f);
547             float top = (canvas.getHeight() / 2.0f) - (height / 2.0f);
548             gridRect = new RectF(left, top, left + width, top + height);
549         }
550
551         Paint framePaint = new Paint();
552         framePaint.setStyle(Paint.Style.STROKE);
553         framePaint.setAntiAlias(true);
554
555         //DisplayMetrics dm = getResources().getDisplayMetrics();
556         //float strokeWidth = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1.0f, dm);
557         //framePaint.setStrokeWidth(strokeWidth);
558         framePaint.setStrokeWidth(0.0f);
559         framePaint.setColor(gridFrameDrawer.getDrawColor());
560         gridFrameDrawer.drawFramingGrid(canvas, gridRect, framePaint);
561     }
562
563     /**
564      *   デジタル水準器の表示
565      *
566      */
567     private void drawLevelGauge(Canvas canvas, RectF viewRect)
568     {
569        ILevelGauge levelGauge = messageHolder.getLevelGauge();
570         if (levelGauge == null)
571         {
572             // デジタル水準器がとれない場合は、何もしない
573             return;
574         }
575
576         // レベルゲージの表示位置
577         int height = (int) viewRect.bottom; // canvas.getHeight();
578         int width =  (int) viewRect.right;  // canvas.getWidth();
579         int centerX = width / 2;
580         int centerY = height / 2;
581
582         //float maxBandWidth = width / 3.0f;     // ゲージの最大長 (画面の 1/3 ぐらい)
583         float maxBandHeight = height / 3.0f;   // ゲージの最大長 (画面の 1/3 ぐらい)
584         int barWidthInitial = 4;               // 表示するゲージの幅(の初期値)
585         int barWidth;                          // 実際に表示するゲージの幅
586
587         Paint paint = new Paint();
588
589         // 垂直線
590         float verticalValue = levelGauge.getLevel(ILevelGauge.LevelArea.LEVEL_VERTICAL);
591         float verticalSize = verticalValue / 60.0f * maxBandHeight;  // 45度で切り替わるはずだが、一応...
592         if (Math.abs(verticalSize) < 1.0f)
593         {
594             // 線引き限界以下、水平検出とする (この時の線は倍の長さにする)
595             verticalSize = 1.0f;
596             barWidth = barWidthInitial * 2;
597         }
598         else
599         {
600             barWidth = barWidthInitial;
601         }
602         paint.setStrokeWidth(barWidth);
603         paint.setColor(levelGauge.getLevelColor(verticalValue));
604         canvas.drawLine((width - barWidth), centerY, (width - barWidth), (centerY + verticalSize), paint);
605
606         // 水平線の表示
607         float horizontalValue = levelGauge.getLevel(ILevelGauge.LevelArea.LEVEL_HORIZONTAL);
608         paint.setStrokeWidth(2.0f);
609         paint.setAntiAlias(true);
610         paint.setColor(levelGauge.getLevelColor(horizontalValue));
611         if ((imageRotationDegrees == 0) || (imageRotationDegrees == 180))
612         {
613             // 通常状態
614             float YY = canvas.getHeight() / 2.0f; // centerY
615             float diffY = (float) Math.sin(Math.toRadians(horizontalValue)) * (float) centerX;
616             canvas.drawLine(0, (YY + diffY), width, (YY - diffY), paint);
617         }
618         else
619         {
620             // 縦持ち状態
621             float XX = canvas.getWidth() / 2.0f; // centerX
622             float diffX = (float) Math.sin(Math.toRadians(horizontalValue)) * (float) centerY;
623             canvas.drawLine((XX + diffX), 0, (XX - diffX), canvas.getHeight(), paint);
624
625         }
626 /*
627         // 縦と同じ水平線を表示する場合...
628         float horizontalValue = levelGauge.getLevel(ILevelGauge.LevelArea.LEVEL_HORIZONTAL);
629         float horizontalSize = horizontalValue / 60.0f * maxBandWidth;  // 45度ぐらいで切り替わるはずだが、一応...
630         if (Math.abs(horizontalSize) < 1.0f)
631         {
632             // 線引き限界以下、水平検出とする (この時の線は倍の長さにする)
633             horizontalSize = 1.0f;
634             barWidth = barWidthInitial * 2;
635         }
636         else
637         {
638             barWidth = barWidthInitial;
639         }
640         paint.setStrokeWidth(barWidth);
641         paint.setColor(levelGauge.getLevelColor(horizontalValue));
642         canvas.drawLine(centerX, (height - barWidth), (centerX + horizontalSize),  (height - barWidth), paint);
643 */
644     }
645
646     /**
647      *   画面にメッセージを表示する
648      */
649     private void drawInformationMessages(Canvas canvas)
650     {
651         String message;
652         RectF viewRect;
653         if (imageBitmap != null)
654         {
655             // ビットマップの表示エリアに合わせて位置をチューニングする
656             viewRect = decideViewRect(canvas, imageBitmap, 0);
657         }
658         else
659         {
660             // 適当なサイズ...
661             viewRect = new RectF(5.0f, 0.0f, canvas.getWidth() - 5.0f, canvas.getHeight() - 55.0f);
662         }
663
664         // 画面の中心に表示する
665         message = messageHolder.getMessage(ShowMessageHolder.MessageArea.CENTER);
666         if ((message != null)&&(message.length() > 0))
667         {
668             Paint paint = new Paint();
669             paint.setColor(messageHolder.getColor(ShowMessageHolder.MessageArea.CENTER));
670             paint.setTextSize(messageHolder.getSize(ShowMessageHolder.MessageArea.CENTER));
671             paint.setAntiAlias(true);
672             Paint.FontMetrics fontMetrics = paint.getFontMetrics();
673             float cx = (canvas.getWidth() / 2.0f) - (paint.measureText(message) / 2.0f);
674             float cy = (canvas.getHeight() / 2.0f) - ((fontMetrics.ascent + fontMetrics.descent) / 2.0f);
675             canvas.drawText(message, cx, cy, paint);
676         }
677
678         // 画面上部左側に表示する
679         message = messageHolder.getMessage(ShowMessageHolder.MessageArea.UPLEFT);
680         if ((message != null)&&(message.length() > 0))
681         {
682             Paint paintUp = new Paint();
683             paintUp.setColor(messageHolder.getColor(ShowMessageHolder.MessageArea.UPLEFT));
684             paintUp.setTextSize(messageHolder.getSize(ShowMessageHolder.MessageArea.UPLEFT));
685             paintUp.setAntiAlias(true);
686             Paint.FontMetrics fontMetrics = paintUp.getFontMetrics();
687             canvas.drawText(message, viewRect.left + 3.0f, viewRect.top + (fontMetrics.descent - fontMetrics.ascent), paintUp);
688         }
689
690         // 画面上部右側に表示する
691         message = messageHolder.getMessage(ShowMessageHolder.MessageArea.UPRIGHT);
692         if ((message != null)&&(message.length() > 0))
693         {
694             Paint paintUp = new Paint();
695             paintUp.setColor(messageHolder.getColor(ShowMessageHolder.MessageArea.UPRIGHT));
696             paintUp.setTextSize(messageHolder.getSize(ShowMessageHolder.MessageArea.UPRIGHT));
697             paintUp.setAntiAlias(true);
698             float width = paintUp.measureText(message);
699             Paint.FontMetrics fontMetrics = paintUp.getFontMetrics();
700             canvas.drawText(message, (viewRect.right - 3.0f) - width, viewRect.top + (fontMetrics.descent - fontMetrics.ascent), paintUp);
701         }
702
703         // 画面下部左側に表示する
704         message = messageHolder.getMessage(ShowMessageHolder.MessageArea.LOWLEFT);
705         if ((message != null)&&(message.length() > 0))
706         {
707             Paint paint = new Paint();
708             paint.setColor(messageHolder.getColor(ShowMessageHolder.MessageArea.LOWLEFT));
709             paint.setTextSize(messageHolder.getSize(ShowMessageHolder.MessageArea.LOWLEFT));
710             paint.setAntiAlias(true);
711             Paint.FontMetrics fontMetrics = paint.getFontMetrics();
712             canvas.drawText(message, viewRect.left + 3.0f, viewRect.bottom - fontMetrics.bottom, paint);
713         }
714
715         // 画面下部右側に表示する
716         message = messageHolder.getMessage(ShowMessageHolder.MessageArea.LOWRIGHT);
717         if ((message != null)&&(message.length() > 0))
718         {
719             Paint paint = new Paint();
720             paint.setColor(messageHolder.getColor(ShowMessageHolder.MessageArea.LOWRIGHT));
721             paint.setTextSize(messageHolder.getSize(ShowMessageHolder.MessageArea.LOWRIGHT));
722             paint.setAntiAlias(true);
723             float width = paint.measureText(message);
724             Paint.FontMetrics fontMetrics = paint.getFontMetrics();
725             canvas.drawText(message, (viewRect.right - 3.0f) - width, viewRect.bottom - fontMetrics.bottom, paint);
726         }
727
728 /**/
729         // 画面上部中央に表示する
730         message = messageHolder.getMessage(ShowMessageHolder.MessageArea.UPCENTER);
731         if ((message != null)&&(message.length() > 0))
732         {
733             Paint paintUp = new Paint();
734             paintUp.setColor(messageHolder.getColor(ShowMessageHolder.MessageArea.UPCENTER));
735             paintUp.setTextSize(messageHolder.getSize(ShowMessageHolder.MessageArea.UPCENTER));
736             paintUp.setAntiAlias(true);
737             float width = paintUp.measureText(message) / 2.0f;
738             Paint.FontMetrics fontMetrics = paintUp.getFontMetrics();
739             canvas.drawText(message, (viewRect.centerX()) - width, viewRect.top + (fontMetrics.descent - fontMetrics.ascent), paintUp);
740         }
741
742         // 画面下部中央に表示する
743         message = messageHolder.getMessage(ShowMessageHolder.MessageArea.LOWCENTER);
744         if ((message != null)&&(message.length() > 0))
745         {
746             Paint paint = new Paint();
747             paint.setColor(messageHolder.getColor(ShowMessageHolder.MessageArea.LOWCENTER));
748             paint.setTextSize(messageHolder.getSize(ShowMessageHolder.MessageArea.LOWCENTER));
749             paint.setAntiAlias(true);
750             float width = paint.measureText(message) / 2.0f;
751             Paint.FontMetrics fontMetrics = paint.getFontMetrics();
752             canvas.drawText(message, (viewRect.centerX()) - width, viewRect.bottom - fontMetrics.bottom, paint);
753         }
754 /**/
755     }
756
757     /**
758      * Converts a point on image area to a point on view area.
759      *
760      * @param point A point on image area. (e.g. a live preview image)
761      * @return A point on view area. (e.g. a touch panel view)
762      */
763     private PointF convertPointFromImageArea(PointF point) {
764         if (imageBitmap == null) {
765             return new PointF();
766         }
767
768         float viewPointX = point.x;
769         float viewPointY = point.y;
770         float imageSizeWidth;
771         float imageSizeHeight;
772         if (imageRotationDegrees == 0 || imageRotationDegrees == 180) {
773             imageSizeWidth = imageBitmap.getWidth();
774             imageSizeHeight = imageBitmap.getHeight();
775         } else {
776             imageSizeWidth = imageBitmap.getHeight();
777             imageSizeHeight = imageBitmap.getWidth();
778         }
779         float viewSizeWidth = this.getWidth();
780         float viewSizeHeight = this.getHeight();
781         float ratioX = viewSizeWidth / imageSizeWidth;
782         float ratioY = viewSizeHeight / imageSizeHeight;
783         float scale;
784
785         switch (imageScaleType) {
786             case FIT_XY:
787                 viewPointX *= ratioX;
788                 viewPointY *= ratioY;
789                 break;
790             case FIT_CENTER:    // go to next label.
791             case CENTER_INSIDE:
792                 scale = Math.min(ratioX, ratioY);
793                 viewPointX *= scale;
794                 viewPointY *= scale;
795                 viewPointX += (viewSizeWidth - imageSizeWidth * scale) / 2.0f;
796                 viewPointY += (viewSizeHeight - imageSizeHeight * scale) / 2.0f;
797                 break;
798             case CENTER_CROP:
799                 scale = Math.max(ratioX, ratioY);
800                 viewPointX *= scale;
801                 viewPointY *= scale;
802                 viewPointX += (viewSizeWidth - imageSizeWidth * scale) / 2.0f;
803                 viewPointY += (viewSizeHeight - imageSizeHeight * scale) / 2.0f;
804                 break;
805             case CENTER:
806                 viewPointX += viewSizeWidth / 2.0 - imageSizeWidth / 2.0f;
807                 viewPointY += viewSizeHeight / 2.0 - imageSizeHeight / 2.0f;
808                 break;
809             default:
810                 break;
811         }
812         return new PointF(viewPointX, viewPointY);
813     }
814
815     /**
816      * Converts a point on view area to a point on image area.
817      *
818      * @param point A point on view area. (e.g. a touch panel view)
819      * @return A point on image area. (e.g. a live preview image)
820      */
821     private PointF convertPointFromViewArea(PointF point) {
822         if (imageBitmap == null) {
823             return new PointF();
824         }
825
826         float imagePointX = point.x;
827         float imagePointY = point.y;
828         float imageSizeWidth;
829         float imageSizeHeight;
830         if (imageRotationDegrees == 0 || imageRotationDegrees == 180) {
831             imageSizeWidth = imageBitmap.getWidth();
832             imageSizeHeight = imageBitmap.getHeight();
833         } else {
834             imageSizeWidth = imageBitmap.getHeight();
835             imageSizeHeight = imageBitmap.getWidth();
836         }
837         float viewSizeWidth = this.getWidth();
838         float viewSizeHeight = this.getHeight();
839         float ratioX = viewSizeWidth / imageSizeWidth;
840         float ratioY = viewSizeHeight / imageSizeHeight;
841         float scale;
842
843         switch (imageScaleType) {
844             case FIT_XY:
845                 imagePointX /= ratioX;
846                 imagePointY /= ratioY;
847                 break;
848             case FIT_CENTER:    // go to next label.
849             case CENTER_INSIDE:
850                 scale = Math.min(ratioX, ratioY);
851                 imagePointX -= (viewSizeWidth - imageSizeWidth * scale) / 2.0f;
852                 imagePointY -= (viewSizeHeight - imageSizeHeight * scale) / 2.0f;
853                 imagePointX /= scale;
854                 imagePointY /= scale;
855                 break;
856             case CENTER_CROP:
857                 scale = Math.max(ratioX, ratioY);
858                 imagePointX -= (viewSizeWidth - imageSizeWidth * scale) / 2.0f;
859                 imagePointY -= (viewSizeHeight - imageSizeHeight * scale) / 2.0f;
860                 imagePointX /= scale;
861                 imagePointY /= scale;
862                 break;
863             case CENTER:
864                 imagePointX -= (viewSizeWidth - imageSizeWidth) / 2.0f;
865                 imagePointY -= (viewSizeHeight - imageSizeHeight) / 2.0f;
866                 break;
867             default:
868                 break;
869         }
870         return new PointF(imagePointX, imagePointY);
871     }
872
873     /**
874      * Converts a rectangle on image area to a rectangle on view area.
875      *
876      * @param rect A rectangle on image area. (e.g. a live preview image)
877      * @return A rectangle on view area. (e.g. a touch panel view)
878      */
879     private RectF convertRectFromImageArea(RectF rect)
880     {
881         if (imageBitmap == null)
882         {
883             return new RectF();
884         }
885
886         PointF imageTopLeft = new PointF(rect.left, rect.top);
887         PointF imageBottomRight = new PointF(rect.right, rect.bottom);
888
889         PointF viewTopLeft = convertPointFromImageArea(imageTopLeft);
890         PointF viewBottomRight = convertPointFromImageArea(imageBottomRight);
891
892         return (new RectF(viewTopLeft.x, viewTopLeft.y, viewBottomRight.x, viewBottomRight.y));
893     }
894
895     /**
896      *
897      *
898      */
899     public void setShowGridFrame(boolean isShowGridFeature)
900     {
901         showGridFeature = isShowGridFeature;
902         SharedPreferences preferences = android.support.v7.preference.PreferenceManager.getDefaultSharedPreferences(getContext());
903         SharedPreferences.Editor editor = preferences.edit();
904         editor.putBoolean(ICameraPropertyAccessor.SHOW_GRID_STATUS, showGridFeature);
905         editor.apply();
906     }
907
908     /**
909      *
910      *
911      */
912     @Override
913     public void toggleShowGridFrame()
914     {
915         setShowGridFrame(!showGridFeature);
916     }
917
918     /**
919      *
920      *
921      */
922     public void setShowLevelGauge(boolean isShowLevelGaugeFeature)
923     {
924         Log.v(TAG, "setShowLevelGauge : " + isShowLevelGaugeFeature);
925         showLevelGaugeFeature = isShowLevelGaugeFeature;
926         SharedPreferences preferences = android.support.v7.preference.PreferenceManager.getDefaultSharedPreferences(getContext());
927         SharedPreferences.Editor editor = preferences.edit();
928         editor.putBoolean(ICameraPropertyAccessor.SHOW_LEVEL_GAUGE_STATUS, showLevelGaugeFeature);
929         editor.apply();
930         ILevelGauge levelGauge = messageHolder.getLevelGauge();
931         if (levelGauge == null)
932         {
933             // デジタル水準器がとれない場合は、何もしない
934             Log.v(TAG, "setShowLevelGauge : levelGauge is null.");
935             return;
936         }
937         levelGauge.updateLevelGaugeChecking(isShowLevelGaugeFeature);
938     }
939
940     /**
941      *
942      *
943      */
944     @Override
945     public void toggleShowLevelGauge()
946     {
947         setShowLevelGauge(!showLevelGaugeFeature);
948     }
949
950     /**
951      *
952      *
953      */
954     @Override
955     public boolean isShowLevelGauge()
956     {
957         return (showLevelGaugeFeature);
958     }
959
960     /**
961      *
962      *
963      */
964     @Override
965     public boolean isShowGrid()
966     {
967         return (showGridFeature);
968     }
969
970
971     /**
972      *
973      *
974      */
975     public IMessageDrawer getMessageDrawer()
976     {
977         return (messageHolder);
978     }
979 }