1. 程式人生 > >使用SurfaceView實現手機息屏狀態下的靜默拍照儲存,上傳伺服器

使用SurfaceView實現手機息屏狀態下的靜默拍照儲存,上傳伺服器

注意:本文章只適用於技術交流,請你友好交流淨化開發環境

思考

  • 由於谷歌強制在Android應用開發中編寫拍照程式是必需要有影象預覽的。這對那些惡意程式比如Android中氾濫的Service在後臺偷偷記錄手機使用者的行為與周邊資訊。這樣的門檻還包括手機廠商自帶的相機軟體在拍照時必須是有聲音,這樣要避免一些偷拍的情況;據說oppo find系列及vivo Nex系列可以檢測出那些流氓軟體這麼做了。

步驟

  1. 建立一個surfaView物件

    preview = new SurfaceView(this);
        holder = preview.getHolder();
        // deprecated setting, but required on Android versions prior to 3.0
    holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); holder.addCallback(new SurfaceHolder.Callback() { @Override //The preview must happen at or after this point or takePicture fails public void surfaceCreated(SurfaceHolder holder) { //建立成功以後開啟相機 /** * camaraType: Camera.CameraInfo.CAMERA_FACING_FRONT :開啟前置攝像頭 * camaraType: Camera.CameraInfo.CAMERA_FACING_BACK :開啟後置攝像頭 */
    try { camera = Camera.open(camaraType); try { camera.setPreviewDisplay(holder); } catch (IOException e) { throw new RuntimeException(e); } camera.startPreview(); Log.d(TAG, "Started preview"
    ); camera.takePicture(null, null, pictureCallback); } catch (Exception e) { if (camera != null) camera.release(); throw new RuntimeException(e); } } @Override public void surfaceDestroyed(SurfaceHolder holder) {} @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {} });
  2. 使用WindowManager增加一個1*1px的懸浮框
    wm = (WindowManager)getSystemService(Context.WINDOW_SERVICE);
    //設定懸浮框為:1 * 1 :記得用後將其remove否則其他介面得不到交點,並且下拉框會有提示:應用在他應用的上層顯示的應用,關於這個設定選項
    WindowManager.LayoutParams params = new WindowManager.LayoutParams(
        1, 1, //設定成寬:1px , 高:1px
        WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,0, PixelFormat.UNKNOWN);

         /**
         * 根據不同的版本設定:TYPE_APPLICATION_OVERLAY 在低於26版本中報錯崩潰
         * 但是在Android O的系統中,google規定申請android.permission.SYSTEM_ALERT_WINDOW許可權的應用需要給懸浮視窗設定如下params.type
         */
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            params.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
        }
  1. 將SurfaceView新增到WindowManager中

    wm.addView(preview, params);
  2. 拍照結果的回掉儲存(注意: 上層的1*1px的拍照佈局 : 一定要移除,一定要移除,一定要移除,重要的妖怪打三遍---不然切換點選螢幕其他位置手機是獲取不到焦點,沒有反應的)

    /**
     * 拍照開始後結果的回撥
     */
    private Camera.PictureCallback pictureCallback = new Camera.PictureCallback() {
        @Override
        public void onPictureTaken(byte[] data, Camera camera) {
            Log.d(TAG, "onPictureTaken");
            if(null == data){
                return;
            }
            Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
            camera.stopPreview();
            Matrix matrix = new Matrix();
            matrix.postRotate((float) 270.0); //旋轉拍照結果,可能方向不正確
            bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(),
                    bitmap.getHeight(), matrix, false);
            Log.d(TAG, "original bitmap width: " + bitmap.getWidth() +
                    " height: " + bitmap.getHeight());
            Bitmap sizeBitmap = Bitmap.createScaledBitmap(bitmap,
                    bitmap.getWidth()/3, bitmap.getHeight()/3, true);
            Log.d(TAG,"size bitmap width "+sizeBitmap.getWidth()+" height "+sizeBitmap.getHeight());
    
            //裁剪bitmap
            int leftOffset = (int)(sizeBitmap.getWidth() * 0.25);
            int topOffset = (int)(sizeBitmap.getHeight() * 0.25);
            Rect rect = new Rect(leftOffset, topOffset, sizeBitmap.getWidth() - leftOffset,
                    sizeBitmap.getHeight() - topOffset);
            Bitmap rectBitmap = Bitmap.createBitmap(sizeBitmap,
                    rect.left, rect.top, rect.width(), rect.height());
            try {
                //儲存圖片
                FileOutputStream outputStream = new FileOutputStream(Environment
                        .getExternalStorageDirectory().toString()+"/photoResize.jpg");
                sizeBitmap.compress(Bitmap.CompressFormat.JPEG, 30, outputStream);
                outputStream.close();
                FileOutputStream outputStreamOriginal = new FileOutputStream(Environment
                        .getExternalStorageDirectory().toString()+"/photoOriginal.jpg");
                bitmap.compress(Bitmap.CompressFormat.JPEG, 20, outputStreamOriginal);
                outputStreamOriginal.close();
    
                FileOutputStream outputStreamCut = new FileOutputStream(Environment
                        .getExternalStorageDirectory().toString()+"/photoCut.jpg");
                rectBitmap.compress(Bitmap.CompressFormat.JPEG, 100, outputStreamCut);
                outputStreamCut.close();
    
                //通知系統相簿更新
                sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.parse("file://"+ Environment
                        .getExternalStorageDirectory().toString()+"/photoResize.jpg")));
                sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.parse("file://"+ Environment
                        .getExternalStorageDirectory().toString()+"/photoOriginal.jpg")));
                sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.parse("file://" + Environment
                        .getExternalStorageDirectory().toString() + "/photoCut.jpg")));
    
                Log.d(TAG,"picture saved!");
                if (camera != null) {
                    camera.release();
                    //移除上層的1*1px的拍照佈局 : 一定要移除,不然點選螢幕其他位置手機沒有反應
                    wm.removeView(preview);
                }
    
                Toast.makeText(TakePhotoActy.this , "照片儲存成功,可以開啟服務上傳照片然後注意刪除本地相簿!" , Toast.LENGTH_SHORT).show();
    //                System.exit(0); //如果沒有設定removeView()方法,可以通過強制退出實現焦點回歸
    
            } catch(Exception e) {
                e.printStackTrace();
            }
        }
    };
  3. 新增許可權(匯入三方許可權管理) 點選檢視: xxpermissions

    //android6.0以上系統需要動態申請拍照及儲存許可權,對於測試可以手動開啟許可權管理給與對應許可權即可
    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.CAMERA" />
    <uses-feature android:name="android.hardware.camera" />
    <uses-feature android:name="android.hardware.camera.autofocus" />
  4. 許可權管理

    //使用三方控制元件:https://github.com/getActivity/XXPermissions 簡單演示
    //build中匯入
    implementation 'com.hjq:xxpermissions:5.0'
    if (Build.VERSION.SDK_INT >= 23) {
            requestPermission();
     }
    private void requestPermission() {
        //1. 檢查是否已經有該許可權
        XXPermissions.with(this)
                .constantRequest() //可設定被拒絕後繼續申請,直到使用者授權或者永久拒絕
                .permission(Permission.WRITE_EXTERNAL_STORAGE , Permission.CAMERA) //不指定許可權則自動獲取清單中的危險許可權
                .request(new OnPermission() {
    
                    @Override
                    public void hasPermission(List<String> granted, boolean isAll) {
                        if (isAll) {
    //                            Toast.makeText(TakePhotoActy.this, "獲取許可權成功", Toast.LENGTH_SHORT).show();
                        }else {
    //                            Toast.makeText(TakePhotoActy.this, "獲取許可權成功,部分許可權未正常授予", Toast.LENGTH_SHORT).show();
                        }
                    }
    
                    @Override
                    public void noPermission(List<String> denied, boolean quick) {
                        if(quick) {
                            Toast.makeText(TakePhotoActy.this, "拍照需要你授權,否則不能正常使用", Toast.LENGTH_SHORT).show();
                            //如果是被永久拒絕就跳轉到應用許可權系統設定頁面
    //                            XXPermissions.gotoPermissionSettings(TakePhotoActy.this);
                        }else {
                            Toast.makeText(TakePhotoActy.this, "獲取許可權失敗", Toast.LENGTH_SHORT).show();
                        }
                    }
                });
    
    }
    
    

全部示例程式碼(在小米8:8.0系統,魅族6.0上均測試通過)

  1. activity程式碼:
/**
 * created by shi on 2018/9/10/010
 */
public class TakePhotoActy extends Activity implements View.OnClickListener {

    private static final String TAG = "shiq";
    private SurfaceView preview;
    private SurfaceHolder holder;
    private final int MESSAGE_LOGIN = 1;
    private int camaraType = Camera.CameraInfo.CAMERA_FACING_FRONT;

    /**
     * 測試息屏狀態10s拍照效果
     */
    private Handler handler = new Handler(new Handler.Callback() {
        @Override
        public boolean handleMessage(Message msg) {
            if (msg.what == MESSAGE_LOGIN) {
                Log.e(TAG, "我是收到的拍照介面");
                setTakePhoto();
            }
            return true;
        }
    });
    private WindowManager wm;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_take);
        initView();
    }

    private void initView() {

        Button bt_photo_force = findViewById(R.id.bt_photo_force);
        bt_photo_force.setOnClickListener(this);
        Button bt_photo_back = findViewById(R.id.bt_photo_back);
        bt_photo_back.setOnClickListener(this);

        if (Build.VERSION.SDK_INT >= 23) {
            requestPermission();
        }

        //驗證息屏狀態下的拍照:五秒後傳送
        //handler.sendEmptyMessageDelayed(MESSAGE_LOGIN, 10000);

    }
     /**
     * 許可權管理請求:需要儲存及相機許可權,如果上傳到伺服器後刪除,加上請求讀取許可權
     */
    private void requestPermission() {

        //1. 檢查是否已經有該許可權
        XXPermissions.with(this)
                .constantRequest() //可設定被拒絕後繼續申請,直到使用者授權或者永久拒絕
                .permission(Permission.WRITE_EXTERNAL_STORAGE , Permission.CAMERA) //不指定許可權則自動獲取清單中的危險許可權
                .request(new OnPermission() {
                    @Override
                    public void hasPermission(List<String> granted, boolean isAll) {
                        if (isAll) {
//                            Toast.makeText(TakePhotoActy.this, "獲取許可權成功", Toast.LENGTH_SHORT).show();
                        }else {
//                            Toast.makeText(TakePhotoActy.this, "獲取許可權成功,部分許可權未正常授予", Toast.LENGTH_SHORT).show();
                        }
                    }

                    @Override
                    public void noPermission(List<String> denied, boolean quick) {
                        if(quick) {
                            Toast.makeText(TakePhotoActy.this, "拍照需要你授權,否則不能正常使用", Toast.LENGTH_SHORT).show();
                            //如果是被永久拒絕就跳轉到應用許可權系統設定頁面
//                            XXPermissions.gotoPermissionSettings(TakePhotoActy.this);
                        }else {
                            Toast.makeText(TakePhotoActy.this, "獲取許可權失敗", Toast.LENGTH_SHORT).show();
                        }
                    }
                });

    }

    private Camera camera = null;

    @Override
    public void onClick(View v) {

        switch (v.getId()) {
            case R.id.bt_photo_force:
                camaraType = Camera.CameraInfo.CAMERA_FACING_FRONT;
                break;
            case R.id.bt_photo_back:
                camaraType = Camera.CameraInfo.CAMERA_FACING_BACK;
                break;
        }

        setTakePhoto();


    }

    private void setTakePhoto() {

        preview = new SurfaceView(this);
        holder = preview.getHolder();
        // deprecated setting, but required on Android versions prior to 3.0
        holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

        holder.addCallback(new SurfaceHolder.Callback() {
            @Override
            //The preview must happen at or after this point or takePicture fails
            public void surfaceCreated(SurfaceHolder holder) {
                //建立成功以後開啟相機
                /**
                 * camaraType: Camera.CameraInfo.CAMERA_FACING_FRONT :開啟前置攝像頭
                 * camaraType: Camera.CameraInfo.CAMERA_FACING_BACK :開啟後置攝像頭
                 */
                try {
                    camera = Camera.open(camaraType);
                    try {
                        camera.setPreviewDisplay(holder);
                    } catch (IOException e) {
                        throw new RuntimeException(e);
                    }

                    camera.startPreview();
                    Log.d(TAG, "Started preview");
                    camera.takePicture(null, null, pictureCallback);
                } catch (Exception e) {
                    if (camera != null)
                        camera.release();
                    throw new RuntimeException(e);
                }
            }

            @Override
            public void surfaceDestroyed(SurfaceHolder holder) {
            }

            @Override
            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
            }
        });

        wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
        //設定懸浮框為:1 * 1 :記得用後將其remove否則其他介面得不到交點,並且下拉框會有提示:應用在他應用的上層顯示的應用,關於這個設定選項
        WindowManager.LayoutParams params = new WindowManager.LayoutParams(
                1, 1, //設定成寬:1px , 高:1px
                WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY, 0, PixelFormat.UNKNOWN);

         /**
         * 根據不同的版本設定:TYPE_APPLICATION_OVERLAY 在低於26版本中報錯崩潰
         * 但是在Android O的系統中,google規定申請android.permission.SYSTEM_ALERT_WINDOW許可權的應用需要給懸浮視窗設定如下params.type
         */
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            params.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
        }
        wm.addView(preview, params);

    }

    /**
     * 拍照開始後結果的回撥
     */
    private Camera.PictureCallback pictureCallback = new Camera.PictureCallback() {
        @Override
        public void onPictureTaken(byte[] data, Camera camera) {
            Log.d(TAG, "onPictureTaken");
            if (null == data) {
                return;
            }
            Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
            camera.stopPreview();
            Matrix matrix = new Matrix();
            matrix.postRotate((float) 270.0); //旋轉拍照結果,可能方向不正確
            bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(),
                    bitmap.getHeight(), matrix, false);
            Log.d(TAG, "original bitmap width: " + bitmap.getWidth() +
                    " height: " + bitmap.getHeight());
            Bitmap sizeBitmap = Bitmap.createScaledBitmap(bitmap,
                    bitmap.getWidth() / 3, bitmap.getHeight() / 3, true);
            Log.d(TAG, "size bitmap width " + sizeBitmap.getWidth() + " height " + sizeBitmap.getHeight());

            //裁剪bitmap
            int leftOffset = (int) (sizeBitmap.getWidth() * 0.25);
            int topOffset = (int) (sizeBitmap.getHeight() * 0.25);
            Rect rect = new Rect(leftOffset, topOffset, sizeBitmap.getWidth() - leftOffset,
                    sizeBitmap.getHeight() - topOffset);
            Bitmap rectBitmap = Bitmap.createBitmap(sizeBitmap,
                    rect.left, rect.top, rect.width(), rect.height());
            try {
                //儲存圖片
                FileOutputStream outputStream = new FileOutputStream(Environment
                        .getExternalStorageDirectory().toString() + "/photoResize.jpg");
                sizeBitmap.compress(Bitmap.CompressFormat.JPEG, 30, outputStream);
                outputStream.close();
                FileOutputStream outputStreamOriginal = new FileOutputStream(Environment
                        .getExternalStorageDirectory().toString() + "/photoOriginal.jpg");
                bitmap.compress(Bitmap.CompressFormat.JPEG, 20, outputStreamOriginal);
                outputStreamOriginal.close();

                FileOutputStream outputStreamCut = new FileOutputStream(Environment
                        .getExternalStorageDirectory().toString() + "/photoCut.jpg");
                rectBitmap.compress(Bitmap.CompressFormat.JPEG, 100, outputStreamCut);
                outputStreamCut.close();

                //通知系統相簿更新
                sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.parse("file://" + Environment
                        .getExternalStorageDirectory().toString() + "/photoResize.jpg")));
                sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.parse("file://" + Environment
                        .getExternalStorageDirectory().toString() + "/photoOriginal.jpg")));
                sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.parse("file://" + Environment
                        .getExternalStorageDirectory().toString() + "/photoCut.jpg")));

                Log.d(TAG, "picture saved!");
                if (camera != null) {
                    camera.release();
                    //移除上層的1*1px的拍照佈局 : 一定要移除,不然點選螢幕其他位置手機沒有反應
                    wm.removeView(preview);
                }

                Toast.makeText(TakePhotoActy.this, "照片儲存成功,可以開啟服務上傳照片然後注意刪除本地相簿!", Toast.LENGTH_SHORT).show();
                //System.exit(0); //如果沒有設定removeView()方法,可以通過強制退出實現焦點回歸

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

  1. 佈局檔案很簡單就是普通的兩個button測試

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">
    
    <Button
        android:id="@+id/bt_photo_force"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="前置拍照"
        />
    
    <Button
        android:id="@+id/bt_photo_back"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="後置拍照" />
    
    </LinearLayout

相關推薦

使用SurfaceView實現手機狀態靜默拍照儲存,伺服器

注意:本文章只適用於技術交流,請你友好交流淨化開發環境 思考 由於谷歌強制在Android應用開發中編寫拍照程式是必需要有影象預覽的。這對那些惡意程式比如Android中氾濫的Service在後臺偷偷記錄手機使用者的行為與周邊資訊。這樣的門檻還包括手機

H5移動端橫豎切換監聽 副作用——手機狀態安卓機input 問題

H5移動端橫豎屏切換監聽 上一次說過了 H5移動端橫豎屏切換監聽的寫法。 橫豎屏監聽程式碼如下,這裡就不做詳細說明了。完整說明 $(function(){//監聽橫豎屏旋轉,ios 和 Android 寫法不一樣 onResize();

Android鎖或滅狀態,快速按兩次音量實現抓拍功能(1.1Framework層使用廣播形式實現

實現思路:     WindowManagerService迴圈讀取下面按鍵訊息並分發給視窗,在訊息分發前會在PhoneWindowManager.interceptKeyBeforeQueueing方法中進行訊息的過濾。因此該實現方式為在訊息分發前的interceptKe

Android鎖或滅狀態,快速按兩次音量實現抓拍功能(一,Framework層實現

    WindowManagerService迴圈讀取下面按鍵訊息並分發給視窗,在訊息分發前會在PhoneWindowManager.interceptKeyBeforeQueueing方法中進行訊息的過濾。因此該實現方式為在訊息分發前的interceptKeyBeforeQueueing方法中監聽當前按

HDFS設計思路,HDFS使用,查看集群狀態,HDFS,HDFS文件,HDFS載文件,yarn web管理界面信查看,運行一個mapreduce程序,mapreduce的demo

b2c 數據系統 set 打包 value map mode format drive 26 集群使用初步 HDFS的設計思路 l 設計思想 分而治之:將大文件、大批量文件,分布式存放在大量服務器上,以便於采取分而治之的方式對海量數據進行運算分析; l 在大數據系

移動端判斷手機橫豎狀態

func ble ole dcl 功能 dia 使用 ati 必須 禁用用戶自動縮放功能: <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0

js和css實現手機橫豎預覽思路整理

實現效果,如上圖。   首先,實現手機頁面在PC端預覽, 則先在網上找到一個手機的背景圖片,算好大概內間距,用來放預覽的頁面,我這裡是給手機預覽頁面的尺寸按iphone5的尺寸來的; 一個手機頁面在這裡預覽,要通過<iframe>標籤,左邊選擇不同的select選項,通過監

android 滑動鎖狀態如何禁止狀態

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

仿QQ鎖狀態訊息提醒

最近專案開發中需要手機螢幕喚醒功能,查閱資料後整理了demo,當鎖屏狀態下收到通知,喚醒螢幕。主要思路為通過MyService服務傳送一條廣播,然後判斷如果為鎖屏狀態就啟動鎖屏訊息的activity.此時有震動和鈴聲提示,顯示倒計時。 下面請看效果圖: 實現步驟: 1:在

使用Python+uiautomator2實現手機解鎖(期望輸入的鎖密碼,基於滑動解鎖)

業務需求:需要測試手機滑動解鎖失敗時事件的次數及等待的時間,本來想利用Python+Appium實現,但是Appium執行時自動給我解鎖了.... python-uiautomator2是一個自動化測試開源工具,僅支援Android平臺的原生應用測試 python-u

android 鎖狀態顯示activity

在activity onCreate下新增  int flags = WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED; getWindow().addFlags(flags); WindowManager.LayoutPar

android鎖狀態, 新訊息喚醒螢幕,並跳轉到指定頁面

最近在做一個專案,有個功能,就和QQ電話差不多,我這邊手機鎖屏狀態,當QQ電話過來時,立刻喚醒螢幕,並顯示QQ來電介面,我的是當裝置端有事件發生時通知app端彈出介面,實時顯示裝置端資訊。 最核心的程

Android鎖狀態點亮螢幕並彈窗提醒

類似於手機鎖屏狀態下QQ來訊息然後點亮螢幕並彈窗,如圖。 相信QQ的這個功能大家都是很熟悉的了,下面就開始講具體的實現步驟。 一、新建一個Activity並在OnCreate中新增四個標識 @Override protected

解決安卓全“FLAG_FULLSCREEN”狀態“adjustResize”失效,全狀態WebView的輸入框被軟鍵盤擋住的問題

沿著這個問題的線索,可以追溯到:http://code.google.com/p/android/issues/detail?id=5497   ,安卓官方問題回饋帖,這個問題的代號為“5497” ,就這個問題帖的回覆來看,該問題困惑了許多人數年之久,問題釋出日期“Dec

懸浮球只在一側滑動 並且是橫狀態

公司有一個新的需求 是需要懸浮球在一側上下滑動 其實是很簡單的 而且網上都有各種案例,但是 偏偏是橫屏狀態下 ,而且不是手機橫屏 是用css強制旋轉螢幕90度之後的橫屏,所以就會出現座標系的紊亂,然後我這個功能一開始做成的效果就是觸控上下滑動的時候 ,懸浮球是左右走(目前的這個圖片的上下左右),當時非常的苦惱

安卓實現拍照圖片以及剪圖片

效果圖: 總結一下專案實現的選擇圖片、拍照、以及剪下圖片,再加一下圖片壓縮,上傳到伺服器等功能 網上有好多關於圖片上傳、拍照的方法,我這只是自己專案的一種方式,之前部落格也是總結過圖集上傳,裡面也包含圖片上傳,拍照的相關程式碼,在這我單獨拿出來總結一下,還有關於呼叫系統

SpringMVCExcel檔案的下載實現

 在實際應用中,經常會遇到上傳Excel或者下載Excel的情況,比如匯入資料、下載統計資料等等場景。針對這個問題,我寫了個基於SpringMVC的簡單上傳下載示例,其中Excel的處理使用Apache的POI元件。 主要依賴的包如下:  <dependency> <groupId

Tomcat檔案下載與的簡單實現

實現下載 實現下載需要 - 修改Tomcat中的server.xml - 修改web.xml 修改server.xml 在<Host> </Host>中加入(一般在檔案末尾可以找到) <Contex

在ThinkPHP5框架引入Ueditor並實現向七牛雲物件儲存圖片同時將圖片資訊儲存到MySQL資料庫,同時實現lazyload懶載入

這是我花了很多天的時間才得以真正實現的一組需求。 文章後面有完整Demo的GitHub連結。 一、 需求描述 1. 應用是基於ThinkPHP5開發的; 2. 伺服器環境是LNMP,PHP版本是7.2,資料庫是MySQL5.6; 3. 由使用者(包括管理員)上傳的圖片一類的媒體檔案不能直接上傳到應用

Java實現FTP文件與文件夾的和下載

連接 rem odi 一個 nec stat mod plog erlang Java實現FTP文件與文件夾的上傳和下載   FTP 是File Transfer Protocol(文件傳輸協議)的英文簡稱,而中文簡稱為“文傳協議”。用於Int