假期学习记录17(Android拍照并将图片上传到服务器)

首先在layout文件中布局如下,很简单就是一个ImageView用于显示图片,一个按钮拍照,一个按钮上传

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_up_photo"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:gravity="center"
    tools:context="com.example.sportrecord.UpPhoto">
<ImageView
    android:id="@+id/photoshow"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <Button
            android:layout_marginLeft="10dp"
            android:text="拍照打卡"
            android:id="@+id/takephoto"
            android:layout_width="180dp"
            android:layout_height="match_parent" />
        <Button
            android:layout_marginRight="0dp"
            android:text="确认上传"
            android:id="@+id/upphoto"
            android:layout_width="180dp"
            android:layout_height="match_parent" />
    </LinearLayout>
</LinearLayout>

然后再activity的java文件中代码如下

package com.example.sportrecord;

import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Build;
import android.provider.MediaStore;
import android.support.v4.content.FileProvider;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Base64;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Toast;

import com.example.sportrecord.Util.BitmapUtils;
import com.example.sportrecord.Util.NetUtil;

import java.io.ByteArrayOutputStream;
import java.io.File;

public class UpPhoto extends Activity {
    public static final int TAKE_PHOTO=1;
    private ImageView photoshow;
    private Uri imageUri;
    private Button takephoto;
    private Button upphoto;
    public  Bitmap bitmap1;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_up_photo);
        takephoto=(Button)findViewById(R.id.takephoto);
        upphoto=(Button)findViewById(R.id.upphoto);
        photoshow=(ImageView)findViewById(R.id.photoshow);
        Intent intent=getIntent();
        String point=intent.getStringExtra("point");
        takephoto.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                File outputImage =new File(getExternalCacheDir(),"output_image.jpg");//将拍照文件存在本地
                try{
                    if (outputImage.exists()){
                        outputImage.delete();
                    }
                    outputImage.createNewFile();
                }catch (Exception e){

                }
                if(Build.VERSION.SDK_INT>=24){
                    imageUri= FileProvider.getUriForFile(UpPhoto.this,"com.example.SportRecord.fileprovider",outputImage);//fileprovider下面会定义
                }else {
                    imageUri=Uri.fromFile(outputImage);
                }
                Intent intent=new Intent("android.media.action.IMAGE_CAPTURE");//打开相机
                intent.putExtra(MediaStore.EXTRA_OUTPUT,imageUri);
                startActivityForResult(intent,TAKE_PHOTO);
            }

        });
        upphoto.setOnClickListener(new View.OnClickListener() {//上传图片
            @Override
            public void onClick(View v) {
                if (bitmap1==null){
                    Toast.makeText(UpPhoto.this,"无图片",Toast.LENGTH_LONG).show();
                }else {
                SharedPreferences pref=getSharedPreferences("userMessage",MODE_PRIVATE);//获取用户id,项目需要,例子中直接删了就好
                String useraccount=pref.getString("useraccount","");
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        NetUtil.getPhotoMes(UpPhoto.this,bitmap1,useraccount,point);//NetUtil.getPhotoMes是一个自定义函数用来和服务器连接,下面有代码
                    }
                }).start();
               Toast.makeText(UpPhoto.this,"成功",Toast.LENGTH_LONG).show();
               UpPhoto.this.finish();
            }
            }
        });
    }
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {//显示图片startActivityForResult启动的intent会自动跳到这里
        switch (requestCode) {
            case TAKE_PHOTO:
                if (resultCode == RESULT_OK) {
                    try {
                        Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(imageUri));
                        bitmap1= BitmapUtils.zoomImage(bitmap,400,550);//压缩图片,下面也有源码
                        photoshow.setImageBitmap(bitmap1);
                    } catch (Exception e) {

                    }
                }
                break;
            default:
                break;
        }
    }
}

服务器连接函数NetUtil.getPhotoMes

public static void getPhotoMes(Context cont, Bitmap photodata, String user_account, String point) {
        try {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();

            //将bitmap一字节流输出 Bitmap.CompressFormat.PNG 压缩格式,100:压缩率,baos:字节流
            photodata.compress(Bitmap.CompressFormat.PNG, 100, baos);
            baos.close();
            byte[] buffer = baos.toByteArray();
            System.out.println("图片的大小:"+buffer.length);

            //将图片的字节流数据加密成base64字符输出
            String photo = Base64.encodeToString(buffer, 0, buffer.length,Base64.DEFAULT);

            //photo=URLEncoder.encode(photo,"UTF-8");
            RequestParams params = new RequestParams();
            params.put("photo", photo);
            params.put("user_account", user_account);//传输的字符数据
            params.put("point", point);//传输的字符数据
            String url = "服务器sevlet地址";


            AsyncHttpClient client = new AsyncHttpClient();
            client.post(url, params, new AsyncHttpResponseHandler() {
            });

        } catch (Exception e) {
            e.printStackTrace();
        }

    }

 




/图片压缩函数BitmapUtils.zoomImage,我给的函数较多,我使用的是zoomImage这个函数输入一个bitmap返回一个压缩后的bitmap,嫌累直接看zoomImage就好

package com.example.sportrecord.Util;

import android.content.Context;
import android.content.CursorLoader;
import android.content.res.Resources;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.net.Uri;
import android.provider.MediaStore;

public class BitmapUtils {

    private static int mDesiredWidth;
    private static int mDesiredHeight;

    /**
     * @description 从Resources中加载图片
     *
     * @param res
     * @param resId
     * @param reqWidth
     * @param reqHeight
     * @return
     */
    public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId, int reqWidth, int reqHeight) {
        BitmapFactory.Options options = new BitmapFactory.Options();
        //Bitmap bmp = BitmapFactory.decodeFile(path,options);
        // 设置成了true,不占用内存,只获取bitmap宽高
        options.inJustDecodeBounds = true;
        // 初始化options对象
        BitmapFactory.decodeResource(res, resId, options);
        // 得到计算好的options,目标宽、目标高
        options = getBestOptions(options, reqWidth, reqHeight);
        Bitmap src = BitmapFactory.decodeResource(res, resId, options); // 载入一个稍大的缩略图
        return createScaleBitmap(src, mDesiredWidth, mDesiredHeight); // 进一步得到目标大小的缩略图
    }
    public static Bitmap zoomImage(Bitmap bgimage, double newWidth,
                                   double newHeight) {
        // 获取这个图片的宽和高
        float width = bgimage.getWidth();
        float height = bgimage.getHeight();
        // 创建操作图片用的matrix对象
        Matrix matrix = new Matrix();
        // 计算宽高缩放率
        float scaleWidth = ((float) newWidth) / width;
        float scaleHeight = ((float) newHeight) / height;
        // 缩放图片动作
        matrix.postScale(scaleWidth, scaleHeight);
        Bitmap bitmap = Bitmap.createBitmap(bgimage, 0, 0, (int) width,
                (int) height, matrix, true);
        return bitmap;
    }
    /**
     * @description 从SD卡上加载图片
     *
     * @param pathName
     * @param reqWidth
     * @param reqHeight
     * @return
     */
    public static Bitmap decodeSampledBitmapFromFile(String pathName, int reqWidth, int reqHeight) {
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(pathName, options);
        options = getBestOptions(options, reqWidth, reqHeight);
        Bitmap src = BitmapFactory.decodeFile(pathName, options);
        return createScaleBitmap(src, mDesiredWidth, mDesiredHeight);
    }

    /**
     * @description 计算目标宽度,目标高度,inSampleSize
     *
     * @param options
     * @param reqWidth
     * @param reqHeight
     * @return BitmapFactory.Options对象
     */
    private static BitmapFactory.Options getBestOptions(BitmapFactory.Options options, int reqWidth, int reqHeight) {
        // 读取图片长宽
        int actualWidth = options.outWidth;
        int actualHeight = options.outHeight;
        // Then compute the dimensions we would ideally like to decode to.
        mDesiredWidth = getResizedDimension(reqWidth, reqHeight, actualWidth, actualHeight);
        mDesiredHeight = getResizedDimension(reqHeight, reqWidth, actualHeight, actualWidth);
        // 根据现在得到计算inSampleSize
        options.inSampleSize = calculateBestInSampleSize(actualWidth, actualHeight, mDesiredWidth, mDesiredHeight);
        // 使用获取到的inSampleSize值再次解析图片
        options.inJustDecodeBounds = false;
        return options;
    }

    /**
     * Scales one side of a rectangle to fit aspect ratio. 最终得到重新测量的尺寸
     *
     * @param maxPrimary
     *            Maximum size of the primary dimension (i.e. width for max
     *            width), or zero to maintain aspect ratio with secondary
     *            dimension
     * @param maxSecondary
     *            Maximum size of the secondary dimension, or zero to maintain
     *            aspect ratio with primary dimension
     * @param actualPrimary
     *            Actual size of the primary dimension
     * @param actualSecondary
     *            Actual size of the secondary dimension
     */
    private static int getResizedDimension(int maxPrimary, int maxSecondary, int actualPrimary, int actualSecondary) {
        double ratio = (double) actualSecondary / (double) actualPrimary;
        int resized = maxPrimary;
        if (resized * ratio > maxSecondary) {
            resized = (int) (maxSecondary / ratio);
        }
        return resized;
    }

    /**
     * Returns the largest power-of-two divisor for use in downscaling a bitmap
     * that will not result in the scaling past the desired dimensions.
     *
     * @param actualWidth
     *            Actual width of the bitmap
     * @param actualHeight
     *            Actual height of the bitmap
     * @param desiredWidth
     *            Desired width of the bitmap
     * @param desiredHeight
     *            Desired height of the bitmap
     */
    // Visible for testing.
    private static int calculateBestInSampleSize(int actualWidth, int actualHeight, int desiredWidth, int desiredHeight) {
        double wr = (double) actualWidth / desiredWidth;
        double hr = (double) actualHeight / desiredHeight;
        double ratio = Math.min(wr, hr);
        float inSampleSize = 1.0f;
        while ((inSampleSize * 2) <= ratio) {
            inSampleSize *= 2;
        }

        return (int) inSampleSize;
    }


    private static Bitmap createScaleBitmap(Bitmap tempBitmap, int desiredWidth, int desiredHeight) {
        // If necessary, scale down to the maximal acceptable size.
        if (tempBitmap != null && (tempBitmap.getWidth() > desiredWidth || tempBitmap.getHeight() > desiredHeight)) {
            // 如果是放大图片,filter决定是否平滑,如果是缩小图片,filter无影响
            Bitmap bitmap = Bitmap.createScaledBitmap(tempBitmap, desiredWidth, desiredHeight, true);
            tempBitmap.recycle(); // 释放Bitmap的native像素数组
            return bitmap;
        } else {
            return tempBitmap; // 如果没有缩放,那么不回收
        }
    }
    public static String getRealPathFromUri(Context context, Uri uri) {
        if (context == null || uri == null) {
            return null;
        }
        if ("file".equalsIgnoreCase(uri.getScheme())) {
            return getRealPathFromUri_Byfile(context, uri);
        } else if ("content".equalsIgnoreCase(uri.getScheme())) {
            return getRealPathFromUri_Api11To18(context, uri);
        }
        return null;
    }




    public static String getRealPathFromUri_Byfile(Context context,Uri uri){
        String uri2Str = uri.toString();
        String filePath = uri2Str.substring(uri2Str.indexOf(":") + 3);
        return filePath;
    }
    private static String getRealPathFromUri_Api11To18(Context context, Uri uri) {
        String filePath = null;
        String[] projection = { MediaStore.Images.Media.DATA };

        CursorLoader loader = new CursorLoader(context, uri, projection, null,
                null, null);
        Cursor cursor = loader.loadInBackground();

        if (cursor != null) {
            cursor.moveToFirst();
            filePath = cursor.getString(cursor.getColumnIndex(projection[0]));
            cursor.close();
        }
        return filePath;
    }

}

然后我们需要一些配置

在androidManifest中加入一个provider,写在appliation中

   <provider
            android:exported="false"
            android:grantUriPermissions="true"
            android:authorities="com.example.SportRecord.fileprovider"
            android:name="android.support.v4.content.FileProvider">
            <meta-data android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_paths"/>
        </provider>

然后右击res建立新目录xml文件夹然后创建一个file_paths.xml文件代码如下

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path name="my_images" path=""></external-path>
</paths>


最后需要声明下权限androidManifest中

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <!-- SD卡权限 -->

接下来是服务器代码

package org.java.servlet;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.java.write.WriteMorningWay;

import sun.misc.BASE64Decoder;

/**
 * Servlet implementation class getPhotoMes
 */
@WebServlet("/getPhotoMes")
public class getPhotoMes extends HttpServlet {
    private static final long serialVersionUID = 1L;
       
    /**
     * @see HttpServlet#HttpServlet()
     */
    public getPhotoMes() {
        super();
        // TODO Auto-generated constructor stub
    }

    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
            request.setCharacterEncoding("utf-8");
            response.setCharacterEncoding("utf-8");
            response.setContentType("text/html");
            String photo = request.getParameter("photo");
            String user_account = request.getParameter("user_account");
            String point = request.getParameter("point");
            try {
     
                // 对base64数据进行解码 生成 字节数组,不能直接用Base64.decode();进行解密
                byte[] photoimg = new BASE64Decoder().decodeBuffer(photo);
                for (int i = 0; i < photoimg.length; ++i) {
                    if (photoimg[i] < 0) {
                        // 调整异常数据
                        photoimg[i] += 256;
                    }
                }
     
                // byte[] photoimg = Base64.decode(photo);//此处不能用Base64.decode()方法解密,我调试时用此方法每次解密出的数据都比原数据大  所以用上面的函数进行解密,在网上直接拷贝的,花了好几个小时才找到这个错误(菜鸟不容易啊)
                String savePath = this.getServletContext().getRealPath("/photoUpload/");
                SimpleDateFormat df = new SimpleDateFormat("yyyyMMddHHmmss");//设置日期格式来命名图片
                String string=df.format(new Date());
                String photoname=string+user_account+".png";
                System.out.print("length:"+savePath);
                File file = new File(savePath, photoname);
                if (!file.exists()) {
                    file.createNewFile();
                }
            
                FileOutputStream out = new FileOutputStream(file);
                out.write(photoimg);
                out.flush();
                out.close();
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
    }

    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        doGet(request, response);
    }

}

 

posted @ 2020-04-02 01:25  王怀宇  阅读(701)  评论(0编辑  收藏  举报