准备工作

  • github 找一个图片编辑器 地址,这个图就是对单个本地图片进行编辑,加载大图有问题,页面传递bitmap有问题
  • 目前已有功能:编辑一张本地图片
  • 想要效果:传入图片下载list,第一个页面要有图片切换效果,点击按钮对图片进行编辑,图片保存

优化

  • 首页直接glide加载图片,viewpager左右切换,对bitmap压缩防止过大导致页面崩溃
  • 点击进入编辑页的时候,对对应的图片进行下载,压缩,之后再编辑,跳转页面的时候传下载压缩后的路径,而不是传递bitmap
  • 因为编辑的时候是对本地图编辑,会有图片下载,保证本地相册不会过多下载图片

代码

首页传入图片集合,进行展示,对图片编辑需要申请权限

package me.minetsh.imagingimport android.Manifest
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.net.Uriimport android.os.Bundle
import android.support.v4.app.Fragment
import android.support.v4.app.FragmentManager
import android.support.v4.app.FragmentPagerAdapter
import android.support.v4.view.PagerAdapter
import android.support.v4.view.ViewPager
import android.support.v7.app.AppCompatActivityimport android.view.View
import android.view.ViewGroup
import com.blankj.utilcode.util.LogUtils
import com.blankj.utilcode.util.ToastUtils
import com.htjy.app.common_util.ext.clickWithTrigger
import com.htjy.app.common_util.util.LuBanUtilsimport com.tbruyelle.rxpermissions2.RxPermissions
import kotlinx.android.synthetic.main.image_activity_img_handle.*
import kotlinx.android.synthetic.main.image_edit_ready.*/**
Func:点评的首页
# 老师点评图片不可超过9张,超过时不可再点击”红笔点评“按钮,点击提示:“点评图片不可超过9张”
# 点击老师点评的图片可继续点评,保存后替换原点评图片
# 点评跳转的是新页面-仿微信
# 点评不能左右翻动
# 点评的时候不传递bitmap,而是传递路径*/
const val EDIT_IMG_REQUESTCODE = 1000class IMGHandleActivity : AppCompatActivity() {private lateinit var dataList: ArrayList<String>  //数据源private var type: Int = 0   //0 是网络  1是本地//测试的网络数据private val testUrl = arrayListOf("https://animal-crossing.com/amiibo/assets/img/cards/NVL-C-MAAL-USZ-F0(0)011.png","https://animal-crossing.com/amiibo/assets/img/cards/NVL-C-MAAM-USZ-F0(0)012.png", "https://animal-crossing.com/amiibo/assets/img/cards/NVL-C-MAAA-USZ-F0(0)001.png","https://animal-crossing.com/amiibo/assets/img/cards/NVL-C-MAAB-USZ-F0(0)002.png","https://animal-crossing.com/amiibo/assets/img/cards/NVL-C-MAEC-USZ-F0(0)099.png","https://animal-crossing.com/amiibo/assets/img/cards/NVL-C-MACD-USZ-F0(0)052.png","https://animal-crossing.com/amiibo/assets/img/cards/NVL_C_MAGY_USZlow_167_R_ad.png","https://animal-crossing.com/amiibo/assets/img/cards/NVL_C_MAHB_USZlow_170_R_ad.png","https://animal-crossing.com/amiibo/assets/img/cards/NVL_C_MALZ_USZlow_264_R_ad.png")//测试的本地数据private var test = arrayListOf("/storage/emulated/0/DCIM/Screenshots/Screenshot_2019-10-30-10-09-35-727_com.htjy.gardener.component_remark_teacher.png", "/storage/emulated/0/BesttimerCamera2/picture_1574761262840.jpg")override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.image_activity_img_handle)//EventBus.getDefault().register(IMGHandleActivity@ this)initData()//initView()}override fun onDestroy() {super.onDestroy()//EventBus.getDefault().unregister(IMGHandleActivity@ this)}companion object {fun launch(from: Activity, data: ArrayList<String>, type: Int) {val intent = Intent(from, IMGHandleActivity::class.java)intent.putExtra("type", type)intent.putStringArrayListExtra("data", data)from.startActivityForResult(intent, EDIT_IMG_REQUESTCODE)}}private fun initData() {//dataList = testUrldataList = intent.getStringArrayListExtra("data")type = intent.getIntExtra("type", 0)//申请读写权限//Singleton().test(arrayListOf("1","2","3"))RxPermissions(IMGHandleActivity@ this).request(Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE).subscribe {if (it) {initView()} else {finish()}}}private var currentPage = 0private val fragmentList = arrayListOf<ItemFragment>()private fun initView() {//获取Bitmap//val layoutInflater = LayoutInflater.from(IMGHandleActivity@ this)for (value in dataList) {fragmentList.add(ItemFragment.launch(value))}val adapter = MyItemFragmentPagerAdapter(supportFragmentManager, fragmentList)vp_images.adapter = adaptervp_images.offscreenPageLimit = dataList.sizetv_count.text = "${currentPage + 1}/${dataList.size}"vp_images.addOnPageChangeListener(object : ViewPager.OnPageChangeListener {override fun onPageScrollStateChanged(state: Int) {}override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {}override fun onPageSelected(position: Int) {currentPage = positiontv_count.text = "${currentPage + 1}/${dataList.size}"}})/*** 点评:如果是网络图片必须要先下载才能进入点评,步骤为:下载,copy,压缩*/btn_dianping.clickWithTrigger {when (type) {0 -> {LuBanUtils.loadPicFromNet(dataList[currentPage], IMGHandleActivity@ this) { isSuccess, path ->if (isSuccess) {IMGEditActivity.launch(path, this@IMGHandleActivity)}}}1 -> {LuBanUtils.loadPicFromLocal(dataList[currentPage], IMGHandleActivity@ this) { isSuccess, path ->if (isSuccess) {IMGEditActivity.launch(path, this@IMGHandleActivity)}}}}}btn_save.clickWithTrigger {//保存when (type) {0 -> {LuBanUtils.downloadPicFromNet(dataList[currentPage], IMGHandleActivity@ this) { isSuccess, path ->if (isSuccess) {// 最后通知图库更新sendBroadcast(Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.parse("file://$path")))ToastUtils.showShort("图片保存成功")} else {ToastUtils.showShort("图片保存失败")}}}
//                1 -> {//                    LuBanUtils.loadPicFromLocal(dataList[currentPage], IMGHandleActivity@ this) { isSuccess, path ->
//                        if (isSuccess) {//                            IMGEditActivity.launch(path, this@IMGHandleActivity)
//                        }
//                    }
//                }}}}private inner class MyItemFragmentPagerAdapter(fm: FragmentManager, var data: List<Fragment>) : FragmentPagerAdapter(fm) {override fun getItem(position: Int): Fragment {return data[position]}override fun getCount(): Int {return data.size}}private inner class MyImgViewPagerAdapter(var context: Context, var data: List<View>) : PagerAdapter() {override fun isViewFromObject(view: View, obj: Any): Boolean {return view == obj}override fun getCount(): Int {return data.size}override fun destroyItem(container: ViewGroup, position: Int, `object`: Any) {container.removeView(data[position])}override fun instantiateItem(container: ViewGroup, position: Int): Any {container.addView(data[position])return data[position]}}override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {super.onActivityResult(requestCode, resultCode, data)if (requestCode == EDIT_IMG_REQUESTCODE && resultCode == Activity.RESULT_OK) {//编辑图片成功的返回data?.let {val savePath = it.getStringExtra(IMGEditActivity.EXTRA_IMAGE_SAVE_PATH)LogUtils.d("保存图片的绝对路径==上级页面收到>>>$savePath")setResult(EDIT_IMG_REQUESTCODE, it)finish()}}}
}

图片编辑页的修改

package me.minetsh.imaging;import android.app.Activity;import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;import android.text.TextUtils;import com.blankj.utilcode.util.LogUtils;import me.minetsh.imaging.core.IMGMode;
import me.minetsh.imaging.core.IMGText;import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.UUID;import static me.minetsh.imaging.IMGHandleActivityKt.EDIT_IMG_REQUESTCODE;public class IMGEditActivity extends IMGEditBaseActivity {private static final int MAX_WIDTH = 1024;private static final int MAX_HEIGHT = 1024;public static final String EXTRA_IMAGE_URI = "IMAGE_URI";public static final String EXTRA_IMAGE_SAVE_PATH = "IMAGE_SAVE_PATH";public static void launch(String url, Activity fromContext) {Intent intent = new Intent(fromContext, IMGEditActivity.class);intent.putExtra("bitmap", url);//默认一个编辑图片后的路径intent.putExtra(EXTRA_IMAGE_SAVE_PATH, UUID.randomUUID().toString() + ".jpg");fromContext.startActivityForResult(intent, EDIT_IMG_REQUESTCODE);}@Overridepublic void onCreated() {}private File currentFile;@Overridepublic void onBackPressed() {super.onBackPressed();if (currentFile != null && currentFile.exists()) {currentFile.delete();}}@Overridepublic Bitmap getBitmap() {String url = getIntent().getStringExtra("bitmap");// String localPath = LuBanUtils.INSTANCE.getPicMap().get(url);currentFile = new File(url);Bitmap bitmap = BitmapFactory.decodeFile(currentFile.getPath());// Bitmap bitmap = getIntent().getParcelableExtra("bitmap");//        Intent intent = getIntent();
//        if (intent == null) {//            return null;
//        }
//
//        Uri uri = intent.getParcelableExtra(EXTRA_IMAGE_URI);
//        if (uri == null) {//            return null;
//        }
//
//        IMGDecoder decoder = null;
//
//        String path = uri.getPath();
//        if (!TextUtils.isEmpty(path)) {//            switch (uri.getScheme()) {//                case "asset":
//                    decoder = new IMGAssetFileDecoder(this, uri);
//                    break;
//                case "file":
//                    decoder = new IMGFileDecoder(uri);
//                    break;
//            }
//        }
//
//        if (decoder == null) {//            return null;
//        }
//
//        BitmapFactory.Options options = new BitmapFactory.Options();
//        options.inSampleSize = 1;
//        options.inJustDecodeBounds = true;
//
//        decoder.decode(options);
//
//        if (options.outWidth > MAX_WIDTH) {//            options.inSampleSize = IMGUtils.inSampleSize(Math.round(1f * options.outWidth / MAX_WIDTH));
//        }
//
//        if (options.outHeight > MAX_HEIGHT) {//            options.inSampleSize = Math.max(options.inSampleSize,
//                    IMGUtils.inSampleSize(Math.round(1f * options.outHeight / MAX_HEIGHT)));
//        }
//
//        options.inJustDecodeBounds = false;
//
//        Bitmap bitmap = decoder.decode(options);
//        if (bitmap == null) {//            return null;
//        }return bitmap;}@Overridepublic void onText(IMGText text) {mImgView.addStickerText(text);}@Overridepublic void onModeClick(IMGMode mode) {IMGMode cm = mImgView.getMode();if (cm == mode) {mode = IMGMode.NONE;}mImgView.setMode(mode);updateModeUI();if (mode == IMGMode.CLIP) {setOpDisplay(OP_CLIP);}}@Overridepublic void onUndoClick() {IMGMode mode = mImgView.getMode();if (mode == IMGMode.DOODLE) {mImgView.undoDoodle();} else if (mode == IMGMode.MOSAIC) {mImgView.undoMosaic();}}@Overridepublic void onCancelClick() {onBackPressed();}@Overridepublic void onDoneClick() {File file = new File(getCacheDir(), getIntent().getStringExtra(EXTRA_IMAGE_SAVE_PATH));String path = file.getAbsolutePath();if (!TextUtils.isEmpty(path)) {Bitmap bitmap = mImgView.saveBitmap();if (bitmap != null) {FileOutputStream fout = null;try {fout = new FileOutputStream(path);bitmap.compress(Bitmap.CompressFormat.JPEG, 80, fout);} catch (FileNotFoundException e) {e.printStackTrace();} finally {if (fout != null) {try {fout.close();} catch (IOException e) {e.printStackTrace();}}}Intent intent = new Intent();//把保存的图片的绝对路径返回出去intent.putExtra(EXTRA_IMAGE_SAVE_PATH, path);LogUtils.d("保存图片的绝对路径>>>" + path);setResult(RESULT_OK, intent);finish();return;}}setResult(RESULT_CANCELED);finish();}@Overridepublic void onCancelClipClick() {mImgView.cancelClip();setOpDisplay(mImgView.getMode() == IMGMode.CLIP ? OP_CLIP : OP_NORMAL);}@Overridepublic void onDoneClipClick() {mImgView.doClip();setOpDisplay(mImgView.getMode() == IMGMode.CLIP ? OP_CLIP : OP_NORMAL);}@Overridepublic void onResetClipClick() {mImgView.resetClip();}@Overridepublic void onRotateClipClick() {mImgView.doRotate();}@Overridepublic void onColorChanged(int checkedColor) {mImgView.setPenColor(checkedColor);}
}

图片下载压缩,过多文件删除的工具类

package com.htjy.app.common_util.utilimport android.content.Context
import android.os.Environment
import com.blankj.utilcode.util.LogUtils
import com.htjy.baselibrary.widget.imageloader.ImageLoaderUtil
import com.htjy.baselibrary.widget.imageloader.listener.ImageDownloadListener
import io.reactivex.Flowable
import io.reactivex.schedulers.Schedulers
import top.zibin.luban.Luban
import top.zibin.luban.OnCompressListener
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
import java.io.IOException/*** 鲁班压缩工具类*/
object LuBanUtils {/*** 复制文件** @param source 输入文件* @param target 输出文件*/private fun copy(source: File?, callBack: (pathFile: File) -> Unit) {//获取到下载得到的图片,进行本地保存//获取到下载得到的图片,进行本地保存val pictureFolder: File = Environment.getExternalStorageDirectory()//第二个参数为你想要保存的目录名称//第二个参数为你想要保存的目录名称val appDir = File(pictureFolder, "my_edit_pic")if (!appDir.exists()) {appDir.mkdirs()}val fileName = System.currentTimeMillis().toString() + ".jpg"val destFile = File(appDir, fileName)var fileInputStream: FileInputStream? = nullvar fileOutputStream: FileOutputStream? = nulltry {fileInputStream = FileInputStream(source)fileOutputStream = FileOutputStream(destFile)val buffer = ByteArray(1024)while (fileInputStream.read(buffer) > 0) {fileOutputStream.write(buffer)}} catch (e: Exception) {e.printStackTrace()} finally {try {fileInputStream?.close()fileOutputStream?.close()} catch (e: IOException) {e.printStackTrace()}//删掉源文件if (source != null && source.exists()) {source.delete()}callBack.invoke(destFile)}}private  fun deleteFile(file: File?) {if (file != null && file.exists()) {file.delete()}}/*** 下载图片 copy  压缩*/fun loadPicFromNet(uri: String, context: Context, callBack: (isSuccess: Boolean, path: String?) -> Unit) {Flowable.just(uri).subscribeOn(Schedulers.io()).map {//下载图片ImageLoaderUtil.getInstance().downloadOnly(context, uri, object : ImageDownloadListener {override fun onSuccess(path: String?) {LogUtils.d("鲁班>>>Gilde下载图片成功==${uri}")LogUtils.d("鲁班>>>Gildecopy图片")path?.let {val file = File(it)if (file != null && file.exists()) {//这里只是缓存文件,还需要copy成正式文件copy(file) { targetFile ->LogUtils.d("鲁班==copy成功===${targetFile.absolutePath}")LogUtils.d("鲁班>>>压缩图片")Luban.with(context).load(targetFile).setTargetDir(targetFile.parent).ignoreBy(10).setCompressListener(object : OnCompressListener {override fun onSuccess(file: File?) {LogUtils.d("鲁班>>>压缩成功==${uri}===${file?.absolutePath}")//删掉copy的文件deleteFile(targetFile)callBack.invoke(true, file?.absolutePath)}override fun onError(e: Throwable?) {LogUtils.d("鲁班>>>压缩失败==${uri}===${e?.message}")callBack.invoke(false, null)}override fun onStart() {LogUtils.d("鲁班>>>开始压缩==${uri}===")}}).launch()}}}}override fun onFail() {LogUtils.d("鲁班>>>Gilde下载图片失败==${uri}")callBack.invoke(false, null)}})}.subscribe()}/*** 加载本地图片并压缩*/fun loadPicFromLocal(path: String, context: Context, callBack: (isSuccess: Boolean, path: String?) -> Unit) {//对本地图做一定的压缩就行了Flowable.just(path).subscribeOn(Schedulers.io()).map { uri ->val file = File(uri)LogUtils.d("鲁班>>>开始压缩==${uri}")if (file != null && file.exists()) {Luban.with(context).load(file).setCompressListener(object : OnCompressListener {override fun onSuccess(file: File?) {if (file != null && file.exists()) {LogUtils.d("鲁班>>>压缩成功==${uri}===${file?.absolutePath}")callBack.invoke(true, file?.absolutePath)//target.onNext("")}}override fun onError(e: Throwable?) {LogUtils.d("鲁班>>>压缩失败==${uri}===${e?.message}")callBack.invoke(false, null)}override fun onStart() {LogUtils.d("鲁班>>>开始压缩==${uri}===")}}).launch()}}.subscribe()}/*** 下载线上的图片*/fun downloadPicFromNet(uri: String, context: Context, callBack: (isSuccess: Boolean, path: String?) -> Unit) {Flowable.just(uri).subscribeOn(Schedulers.io()).map {//下载图片ImageLoaderUtil.getInstance().downloadOnly(context, uri, object : ImageDownloadListener {override fun onSuccess(path: String?) {LogUtils.d("鲁班>>>Gilde下载图片成功==${uri}")LogUtils.d("鲁班>>>Gildecopy图片")path?.let {val file = File(it)if (file != null && file.exists()) {//这里只是缓存文件,还需要copy成正式文件copy(file) { targetFile ->LogUtils.d("鲁班==下载成功===${targetFile.absolutePath}")callBack.invoke(true, targetFile.absolutePath)}}}}override fun onFail() {LogUtils.d("鲁班>>>Gilde下载图片失败==${uri}")callBack.invoke(false, null)}})}.subscribe()}
}

分享一个下载图片,并刷新手机相册的工具类

二进制bytearr转bitmap

    fun getBitmapFromByte(temp: ByteArray): Bitmap? {return if (temp != null) {BitmapFactory.decodeByteArray(temp, 0, temp.size)} else {null}}

下载图片保存,刷新相册

/*** 保存图片到图库** @param context* @param bmp*/public static void saveImageToGallery(Context context, Bitmap bmp, String picDirName) {// 首先保存图片
//        File appDir = new File(Environment.getExternalStorageDirectory(),
//                picDirName);File appDir = new File(getFilePath(context,picDirName));if (!appDir.exists()) {appDir.mkdir();}LogUtils.d("下载啊目录>>"+appDir.getAbsolutePath());String fileName = System.currentTimeMillis() + ".jpg";File file = new File(appDir, fileName);try {FileOutputStream fos = new FileOutputStream(file);bmp.compress(Bitmap.CompressFormat.JPEG, 100, fos);fos.flush();fos.close();} catch (FileNotFoundException e) {ToastUtils.showShort("保存失败");e.printStackTrace();} catch (IOException e) {ToastUtils.showShort("保存失败");e.printStackTrace();}// 其次把文件插入到系统图库try {MediaStore.Images.Media.insertImage(context.getContentResolver(),file.getAbsolutePath(), fileName, null);ToastUtils.showShort("保存成功");} catch (FileNotFoundException e) {ToastUtils.showShort("保存失败");e.printStackTrace();}// 最后通知图库更新context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE,Uri.fromFile(file)));}public static String getFilePath(Context context, String dir) {String directoryPath = "";//判断SD卡是否可用if (MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {directoryPath = context.getExternalFilesDir(dir).getAbsolutePath();// directoryPath =context.getExternalCacheDir().getAbsolutePath() ;} else {//没内存卡就存机身内存directoryPath = context.getFilesDir() + File.separator + dir;// directoryPath=context.getCacheDir()+File.separator+dir;}File file = new File(directoryPath);if (!file.exists()) {//判断文件目录是否存在file.mkdirs();}LogUtil.i("filePath====>" + directoryPath);return directoryPath;}

Android用kotlin修改一个图片编辑库做一个作业点评的功能相关推荐

  1. 利用monment库做一个日历表

    利用monment库做一个日历表 先看完成品 点击上月和下月根据当前系统的时间进行变化 这是布局 <div class="wapper"><div class=& ...

  2. Android仿微信图片编辑库,你想要的功能这里都有

    最近项目需要,写了一个和微信中图片编辑功能类似的图片编辑库,除去问题操作上摈弃掉不方便的手势操作外,其余微信中的核心功能全部一致,保留了微信中涂鸦.马赛克.文字等随时随着图片缩放的功能,这点是我所找的 ...

  3. 【Android】炫酷ui 带你做一个背景跟着滚动的工具

    在用ViewPager配合Fragment开发的模式中,想做一个类似于桌面壁纸的背景图,可以跟着ViewPager滑动.这里贴一下项目初期实现了的效果: 可以看到,界面中ViewPager滑动的同时背 ...

  4. 怎么做个修改ip服务器,自己做一个服务器怎么固定ip地址

    自己做一个服务器怎么固定ip地址 内容精选 换一换 客户端IP指的是访问者(用户设备)的IP地址.在Web应用开发中,通常需要获取客户端真实的IP地址.例如,投票系统为了防止刷票,需要通过获取客户端真 ...

  5. android登陆界面左右两种登陆布局,Android UI组件----用相对布局RelativeLayout做一个登陆界面...

    [声明] 欢迎转载,但请保留文章原始出处→_→ [正文] 两个小时的学习成果,对于我这种还没入门但渴望不断进步的初学者来说,是一种激励.通过自己一行一行的敲代码,实现了用相对布局做一个登陆界面的效果. ...

  6. 做一个简单网页(做一个简单网页多少钱)

    怎样做一个简易的网页?做一个简单网页多少钱 做一个简易的普通网页比较容易.当然,制作的方法有好几种,有的是直接写代码.有的是用绘图软件绘制页面再导出网页.常用的是使用网页制作软件做网页.下面以普通静态 ...

  7. android canvans 画3d,如何用Canvas做一个3D球

    先前在博客园看过Waxes同学在博客园做的3D球的Demo,地址在这 把他的Demo pull了下面,很多数学公式,即便在他的博客园里也有两个公式无法解释.因此,这里就写一篇自己思路的文章,教大家如何 ...

  8. 【Android学习之路】之从零开始做一个小项目(一)

    最近在学Android(初学者吖),写下这个[Android学习之路]系列记录一下自己学习的过程,欢迎阅读~

  9. Python/用 Pgzrun 库做一个简单小游戏

    游戏内容: 有敌人从屏幕上方冲向你的人物.你可以用方向键去操控人物移动,空格键发射武器. '_Henry原创_'import pgzrun import random# 设置窗口宽和高 WIDTH = ...

最新文章

  1. Java编译那些事儿【转】
  2. 【 FPGA 】FIR滤波器目录
  3. 服务器巡检文档,服务器巡检工具
  4. 人文英语学习品牌「友邻优课」携手神策数据 精细化数据分析让每一次互动都有价值
  5. C++ inline内联函数
  6. Python基于python实现的http+json协议接口自动化测试框架源码(实用改进版)
  7. 无头虚拟化服务器,在 Ubuntu 18.04 LTS 上使用 KVM 配置无头虚拟化服务器
  8. C# 取二位小数点(四舍五入)
  9. 浪潮云海OS C位出道,融合开放基础设施呼之欲出
  10. C# System.Timers.Timers的用法在工控设备上位中的用法
  11. 类的加载过程详解之过程五:类的Unloading(卸载)
  12. 博图v14编程c语言教程_10个步骤完成PLC从编程到下载,超详细的TIA博途V13软件使用教程...
  13. BUCK降压电路和BOOST升压电路
  14. pi启动configtool
  15. Pyrene-PEG-Acid,芘丁酸聚乙二醇羧基,Pyrene-PEG-COOH
  16. 什么是MIMO(多输入多输出),以及MIMO的分类和测试(一)
  17. 明源售楼系统技术解析 房源生成(二)
  18. 恢复视力的方法(飞行员都用)治近视的秘方!1000度近视降到只有200
  19. 柬埔寨攻略―签证、机票
  20. Holtek HT32 e-Link32 Pro 驱动正常无法安装 解决办法

热门文章

  1. SCCM 2007服务端简单配置与客户端设置
  2. Java各种循环的使用分享(兔C残篇)
  3. 如何使用Wireshark抓包自己的账号和密码
  4. linux 进入编辑文件,保存退出相关命令
  5. python绘图有什么用_python用处_python 绘图
  6. 无头单向链表删除中间节点-狸猫换太子
  7. Java+SpringBoot音乐网站(含源码+论文+答辩PPT等)
  8. 从互联网金融企业资金流向 看90后消费
  9. 截图识别文字有哪些方法?这个方法看一下
  10. CSS 文本一行两端对齐无效解决方案