OSDN Git Service

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