| | |
| | | package cn.flightfeather.thirdappmodule.module.common |
| | | |
| | | import android.annotation.SuppressLint |
| | | import android.app.Activity |
| | | import android.content.Intent |
| | | import android.graphics.Bitmap |
| | | import android.graphics.BitmapFactory |
| | | import android.graphics.Canvas |
| | | import android.graphics.Matrix |
| | | import android.media.ExifInterface |
| | | import android.os.Bundle |
| | | import android.os.Environment |
| | | import android.os.Environment.DIRECTORY_PICTURES |
| | | import android.view.View |
| | | import cn.flightfeather.thirdappmodule.R |
| | | import cn.flightfeather.thirdappmodule.activity.PhotoViewerActivity |
| | | import cn.flightfeather.thirdappmodule.module.base.BaseActivity |
| | | import cn.flightfeather.thirdappmodule.module.base.BaseTakePicActivity |
| | | import cn.flightfeather.thirdappmodule.util.DateFormatter |
| | | import cn.flightfeather.thirdappmodule.module.base.VIEW_PHOTO |
| | | import cn.flightfeather.thirdappmodule.util.* |
| | | import cn.flightfeather.thirdappmodule.util.location.LocationUtil |
| | | import cn.flightfeather.thirdappmodule.util.photo.ExifHelper |
| | | import cn.flightfeather.thirdappmodule.util.photo.ImageMergeUtil |
| | | import com.lcw.library.imagepicker.ImagePicker |
| | | import com.otaliastudios.cameraview.CameraListener |
| | | import com.otaliastudios.cameraview.CameraOptions |
| | | import com.otaliastudios.cameraview.Size |
| | | import io.reactivex.Observable |
| | | import io.reactivex.android.schedulers.AndroidSchedulers |
| | | import io.reactivex.schedulers.Schedulers |
| | | import kotlinx.android.synthetic.main.activity_camera.* |
| | | import java.io.File |
| | | import java.io.FileOutputStream |
| | | import java.io.Serializable |
| | | import java.util.* |
| | | import kotlin.collections.ArrayList |
| | | import kotlin.math.abs |
| | | import kotlin.math.round |
| | | |
| | | /** |
| | | * |
| | | */ |
| | | class CameraActivity : BaseActivity(), View.OnClickListener { |
| | | |
| | | // gps定位工具 |
| | | private lateinit var locationUtil: LocationUtil |
| | | |
| | | // 图片文本合并工具 |
| | | private lateinit var imageMergeUtil: ImageMergeUtil |
| | | |
| | | // 拍摄图片缓存地址 |
| | | private var photoPath = mutableListOf<String>() |
| | | |
| | | // 图片水印 |
| | | private lateinit var logo: Bitmap |
| | | |
| | | // 允许最大图片拍摄数量 |
| | | private var maxPic = 3 |
| | | |
| | | override fun getLayoutId(): Int =R.layout.activity_camera |
| | | |
| | | override fun onCreate(savedInstanceState: Bundle?) { |
| | | super.onCreate(savedInstanceState) |
| | | initLogoBitmap() |
| | | initCamera() |
| | | initLocation() |
| | | img_cancel.setOnClickListener(this) |
| | | img_confirm.setOnClickListener(this) |
| | | img_thumbnail.setOnClickListener(this) |
| | | // toggle(false) |
| | | |
| | | maxPic = intent.getIntExtra("maxPic", 3) |
| | | |
| | | onShootDone() |
| | | } |
| | | |
| | | override fun onResume() { |
| | | camera_view.start() |
| | | super.onResume() |
| | | camera_view.start() |
| | | } |
| | | |
| | | override fun onPause() { |
| | | camera_view.stop() |
| | | super.onPause() |
| | | camera_view.stop() |
| | | } |
| | | |
| | | override fun onDestroy() { |
| | | locationUtil.onDestroy() |
| | | super.onDestroy() |
| | | camera_view.destroy() |
| | | locationUtil.onDestroy() |
| | | } |
| | | |
| | | private fun toggle(isShot: Boolean = true) { |
| | | if (isShot) { |
| | | cl_part1.visibility = View.GONE |
| | | cl_part2.visibility = View.VISIBLE |
| | | } else { |
| | | cl_part1.visibility = View.VISIBLE |
| | | cl_part2.visibility = View.GONE |
| | | } |
| | | } |
| | | |
| | | private fun initLogoBitmap() { |
| | | logo = BitmapFactory.decodeResource(resources, R.mipmap.ic_logo) |
| | | } |
| | | |
| | | private fun initCamera() { |
| | | imageMergeUtil = ImageMergeUtil(this) |
| | | |
| | | // 根据系统提供的可选分辨率,选择和当前显示区域最接近的 |
| | | camera_view.setPictureSize{ |
| | | var min = -1//当前分辨率与最小分辨率的长宽分别对应的差值的和 |
| | | |
| | | // val screenWith = ScreenUtils.getScreenWidth(this) |
| | | // val screenHeight = ScreenUtils.getScreenHeight(this) |
| | | |
| | | val screenWith = camera_view.width |
| | | val screenHeight = camera_view.height |
| | | |
| | | val resultList = mutableListOf<Size>() |
| | | |
| | | it.forEach {size -> |
| | | if (size.width > screenWith) return@forEach |
| | | |
| | | val w = abs(size.width - screenWith) |
| | | val h = abs(size.height - screenHeight) |
| | | if (min < 0) { |
| | | min = w + h |
| | | resultList.add(0, size) |
| | | }else if (w + h < min) { |
| | | min = w + h |
| | | resultList.add(0, size) |
| | | } |
| | | } |
| | | resultList |
| | | } |
| | | camera_view.addCameraListener(object : CameraListener() { |
| | | override fun onCameraOpened(options: CameraOptions) { |
| | | super.onCameraOpened(options) |
| | | btn_shot.setOnClickListener(this@CameraActivity) |
| | | btn_shoot.setOnClickListener(this@CameraActivity) |
| | | } |
| | | |
| | | |
| | | override fun onPictureTaken(jpeg: ByteArray?) { |
| | | super.onPictureTaken(jpeg) |
| | | val d = Observable.create<String> { |
| | | camera_view.stop() |
| | | jpeg?.let { |
| | | var b = toBitmap(it) |
| | | val x = txt_location.x - camera_view.x |
| | | val y = txt_location.y - camera_view.y |
| | | b?.let {bitmap -> |
| | | b = imageMergeUtil.mergeText(bitmap, txt_location.text.toString(), Pair(x, y)) |
| | | // todo: 2020/5/31 保存图片 |
| | | // SystemServiceUtils.saveBitmap(0) |
| | | toBitmap(it)?.let {b-> |
| | | merge(b) |
| | | } |
| | | } |
| | | } |
| | | val pathList = arrayListOf<String>() |
| | | val intent = Intent() |
| | | intent.putStringArrayListExtra(BaseTakePicActivity.EXTRA_SELECT_IMAGES, pathList) |
| | | setResult(Activity.RESULT_OK, intent) |
| | | onBackPressed() |
| | | } |
| | | |
| | | override fun onCameraClosed() { |
| | | super.onCameraClosed() |
| | | onBackPressed() |
| | | } |
| | | }) |
| | | } |
| | | |
| | | @SuppressLint("SetTextI18n") |
| | | private fun initLocation() { |
| | | locationUtil = LocationUtil(this) |
| | | locationUtil.startLocation { |
| | | val date = Date() |
| | | val time = DateFormatter.dateTimeFormat3.format(date) |
| | | val locationInfo = "经度: ${it.longitude}" + |
| | | "\n纬度: ${it.latitude}" + |
| | | "\n地址: ${it.address}" + |
| | | "\n时间: $time" |
| | | runOnUiThread { |
| | | txt_location.text = locationInfo |
| | | txt_latitude.text = "经度: ${round(it.longitude * 1000000) / 1000000}" |
| | | txt_longitude.text = "纬度: ${round(it.latitude * 1000000) / 1000000}" |
| | | txt_address.text = "地址: ${it.address}" |
| | | txt_time.text = "时间: $time" |
| | | } |
| | | } |
| | | } |
| | | |
| | | override fun onClick(v: View?) { |
| | | camera_view.capturePicture() |
| | | private fun merge(b: Bitmap) { |
| | | val d = Observable.create<Bitmap> { emitter -> |
| | | var newB: Bitmap |
| | | val width = camera_view.width |
| | | val height = camera_view.height |
| | | |
| | | var x = txt_latitude.x - camera_view.x |
| | | var y = txt_latitude.y - camera_view.y |
| | | var xScale = x / width |
| | | var yScale = y / height |
| | | newB = imageMergeUtil.mergeText(b, txt_latitude, Pair(x, y), xScale, yScale) |
| | | |
| | | x = txt_longitude.x - camera_view.x |
| | | y = txt_longitude.y - camera_view.y |
| | | xScale = x / width |
| | | yScale = y / height |
| | | newB = imageMergeUtil.mergeText(newB, txt_longitude, Pair(x, y), xScale, yScale) |
| | | |
| | | x = txt_address.x - camera_view.x |
| | | y = txt_address.y - camera_view.y |
| | | xScale = x / width |
| | | yScale = y / height |
| | | newB = imageMergeUtil.mergeText(newB, txt_address, Pair(x, y), xScale, yScale) |
| | | |
| | | x = txt_time.x - camera_view.x |
| | | y = txt_time.y - camera_view.y |
| | | xScale = x / width |
| | | yScale = y / height |
| | | newB = imageMergeUtil.mergeText(newB, txt_time, Pair(x, y), xScale, yScale) |
| | | |
| | | newB = imageMergeUtil.addLogo(newB, logo) |
| | | |
| | | // 缓存图片 |
| | | val path = Environment.getExternalStorageDirectory().path + "/FlightFeather/Temp/" + UUIDGenerator.generateUUID(4) + ".jpg" |
| | | photoPath.add(path) |
| | | SystemServiceUtils.saveBitmap(path, newB) |
| | | |
| | | emitter.onNext(newB) |
| | | emitter.onComplete() |
| | | }.subscribeOn(Schedulers.io()) |
| | | .observeOn(AndroidSchedulers.mainThread()) |
| | | .subscribe { |
| | | // toggle(true) |
| | | |
| | | // 拍摄loading结束 |
| | | onShootDone() |
| | | |
| | | // 在缩略图上显示最新一张图片, 并更新确认按钮文字显示 |
| | | img_thumbnail.setImageBitmap(it) |
| | | val t = "${getString(R.string.yes)}(${photoPath.size}/${maxPic})" |
| | | img_confirm.text = t |
| | | // 判断是否达到允许最大图片数量 |
| | | if (photoPath.size == maxPic) { |
| | | // 弹出提示框,确认或者重拍 |
| | | DialogUtil2.showAlertDialog2(this, "最多拍${maxPic}张照片", getString(R.string.yes), getString(R.string.reshoot), { d -> |
| | | d.dismiss() |
| | | onConfirm() |
| | | }, { d -> |
| | | d.dismiss() |
| | | onCancel() |
| | | camera_view.start() |
| | | }) |
| | | } else { |
| | | camera_view.start() |
| | | } |
| | | } |
| | | disposableList.add(d) |
| | | } |
| | | |
| | | private fun toBitmap(source: ByteArray): Bitmap? { |
| | |
| | | } |
| | | return bitmap |
| | | } |
| | | |
| | | /** |
| | | * 确认返回 |
| | | */ |
| | | private fun onConfirm() { |
| | | if (photoPath.isEmpty()) return |
| | | val intent = Intent() |
| | | intent.putStringArrayListExtra(ImagePicker.EXTRA_SELECT_IMAGES, ArrayList(photoPath)) |
| | | setResult(Activity.RESULT_OK, intent) |
| | | this.finish() |
| | | } |
| | | |
| | | /** |
| | | * 取消拍摄 |
| | | */ |
| | | private fun onCancel() { |
| | | photoPath.forEach { |
| | | val pic = File(it) |
| | | if (pic.exists()) pic.delete() |
| | | } |
| | | photoPath.clear() |
| | | img_thumbnail.setImageResource(R.drawable.bg_btngroup) |
| | | img_confirm.text = getString(R.string.yes) |
| | | } |
| | | |
| | | /** |
| | | * 照片拍摄处理中 |
| | | */ |
| | | private fun onShooting() { |
| | | pro_shooting.visibility = View.VISIBLE |
| | | btn_shoot.isEnabled = false |
| | | } |
| | | |
| | | /** |
| | | * 照片拍摄处理完毕 |
| | | */ |
| | | private fun onShootDone() { |
| | | pro_shooting.visibility = View.GONE |
| | | btn_shoot.isEnabled = true |
| | | } |
| | | |
| | | override fun onBackPressed() { |
| | | onCancel() |
| | | super.onBackPressed() |
| | | } |
| | | |
| | | override fun onClick(v: View?) { |
| | | when (v?.id) { |
| | | R.id.btn_shoot -> { |
| | | onShooting() |
| | | camera_view.capturePicture() |
| | | // capture() |
| | | } |
| | | // 取消拍摄的图片并回退 |
| | | R.id.img_cancel -> { |
| | | onBackPressed() |
| | | } |
| | | // |
| | | R.id.img_confirm -> onConfirm() |
| | | R.id.img_thumbnail -> { |
| | | if (photoPath.isEmpty()) return |
| | | val fileList = mutableListOf<File>() |
| | | photoPath.forEach { fileList.add(File(it)) } |
| | | val intent = Intent(this, PhotoViewerActivity::class.java) |
| | | intent.putExtra("position", fileList.size - 1) |
| | | intent.putExtra("type", PhotoViewerActivity.EVIDENCE_PHOTO_TEMP) |
| | | intent.putExtra("deletable", false) |
| | | intent.putExtra(PhotoViewerActivity.PARA_FILES, fileList as Serializable) |
| | | startActivityForResult(intent, VIEW_PHOTO) |
| | | } |
| | | } |
| | | } |
| | | } |