diff --git a/app/src/main/assets/omdb_config.json b/app/src/main/assets/omdb_config.json index 5dd373d9..e7d55baa 100644 --- a/app/src/main/assets/omdb_config.json +++ b/app/src/main/assets/omdb_config.json @@ -65,8 +65,8 @@ "table": "OMDB_LINK_NAME", "code": 2011, "name": "道路名", - "zoomMin": 18, - "zoomMax": 20, + "zoomMin": 15, + "zoomMax": 17, "checkLinkId": false, "transformer": [ { @@ -243,11 +243,6 @@ } ] }, - "2097": { - "table": "OMDB_PHY_LANENUM", - "code": 2097, - "name": "物理车道数" - }, "2201": { "table": "OMDB_BRIDGE", "code": 2201, @@ -282,6 +277,22 @@ } ] }, + "2617": { + "table": "OMDB_PHY_LANENUM", + "code": 2617, + "name": "物理车道数", + "zoomMin": 15, + "zoomMax": 18, + "catch": true, + "transformer": [ + { + "k": "geometry", + "v": "~", + "klib": "geometry", + "vlib": "generatePhyName()" + } + ] + }, "2638": { "table": "OMDB_LANE_ACCESS", "code": 2638, @@ -603,6 +614,7 @@ "zoomMin": 18, "zoomMax": 20, "filterData": true, + "checkLinkId": false, "catch": true, "transformer": [ { diff --git a/app/src/main/java/com/navinfo/omqs/db/ImportOMDBHelper.kt b/app/src/main/java/com/navinfo/omqs/db/ImportOMDBHelper.kt index cc425dc8..716095c0 100644 --- a/app/src/main/java/com/navinfo/omqs/db/ImportOMDBHelper.kt +++ b/app/src/main/java/com/navinfo/omqs/db/ImportOMDBHelper.kt @@ -194,12 +194,12 @@ class ImportOMDBHelper @AssistedInject constructor( tableNum += importConfig.tableMap.size } //缓存任务link信息,便于下面与数据进行任务link匹配 - val hashMap: HashMap = HashMap() + val hashMap: HashMap = HashMap() // val lineList = arrayOfNulls(task.hadLinkDvoList.size) // var index = 0 task.hadLinkDvoList.forEach { - hashMap[it.linkPid.toLong()] = it + hashMap[it.linkPid] = it // lineList[index] = GeometryTools.createGeometry(it.geometry) as LineString // index++ } @@ -310,7 +310,7 @@ class ImportOMDBHelper @AssistedInject constructor( currentEntry: MutableMap.MutableEntry, task: TaskBean, importConfig: ImportConfig, - hashMap: HashMap, + hashMap: HashMap, isEmit: Boolean = true) = callbackFlow { val cancellable= importData(f,unZipFiles,currentEntry,task,importConfig,hashMap,isEmit,object :MultiPathsCallback{ override fun onProgress(value: Int) { @@ -342,7 +342,7 @@ class ImportOMDBHelper @AssistedInject constructor( currentEntry: MutableMap.MutableEntry, task: TaskBean, importConfig: ImportConfig, - hashMap: HashMap, + hashMap: HashMap, isEmit: Boolean = true, callback: MultiPathsCallback? ):NonCancellable { val resHashMap: HashMap = HashMap() //define empty hashmap @@ -379,13 +379,6 @@ class ImportOMDBHelper @AssistedInject constructor( } newTime = System.currentTimeMillis() -// if (elementIndex % 50 == 0) { -// Log.e( -// "jingo", -// "安装数据 ${currentConfig.table} $elementIndex ${listRenderEntity.size} ${newTime - time}" -// ) -// } - time = newTime elementIndex += 1 @@ -409,16 +402,25 @@ class ImportOMDBHelper @AssistedInject constructor( renderEntity.zoomMin = map["qi_zoomMin"].toString().toInt() renderEntity.zoomMax = map["qi_zoomMax"].toString().toInt() + //缓存当前数据对应的导航linkpid信息,根据与任务对应关系保留任务唯一linkpid + var linkPidList = mutableListOf() + // 在外层记录当前数据的linkPid - if (map.containsKey("linkPid")) { - renderEntity.linkPid = map["linkPid"].toString().split(",")[0] + if (map.containsKey("linkPid")&& map["linkPid"].toString().split(",").isNotEmpty()) { + + linkPidList.addAll(map["linkPid"].toString().split(",")) + } else if (map.containsKey("linkList")) { + val linkList = map["linkList"].toString() + if (!linkList.isNullOrEmpty() && linkList != "null") { - val list: List = gson.fromJson( - linkList, object : TypeToken>() {}.type - ) - renderEntity.linkPid = list[0].linkPid + + val list: List = gson.fromJson(linkList, object : TypeToken>() {}.type) + + list.forEach { + linkPidList.add(it.linkPid) + } } } @@ -514,25 +516,16 @@ class ImportOMDBHelper @AssistedInject constructor( //遍历判断只显示与任务Link相关的任务数据 if (currentConfig.checkLinkId) { - if (renderEntity.linkPid.isNotEmpty()) { + if (linkPidList.isNotEmpty()) { - val currentLinkPid = renderEntity.linkPid - - if (!currentLinkPid.isNullOrEmpty() && currentLinkPid != "null") { - - val list = currentLinkPid.split(",") - - if (list.isNotEmpty()) { - - m@ for (linkPid in list) { - if (hashMap.containsKey(linkPid.toLong())) { - renderEntity.enable = 1 - break@m - } - } + m@ for (linkPid in linkPidList) { + Log.e("jingo", "$linkPid=======linkPid") + if (linkPid!=null&&hashMap.containsKey(linkPid)) { + renderEntity.enable = 1 + renderEntity.linkPid = linkPid + break@m } } - } else if (renderEntity.code.toInt() == DataCodeEnum.OMDB_INTERSECTION.code.toInt() || renderEntity.code.toInt() == DataCodeEnum.OMDB_LANE_CONSTRUCTION.code.toInt() && renderEntity.properties.containsKey( "linkList" ) @@ -548,8 +541,9 @@ class ImportOMDBHelper @AssistedInject constructor( ) m@ for (link in list) { - if (hashMap.containsKey(link.linkPid.toLong())) { + if (hashMap.containsKey(link.linkPid)) { renderEntity.enable = 1 + renderEntity.linkPid = link.linkPid break@m } } diff --git a/app/src/main/java/com/navinfo/omqs/db/ImportPreProcess.kt b/app/src/main/java/com/navinfo/omqs/db/ImportPreProcess.kt index f0d8cee0..cfadd0b4 100644 --- a/app/src/main/java/com/navinfo/omqs/db/ImportPreProcess.kt +++ b/app/src/main/java/com/navinfo/omqs/db/ImportPreProcess.kt @@ -271,7 +271,6 @@ class ImportPreProcess { // 将这个起终点的线记录在数据中 val startReference = ReferenceEntity() -// startReference.renderEntityId = renderEntity.id startReference.name = "${renderEntity.name}参考点" startReference.code = renderEntity.code startReference.table = renderEntity.table @@ -285,7 +284,6 @@ class ImportPreProcess { startReference.properties["qi_table"] = renderEntity.table startReference.properties["type"] = "s${if (renderEntity.properties["laneType"]!!.toInt() and (0b1000) > 0) "_dec" else "_acc"}" - startReference.properties["geometry"] = startReference.geometry startReference.propertiesDb = DeflaterUtil.zipString(JSON.toJSONString(startReference.properties)) renderEntity.referenceEntitys.add(startReference) @@ -304,7 +302,6 @@ class ImportPreProcess { endReference.properties["qi_table"] = renderEntity.table endReference.properties["type"] = "e${if (renderEntity.properties["laneType"]!!.toInt() and (0b1000) > 0) "_dec" else "_acc"}" - endReference.properties["geometry"] = endReference.geometry endReference.propertiesDb = DeflaterUtil.zipString(JSON.toJSONString(endReference.properties)) renderEntity.referenceEntitys.add(endReference) } @@ -353,7 +350,6 @@ class ImportPreProcess { Log.e("qj", "generateS2EReferencePoint===${startReference.geometry}") - startReference.properties["geometry"] = startReference.geometry startReference.propertiesDb = DeflaterUtil.zipString(JSON.toJSONString(startReference.properties)) listResult.add(startReference) @@ -388,7 +384,6 @@ class ImportPreProcess { endReference.properties["type"] = "e_2_p" Log.e("qj", "generateS2EReferencePoint===e_2_p${renderEntity.name}") } - endReference.properties["geometry"] = endReference.geometry endReference.propertiesDb = DeflaterUtil.zipString(JSON.toJSONString(endReference.properties)) renderEntity.referenceEntitys.add(endReference) @@ -740,6 +735,15 @@ class ImportPreProcess { } } + /** + * 生成默认物理车道数据 + * */ + fun generatePhyName(renderEntity: RenderEntity) { + // 物理车道数 + if (renderEntity.properties.containsKey("laneS2e")&&renderEntity.properties.containsKey("laneE2s")) { + renderEntity.properties["name"] = "${renderEntity.properties["laneS2e"]}|${renderEntity.properties["laneE2s"]}" + } + } /** * 生成默认道路名数据 @@ -835,14 +839,24 @@ class ImportPreProcess { when(renderEntity.properties["direct"]?.toInt()){ 0,1,2->{ if (medianWidth != null) { - angleReference.geometry = - GeometryTools.computeLine(0.000012, 0.0, renderEntity.geometry) + if(side=="0"){ + angleReference.geometry = + GeometryTools.computeLine(0.000015, 0.0, renderEntity.geometry) + }else{ + angleReference.geometry = + GeometryTools.computeLine( 0.0, 0.000015,renderEntity.geometry) + } } } 3->{ if (medianWidth != null) { - angleReference.geometry = - GeometryTools.computeLine(0.0, 0.000012, renderEntity.geometry) + if(side=="0"){ + angleReference.geometry = + GeometryTools.computeLine(0.0, 0.000015, renderEntity.geometry) + }else{ + angleReference.geometry = + GeometryTools.computeLine(0.000015, 0.0, renderEntity.geometry) + } } } } @@ -850,7 +864,7 @@ class ImportPreProcess { angleReference.table = renderEntity.table angleReference.code = renderEntity.code angleReference.properties["qi_table"] = renderEntity.table - angleReference.properties["medianSurface"] = medianSurface.toString() + angleReference.properties["medianSurfaceGeometry"] = medianSurface.toString() angleReference.zoomMin = renderEntity.zoomMin angleReference.zoomMax = renderEntity.zoomMax angleReference.taskId = renderEntity.taskId @@ -1224,6 +1238,8 @@ class ImportPreProcess { if (renderEntity.properties.containsKey("maxSpeed") && renderEntity.properties.containsKey("minSpeed")) { renderEntity.properties["ref"] = "${renderEntity.properties["maxSpeed"]}|${renderEntity.properties["minSpeed"]}" + renderEntity.propertiesDb = + DeflaterUtil.zipString(JSON.toJSONString(renderEntity.properties)) } } @@ -1243,13 +1259,11 @@ class ImportPreProcess { val linkGeometry = GeometryTools.createGeometry(zLevelObject.optString("linkGeometry")) val coordinates = linkGeometry!!.coordinates - val referenceEntityList = mutableListOf() // 判断当前数据的startEnd,如果是0则向前和向后都绘制线,如果是1(起点)则只绘制前两个点组成的线,如果是2(终点)则只绘制后两个点组成的线 if (startEnd == 0 || startEnd == 1) { // 处理向后的线 val zLevelReference = createZLevelReference(renderEntity) zLevelReference.properties["type"] = "zlevelLine" -// zLevelReference.properties["name"] = zLevel.toString() - // 根据shpSeqNum获取对应的点位 + zLevelReference.propertiesDb = DeflaterUtil.zipString(JSON.toJSONString(zLevelReference.properties)) if (shpSeqNum < coordinates.size - 1) { val currentCoordinate = coordinates[shpSeqNum] var nextCoordinate = coordinates[shpSeqNum + 1] @@ -1279,26 +1293,25 @@ class ImportPreProcess { ), GeoPoint(nextCoordinate.y, nextCoordinate.x) ) ).toString() - - referenceEntityList.add(zLevelReference) - + renderEntity.referenceEntitys.add(zLevelReference) val zLevelNameReference = createZLevelReference(renderEntity) zLevelNameReference.properties["type"] = "zlevelName" zLevelNameReference.properties["name"] = zLevel.toString() + zLevelNameReference.propertiesDb = DeflaterUtil.zipString(JSON.toJSONString(zLevelNameReference.properties)) zLevelNameReference.geometry = GeometryTools.createGeometry( GeoPoint( nextCoordinate.y, nextCoordinate.x ) ).toString() - referenceEntityList.add(zLevelNameReference) + renderEntity.referenceEntitys.add(zLevelNameReference) } } if (startEnd == 0 || startEnd == 2) { // 处理向前的线 val zLevelReference = createZLevelReference(renderEntity) zLevelReference.properties["type"] = "zlevelLine" -// zLevelReference.properties["name"] = zLevel.toString() + zLevelReference.propertiesDb = DeflaterUtil.zipString(JSON.toJSONString(zLevelReference.properties)) // 根据shpSeqNum获取对应的点位 if (shpSeqNum < coordinates.size && shpSeqNum > 0) { val currentCoordinate = coordinates[shpSeqNum] @@ -1320,7 +1333,6 @@ class ImportPreProcess { // 计算偏移后的点 preCoordinate = Coordinate(currentCoordinate.getX() + dx, currentCoordinate.getY() + dy) -// } zLevelReference.geometry = GeometryTools.createLineString( arrayListOf( GeoPoint( @@ -1329,19 +1341,17 @@ class ImportPreProcess { ), GeoPoint(preCoordinate.y, preCoordinate.x) ) ).toString() - referenceEntityList.add(zLevelReference) - + renderEntity.referenceEntitys.add(zLevelReference) val zLevelNameReference = createZLevelReference(renderEntity) zLevelNameReference.properties["type"] = "zlevelName" zLevelNameReference.properties["name"] = zLevel.toString() + zLevelNameReference.propertiesDb = DeflaterUtil.zipString(JSON.toJSONString(zLevelNameReference.properties)) zLevelNameReference.geometry = GeometryTools.createGeometry(GeoPoint(preCoordinate.y, preCoordinate.x)) .toString() - referenceEntityList.add(zLevelNameReference) + renderEntity.referenceEntitys.add(zLevelNameReference) } } - - insertData(referenceEntityList) // 移除zlevelList,减小原始数据大小 renderEntity.properties.remove("zlevelList") } diff --git a/app/src/main/java/com/navinfo/omqs/ui/activity/map/MainViewModel.kt b/app/src/main/java/com/navinfo/omqs/ui/activity/map/MainViewModel.kt index 345841cb..fabd1827 100644 --- a/app/src/main/java/com/navinfo/omqs/ui/activity/map/MainViewModel.kt +++ b/app/src/main/java/com/navinfo/omqs/ui/activity/map/MainViewModel.kt @@ -804,7 +804,7 @@ class MainViewModel @Inject constructor( ) } } - DataCodeEnum.OMDB_PHY_LANENUM.code,//物理车道数 + //DataCodeEnum.OMDB_PHY_LANENUM.code,//物理车道数 DataCodeEnum.OMDB_LANE_NUM.code, //车道数 DataCodeEnum.OMDB_RD_LINK_KIND.code,//种别, DataCodeEnum.OMDB_RD_LINK_FUNCTION_CLASS.code, // 功能等级, @@ -960,7 +960,7 @@ class MainViewModel @Inject constructor( ) } } - DataCodeEnum.OMDB_PHY_LANENUM.code,//物理车道数 + //DataCodeEnum.OMDB_PHY_LANENUM.code,//物理车道数 DataCodeEnum.OMDB_LANE_NUM.code, //车道数 DataCodeEnum.OMDB_RD_LINK_KIND.code,//种别, DataCodeEnum.OMDB_RD_LINK_FUNCTION_CLASS.code, // 功能等级, diff --git a/app/src/main/java/com/navinfo/omqs/ui/fragment/evaluationresult/EvaluationResultFragment.kt b/app/src/main/java/com/navinfo/omqs/ui/fragment/evaluationresult/EvaluationResultFragment.kt index a4034382..b5afdd2c 100644 --- a/app/src/main/java/com/navinfo/omqs/ui/fragment/evaluationresult/EvaluationResultFragment.kt +++ b/app/src/main/java/com/navinfo/omqs/ui/fragment/evaluationresult/EvaluationResultFragment.kt @@ -6,6 +6,8 @@ import android.graphics.Bitmap import android.os.Build import android.os.Bundle import android.provider.MediaStore +import android.text.Editable +import android.text.TextWatcher import android.util.Log import android.view.* import android.widget.Toast @@ -90,6 +92,18 @@ class EvaluationResultFragment : BaseFragment(), View.OnClickListener { } + binding.evaluationDescription.addTextChangedListener(object : TextWatcher { + override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) { + } + + override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) { + } + + override fun afterTextChanged(s: Editable?) { + viewModel.description = s.toString() + } + }) + binding.evaluationVoiceRecyclerview.adapter = adapter //返回按钮点击 @@ -128,8 +142,6 @@ class EvaluationResultFragment : BaseFragment(), View.OnClickListener { * 照片view */ binding.evaluationPictureViewpager.adapter = pictureAdapter - val list = mutableListOf("1", "2", "3") - pictureAdapter.refreshData(list) //照片左右选择键点击监听 binding.evaluationPictureLeft.setOnClickListener(this) @@ -205,6 +217,13 @@ class EvaluationResultFragment : BaseFragment(), View.OnClickListener { binding.evaluationDescription.setText(it) } + /** + * 照片view + */ + viewModel.liveDataPictureList.observe(viewLifecycleOwner){ + pictureAdapter.refreshData(it) + } + viewModel.listDataChatMsgEntityList.observe(viewLifecycleOwner) { adapter.refreshData(it) } diff --git a/app/src/main/java/com/navinfo/omqs/ui/fragment/evaluationresult/EvaluationResultViewModel.kt b/app/src/main/java/com/navinfo/omqs/ui/fragment/evaluationresult/EvaluationResultViewModel.kt index 10654ec1..17c20a4f 100644 --- a/app/src/main/java/com/navinfo/omqs/ui/fragment/evaluationresult/EvaluationResultViewModel.kt +++ b/app/src/main/java/com/navinfo/omqs/ui/fragment/evaluationresult/EvaluationResultViewModel.kt @@ -140,6 +140,8 @@ class EvaluationResultViewModel @Inject constructor( var classCodeTemp: String = "" + var description = "" + init { mapController.mMapView.addOnNIMapClickListener(TAG, object : OnGeoPointClickListener { override fun onMapClick(tag: String, point: GeoPoint, other: String) { @@ -457,7 +459,7 @@ class EvaluationResultViewModel @Inject constructor( liveDataToastMessage.postValue("没有绑定到任何link,请选择") return@launch } - if (liveDataQsRecordBean.value!!.classCode == DataCodeEnum.OMDB_LANEINFO.code) + if (liveDataQsRecordBean.value!!.classCode == DataCodeEnum.OMDB_LANEINFO.code){ try { val jsonObject: JSONObject = if (liveDataQsRecordBean.value!!.remarks != "") { JSONObject(liveDataQsRecordBean.value!!.remarks) @@ -488,11 +490,16 @@ class EvaluationResultViewModel @Inject constructor( jsonObject.put("now", jsonOriginalArray) } liveDataQsRecordBean.value!!.remarks = jsonObject.toString() + SignUtil.getLineInfoIcons(renderEntity!!) + Log.e("jingo", "车信json ${liveDataQsRecordBean.value!!.remarks}") } catch (e: Exception) { } + }else{ + liveDataQsRecordBean.value!!.description = description + liveDataQsRecordBean.value!!.remarks = "" + } - Log.e("jingo", "车信json ${liveDataQsRecordBean.value!!.remarks}") val realm = realmOperateHelper.getRealmDefaultInstance() liveDataQsRecordBean.value!!.taskId = liveDataTaskBean.value!!.id liveDataQsRecordBean.value!!.checkTime = DateTimeUtil.getDataTime() @@ -582,6 +589,8 @@ class EvaluationResultViewModel @Inject constructor( } catch (e: Exception) { } + }else{ + } launch(Dispatchers.Main) { @@ -614,6 +623,8 @@ class EvaluationResultViewModel @Inject constructor( } liveDataQsRecordBean.value?.attachmentBeanList = it.attachmentBeanList liveDataLanInfoChange.postValue(it.description) + description = it.description + // 显示语音数据到界面 getChatMsgEntityList() realm.close() @@ -808,14 +819,24 @@ class EvaluationResultViewModel @Inject constructor( out.close() val picList = mutableListOf() if (liveDataPictureList.value == null) { - picList.add(file.absolutePath) + picList.add(file.name) } else { picList.addAll(liveDataPictureList.value!!) - picList.add(file.absolutePath) + picList.add(file.name) } + + var attachmentList: RealmList = RealmList() + //赋值处理 + if (liveDataQsRecordBean.value?.attachmentBeanList?.isEmpty() == false) { + attachmentList = liveDataQsRecordBean.value?.attachmentBeanList!! + } + val attachmentBean = AttachmentBean() + attachmentBean.name = file.name!! + attachmentBean.type = 2 + attachmentList.add(attachmentBean) + liveDataQsRecordBean.value?.attachmentBeanList = attachmentList liveDataPictureList.postValue(picList) } - } /** diff --git a/app/src/main/java/com/navinfo/omqs/ui/fragment/evaluationresult/PictureAdapter.kt b/app/src/main/java/com/navinfo/omqs/ui/fragment/evaluationresult/PictureAdapter.kt index 8b8f03b1..2240bdca 100644 --- a/app/src/main/java/com/navinfo/omqs/ui/fragment/evaluationresult/PictureAdapter.kt +++ b/app/src/main/java/com/navinfo/omqs/ui/fragment/evaluationresult/PictureAdapter.kt @@ -2,9 +2,13 @@ package com.navinfo.omqs.ui.fragment.evaluationresult import android.view.LayoutInflater import android.view.ViewGroup +import com.navinfo.omqs.Constant +import com.navinfo.omqs.R import com.navinfo.omqs.databinding.AdapterPictureBinding import com.navinfo.omqs.ui.other.BaseRecyclerViewAdapter import com.navinfo.omqs.ui.other.BaseViewHolder +import com.navinfo.omqs.util.ImageTools +import java.io.File class PictureAdapter : BaseRecyclerViewAdapter() { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseViewHolder { @@ -15,7 +19,18 @@ class PictureAdapter : BaseRecyclerViewAdapter() { override fun onBindViewHolder(holder: BaseViewHolder, position: Int) { val bd = holder.viewBinding as AdapterPictureBinding - bd.button.text = data[position] + + val myAppDir = File(Constant.USER_DATA_ATTACHEMNT_PATH) + + if (!myAppDir.exists()) myAppDir.mkdirs() // 确保文件夹已创建 + + // 创建一个名为 fileName 的文件 + val file = File(myAppDir, data[position]) + if(file.exists()){ + bd.showImage.setImageBitmap(ImageTools.zoomBitmap(Constant.USER_DATA_ATTACHEMNT_PATH+"/"+data[position],2)) + }else{ + bd.showImage.setBackgroundResource(R.drawable.icon_camera_img) + } } } \ No newline at end of file diff --git a/app/src/main/java/com/navinfo/omqs/ui/fragment/note/NoteFragment.kt b/app/src/main/java/com/navinfo/omqs/ui/fragment/note/NoteFragment.kt index 9d4cd8c2..bc1bcba4 100644 --- a/app/src/main/java/com/navinfo/omqs/ui/fragment/note/NoteFragment.kt +++ b/app/src/main/java/com/navinfo/omqs/ui/fragment/note/NoteFragment.kt @@ -1,17 +1,40 @@ package com.navinfo.omqs.ui.fragment.note +import android.app.Activity +import android.content.Intent +import android.graphics.Bitmap +import android.os.Build import android.os.Bundle +import android.provider.MediaStore import android.text.Editable import android.text.TextWatcher +import android.util.Log import android.view.LayoutInflater +import android.view.MotionEvent import android.view.View import android.view.ViewGroup +import android.view.ViewTreeObserver +import android.widget.Toast +import androidx.activity.result.ActivityResult +import androidx.activity.result.ActivityResultLauncher +import androidx.activity.result.contract.ActivityResultContracts +import androidx.annotation.RequiresApi import androidx.navigation.findNavController import androidx.navigation.fragment.findNavController +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import com.navinfo.collect.library.enums.DataCodeEnum +import com.navinfo.omqs.Constant import com.navinfo.omqs.R import com.navinfo.omqs.databinding.FragmentNoteBinding import com.navinfo.omqs.ui.dialog.FirstDialog import com.navinfo.omqs.ui.fragment.BaseFragment +import com.navinfo.omqs.ui.fragment.evaluationresult.EvaluationResultFragment +import com.navinfo.omqs.ui.fragment.evaluationresult.EvaluationResultViewModel +import com.navinfo.omqs.ui.fragment.evaluationresult.PhenomenonFragment +import com.navinfo.omqs.ui.fragment.evaluationresult.PictureAdapter +import com.navinfo.omqs.ui.fragment.evaluationresult.ProblemLinkFragment +import com.navinfo.omqs.ui.fragment.evaluationresult.SoundtListAdapter import com.navinfo.omqs.ui.other.shareViewModels import dagger.hilt.android.AndroidEntryPoint @@ -20,8 +43,30 @@ class NoteFragment : BaseFragment(), View.OnClickListener { private var _binding: FragmentNoteBinding? = null private val binding get() = _binding!! + private var mCameraLauncher: ActivityResultLauncher? = null + private val viewModel by shareViewModels("note") + private val pictureAdapter by lazy { + PictureAdapter() + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + mCameraLauncher = registerForActivityResult( + ActivityResultContracts.StartActivityForResult() + ) { result: ActivityResult -> + if (result.resultCode == Activity.RESULT_OK) { + // 处理相机返回的结果 + val extras = result.data!!.extras + val imageBitmap: Bitmap? = extras!!["data"] as Bitmap? + // 在这里处理图片数据 + if (imageBitmap != null) + viewModel.savePhoto(imageBitmap) + } + } + } + override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View { @@ -29,7 +74,19 @@ class NoteFragment : BaseFragment(), View.OnClickListener { return binding.root } + @RequiresApi(Build.VERSION_CODES.N) override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + + activity?.run { + findNavController( + R.id.main_activity_middle_fragment + ).navigate(R.id.CanvasFragment) + } + + //// 设置 RecyclerView 的固定大小,避免在滚动时重新计算视图大小和布局,提高性能 + binding.noteVoiceRecyclerview.setHasFixedSize(true) + val layoutManager = LinearLayoutManager(context) + binding.noteVoiceRecyclerview.layoutManager = layoutManager binding.sketchEraser.setOnClickListener(this) binding.sketchClear.setOnClickListener(this) binding.sketchForward.setOnClickListener(this) @@ -37,6 +94,7 @@ class NoteFragment : BaseFragment(), View.OnClickListener { binding.noteBarSave.setOnClickListener(this) binding.noteBarCancel.setOnClickListener(this) binding.noteBarDelete.setOnClickListener(this) + binding.noteCamera.setOnClickListener(this) binding.noteDescription.addTextChangedListener(object : TextWatcher { override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) { } @@ -48,6 +106,30 @@ class NoteFragment : BaseFragment(), View.OnClickListener { viewModel.noteBeanDescription = s.toString() } }) + + viewModel.liveDataNoteBean.observe(viewLifecycleOwner) { + binding.noteDescription.setText(it.description) + } + + //监听要提示的信息 + viewModel.liveDataToastMessage.observe(viewLifecycleOwner) { + Toast.makeText(requireContext(), it, Toast.LENGTH_SHORT).show() + } + /** + * 监听左侧栏的点击事件 + */ + val adapter = SoundtListAdapter { _, _ -> + + } + binding.noteVoiceRecyclerview.adapter = adapter + /** + * 照片view + */ + /** + * 照片view + */ + binding.notePictureViewpager.adapter = pictureAdapter + /** * 数据操作结束 */ @@ -69,29 +151,107 @@ class NoteFragment : BaseFragment(), View.OnClickListener { } } } - } + /** + * 音频view + */ + viewModel.listDataChatMsgEntityList.observe(viewLifecycleOwner) { + adapter.refreshData(it) + } - override fun onStart() { - super.onStart() - activity?.run { - findNavController( - R.id.main_activity_middle_fragment - ).navigate(R.id.CanvasFragment) + /** + * 照片view + */ + viewModel.liveDataPictureList.observe(viewLifecycleOwner){ + pictureAdapter.refreshData(it) + } + + //照片左右选择键点击监听 + binding.notePictureLeft.setOnClickListener(this) + binding.notePictureRight.setOnClickListener(this) + binding.noteCamera.setOnClickListener(this) + //设置照片偏移量 + val viewPager = binding.notePictureViewpager + val vto = viewPager.viewTreeObserver + vto.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener { + override fun onGlobalLayout() { + val width = viewPager.width + // 处理View宽度 + // 在回调完成后,需要将监听器从View树中移除,以避免重复调用 + viewPager.viewTreeObserver.removeOnGlobalLayoutListener(this) + + val recyclerView = viewPager.getChildAt(0) as RecyclerView + + recyclerView.setPadding(0, 0, width / 2 - 30, 0) + recyclerView.clipToPadding = false + } + }) + + binding.noteVoice.setOnTouchListener { _, event -> + Log.e("qj", event?.action.toString()) + when (event?.action) { + MotionEvent.ACTION_DOWN -> { + voiceOnTouchStart()//Do Something + } + + MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL, MotionEvent.ACTION_OUTSIDE -> { + voiceOnTouchStop()//Do Something + } + } + true } } - override fun onStop() { - super.onStop() - activity?.run { - findNavController( - R.id.main_activity_middle_fragment - ).navigateUp() + private fun voiceOnTouchStart() { + viewModel.startSoundMetter(requireActivity(), binding.noteVoice) + } + + private fun voiceOnTouchStop() { + Log.e("qj", "voiceOnTouchStop====${Constant.IS_VIDEO_SPEED}") + if (Constant.IS_VIDEO_SPEED) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + viewModel.stopSoundMeter() + } } } + private fun takePhoto() { + try { + val takePictureIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE) + if (takePictureIntent.resolveActivity(requireActivity().packageManager) != null) { + mCameraLauncher!!.launch(takePictureIntent) + } + } catch (e: Exception) { + Log.d("TTTT", e.toString()) + } + } + + override fun onDestroy() { + activity?.run { + val result = findNavController(R.id.main_activity_middle_fragment).navigateUp() + Log.e("qj","onStop===$result") + } + super.onDestroy() + } + override fun onClick(v: View) { when (v) { + binding.notePictureLeft->{ + val currentItem = binding.notePictureViewpager.currentItem + if (currentItem > 0) { + binding.notePictureViewpager.currentItem = currentItem - 1 + } else { + return + } + } + binding.notePictureRight->{ + val currentItem = binding.notePictureViewpager.currentItem + if (currentItem < pictureAdapter.data.size - 1) { + binding.notePictureViewpager.currentItem = currentItem + 1 + } else { + return + } + } binding.sketchEraser -> { viewModel.onEraser() binding.sketchEraser.isSelected = viewModel.isEraser @@ -125,6 +285,9 @@ class NoteFragment : BaseFragment(), View.OnClickListener { mDialog.setNegativeButton("取消", null) mDialog.show() } + binding.noteCamera-> { + takePhoto() + } } } diff --git a/app/src/main/java/com/navinfo/omqs/ui/fragment/note/NoteViewModel.kt b/app/src/main/java/com/navinfo/omqs/ui/fragment/note/NoteViewModel.kt index 20e2dc97..82bbfb16 100644 --- a/app/src/main/java/com/navinfo/omqs/ui/fragment/note/NoteViewModel.kt +++ b/app/src/main/java/com/navinfo/omqs/ui/fragment/note/NoteViewModel.kt @@ -1,18 +1,43 @@ package com.navinfo.omqs.ui.fragment.note +import android.app.Activity import android.content.Context +import android.graphics.Bitmap +import android.graphics.drawable.AnimationDrawable +import android.graphics.drawable.BitmapDrawable +import android.os.Build +import android.view.Gravity +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.PopupWindow +import androidx.annotation.RequiresApi import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import com.blankj.utilcode.util.ToastUtils +import com.navinfo.collect.library.data.entity.AttachmentBean import com.navinfo.collect.library.data.entity.NoteBean +import com.navinfo.collect.library.data.entity.QsRecordBean import com.navinfo.collect.library.map.NIMapController import com.navinfo.collect.library.utils.MapParamUtils +import com.navinfo.omqs.Constant +import com.navinfo.omqs.R +import com.navinfo.omqs.bean.ChatMsgEntity import com.navinfo.omqs.db.RealmOperateHelper import com.navinfo.omqs.ui.dialog.FirstDialog +import com.navinfo.omqs.util.DateTimeUtil +import com.navinfo.omqs.util.SoundMeter +import com.navinfo.omqs.util.SpeakMode import dagger.hilt.android.lifecycle.HiltViewModel import io.realm.Realm +import io.realm.RealmList import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch +import java.io.File +import java.io.FileOutputStream +import java.util.ArrayList +import java.util.UUID import javax.inject.Inject @HiltViewModel @@ -24,32 +49,40 @@ class NoteViewModel @Inject constructor( lateinit var canvasView: CanvasView - var mNoteBean: NoteBean? = null + /** + * 要保存的评测数据 + */ + val liveDataNoteBean = MutableLiveData(NoteBean(id = UUID.randomUUID().toString())) + /** + * 语音列表 + */ + val listDataChatMsgEntityList = MutableLiveData>() + + /** + * 照片列表 + */ + val liveDataPictureList = MutableLiveData>() var isEraser = false var noteBeanDescription = "" -// /** -// * 橡皮擦开关 -// */ -// val liveEraserData = MutableLiveData(false) -// -// /** -// * 清除按钮 -// */ -// val liveClearData = MutableLiveData(false) -// -// /** -// * 回退按钮 -// */ -// val liveBackData = MutableLiveData(false) -// -// /** -// * 撤销按钮 -// */ -// val liveForward = MutableLiveData(false) + //语音窗体 + private var pop: PopupWindow? = null + + private var mSpeakMode: SpeakMode? = null + + var oldBean: NoteBean? = null + + //录音图标 + var volume: ImageView? = null + + var mSoundMeter: SoundMeter? = null + /** + * toast信息 + */ + val liveDataToastMessage = MutableLiveData() /** * 处理结束关闭fragment */ @@ -105,21 +138,21 @@ class NoteViewModel @Inject constructor( fun onSaveData() { viewModelScope.launch(Dispatchers.IO) { if (canvasView.paths != null && canvasView.paths!!.isNotEmpty()) { - var noteBean = - CanvasViewHelper.createNoteBean(mapController, canvasView.paths!!) - if (mNoteBean != null) { - noteBean.id = mNoteBean!!.id - noteBean.description = noteBeanDescription - } - noteBean.taskId = MapParamUtils.getTaskId() - mNoteBean = noteBean + var noteBean = CanvasViewHelper.createNoteBean(mapController, canvasView.paths!!) + liveDataNoteBean.value!!.taskId = MapParamUtils.getTaskId() + liveDataNoteBean.value!!.list = noteBean.list + liveDataNoteBean.value!!.description = noteBeanDescription + liveDataNoteBean.value!!.guideGeometry = noteBean.guideGeometry val realm = realmOperateHelper.getRealmDefaultInstance() realm.executeTransaction { - it.copyToRealmOrUpdate(noteBean) + it.copyToRealmOrUpdate(liveDataNoteBean.value) } - mapController.markerHandle.addOrUpdateNoteMark(mNoteBean!!) + mapController.markerHandle.addOrUpdateNoteMark(liveDataNoteBean.value!!) liveDataFinish.postValue(true) + realm.refresh() realm.close() + }else{ + liveDataToastMessage.postValue("请绘制内容!") } } } @@ -128,7 +161,7 @@ class NoteViewModel @Inject constructor( * 删除数据 */ fun deleteData(context: Context) { - if (mNoteBean == null) { + if (liveDataNoteBean.value == null) { liveDataFinish.postValue(true) return } else { @@ -143,10 +176,10 @@ class NoteViewModel @Inject constructor( val realm = realmOperateHelper.getRealmDefaultInstance() realm.executeTransaction { val objects = it.where(NoteBean::class.java) - .equalTo("id", mNoteBean!!.id).findFirst() + .equalTo("id", liveDataNoteBean.value!!.id).findFirst() objects?.deleteFromRealm() } - mapController.markerHandle.removeNoteMark(mNoteBean!!) + mapController.markerHandle.removeNoteMark(liveDataNoteBean.value!!) liveDataFinish.postValue(true) realm.close() } @@ -159,20 +192,200 @@ class NoteViewModel @Inject constructor( /** * 初始化数据 */ + @RequiresApi(Build.VERSION_CODES.N) fun initData(id: String) { viewModelScope.launch(Dispatchers.IO) { val realm = realmOperateHelper.getRealmDefaultInstance() realm.executeTransaction { it -> val objects = it.where(NoteBean::class.java) .equalTo("id", id).findFirst() - mNoteBean = realm.copyFromRealm(objects) - mNoteBean?.let { bean -> - noteBeanDescription = bean.description - val list = CanvasViewHelper.createDrawPaths(mapController, bean) - canvasView.setDrawPathList(list) + if(objects!=null){ + oldBean = realm.copyFromRealm(objects) + oldBean?.let { + noteBeanDescription = it.description + liveDataNoteBean.postValue(it.copy()) + val list = CanvasViewHelper.createDrawPaths(mapController, it) + canvasView.setDrawPathList(list) + liveDataNoteBean.value?.attachmentBeanList = it.attachmentBeanList + } } } + // 显示语音数据到界面 + getChatMsgEntityList() + realm.close() + } } + + fun startSoundMetter(activity: Activity, v: View) { + + if (mSpeakMode == null) { + mSpeakMode = SpeakMode(activity) + } + + //语音识别动画 + if (pop == null) { + pop = PopupWindow() + pop!!.width = ViewGroup.LayoutParams.MATCH_PARENT + pop!!.height = ViewGroup.LayoutParams.WRAP_CONTENT + pop!!.setBackgroundDrawable(BitmapDrawable()) + val view = + View.inflate(activity as Context, R.layout.cv_card_voice_rcd_hint_window, null) + pop!!.contentView = view + volume = view.findViewById(R.id.volume) + } + + pop!!.update() + + Constant.IS_VIDEO_SPEED = true + //录音动画 + if (pop != null) { + pop!!.showAtLocation(v, Gravity.CENTER, 0, 0) + } + volume!!.setBackgroundResource(R.drawable.pop_voice_img) + val animation = volume!!.background as AnimationDrawable + animation.start() + + val name: String = DateTimeUtil.getTimeSSS().toString() + ".m4a" + if (mSoundMeter == null) { + mSoundMeter = SoundMeter() + } + mSoundMeter!!.setmListener(object : SoundMeter.OnSoundMeterListener { + @RequiresApi(Build.VERSION_CODES.Q) + override fun onSuccess(filePath: String?) { + filePath?.let { + val file = File(it) + if (file.exists() && file.length() < 1600) { + ToastUtils.showLong("语音时间太短,无效!") + mSpeakMode!!.speakText("语音时间太短,无效") + stopSoundMeter() + return + } + } + + mSpeakMode!!.speakText("结束录音") + addChatMsgEntity(filePath!!) + } + + @RequiresApi(api = Build.VERSION_CODES.Q) + override fun onfaild(message: String?) { + ToastUtils.showLong("录制失败!") + mSpeakMode!!.speakText("录制失败") + stopSoundMeter() + } + }) + + mSoundMeter!!.start(Constant.USER_DATA_ATTACHEMNT_PATH + name) + ToastUtils.showLong("开始录音") + mSpeakMode!!.speakText("开始录音") + } + + //停止语音录制 + @RequiresApi(api = Build.VERSION_CODES.Q) + fun stopSoundMeter() { + //先重置标识,防止按钮抬起时触发语音结束 + Constant.IS_VIDEO_SPEED = false + if (mSoundMeter != null && mSoundMeter!!.isStartSound) { + mSoundMeter!!.stop() + } + pop?.let { + if (it.isShowing) { + it.dismiss() + } + } + } + + + fun savePhoto(bitmap: Bitmap) { + viewModelScope.launch(Dispatchers.IO) { + // 创建一个名为 "MyApp" 的文件夹 + val myAppDir = File(Constant.USER_DATA_ATTACHEMNT_PATH) + if (!myAppDir.exists()) myAppDir.mkdirs() // 确保文件夹已创建 + + // 创建一个名为 fileName 的文件 + val file = File(myAppDir, "${UUID.randomUUID()}.png") + file.createNewFile() // 创建文件 + + // 将 Bitmap 压缩为 JPEG 格式,并将其写入文件中 + val out = FileOutputStream(file) + bitmap.compress(Bitmap.CompressFormat.JPEG, 90, out) + out.flush() + out.close() + val picList = mutableListOf() + if (liveDataPictureList.value == null) { + picList.add(file.name) + } else { + picList.addAll(liveDataPictureList.value!!) + picList.add(file.name) + } + + var attachmentList: RealmList = RealmList() + //赋值处理 + if (liveDataNoteBean.value?.attachmentBeanList?.isEmpty() == false) { + attachmentList = liveDataNoteBean.value?.attachmentBeanList!! + } + val attachmentBean = AttachmentBean() + attachmentBean.name = file.name!! + attachmentBean.type = 2 + attachmentList.add(attachmentBean) + liveDataNoteBean.value?.attachmentBeanList = attachmentList + liveDataPictureList.postValue(picList) + } + + } + + + /** + * 多媒体列表 + */ + private suspend fun getChatMsgEntityList() { + val chatMsgEntityList: MutableList = ArrayList() + val pictureList: MutableList = ArrayList() + liveDataNoteBean.value?.attachmentBeanList?.forEach { + //1 录音 + if (it.type == 1) { + val chatMsgEntity = ChatMsgEntity() + chatMsgEntity.name = it.name + chatMsgEntity.voiceUri = Constant.USER_DATA_ATTACHEMNT_PATH + chatMsgEntityList.add(chatMsgEntity) + }else if(it.type==2){ + pictureList.add(it.name) + } + + } + listDataChatMsgEntityList.postValue(chatMsgEntityList) + liveDataPictureList.postValue(pictureList) + } + + fun addChatMsgEntity(filePath: String) { + + if (filePath.isNotEmpty()) { + var chatMsgEntityList: MutableList = ArrayList() + if (listDataChatMsgEntityList.value?.isEmpty() == false) { + chatMsgEntityList = listDataChatMsgEntityList.value!! + } + val chatMsgEntity = ChatMsgEntity() + chatMsgEntity.name = filePath.replace(Constant.USER_DATA_ATTACHEMNT_PATH, "").toString() + chatMsgEntity.voiceUri = Constant.USER_DATA_ATTACHEMNT_PATH + chatMsgEntityList.add(chatMsgEntity) + + + var attachmentList: RealmList = RealmList() + + //赋值处理 + if (liveDataNoteBean.value?.attachmentBeanList?.isEmpty() == false) { + attachmentList = liveDataNoteBean.value?.attachmentBeanList!! + } + + val attachmentBean = AttachmentBean() + attachmentBean.name = chatMsgEntity.name!! + attachmentBean.type = 1 + attachmentList.add(attachmentBean) + liveDataNoteBean.value?.attachmentBeanList = attachmentList + + listDataChatMsgEntityList.postValue(chatMsgEntityList) + } + } + } \ No newline at end of file diff --git a/app/src/main/java/com/navinfo/omqs/ui/fragment/signMoreInfo/SignMoreInfoFragment.kt b/app/src/main/java/com/navinfo/omqs/ui/fragment/signMoreInfo/SignMoreInfoFragment.kt index 37023521..7eecbd69 100644 --- a/app/src/main/java/com/navinfo/omqs/ui/fragment/signMoreInfo/SignMoreInfoFragment.kt +++ b/app/src/main/java/com/navinfo/omqs/ui/fragment/signMoreInfo/SignMoreInfoFragment.kt @@ -105,6 +105,13 @@ class SignMoreInfoFragment : BaseFragment() { } else -> { val adapter = SignUtil.getMoreInfoAdapter(it.renderEntity) + //增加详情为空不显示业务 + if(adapter==null || adapter.data.isEmpty()){ + activity?.run { + supportFragmentManager.beginTransaction().remove(this@SignMoreInfoFragment) + .commit() + } + } binding.signInfoRecyclerview.adapter = adapter } } diff --git a/app/src/main/java/com/navinfo/omqs/util/ImageLoad.java b/app/src/main/java/com/navinfo/omqs/util/ImageLoad.java new file mode 100644 index 00000000..c8c4a78d --- /dev/null +++ b/app/src/main/java/com/navinfo/omqs/util/ImageLoad.java @@ -0,0 +1,943 @@ +package com.navinfo.omqs.util; + + +//Download by http://www.codefans.net + +import android.app.Activity; +import android.content.ContentResolver; +import android.content.Context; +import android.database.Cursor; +import android.graphics.Bitmap; +import android.graphics.Bitmap.Config; +import android.graphics.BitmapFactory; +import android.graphics.Canvas; +import android.graphics.LinearGradient; +import android.graphics.Matrix; +import android.graphics.Paint; +import android.graphics.PixelFormat; +import android.graphics.PorterDuff.Mode; +import android.graphics.PorterDuffXfermode; +import android.graphics.Rect; +import android.graphics.RectF; +import android.graphics.Shader.TileMode; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.media.ExifInterface; +import android.net.Uri; +import android.util.Log; +import android.view.Display; +import android.view.WindowManager; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; + +/** + * Tools for handler picture + * + * @author Ryan.Tang + * + */ +public final class ImageLoad { + static Bitmap bitmap = null; + Context con; + + public ImageLoad(Context con){ + this.con=con; + } + + /** + * Transfer drawable to bitmap + * + * @param drawable + * @return + */ + public static Bitmap drawableToBitmap(Drawable drawable) { + int w = drawable.getIntrinsicWidth(); + int h = drawable.getIntrinsicHeight(); + + Config config = drawable.getOpacity() != PixelFormat.OPAQUE ? Config.ARGB_8888 + : Config.RGB_565; + Bitmap bitmap = Bitmap.createBitmap(w, h, config); + Canvas canvas = new Canvas(bitmap); + drawable.setBounds(0, 0, w, h); + drawable.draw(canvas); + return bitmap; + } + + /** + * Bitmap to drawable + * + * @param bitmap + * @return + */ + public static Drawable bitmapToDrawable(Bitmap bitmap) { + return new BitmapDrawable(bitmap); + } + + /** + * Input stream to bitmap + * + * @param inputStream + * @return + * @throws Exception + */ + public static Bitmap inputStreamToBitmap(InputStream inputStream) + throws Exception { + return BitmapFactory.decodeStream(inputStream); + } + + /** + * Byte transfer to bitmap + * + * @param byteArray + * @return + */ + public static Bitmap byteToBitmap(byte[] byteArray) { + if (byteArray.length != 0) { + return BitmapFactory + .decodeByteArray(byteArray, 0, byteArray.length); + } else { + return null; + } + } + + /** + * Byte transfer to drawable + * + * @param byteArray + * @return + */ + public static Drawable byteToDrawable(byte[] byteArray) { + ByteArrayInputStream ins = null; + if (byteArray != null) { + ins = new ByteArrayInputStream(byteArray); + } + return Drawable.createFromStream(ins, null); + } + + /** + * Bitmap transfer to bytes + * + * @param byteArray + * @return + */ + public static byte[] bitmapToBytes(Bitmap bm) { + byte[] bytes = null; + if (bm != null) { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + bm.compress(Bitmap.CompressFormat.PNG, 100, baos); + bytes = baos.toByteArray(); + } + return bytes; + } + + /** + * Drawable transfer to bytes + * + * @param drawable + * @return + */ + public static byte[] drawableToBytes(Drawable drawable) { + BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable; + Bitmap bitmap = bitmapDrawable.getBitmap(); + byte[] bytes = bitmapToBytes(bitmap); + ; + return bytes; + } + + /** + * Base64 to byte[] // + */ + // public static byte[] base64ToBytes(String base64) throws IOException { + // byte[] bytes = Base64.decode(base64); + // return bytes; + // } + // + // /** + // * Byte[] to base64 + // */ + // public static String bytesTobase64(byte[] bytes) { + // String base64 = Base64.encode(bytes); + // return base64; + // } + + /** + * Create reflection images + * + * @param bitmap + * @return + */ + public static Bitmap createReflectionImageWithOrigin(Bitmap bitmap) { + final int reflectionGap = 4; + int w = bitmap.getWidth(); + int h = bitmap.getHeight(); + + Matrix matrix = new Matrix(); + matrix.preScale(1, -1); + + Bitmap reflectionImage = Bitmap.createBitmap(bitmap, 0, h / 2, w, + h / 2, matrix, false); + + Bitmap bitmapWithReflection = Bitmap.createBitmap(w, (h + h / 2), + Config.ARGB_8888); + + Canvas canvas = new Canvas(bitmapWithReflection); + canvas.drawBitmap(bitmap, 0, 0, null); + Paint deafalutPaint = new Paint(); + canvas.drawRect(0, h, w, h + reflectionGap, deafalutPaint); + + canvas.drawBitmap(reflectionImage, 0, h + reflectionGap, null); + + Paint paint = new Paint(); + LinearGradient shader = new LinearGradient(0, bitmap.getHeight(), 0, + bitmapWithReflection.getHeight() + reflectionGap, 0x70ffffff, + 0x00ffffff, TileMode.CLAMP); + paint.setShader(shader); + // Set the Transfer mode to be porter duff and destination in + paint.setXfermode(new PorterDuffXfermode(Mode.DST_IN)); + // Draw a rectangle using the paint with our linear gradient + canvas.drawRect(0, h, w, bitmapWithReflection.getHeight() + + reflectionGap, paint); + + return bitmapWithReflection; + } + + /** + * 圆角 + * + * @param bitmap + * @param roundPx + * 5 10 + * @return + */ + public static Bitmap getRoundedCornerBitmap(Bitmap bitmap, float roundPx) { + int w = bitmap.getWidth(); + int h = bitmap.getHeight(); + Bitmap output = Bitmap.createBitmap(w, h, Config.ARGB_8888); + Canvas canvas = new Canvas(output); + final int color = 0xff424242; + final Paint paint = new Paint(); + final Rect rect = new Rect(0, 0, w, h); + final RectF rectF = new RectF(rect); + paint.setAntiAlias(true); + canvas.drawARGB(0, 0, 0, 0); + paint.setColor(color); + canvas.drawRoundRect(rectF, roundPx, roundPx, paint); + paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN)); + canvas.drawBitmap(bitmap, rect, rect, paint); + + return output; + } + + /** + * Resize the bitmap + * + * @param bitmap + * @param width + * @param height + * @return + */ + public static Bitmap zoomBitmap(Bitmap bitmap, int width, int height) { + int w = bitmap.getWidth(); + int h = bitmap.getHeight(); + Matrix matrix = new Matrix(); + float scaleWidth = ((float) width / w); + float scaleHeight = ((float) height / h); + matrix.postScale(scaleWidth, scaleHeight); + Bitmap newbmp = Bitmap.createBitmap(bitmap, 0, 0, w, h, matrix, true); + return newbmp; + } + + public static Bitmap zoomBitmap(String cameraPath,int width,int height, int size) { + + // 获取图片Exif + ExifInterface exif; + int degree = 0; + try { + exif = new ExifInterface(cameraPath); + // 获取指定tag的属性值 + int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, -1); + if (orientation != -1) { + // We only recognize a subset of orientation tag values. + switch (orientation) { + case ExifInterface.ORIENTATION_NORMAL: + degree = 0 ; + break; + case ExifInterface.ORIENTATION_UNDEFINED: + degree = 0 ; + break; + case ExifInterface.ORIENTATION_ROTATE_90: + degree = 90; + break; + case ExifInterface.ORIENTATION_ROTATE_180: + degree = 180; + break; + case ExifInterface.ORIENTATION_ROTATE_270: + degree = 270; + break; + default: + degree = 90; + break; + } + } + } catch (IOException e) { + + e.printStackTrace(); + CMLog.writeLogtoFile("展示图片生成异常", "异常", e.toString()); + } + + try { + BitmapFactory.Options bmpFactoryOptions = new BitmapFactory.Options(); + bmpFactoryOptions.inJustDecodeBounds = true; + bitmap = BitmapFactory.decodeFile(cameraPath,bmpFactoryOptions);//此时返回bm为空 + bmpFactoryOptions.inJustDecodeBounds = false; + bmpFactoryOptions.inSampleSize = size; + int heightRatio = (int) Math.ceil(bmpFactoryOptions.outHeight/ (float) height); + int widthRatio = (int) Math.ceil(bmpFactoryOptions.outWidth/ (float) width); + if (heightRatio > 1 && widthRatio > 1) { + bmpFactoryOptions.inSampleSize = heightRatio < widthRatio ? heightRatio: widthRatio; + } + + bmpFactoryOptions.inPreferredConfig = Config.ARGB_8888;//该模式是默认的,可不设 + bmpFactoryOptions.inPurgeable = true;// 同时设置才会有效 + bmpFactoryOptions.inInputShareable = true;//。当系统内存不够时候图片自动被回收 + if(bitmap!=null&&!bitmap.isRecycled()) + bitmap.recycle(); + bitmap=BitmapFactory.decodeFile(cameraPath, bmpFactoryOptions); + + if (degree != 0 && bitmap != null) { + Matrix m = new Matrix(); + m.setRotate(degree, (float) bitmap.getWidth() / 2,(float) bitmap.getHeight() / 2); + + Bitmap b2 = Bitmap.createBitmap(bitmap, 0, 0,bitmap.getWidth(), bitmap.getHeight(), m, true); + if (bitmap != b2) { + bitmap.recycle(); + bitmap = b2; + if(b2!=null&&b2.isRecycled()) + b2.recycle(); + } + } + + } catch (OutOfMemoryError e) { + CMLog.writeLogtoFile("照片内存溢出", "异常", "创建展示图异常:OutOfMemoryError"); + System.gc(); + } + //new File(cameraPath).delete(); + return bitmap; + + } + + public static Bitmap zoomBitmap(String cameraPath, int multiple) { + + Bitmap bitmap = null; + BitmapFactory.Options options = new BitmapFactory.Options(); + options.inSampleSize = multiple; // 图片宽高都为原来的二分之一,即图片为原来的四分之一 + // 获取图片Exif + ExifInterface exif; + int degree = 0; + try { + exif = new ExifInterface(cameraPath); + // 获取指定tag的属性值 + int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, -1); + if (orientation != -1) { + // We only recognize a subset of orientation tag values. + switch (orientation) { + case ExifInterface.ORIENTATION_ROTATE_90: + degree = 90; + break; + case ExifInterface.ORIENTATION_ROTATE_180: + degree = 180; + break; + case ExifInterface.ORIENTATION_ROTATE_270: + degree = 270; + break; +/* default: + degree = 90; + break; + */ + } + } + } catch (IOException e) { + + e.printStackTrace(); + CMLog.writeLogtoFile("缩略图生成异常", "异常", e.toString()); + } + + try { + + bitmap = ImageCrop(BitmapFactory.decodeFile(cameraPath, options)); + if (degree != 0 && bitmap != null) { + Matrix m = new Matrix(); + m.setRotate(degree, (float) bitmap.getWidth() / 2,(float) bitmap.getHeight() / 2); + + Bitmap b2 = Bitmap.createBitmap(bitmap, 0, 0, + bitmap.getWidth(), bitmap.getHeight(), m, true); + if (bitmap != b2) { + bitmap.recycle(); + bitmap = b2; + } + } + } catch (OutOfMemoryError e) { + CMLog.writeLogtoFile("照片内存溢出", "异常", "创建缩略图异常:OutOfMemoryError"); + System.gc(); + } + if (bitmap == null) { + + } + return bitmap; + + } + + private static int getDegree(String filePath){ + if(!new File(filePath).exists()) + return 0; + ExifInterface exif; + int degree = 0; + try { + exif = new ExifInterface(filePath); + // 获取指定tag的属性值 + int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, -1); + if (orientation != -1) { + // We only recognize a subset of orientation tag values. + switch (orientation) { + case ExifInterface.ORIENTATION_ROTATE_90: + degree = 90; + break; + case ExifInterface.ORIENTATION_ROTATE_180: + degree = 180; + break; + case ExifInterface.ORIENTATION_ROTATE_270: + degree = 270; + break; +/* default: + degree = 90; + break; + */ + } + } + } catch (IOException e) { + + e.printStackTrace(); + CMLog.writeLogtoFile("缩略图生成异常", "异常", e.toString()); + } + return degree; + } + + /** + * 按正方形裁切图片 + */ + public static Bitmap ImageCrop(Bitmap bitmap) { + if(bitmap == null) + return null; + int w = bitmap.getWidth(); // 得到图片的宽,高 + int h = bitmap.getHeight(); + + int wh = w > h ? h : w;// 裁切后所取的正方形区域边长 + + int retX = w > h ? (w - h) / 2 : 0;// 基于原图,取正方形左上角x坐标 + int retY = w > h ? 0 : (h - w) / 2; + + // 下面这句是关键 + return Bitmap.createBitmap(bitmap, retX, retY, wh, wh, null, false); + } + + public static Bitmap zoomBitmap(byte[] data, int multiple, int degrees) { + + Bitmap bitmap = null; + BitmapFactory.Options options = new BitmapFactory.Options(); + options.inSampleSize = multiple; // 图片宽高都为原来的二分之一,即图片为原来的四分之一 + try { + bitmap = BitmapFactory.decodeByteArray(data, 0, data.length,options); + + if (degrees != 0 && bitmap != null) { + Matrix m = new Matrix(); + m.setRotate(degrees, (float) bitmap.getWidth() / 2, + (float) bitmap.getHeight() / 2); + try { + Bitmap b2 = Bitmap.createBitmap(bitmap, 0, 0, + bitmap.getWidth(), bitmap.getHeight(), m, true); + if (bitmap != b2) { + bitmap.recycle(); + bitmap = b2; + } + } catch (OutOfMemoryError ex) { + // We have no memory to rotate. Return the original bitmap. + } + } + + } catch (OutOfMemoryError e) { + CMLog.writeLogtoFile("照片内存溢出", "异常", "创建缩略图异常:OutOfMemoryError"); + System.gc(); + } + if (bitmap == null) { + + } + return bitmap; + + } + + /** + * Resize the drawable + * + * @param drawable + * @param w + * @param h + * @return + */ + public static Drawable zoomDrawable(Drawable drawable, int w, int h) { + int width = drawable.getIntrinsicWidth(); + int height = drawable.getIntrinsicHeight(); + Bitmap oldbmp = drawableToBitmap(drawable); + Matrix matrix = new Matrix(); + float sx = ((float) w / width); + float sy = ((float) h / height); + matrix.postScale(sx, sy); + Bitmap newbmp = Bitmap.createBitmap(oldbmp, 0, 0, width, height, + matrix, true); + return new BitmapDrawable(newbmp); + } + + /** + * Get images from SD card by path and the name of image + * + * @param photoName + * @return + */ + public static Bitmap getPhotoFromSDCard(String path, String photoName) { + Bitmap photoBitmap = BitmapFactory.decodeFile(path + "/" + photoName + + ".png"); + if (photoBitmap == null) { + return null; + } else { + return photoBitmap; + } + } + + /** + * Check the SD card + * + * @return + */ + public static boolean checkSDCardAvailable() { + return android.os.Environment.getExternalStorageState().equals( + android.os.Environment.MEDIA_MOUNTED); + } + + /** + * Get image from SD card by path and the name of image + * + * @param photoName + * @return + */ + public static boolean findPhotoFromSDCard(String path, String photoName) { + boolean flag = false; + + if (checkSDCardAvailable()) { + File dir = new File(path); + if (dir.exists()) { + File folders = new File(path); + File photoFile[] = folders.listFiles(); + for (int i = 0; i < photoFile.length; i++) { + String fileName = photoFile[i].getName().split("\\.")[0]; + if (fileName.equals(photoName)) { + flag = true; + } + } + } else { + flag = false; + } + // File file = new File(path + "/" + photoName + ".jpg" ); + // if (file.exists()) { + // flag = true; + // }else { + // flag = false; + // } + + } else { + flag = false; + } + return flag; + } + + /** + * Save image to the SD card + * + * @param photoBitmap + * @param photoName + * @param path + */ + public static void savePhotoToSDCard(Bitmap photoBitmap, String path, + String photoName) { + if (checkSDCardAvailable()) { + File dir = new File(path); + if (!dir.exists()) { + dir.mkdirs(); + } + + File photoFile = new File(path, photoName + ".png"); + FileOutputStream fileOutputStream = null; + try { + fileOutputStream = new FileOutputStream(photoFile); + if (photoBitmap != null) { + if (photoBitmap.compress(Bitmap.CompressFormat.PNG, 100, + fileOutputStream)) { + fileOutputStream.flush(); + // fileOutputStream.close(); + } + } + } catch (FileNotFoundException e) { + photoFile.delete(); + e.printStackTrace(); + } catch (IOException e) { + photoFile.delete(); + e.printStackTrace(); + } finally { + try { + fileOutputStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + } + + /** + * Delete the image from SD card + * + * @param path + * file:///sdcard/temp.jpg + */ + public static void deleteAllPhoto(String path) { + if (checkSDCardAvailable()) { + File folder = new File(path); + File[] files = folder.listFiles(); + for (int i = 0; i < files.length; i++) { + files[i].delete(); + } + } + } + + public static void deletePhotoAtPathAndName(String path, String fileName) { + if (checkSDCardAvailable()) { + File folder = new File(path); + File[] files = folder.listFiles(); + for (int i = 0; i < files.length; i++) { + System.out.println(files[i].getName()); + if (files[i].getName().equals(fileName)) { + files[i].delete(); + } + } + } + } + + public Bitmap setImage(Uri mImageCaptureUri) { + // 不管是拍照还是选择图片每张图片都有在数据中存储也存储有对应旋转角度orientation值 + // 所以我们在取出图片是把角度值取出以便能正确的显示图片,没有旋转时的效果观看 + + ContentResolver cr = con.getContentResolver(); + Cursor cursor = cr.query(mImageCaptureUri, null, null, null, null);// 根据Uri从数据库中找 + if (cursor != null) { + cursor.moveToFirst();// 把游标移动到首位,因为这里的Uri是包含ID的所以是唯一的不需要循环找指向第一个就是了 + String filePath = cursor.getString(cursor.getColumnIndex("_data"));// 获取图片路 + String orientation = cursor.getString(cursor + .getColumnIndex("orientation"));// 获取旋转的角度 + cursor.close(); + if (filePath != null) { + Bitmap bitmap = BitmapFactory.decodeFile(filePath);// 根据Path读取资源图片 + int angle = 0; + if (orientation != null && !"".equals(orientation)) { + angle = Integer.parseInt(orientation); + } + if (angle != 0) { + // 下面的方法主要作用是把图片转一个角度,也可以放大缩小等 + Matrix m = new Matrix(); + int width = bitmap.getWidth(); + int height = bitmap.getHeight(); + m.setRotate(angle); // 旋转angle度 + bitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height, + m, true);// 从新生成图片 + } + // photo.setImageBitmap(bitmap); + return bitmap; + } + } + return null; + } + + /** + * 读取图片属性:旋转的角度 + * + * @param path + * 图片绝对路径 + * @return degree旋转的角度 + */ + public static int readPictureDegree(String path) { + int degree = 0; + try { + ExifInterface exifInterface = new ExifInterface(path); + int orientation = exifInterface.getAttributeInt( + ExifInterface.TAG_ORIENTATION, -1); + switch (orientation) { + case ExifInterface.ORIENTATION_ROTATE_90: + degree = 90; + break; + case ExifInterface.ORIENTATION_ROTATE_180: + degree = 180; + break; + case ExifInterface.ORIENTATION_ROTATE_270: + degree = 270; + break; + } + Log.i("ImageTools", "获取拍照角度:" + degree); + } catch (IOException e) { + e.printStackTrace(); + Log.i("ImageTools", "获取拍照角度异常:" + e.getMessage()); + } + return degree; + } + + /* + * 旋转图片 + * + * @param angle + * + * @param bitmap + * + * @return Bitmap + */ + public static Bitmap rotaingImageView(int angle, Bitmap bitmap) { + // 旋转图片 动作 + Matrix matrix = new Matrix(); + matrix.postRotate(angle); + System.out.println("angle2=" + angle); + if (bitmap != null) { + // 创建新的图片 + Bitmap resizedBitmap = Bitmap.createBitmap(bitmap, 0, 0, + bitmap.getWidth(), bitmap.getHeight(), matrix, true); + return resizedBitmap; + } + + return null; + } + + /* + * 旋转图片 + * + * @param bitmap + * + * @param filePath + * + * @return Bitmap + */ + public static void saveBitmap(Bitmap bitmap, String filePath) { + File f = new File(filePath); + if (f.exists()) { + f.delete(); + } + try { + FileOutputStream out = new FileOutputStream(f); + bitmap.compress(Bitmap.CompressFormat.JPEG, 90, out); + out.flush(); + out.close(); + } catch (FileNotFoundException e) { + // TODO Auto-generated catch block + CMLog.writeLogtoFile("照片生成", "拍照", "重新生成照片异常FileNotFoundException:" + + e.getMessage()); + e.printStackTrace(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + CMLog.writeLogtoFile("照片生成", "拍照", "重新生成照片IO异常:" + e.getMessage()); + } + + } + + /* + * 释放Bitmap + * + * @param bitmap + */ + public static void recycleBitmap(Bitmap bitmap) { + if (bitmap != null && !bitmap.isRecycled()) { + + // 回收并且置为null + + bitmap.recycle(); + + bitmap = null; + + } + + System.gc(); + + } + + /* + * 创建缩略图 + * + * @param filePath + * + * @return Bitmap + */ + public static Bitmap createZoominBitmap(String filePath) { + Bitmap bitmap = null; + + try { + + // 实例化Bitmap + + bitmap = BitmapFactory.decodeFile(filePath); + + } catch (OutOfMemoryError e) { + + // + + } + return bitmap; + } + + public static Bitmap getBitmapLittle(Context context, String absolutePath) { + BitmapFactory.Options opt = new BitmapFactory.Options(); + // 这个isjustdecodebounds很重要 + opt.inJustDecodeBounds = true; + Bitmap bm = BitmapFactory.decodeFile(absolutePath, opt); + + // 获取到这个图片的原始宽度和高度 + int picWidth = opt.outWidth; + int picHeight = opt.outHeight; + + // 获取屏的宽度和高度 + WindowManager windowManager = ((Activity)context).getWindowManager(); + Display display = windowManager.getDefaultDisplay(); + int screenWidth = display.getWidth(); + int screenHeight = display.getHeight(); + + // isSampleSize是表示对图片的缩放程度,比如值为2图片的宽度和高度都变为以前的1/2 + opt.inSampleSize = 1; + // 根据屏的大小和图片大小计算出缩放比例 + if (picWidth > picHeight) { + if (picWidth > screenWidth) + opt.inSampleSize = picWidth / screenWidth; + } else { + if (picHeight > screenHeight) + + opt.inSampleSize = picHeight / screenHeight; + } + + // 这次再真正地生成一个有像素的,经过缩放了的bitmap + opt.inJustDecodeBounds = false; + bm = BitmapFactory.decodeFile(absolutePath, opt); + + return bm; + } + + /** + * 计算压缩比例值 + * @param options 解析图片的配置信息 + * @param reqWidth 所需图片压缩尺寸最小宽度 + * @param reqHeight 所需图片压缩尺寸最小高度 + * @return + */ + public static int calculateInSampleSize(BitmapFactory.Options options, + int reqWidth, int reqHeight) { + // 保存图片原宽高值 + final int height = options. outHeight; + final int width = options. outWidth; + // 初始化压缩比例为1 + int inSampleSize = 1; + + // 当图片宽高值任何一个大于所需压缩图片宽高值时,进入循环计算系统 + if (height > reqHeight || width > reqWidth) { + + final int halfHeight = height / 2; + final int halfWidth = width / 2; + + // 压缩比例值每次循环两倍增加, + // 直到原图宽高值的一半除以压缩值后都~大于所需宽高值为止 + while ((halfHeight / inSampleSize) >= reqHeight + && (halfWidth / inSampleSize) >= reqWidth) { + inSampleSize *= 2; + } + } + + return inSampleSize; + } + + /*public static void loadImage(int resid, String url, final ImageView imageView){ + final String tmpUrl = url; + DisplayImageOptions options = new DisplayImageOptions.Builder() + .showImageOnLoading(resid) + .showImageForEmptyUri(resid) + .showImageOnFail(resid) + .cacheInMemory(true) + .cacheOnDisc(true) + .bitmapConfig(Bitmap.Config.ARGB_8888) + .build(); + ImageLoader.getInstance().displayImage(tmpUrl, imageView, options, + new ImageLoadingListener() { + + @Override + public void onLoadingStarted(String arg0, View arg1) { + // TODO Auto-generated method stub + } + + @Override + public void onLoadingFailed(String arg0, View arg1, + FailReason arg2) { + // TODO Auto-generated method stub + + } + + @Override + public void onLoadingComplete(String arg0, View arg1, + Bitmap bmp) { + // TODO Auto-generated method stub + if (bmp == null) + return; + if( ((BaseZoomImageView)arg1).isDestroyed() ){ + bmp.recycle(); + return; + } + String path = ((PictureInfor)arg1.getTag()).mFilePath; + int degree = getDegree(path); + try { + + if (degree != 0 && bmp != null&&!bmp.isRecycled()) { + Matrix m = new Matrix(); + m.setRotate(degree, (float) bmp.getWidth() / 2,(float) bmp.getHeight() / 2); + + Bitmap b2 = Bitmap.createBitmap(bmp, 0, 0, + bmp.getWidth(), bmp.getHeight(), m, true); + if (bmp != b2) { + bmp.recycle(); + bmp = b2; + } + } + } catch (OutOfMemoryError e) { + CMLog.writeLogtoFile("照片内存溢出", "异常", "创建缩略图异常:OutOfMemoryError"); + System.gc(); + } + + ((BaseZoomImageView)arg1).setImageBitmap(bmp); + ((BaseZoomImageView)arg1).setImageDrawable(null); + if(new File(path).exists()) + return; + saveBitmap(bmp, path); + } + + @Override + public void onLoadingCancelled(String arg0, View arg1) { + // TODO Auto-generated method stub + + } + }); + }*/ + + + + +} diff --git a/app/src/main/java/com/navinfo/omqs/util/ImageTools.java b/app/src/main/java/com/navinfo/omqs/util/ImageTools.java new file mode 100644 index 00000000..1c0c3189 --- /dev/null +++ b/app/src/main/java/com/navinfo/omqs/util/ImageTools.java @@ -0,0 +1,1266 @@ +package com.navinfo.omqs.util; + + +//Download by http://www.codefans.net + +import android.app.Activity; +import android.content.ContentResolver; +import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.database.Cursor; +import android.graphics.Bitmap; +import android.graphics.Bitmap.Config; +import android.graphics.BitmapFactory; +import android.graphics.Canvas; +import android.graphics.ColorMatrix; +import android.graphics.ColorMatrixColorFilter; +import android.graphics.LinearGradient; +import android.graphics.Matrix; +import android.graphics.Paint; +import android.graphics.PixelFormat; +import android.graphics.PorterDuff.Mode; +import android.graphics.PorterDuffXfermode; +import android.graphics.Rect; +import android.graphics.RectF; +import android.graphics.Shader.TileMode; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.PictureDrawable; +import android.media.ExifInterface; +import android.net.Uri; +import android.text.TextUtils; +import android.util.Base64; +import android.util.Log; +import android.view.Display; +import android.view.View; +import android.view.WindowManager; +import android.widget.ImageView; + +import com.caverock.androidsvg.SVG; +import com.caverock.androidsvg.SVGParseException; +import com.navinfo.omqs.R; +import com.nostra13.universalimageloader.core.DisplayImageOptions; +import com.nostra13.universalimageloader.core.ImageLoader; +import com.nostra13.universalimageloader.core.assist.FailReason; +import com.nostra13.universalimageloader.core.listener.ImageLoadingListener; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; + +/** + * Tools for handler picture + * 图片处理工具 + * @author Ryan.Tang + */ +public final class ImageTools { + static Bitmap bitmap = null; +// static Context con; + +// public ImageTools(Context con) { +// this.con = con; +// } + + /** + * Transfer drawable to bitmap + * + * @param drawable + * @return + */ + public static Bitmap drawableToBitmap(Drawable drawable) { + int w = drawable.getIntrinsicWidth(); + int h = drawable.getIntrinsicHeight(); + + Config config = drawable.getOpacity() != PixelFormat.OPAQUE ? Config.ARGB_8888 + : Config.RGB_565; + Bitmap bitmap = Bitmap.createBitmap(w, h, config); + Canvas canvas = new Canvas(bitmap); + drawable.setBounds(0, 0, w, h); + drawable.draw(canvas); + return bitmap; + } + + /** + * Bitmap to drawable + * + * @param bitmap + * @return + */ + public static Drawable bitmapToDrawable(Bitmap bitmap) { + return new BitmapDrawable(bitmap); + } + + /** + * Input stream to bitmap + * + * @param inputStream + * @return + * @throws Exception + */ + public static Bitmap inputStreamToBitmap(InputStream inputStream) + throws Exception { + return BitmapFactory.decodeStream(inputStream); + } + + /** + * Byte transfer to bitmap + * + * @param byteArray + * @return + */ + public static Bitmap byteToBitmap(byte[] byteArray) { + if (byteArray!=null&&byteArray.length != 0) { + return BitmapFactory + .decodeByteArray(byteArray, 0, byteArray.length); + } else { + return null; + } + } + + /** + * Byte transfer to drawable + * + * @param byteArray + * @return + */ + public static Drawable byteToDrawable(byte[] byteArray) { + ByteArrayInputStream ins = null; + if (byteArray != null) { + ins = new ByteArrayInputStream(byteArray); + } + return Drawable.createFromStream(ins, null); + } + + /** + * Bitmap transfer to bytes + * + * @param bm + * @return + */ + public static byte[] bitmapToBytes(Bitmap bm) { + byte[] bytes = null; + if (bm != null) { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + bm.compress(Bitmap.CompressFormat.PNG, 100, baos); + bytes = baos.toByteArray(); + } + return bytes; + } + + /** + * Drawable transfer to bytes + * + * @param drawable + * @return + */ + public static byte[] drawableToBytes(Drawable drawable) { + BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable; + Bitmap bitmap = bitmapDrawable.getBitmap(); + byte[] bytes = bitmapToBytes(bitmap); + ; + return bytes; + } + + /** + * Base64 to byte[] // + */ + public static byte[] base64ToBytes(String base64) throws IOException { + byte[] bytes = Base64.decode(base64, Base64.DEFAULT); + return bytes; + } + + /** + * Base64 to Bitmap // + */ + public static Bitmap base64ToBitmap(String base64) throws IOException { + if(!TextUtils.isEmpty(base64)){ + byte[] bytes = Base64.decode(base64, Base64.DEFAULT); + if(bytes!=null) + return byteToBitmap(bytes); + } + + + return null; + } + + /** + * Byte[] to base64 + */ + public static String bytesTobase64(byte[] bytes) { + String base64 = Base64.encodeToString(bytes, Base64.DEFAULT); + return base64; + } + + /** + * Create reflection images + * + * @param bitmap + * @return + */ + public static Bitmap createReflectionImageWithOrigin(Bitmap bitmap) { + final int reflectionGap = 4; + int w = bitmap.getWidth(); + int h = bitmap.getHeight(); + + Matrix matrix = new Matrix(); + matrix.preScale(1, -1); + + Bitmap reflectionImage = Bitmap.createBitmap(bitmap, 0, h / 2, w, + h / 2, matrix, false); + + Bitmap bitmapWithReflection = Bitmap.createBitmap(w, (h + h / 2), + Config.ARGB_8888); + + Canvas canvas = new Canvas(bitmapWithReflection); + canvas.drawBitmap(bitmap, 0, 0, null); + Paint deafalutPaint = new Paint(); + canvas.drawRect(0, h, w, h + reflectionGap, deafalutPaint); + + canvas.drawBitmap(reflectionImage, 0, h + reflectionGap, null); + + Paint paint = new Paint(); + LinearGradient shader = new LinearGradient(0, bitmap.getHeight(), 0, + bitmapWithReflection.getHeight() + reflectionGap, 0x70ffffff, + 0x00ffffff, TileMode.CLAMP); + paint.setShader(shader); + // Set the Transfer mode to be porter duff and destination in + paint.setXfermode(new PorterDuffXfermode(Mode.DST_IN)); + // Draw a rectangle using the paint with our linear gradient + canvas.drawRect(0, h, w, bitmapWithReflection.getHeight() + + reflectionGap, paint); + + return bitmapWithReflection; + } + + /** + * Get rounded corner images + * + * @param bitmap + * @param roundPx 5 10 + * @return + */ + public static Bitmap getRoundedCornerBitmap(Bitmap bitmap, float roundPx) { + int w = bitmap.getWidth(); + int h = bitmap.getHeight(); + Bitmap output = Bitmap.createBitmap(w, h, Config.ARGB_8888); + Canvas canvas = new Canvas(output); + final int color = 0xff424242; + final Paint paint = new Paint(); + final Rect rect = new Rect(0, 0, w, h); + final RectF rectF = new RectF(rect); + paint.setAntiAlias(true); + canvas.drawARGB(0, 0, 0, 0); + paint.setColor(color); + canvas.drawRoundRect(rectF, roundPx, roundPx, paint); + paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN)); + canvas.drawBitmap(bitmap, rect, rect, paint); + + return output; + } + + /** + * Resize the bitmap + * + * @param bitmap + * @param width + * @param height + * @return + */ + public static Bitmap zoomBitmap(Bitmap bitmap, int width, int height) { + int w = bitmap.getWidth(); + int h = bitmap.getHeight(); + Matrix matrix = new Matrix(); + float scaleWidth = ((float) width / w); + float scaleHeight = ((float) height / h); + matrix.postScale(scaleWidth, scaleHeight); + Bitmap newbmp = Bitmap.createBitmap(bitmap, 0, 0, w, h, matrix, true); + return newbmp; + } + + public static Bitmap zoomBitmap(String cameraPath, int width, int height, int size) { + + // 获取图片Exif + ExifInterface exif; + int degree = 0; + try { + exif = new ExifInterface(cameraPath); + // 获取指定tag的属性值 + int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, -1); + if (orientation != -1) { + // We only recognize a subset of orientation tag values. + switch (orientation) { + case ExifInterface.ORIENTATION_NORMAL: + degree = 0; + break; + case ExifInterface.ORIENTATION_UNDEFINED: + degree = 0; + break; + case ExifInterface.ORIENTATION_ROTATE_90: + degree = 90; + break; + case ExifInterface.ORIENTATION_ROTATE_180: + degree = 180; + break; + case ExifInterface.ORIENTATION_ROTATE_270: + degree = 270; + break; + default: + degree = 90; + break; + } + } + } catch (IOException e) { + + e.printStackTrace(); + } + + try { + BitmapFactory.Options bmpFactoryOptions = new BitmapFactory.Options(); + bmpFactoryOptions.inJustDecodeBounds = true; + //Bitmap tmp = BitmapFactory.decodeFile(cameraPath,bmpFactoryOptions);//此时返回bm为空 + bmpFactoryOptions.inJustDecodeBounds = false; + bmpFactoryOptions.inSampleSize = size; + int heightRatio = (int) Math.ceil(bmpFactoryOptions.outHeight / (float) height); + int widthRatio = (int) Math.ceil(bmpFactoryOptions.outWidth / (float) width); + if (heightRatio > 1 && widthRatio > 1) { + bmpFactoryOptions.inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio; + } + + bmpFactoryOptions.inPreferredConfig = Config.ARGB_8888;//该模式是默认的,可不设 + bmpFactoryOptions.inPurgeable = true;// 同时设置才会有效 + bmpFactoryOptions.inInputShareable = true;//。当系统内存不够时候图片自动被回收 + if (bitmap != null && !bitmap.isRecycled()) + bitmap.recycle(); + bitmap = BitmapFactory.decodeFile(cameraPath, bmpFactoryOptions); + + if (degree != 0 && bitmap != null) { + Matrix m = new Matrix(); + m.setRotate(degree, (float) bitmap.getWidth() / 2, (float) bitmap.getHeight() / 2); + + Bitmap b2 = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), m, true); + if (bitmap != b2) { + bitmap.recycle(); + bitmap = b2; + if (b2 != null && b2.isRecycled()) + b2.recycle(); + } + } + + } catch (OutOfMemoryError e) { + System.gc(); + } + new File(cameraPath).delete(); + return bitmap; + + } + + public static Bitmap zoomBitmap(String cameraPath, int multiple) { + + Bitmap bitmap = null; + BitmapFactory.Options options = new BitmapFactory.Options(); + options.inSampleSize = multiple; // 图片宽高都为原来的二分之一,即图片为原来的四分之一 + // 获取图片Exif + ExifInterface exif; + int degree = 0; + try { + exif = new ExifInterface(cameraPath); + // 获取指定tag的属性值 + int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, -1); + if (orientation != -1) { + // We only recognize a subset of orientation tag values. + switch (orientation) { + case ExifInterface.ORIENTATION_ROTATE_90: + degree = 90; + break; + case ExifInterface.ORIENTATION_ROTATE_180: + degree = 180; + break; + case ExifInterface.ORIENTATION_ROTATE_270: + degree = 270; + break; + /* default: + degree = 90; + break; + */ + } + } + } catch (IOException e) { + + e.printStackTrace(); + } + + try { + + bitmap = ImageCrop(BitmapFactory.decodeFile(cameraPath, options)); + if (degree != 0 && bitmap != null) { + Matrix m = new Matrix(); + m.setRotate(degree, (float) bitmap.getWidth() / 2, (float) bitmap.getHeight() / 2); + + Bitmap b2 = Bitmap.createBitmap(bitmap, 0, 0, + bitmap.getWidth(), bitmap.getHeight(), m, true); + if (bitmap != b2) { + bitmap.recycle(); + bitmap = b2; + } + } + } catch (OutOfMemoryError e) { + System.gc(); + }catch (Exception e){ + System.gc(); + } + if (bitmap == null) { + + } + return bitmap; + + } + + private static int getDegree(String filePath) { + if (!new File(filePath).exists()) + return 0; + ExifInterface exif; + int degree = 0; + try { + exif = new ExifInterface(filePath); + // 获取指定tag的属性值 + int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, -1); + if (orientation != -1) { + // We only recognize a subset of orientation tag values. + switch (orientation) { + case ExifInterface.ORIENTATION_ROTATE_90: + degree = 90; + break; + case ExifInterface.ORIENTATION_ROTATE_180: + degree = 180; + break; + case ExifInterface.ORIENTATION_ROTATE_270: + degree = 270; + break; + /* default: + degree = 90; + break; + */ + } + } + } catch (IOException e) { + + e.printStackTrace(); + } + return degree; + } + + /** + * 按正方形裁切图片 + */ + public static Bitmap ImageCrop(Bitmap bitmap) { + int w = bitmap.getWidth(); // 得到图片的宽,高 + int h = bitmap.getHeight(); + + int wh = w > h ? h : w;// 裁切后所取的正方形区域边长 + + int retX = w > h ? (w - h) / 2 : 0;// 基于原图,取正方形左上角x坐标 + int retY = w > h ? 0 : (h - w) / 2; + + // 下面这句是关键 + return Bitmap.createBitmap(bitmap, retX, retY, wh, wh, null, false); + } + + public static Bitmap zoomBitmap(byte[] data, int multiple, int degrees) { + + Bitmap bitmap = null; + BitmapFactory.Options options = new BitmapFactory.Options(); + options.inSampleSize = multiple; // 图片宽高都为原来的二分之一,即图片为原来的四分之一 + try { + bitmap = BitmapFactory.decodeByteArray(data, 0, data.length, options); + + if (degrees != 0 && bitmap != null) { + Matrix m = new Matrix(); + m.setRotate(degrees, (float) bitmap.getWidth() / 2, + (float) bitmap.getHeight() / 2); + try { + Bitmap b2 = Bitmap.createBitmap(bitmap, 0, 0, + bitmap.getWidth(), bitmap.getHeight(), m, true); + if (bitmap != b2) { + bitmap.recycle(); + bitmap = b2; + } + } catch (OutOfMemoryError ex) { + // We have no memory to rotate. Return the original bitmap. + } + } + + } catch (OutOfMemoryError e) { + System.gc(); + } + if (bitmap == null) { + + } + return bitmap; + + } + + /** + * Resize the drawable + * + * @param drawable + * @param w + * @param h + * @return + */ + public static Drawable zoomDrawable(Drawable drawable, int w, int h) { + int width = drawable.getIntrinsicWidth(); + int height = drawable.getIntrinsicHeight(); + Bitmap oldbmp = drawableToBitmap(drawable); + Matrix matrix = new Matrix(); + float sx = ((float) w / width); + float sy = ((float) h / height); + matrix.postScale(sx, sy); + Bitmap newbmp = Bitmap.createBitmap(oldbmp, 0, 0, width, height, + matrix, true); + return new BitmapDrawable(newbmp); + } + + /** + * Get images from SD card by path and the name of image + * + * @param photoName + * @return + */ + public static Bitmap getPhotoFromSDCard(String path, String photoName) { + Bitmap photoBitmap = BitmapFactory.decodeFile(path + "/" + photoName + + ".png"); + if (photoBitmap == null) { + return null; + } else { + return photoBitmap; + } + } + + public static Bitmap getPhotoFromSDCard(String path) { + Bitmap photoBitmap = BitmapFactory.decodeFile(path); + if (photoBitmap == null) { + return null; + } else { + return photoBitmap; + } + } + + /** + * Check the SD card + * + * @return + */ + public static boolean checkSDCardAvailable() { + return android.os.Environment.getExternalStorageState().equals( + android.os.Environment.MEDIA_MOUNTED); + } + + /** + * Get image from SD card by path and the name of image + * + * @param + * @return + */ + public static boolean findPhotoFromSDCard(String path, String photoName) { + boolean flag = false; + + if (checkSDCardAvailable()) { + File dir = new File(path); + if (dir.exists()) { + File folders = new File(path); + File photoFile[] = folders.listFiles(); + for (int i = 0; i < photoFile.length; i++) { + String fileName = photoFile[i].getName().split("\\.")[0]; + if (fileName.equals(photoName)) { + flag = true; + } + } + } else { + flag = false; + } + // File file = new File(path + "/" + photoName + ".jpg" ); + // if (file.exists()) { + // flag = true; + // }else { + // flag = false; + // } + + } else { + flag = false; + } + return flag; + } + + /** + * Save image to the SD card + * + * @param photoBitmap + * @param photoName + * @param path + */ + public static void savePhotoToSDCard(Bitmap photoBitmap, String path, + String photoName) { + if (checkSDCardAvailable()) { + File dir = new File(path); + if (!dir.exists()) { + dir.mkdirs(); + } + + File photoFile = new File(path, photoName + ".png"); + FileOutputStream fileOutputStream = null; + try { + fileOutputStream = new FileOutputStream(photoFile); + if (photoBitmap != null) { + if (photoBitmap.compress(Bitmap.CompressFormat.PNG, 100, + fileOutputStream)) { + fileOutputStream.flush(); + // fileOutputStream.close(); + } + } + } catch (FileNotFoundException e) { + photoFile.delete(); + e.printStackTrace(); + } catch (IOException e) { + photoFile.delete(); + e.printStackTrace(); + } finally { + try { + fileOutputStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + } + + /** + * Delete the image from SD card + * + * @param + * @param path file:///sdcard/temp.jpg + */ + public static void deleteAllPhoto(String path) { + if (checkSDCardAvailable()) { + File folder = new File(path); + File[] files = folder.listFiles(); + for (int i = 0; i < files.length; i++) { + files[i].delete(); + } + } + } + + public static void deletePhotoAtPathAndName(String path, String fileName) { + if (checkSDCardAvailable()) { + File folder = new File(path); + File[] files = folder.listFiles(); + for (int i = 0; i < files.length; i++) { + System.out.println(files[i].getName()); + if (files[i].getName().equals(fileName)) { + files[i].delete(); + } + } + } + } + + public Bitmap setImage(Context con, Uri mImageCaptureUri) { + // 不管是拍照还是选择图片每张图片都有在数据中存储也存储有对应旋转角度orientation值 + // 所以我们在取出图片是把角度值取出以便能正确的显示图片,没有旋转时的效果观看 + + ContentResolver cr = con.getContentResolver(); + Cursor cursor = cr.query(mImageCaptureUri, null, null, null, null);// 根据Uri从数据库中找 + if (cursor != null) { + cursor.moveToFirst();// 把游标移动到首位,因为这里的Uri是包含ID的所以是唯一的不需要循环找指向第一个就是了 + String filePath = cursor.getString(cursor.getColumnIndex("_data"));// 获取图片路 + String orientation = cursor.getString(cursor + .getColumnIndex("orientation"));// 获取旋转的角度 + cursor.close(); + if (filePath != null) { + Bitmap bitmap = BitmapFactory.decodeFile(filePath);// 根据Path读取资源图片 + int angle = 0; + if (orientation != null && !"".equals(orientation)) { + angle = Integer.parseInt(orientation); + } + if (angle != 0) { + // 下面的方法主要作用是把图片转一个角度,也可以放大缩小等 + Matrix m = new Matrix(); + int width = bitmap.getWidth(); + int height = bitmap.getHeight(); + m.setRotate(angle); // 旋转angle度 + bitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height, + m, true);// 从新生成图片 + } + // photo.setImageBitmap(bitmap); + return bitmap; + } + } + return null; + } + + /** + * 读取图片属性:旋转的角度 + * + * @param path 图片绝对路径 + * @return degree旋转的角度 + */ + public static int readPictureDegree(String path) { + int degree = 0; + try { + ExifInterface exifInterface = new ExifInterface(path); + int orientation = exifInterface.getAttributeInt( + ExifInterface.TAG_ORIENTATION, -1); + switch (orientation) { + case ExifInterface.ORIENTATION_ROTATE_90: + degree = 90; + break; + case ExifInterface.ORIENTATION_ROTATE_180: + degree = 180; + break; + case ExifInterface.ORIENTATION_ROTATE_270: + degree = 270; + break; + } + Log.i("ImageTools", "获取拍照角度:" + degree); + } catch (IOException e) { + e.printStackTrace(); + Log.i("ImageTools", "获取拍照角度异常:" + e.getMessage()); + } + return degree; + } + + /* + * 旋转图片 + * + * @param angle + * + * @param bitmap + * + * @return Bitmap + */ + public static Bitmap rotaingImageView(int angle, Bitmap bitmap) { + + if (angle < 0) + return bitmap; + + // 旋转图片 动作 + Matrix matrix = new Matrix(); + matrix.postRotate(angle); + System.out.println("angle2=" + angle); + if (bitmap != null) { + // 创建新的图片 + Bitmap resizedBitmap = Bitmap.createBitmap(bitmap, 0, 0, + bitmap.getWidth(), bitmap.getHeight(), matrix, true); + return resizedBitmap; + } + + return null; + } + + /* + * 旋转图片 + * + * @param bitmap + * + * @param filePath + * + * @return Bitmap + */ + public static void saveBitmap(Bitmap bitmap, String filePath) { + File f = new File(filePath); + if (f.exists()) { + f.delete(); + } + //如果文件夹不存在,则创建对应的文件夹 + if (!f.getParentFile().exists()) { + f.getParentFile().mkdirs(); + } + try { + FileOutputStream out = new FileOutputStream(f); + bitmap.compress(Bitmap.CompressFormat.JPEG, 90, out); + out.flush(); + out.close(); + } catch (FileNotFoundException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + } + + public static void saveBitmapToPNG(Bitmap bitmap, String filePath) { + File f = new File(filePath); + if (f.exists()) { + f.delete(); + } + try { + FileOutputStream out = new FileOutputStream(f); + bitmap.compress(Bitmap.CompressFormat.JPEG, 90, out); + out.flush(); + out.close(); + } catch (FileNotFoundException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + } + + /* + * 释放Bitmap + * + * @param bitmap + */ + public static void recycleBitmap(Bitmap bitmap) { + if (bitmap != null && !bitmap.isRecycled()) { + + // 回收并且置为null + + bitmap.recycle(); + + bitmap = null; + + } + + System.gc(); + + } + + /* + * 创建缩略图 + * + * @param filePath + * + * @return Bitmap + */ + public static Bitmap createZoominBitmap(String filePath) { + Bitmap bitmap = null; + + try { + + // 实例化Bitmap + + bitmap = BitmapFactory.decodeFile(filePath); + + } catch (OutOfMemoryError e) { + + // + + } + return null; + } + + public static Bitmap getBitmapLittle(Context context, String absolutePath) { + BitmapFactory.Options opt = new BitmapFactory.Options(); + // 这个isjustdecodebounds很重要 + opt.inJustDecodeBounds = true; + Bitmap bm = BitmapFactory.decodeFile(absolutePath, opt); + + // 获取到这个图片的原始宽度和高度 + int picWidth = opt.outWidth; + int picHeight = opt.outHeight; + + // 获取屏的宽度和高度 + WindowManager windowManager = ((Activity) context).getWindowManager(); + Display display = windowManager.getDefaultDisplay(); + int screenWidth = display.getWidth(); + int screenHeight = display.getHeight(); + + // isSampleSize是表示对图片的缩放程度,比如值为2图片的宽度和高度都变为以前的1/2 + opt.inSampleSize = 1; + // 根据屏的大小和图片大小计算出缩放比例 + if (picWidth > picHeight) { + if (picWidth > screenWidth) + opt.inSampleSize = picWidth / screenWidth; + } else { + if (picHeight > screenHeight) + + opt.inSampleSize = picHeight / screenHeight; + } + + // 这次再真正地生成一个有像素的,经过缩放了的bitmap + opt.inJustDecodeBounds = false; + bm = BitmapFactory.decodeFile(absolutePath, opt); + + return bm; + } + + /** + * 计算压缩比例值 + * + * @param options 解析图片的配置信息 + * @param reqWidth 所需图片压缩尺寸最小宽度 + * @param reqHeight 所需图片压缩尺寸最小高度 + * @return + */ + public static int calculateInSampleSize(BitmapFactory.Options options, + int reqWidth, int reqHeight) { + // 保存图片原宽高值 + final int height = options.outHeight; + final int width = options.outWidth; + // 初始化压缩比例为1 + int inSampleSize = 1; + + // 当图片宽高值任何一个大于所需压缩图片宽高值时,进入循环计算系统 + if (height > reqHeight || width > reqWidth) { + + final int halfHeight = height / 2; + final int halfWidth = width / 2; + + // 压缩比例值每次循环两倍增加, + // 直到原图宽高值的一半除以压缩值后都~大于所需宽高值为止 + while ((halfHeight / inSampleSize) >= reqHeight + && (halfWidth / inSampleSize) >= reqWidth) { + inSampleSize *= 2; + } + } + + return inSampleSize; + } + + public static Bitmap getBitmapByNameFromRes(Activity activity, String name) { + ApplicationInfo appInfo = activity.getApplicationInfo(); + int resID = activity.getResources().getIdentifier(name, "drawable", appInfo.packageName); + return BitmapFactory.decodeResource(activity.getResources(), resID); + } + + public static Drawable getDrawableByNameFromRes(Activity activity, String name) { + ApplicationInfo appInfo = activity.getApplicationInfo(); + int resID = activity.getResources().getIdentifier(name, "drawable", appInfo.packageName); + return activity.getResources().getDrawable(resID); + } + + public static int getResIdByNameFromRes(Activity activity, String name) { + ApplicationInfo appInfo = activity.getApplicationInfo(); + int resID = activity.getResources().getIdentifier(name, "drawable", appInfo.packageName); + return resID; + } + + public static String getBitmapString(Bitmap bitmap) { + ByteArrayOutputStream baos = new ByteArrayOutputStream();// outputstream + bitmap.compress(Bitmap.CompressFormat.PNG, 100, baos); + byte[] appicon = baos.toByteArray();// 转为byte数组 + return Base64.encodeToString(appicon, Base64.DEFAULT); + } + + public interface LoadImageClickListener { + public void LoadImageClick(); + } + + /** + * 根据View的大小设置图片的大小 + * + * @param view + * @param path 图片路径 + */ + public static void setViewImage(View view, String path) { + if (view == null || path == null || !new File(path).isFile()) return; + int width = view.getWidth(); + int height = view.getHeight(); + if (width == 0 || height == 0) { + setImage(view, ImageLoad.zoomBitmap(path, 4)); + } else { + Bitmap zoomBitmap = zoomBitmap(path, width, height); + setImage(view, ImageCrop(zoomBitmap)); + } + } + + /** + * 根据给的宽高进行计算压缩比缩,返回原图高宽比的图片 + * + * @param path 图片路径 + * @param WinWidth 压缩宽度 + * @param WinHeight 压缩高度 + */ + public static Bitmap zoomBitmap(String path, int WinWidth, int WinHeight) { + //int WinWidth = defaultDisplay.getWidth(); + //int WinHeight = defaultDisplay.getHeight(); + BitmapFactory.Options options = new BitmapFactory.Options(); + options.inJustDecodeBounds = true;// 只解析头文件 + BitmapFactory.decodeFile(path, options); + //图片的高和宽 + int height = options.outHeight; + int width = options.outWidth; + + //用于计算最大的缩放的比例 + int scaleX = height / WinHeight; + int scaleY = width / WinWidth; + int scale = scaleX > scaleY ? scaleX : scaleY; + + options.inSampleSize = scale; + + options.inJustDecodeBounds = false; + //另外,为了节约内存我们还可以使用下面的几个字段: + options.inPreferredConfig = Config.ARGB_4444; // 默认是Bitmap.Config.ARGB_8888 + /* 下面两个字段需要组合使用 */ + options.inPurgeable = true; + options.inInputShareable = true; + + Bitmap decodeFile = BitmapFactory.decodeFile(path, options); + return decodeFile; + } + +// /** +// * 直接设置压缩比,返回原图高宽比的图片 +// * +// * @param path 图片路径 +// * @param scale +// * @return +// */ +// +// public static Bitmap zoomBitmep2(String path, int scale) { +// BitmapFactory.Options options = new BitmapFactory.Options(); +// options.inJustDecodeBounds = true;// 只解析头文件 +// BitmapFactory.decodeFile(path, options); +// options.inSampleSize = scale; +// options.inJustDecodeBounds = false; +// options.inPreferredConfig = Bitmap.Config.ARGB_4444; // 默认是Bitmap.Config.ARGB_8888 +// /* 下面两个字段需要组合使用 */ +// options.inPurgeable = true; +// options.inInputShareable = true; +// Bitmap decodeFile = BitmapFactory.decodeFile(path, options); +// return decodeFile; +// } + + + /** + * 根据屏幕显示图片 + * + * @param context + * @param view + * @param path + */ + public static void setViewImage(Context context, View view, String path) { + if (view == null || path == null || !new File(path).isFile()) return; + setImage(view, ImageLoad.getBitmapLittle(context, path)); + } + + private static void setImage(View view, Bitmap bitmap) { + if (view == null || bitmap == null) return; + if (view instanceof ImageView) { + ImageView iv = (ImageView) view; + iv.setImageBitmap(bitmap); + } else { + view.setBackgroundDrawable(new BitmapDrawable(bitmap)); + } + } + + public static void setViewImage(View view, Bitmap bitmap) { + if (view == null || bitmap == null) return; + int width = view.getWidth(); + int height = view.getHeight(); + Log.i("info", "width:" + width + ",height:" + height); +// if(width==0||height==0){ + setImage(view, bitmap); +// }else{ +// Log.i("info","view.getWidth():"+view.getWidth()); +// int size = 4;//图片的宽高都大于view时,此值不起作用没有用 +// setImage(view, ImageLoad.zoomBitmap(bitmap, width, height)); +// } + } + + /** + * 绘制蓝色圆环带数字 + * + * @param context + * @param text + * @return + */ + + public static Bitmap createNumberPic(Context context, String text) { + + Paint paint = new Paint(); + paint.setAntiAlias(true); //消除锯齿 + + int innerCircle = dip2px(context, 9); //内圆半径 + int ringWidth = dip2px(context, 2); //圆环宽度 + paint.setStrokeWidth(ringWidth); + int l = (innerCircle + ringWidth + 10) * 2; + int center = innerCircle + ringWidth + 10; + Bitmap b = Bitmap.createBitmap(l, l, Config.ARGB_8888); + Canvas canvas = new Canvas(b); + + paint.setColor(context.getResources().getColor(R.color.white)); + canvas.drawCircle(center, center, innerCircle + ringWidth, paint); + + paint.setStyle(Paint.Style.STROKE); //绘制空心圆或 空心矩形 + paint.setARGB(255, 26, 187, 254); + canvas.drawCircle(center, center, innerCircle + ringWidth, paint); + + paint.setTextSize(26f); + paint.setStyle(Paint.Style.FILL); + paint.setStrokeWidth(1); + paint.setTextAlign(Paint.Align.CENTER); + canvas.drawText(text, center, center + center / 3, paint); + return b; + } + + /* 根据手机的分辨率从 dp 的单位 转成为 px(像素) */ + public static int dip2px(Context context, float dpValue) { + final float scale = context.getResources().getDisplayMetrics().density; + return (int) (dpValue * scale + 0.5f); + } + + /** + * 根据手机的分辨率从 px(像素) 的单位 转成为 dp + */ + public static int px2dip(Context context, float pxValue) { + final float scale = context.getResources().getDisplayMetrics().density; + return (int) (pxValue / scale + 0.5f); + } + + /** + * 将bitmap中的某种颜色值替换成新的颜色 + * + * @param oldBitmap + * @param oldColor + * @param newColor + * @return + */ + public static Bitmap replaceBitmapColor(Bitmap oldBitmap, int oldColor, int newColor) { + //相关说明可参考 http://xys289187120.blog.51cto.com/3361352/657590/ + Bitmap mBitmap = oldBitmap.copy(Config.ARGB_8888, true); + //循环获得bitmap所有像素点 + int mBitmapWidth = mBitmap.getWidth(); + int mBitmapHeight = mBitmap.getHeight(); + int mArrayColorLengh = mBitmapWidth * mBitmapHeight; + int[] mArrayColor = new int[mArrayColorLengh]; + int count = 0; + for (int i = 0; i < mBitmapHeight; i++) { + for (int j = 0; j < mBitmapWidth; j++) { + //获得Bitmap 图片中每一个点的color颜色值 + //将需要填充的颜色值如果不是 + //在这说明一下 如果color 是全透明 或者全黑 返回值为 0 + //getPixel()不带透明通道 getPixel32()才带透明部分 所以全透明是0x00000000 + //而不透明黑色是0xFF000000 如果不计算透明部分就都是0了 + int color = mBitmap.getPixel(j, i); + //将颜色值存在一个数组中 方便后面修改 + if (color == oldColor) { + mBitmap.setPixel(j, i, newColor); //将白色替换成透明色 + } + + } + } + return mBitmap; + } + + /** + * 图片饱和度转换 变灰 + */ + + public static Drawable getColorMatrixImage(Drawable drawable) { + if (drawable == null) + return drawable; + ColorMatrix cm = new ColorMatrix(); + cm.setSaturation(0); + ColorMatrixColorFilter cf = new ColorMatrixColorFilter(cm); + drawable.hashCode(); + drawable.getCurrent().setColorFilter(cf); + drawable.getCurrent().hashCode(); + return drawable.getCurrent(); + } + + /** + * 图片饱和度转换 变灰 + */ + + public static Drawable getColorMatrixImage(Drawable drawable, ColorMatrixColorFilter cf) { + if (drawable == null) + return drawable; + drawable.hashCode(); + drawable.getCurrent().setColorFilter(cf); + drawable.getCurrent().hashCode(); + return drawable.getCurrent(); + } + + public static Bitmap mergeBitmap(Bitmap backBitmap, Bitmap frontBitmap) { + + if (backBitmap == null || backBitmap.isRecycled() + || frontBitmap == null || frontBitmap.isRecycled()) { + return null; + } + Bitmap bitmap = backBitmap.copy(Config.ARGB_8888, true); + Canvas canvas = new Canvas(bitmap); + Rect baseRect = new Rect(0, 0, backBitmap.getWidth(), backBitmap.getHeight()); + Rect frontRect = new Rect(0, 0, frontBitmap.getWidth(), frontBitmap.getHeight()); + canvas.drawBitmap(frontBitmap, frontRect, baseRect, null); + return bitmap; + } + + /** + * Get image from newwork + * + * @param path The path of image + * @return byte[] + * @throws Exception + */ + public static byte[] getImage(String path) throws Exception { + URL url = new URL(path); + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + conn.setConnectTimeout(5 * 1000); + conn.setRequestMethod("GET"); + InputStream inStream = conn.getInputStream(); + if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) { + return readStream(inStream); + } + return null; + } + + /** + * Get image from newwork + * + * @param path The path of image + * @return InputStream + * @throws Exception + */ + public static InputStream getImageStream(String path) throws Exception { + URL url = new URL(path); + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + conn.setConnectTimeout(5 * 1000); + conn.setRequestMethod("GET"); + if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) { + return conn.getInputStream(); + } + return null; + } + + /** + * Get data from stream + * + * @param inStream + * @return byte[] + * @throws Exception + */ + public static byte[] readStream(InputStream inStream) throws Exception { + ByteArrayOutputStream outStream = new ByteArrayOutputStream(); + byte[] buffer = new byte[1024]; + int len = 0; + while ((len = inStream.read(buffer)) != -1) { + outStream.write(buffer, 0, len); + } + outStream.close(); + inStream.close(); + return outStream.toByteArray(); + } + + public static Bitmap svgToBimap(byte[] bytes) { + try { + InputStream input = new ByteArrayInputStream(bytes); + SVG svg = SVG.getFromInputStream(input); + Drawable drawable = new PictureDrawable(svg.renderToPicture()); + return ImageTools.drawableToBitmap(drawable); + } catch (SVGParseException e) { + + } + return null; + } +} diff --git a/app/src/main/java/com/navinfo/omqs/util/SignUtil.kt b/app/src/main/java/com/navinfo/omqs/util/SignUtil.kt index d0eb6560..423177fa 100644 --- a/app/src/main/java/com/navinfo/omqs/util/SignUtil.kt +++ b/app/src/main/java/com/navinfo/omqs/util/SignUtil.kt @@ -108,10 +108,10 @@ class SignUtil { } } //物理车道数OMDB_PHY_LANENUM - DataCodeEnum.OMDB_LANE_NUM.code, +/* DataCodeEnum.OMDB_LANE_NUM.code, DataCodeEnum.OMDB_PHY_LANENUM.code -> { "${data.properties["laneS2e"]}|${data.properties["laneE2s"]}" - } + }*/ //常规点限速,条件点限速 DataCodeEnum.OMDB_SPEEDLIMIT.code, DataCodeEnum.OMDB_SPEEDLIMIT_COND.code -> getSpeedLimitMaxText(data) @@ -304,7 +304,7 @@ class SignUtil { title = "逆方向车道数", text = "${data.properties["laneE2s"]}" ) ) - var str = when (data.properties["laneClass"]) { +/* var str = when (data.properties["laneClass"]) { "0" -> "未赋值" "1" -> "一条车道" "2" -> "两或三条" @@ -317,7 +317,7 @@ class SignUtil { TwoItemAdapterItem( title = "车道数等级", text = str ) - ) + )*/ } //路口 DataCodeEnum.OMDB_INTERSECTION.code -> { @@ -833,16 +833,9 @@ class SignUtil { else -> "" })) } - //路牙 - DataCodeEnum.OMDB_OBJECT_CURB.code -> { - list.add(TwoItemAdapterItem(title = "是否符合高精地图", text = when (data.properties["compliant"]) { - "0" -> "否" - "1" -> "是" - else -> "" - })) - } //平行墙 DataCodeEnum.OMDB_OBJECT_WALL.code -> { + list.add(TwoItemAdapterItem(title = "对象号码", text = "${data.properties["objectPid"]}")) list.add(TwoItemAdapterItem(title = "类型", text = when (data.properties["type"]) { "1" -> "隧道墙" "3" -> "其他墙" @@ -851,6 +844,7 @@ class SignUtil { } //警示区 DataCodeEnum.OMDB_OBJECT_WARNING_AREA.code -> { + list.add(TwoItemAdapterItem(title = "对象号码", text = "${data.properties["objectPid"]}")) list.add(TwoItemAdapterItem(title = "颜色", text = when (data.properties["color"]) { "0" -> "未验证" "1" -> "白色" @@ -1928,7 +1922,7 @@ class SignUtil { */ fun getRoadInfoIndex(element: RenderEntity): Int { return when (element.code) { - DataCodeEnum.OMDB_PHY_LANENUM.code,//物理车道数 + //DataCodeEnum.OMDB_PHY_LANENUM.code,//物理车道数 DataCodeEnum.OMDB_LANE_NUM.code -> 0 DataCodeEnum.OMDB_RD_LINK_KIND.code -> 1 DataCodeEnum.OMDB_RD_LINK_FUNCTION_CLASS.code -> 2 diff --git a/app/src/main/res/layout/adapter_picture.xml b/app/src/main/res/layout/adapter_picture.xml index 51ac92e8..5274ce52 100644 --- a/app/src/main/res/layout/adapter_picture.xml +++ b/app/src/main/res/layout/adapter_picture.xml @@ -3,9 +3,12 @@ android:layout_width="match_parent" android:layout_height="match_parent"> -