OSDN Git Service

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