安卓USB通信,PC端預(yù)覽手機(jī)攝像頭并控制手機(jī)拍照

功能需求:

1 手機(jī)端打開(kāi)攝像頭實(shí)時(shí)預(yù)覽爆惧;
2 手機(jī)端作為服務(wù)端择膝,PC端作為客戶端連接;
3 連接成功后PC端可以同時(shí)預(yù)覽手機(jī)端的攝像頭采集的圖像检激;
4 PC端點(diǎn)擊拍照可以控制手機(jī)端拍攝一張照片肴捉,并將照片傳給PC端。

功能模塊:

1 安卓手機(jī)打開(kāi)攝像頭并實(shí)現(xiàn)預(yù)覽和拍照功能叔收;
2 手機(jī)端開(kāi)啟監(jiān)聽(tīng)齿穗,并在連接成功后將攝像頭采集的數(shù)據(jù)傳給PC;
3 手機(jī)端讀取PC發(fā)送的命令指令饺律,執(zhí)行相應(yīng)的操作窃页。

(一)開(kāi)啟攝像頭實(shí)現(xiàn)預(yù)覽

(1) 獲取攝像頭權(quán)限,并添加自動(dòng)對(duì)焦屬性

在應(yīng)用程序的manifest.xml中添加

 <uses-permission android:name="android.permission.CAMERA" />
 <uses-feature android:name="android.hardware.camera" />  
 <uses-feature android:name="android.hardware.camera.autofocus" />
(2) 實(shí)現(xiàn)預(yù)覽

安卓系統(tǒng)使用SurfaceView即可完成預(yù)覽功能复濒,使用方式如下:
activity_main.xml布局文件

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/gray_light"
android:orientation="vertical" >

<SurfaceView
    android:id="@+id/surview"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:scaleType="fitCenter" />

</LinearLayout>

在MainActivity 的onCreate中初始化SurfceView脖卖。初始化方法如下:

private void initSurfaceView() {
    surfaceView = (SurfaceView) findViewById(R.id.surview);
    surfaceHolder = surfaceView.getHolder();
    surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    surfaceHolder.setKeepScreenOn(true);
    surfaceHolder.addCallback(new Callback() {

        @Override
        public void surfaceDestroyed(SurfaceHolder arg0) {

        }

        @Override
        public void surfaceCreated(SurfaceHolder arg0) {
            // 開(kāi)啟攝像頭
            startCamera(curCameraIndex);
        }

        @Override
        public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2,
                int arg3) {

        }
    });
    surfaceView.setFocusable(true);
    surfaceView.setBackgroundColor(TRIM_MEMORY_BACKGROUND);

}

當(dāng)SurfceView創(chuàng)建時(shí)開(kāi)啟攝像頭,開(kāi)啟方法如下:

// 根據(jù)索引初始化攝像頭
@SuppressLint("NewApi")
public void startCamera(int cameraIndex) {

    // 先停止攝像頭
    stopCamera();
    // 再初始化并打開(kāi)攝像頭
    if (camera == null) {
        camera = Camera.open(cameraIndex);
        cameraUtil = new CameraUtil(camera, callback);
        cameraUtil.initCamera(srcFrameHeight, srcFrameWidth, surfaceHolder);
        Log.e(TAG, "打開(kāi)相機(jī)");
    }
}

// 停止并釋放攝像頭
public void stopCamera() {
    if (camera != null) {
        camera.setPreviewCallback(null);
        camera.stopPreview();
        camera.release();
        camera = null;
    }
}

//攝像頭開(kāi)啟預(yù)覽后采集到的數(shù)據(jù)回調(diào)接口
PreviewCallback callback = new PreviewCallback() {

    @Override
    public void onPreviewFrame(byte[] data, Camera camera) {
        Size size = camera.getParameters().getPreviewSize();
        try {
            if (times == 0) {
                YuvImage image = new YuvImage(data, ImageFormat.NV21,
                        size.width, size.height, null);
                if (image != null) {
                    // 將YuvImage對(duì)象轉(zhuǎn)為字節(jié)數(shù)組
                    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
                    image.compressToJpeg(new Rect(0, 0, size.width,
                            size.height), 100, outputStream);
                    byte[] srcData = outputStream.toByteArray();
                    int len = srcData.length;
                    
                    // 字節(jié)數(shù)組轉(zhuǎn)為Bitmap
                    Bitmap src = BitmapFactory.decodeByteArray(srcData, 0,
                            len);
                    src = BitmapUtil.rotate(src, 90);
                    // 壓縮Bitmap巧颈,并獲取壓縮后的字節(jié)數(shù)組畦木,即可獲取預(yù)覽數(shù)據(jù)文件
                    // outdata數(shù)據(jù)即是待發(fā)送給PC端的數(shù)據(jù)
                    byte[] outdata = BitmapUtil.transImage(src,
                            srcFrameWidth / 4, srcFrameHeight / 4);
                    int datalen = outdata.length;

                    if (isOpen) {
                        // 寫(xiě)入頭
                        sendData(new byte[] { (byte) 0xA0 });
                        // 寫(xiě)入數(shù)組長(zhǎng)度
                        sendData(intToByteArray(datalen));
                        // 寫(xiě)入數(shù)據(jù)值
                        sendData(outdata);
                    }

                    // 回收Bitmap
                    if (!src.isRecycled()) {
                        src.recycle();
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
};

CameraUtil為設(shè)置攝像頭的輔助類(lèi),代碼如下:

import java.io.IOException;
import android.annotation.SuppressLint;
import android.graphics.ImageFormat;
import android.hardware.Camera;
import android.hardware.Camera.AutoFocusCallback;
import android.hardware.Camera.PreviewCallback;
import android.view.SurfaceHolder;

public class CameraUtil {
    Camera camera;
    int cameraIndex;
    int srcFrameWidth;
    int srcFrameHeight;
    SurfaceHolder surfaceHolder;
    PreviewCallback callback;

    public CameraUtil(Camera camera, PreviewCallback callback) {
        this.camera = camera;
        this.callback = callback;
    }


    public void initCamera(final int srcFrameWidth, final int srcFrameHeight, final SurfaceHolder surfaceHolder) {
    
        this.srcFrameHeight = srcFrameHeight;
        this.srcFrameWidth = srcFrameWidth;
        this.surfaceHolder = surfaceHolder;
        Camera.Parameters params = camera.getParameters();
        //params.setPreviewSize(srcFrameWidth / 4, srcFrameHeight / 4);
        params.setPreviewFormat(ImageFormat.NV21);
        params.setPreviewFrameRate(30);
        params.setJpegQuality(100);
        params.setPictureFormat(ImageFormat.JPEG);
        params.set("orientation", "portrait");
        params.set("rotation", 90);
        params.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);// 1連續(xù)對(duì)焦
        camera.setParameters(params);
        camera.setDisplayOrientation(90);
        // 設(shè)置顯示圖像的SurfaceView
        try {
            camera.setPreviewDisplay(surfaceHolder);
        } catch (IOException e) {
            e.printStackTrace();
        }
        camera.setPreviewCallback(callback);
        camera.startPreview();
        camera.autoFocus(new AutoFocusCallback() {
        @Override
        public void onAutoFocus(boolean result, Camera camera) {
            
            // 自動(dòng)對(duì)焦完成時(shí)回調(diào)
            if (result) {
                    initCamera(srcFrameWidth, srcFrameHeight, surfaceHolder);
                    camera.cancelAutoFocus();
                }
            }
        });
    }

    @SuppressLint("NewApi") 
    public void startCamera(int cameraIndex) {
    
        this.cameraIndex = cameraIndex;
        // 先停止攝像頭
        stopCamera();
        // 再初始化并打開(kāi)攝像頭
        if (camera == null) {
            camera = Camera.open(cameraIndex);
            initCamera(srcFrameWidth, srcFrameHeight, surfaceHolder);       
        }
    }

    public void stopCamera() {
        if (camera != null) {
            camera.setPreviewCallback(null);
            camera.stopPreview();
            camera.release();
            camera = null;
        }
    }
}

BitmapUtil 為圖片操作輔助類(lèi)

import java.io.ByteArrayOutputStream;
import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.graphics.Bitmap.CompressFormat;

public class BitmapUtil {

// Bitmap按照一定大小轉(zhuǎn)為字節(jié)數(shù)組砸泛,以便寫(xiě)入socket進(jìn)行發(fā)送
    public static byte[] transImage(Bitmap bitmap, int width, int height) {
        // bitmap = adjustPhotoRotation(bitmap, 90);
        try {
            int bitmapWidth = bitmap.getWidth();
            int bitmapHeight = bitmap.getHeight();
            float scaleWidth = (float) width / bitmapWidth;
            float scaleHeight = (float) height / bitmapHeight;
            Matrix matrix = new Matrix();
            matrix.postScale(scaleWidth, scaleHeight);
            // 創(chuàng)建壓縮后的Bitmap
            Bitmap resizeBitemp = Bitmap.createBitmap(bitmap, 0, 0,
                bitmapWidth, bitmapHeight, matrix, false);
        
            // 壓縮圖片質(zhì)量
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            resizeBitemp.compress(CompressFormat.JPEG, 80, outputStream);
            // 轉(zhuǎn)為字節(jié)數(shù)組
            byte[] byteArray = outputStream.toByteArray();
            outputStream.close();

            // 回收資源
            if (!bitmap.isRecycled()) {
                bitmap.recycle();
            }
            if (!resizeBitemp.isRecycled()) {
                resizeBitemp.recycle();
            }
            return byteArray;

        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return null;
    }


    public static Bitmap rotate(Bitmap bitmap, float degree) {
        Matrix matrix = new Matrix();
       // matrix.setScale(0.5f, 0.5f);// 縮小為原來(lái)的一半
        matrix.postRotate(degree);// 旋轉(zhuǎn)45度 == matrix.setSinCos(0.5f, 0.5f);
        bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(),
        bitmap.getHeight(), matrix, true);
        return bitmap;
    }
}

(二) 連接功能實(shí)現(xiàn)

(1) onCreate中注冊(cè)廣播的監(jiān)聽(tīng)
    IntentFilter filter = new IntentFilter();
    filter.addAction("NotifyServiceStart");
    filter.addAction("NotifyServiceStop");
    registerReceiver(receiver, filter);
(2) 接收系統(tǒng)廣播
public class ServiceBroadcastReceiver extends BroadcastReceiver {

    private static final String START_ACTION = "NotifyServiceStart";
    private static final String STOP_ACTION = "NotifyServiceStop";

    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        if (START_ACTION.equalsIgnoreCase(action)) {
            // 啟動(dòng)服務(wù)
            Log.e(TAG, "收到廣播信息啟動(dòng)監(jiān)聽(tīng)");
            new Thread() {
                public void run() {

                    if (serverSocket != null) {
                        try {
                            serverSocket.close();
                        } catch (IOException e) {

                            e.printStackTrace();
                        }
                    }
                    //服務(wù)端啟動(dòng)監(jiān)聽(tīng)
                    doListen();
                };
            }.start();

        } else if (STOP_ACTION.equalsIgnoreCase(action)) {

        }
    }
}

啟動(dòng)監(jiān)聽(tīng)的代碼:

    // 啟動(dòng)服務(wù)器端監(jiān)聽(tīng)
    private void doListen() {
        serverSocket = null;
        try {
            serverSocket = new ServerSocket(SERVER_PORT);
            while (true) {
                Socket socket = serverSocket.accept();
                Log.e(TAG, "監(jiān)聽(tīng)到設(shè)備連接十籍,啟動(dòng)通信線程");
                threadSocket = new ThreadReadWriterIOSocket(socket);
                new Thread(threadSocket).start();
            }
        } catch (IOException e) {
            Log.e(TAG, "服務(wù)端監(jiān)聽(tīng)失敗");
            e.printStackTrace();
        }
    }

ThreadReadWriterIOSocket為負(fù)責(zé)通信的線程,代碼如下:

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
import org.greenrobot.eventbus.EventBus;
import android.util.Log;
import com.myn.usb.bean.MessageEvent;
import com.myn.usb.utils.Constant;

/**
 * 數(shù)據(jù)讀寫(xiě)線程
 * 
 * @author Administrator
     * 
 */
public class ThreadReadWriterIOSocket implements Runnable {

    private static String TAG = "ThreadReadWriterIOSocket";
    private Socket client;
    private BufferedOutputStream out;
    private BufferedInputStream in;
    boolean isConnecting = false;
    private String cmd = "";

    public ThreadReadWriterIOSocket(Socket client) {
        this.client = client;
    }

    @Override
    public void run() {
    
        Log.e(TAG, "有客戶端連接上");
        isConnecting = true;
        try {
            // 獲取輸入輸出流
            out = new BufferedOutputStream(client.getOutputStream());
            in  = new BufferedInputStream(client.getInputStream());

            // 循環(huán)等待,接受PC端的命令
            while (isConnecting) {
                try {
                    if (!client.isConnected()) {
                        break;
                    }
                    // 讀取命令
                    cmd = readCMDFromSocket(in);    
                    Log.e(TAG, "讀取到PC發(fā)送的命令" + cmd);
                    /* 根據(jù)命令分別處理數(shù)據(jù) */
                    if (cmd.equals(Constant.CONNECT)) {// 收到連接命令
                        EventBus.getDefault().post(new MessageEvent(Constant.START));
                        out.flush();
                    } else if (cmd.equalsIgnoreCase(Constant.DISCONNECT)) {// 斷開(kāi)命令
                        EventBus.getDefault().post(new MessageEvent(Constant.STOP));
                        out.flush();
                    }else if (cmd.equals(Const    ant.TAKEPHOTO)) {
                        EventBus.getDefault().post(new MessageEvent(Constant.TAKEPHOTO));
                        out.flush();
                    }
                    in.reset();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            out.close();
            in.close();
        } catch (Exception e) {
            e.printStackTrace();
        } 
    }

    public void cancel() {
        isConnecting = false;
    }

    public void writeData(byte[] data) {
        if (out != null) {
            try {
                out.write((data));
            } catch (IOException e) {
                Log.e(TAG, "輸入輸出異常");
                e.printStackTrace();
            }
        }
    }

    /* 讀取命令 */
    public String readCMDFromSocket(InputStream in) {

        int MAX_BUFFER_BYTES = 2048;
        String msg = "";
        byte[] tempbuffer = new byte[MAX_BUFFER_BYTES];
        try {
            int numReadedBytes = in.read(tempbuffer, 0, tempbuffer.length);
            msg = new String(tempbuffer, 0, numReadedBytes, "utf-8");
            tempbuffer = null;
        } catch (Exception e) {
            Log.e(TAG, "readCMDFromSocket讀數(shù)異常" + e.toString());
            EventBus.getDefault().post(new MessageEvent(Constant.DISCONNECT));
            e.printStackTrace();
        }
        return msg;
    }
}
(3) 傳遞命令信息

通信的通知過(guò)程采用EventBus實(shí)現(xiàn)
onCreate中注冊(cè)EventBus

EventBus.getDefault().register(this);

實(shí)現(xiàn)事件處理函數(shù)

@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(MessageEvent event) {
    switch (event.message) {
    case Constant.DISCONNECT:

        Toast.makeText(MainActivity.this, "客戶端斷開(kāi)", Toast.LENGTH_LONG)
                .show();
        threadSocket.cancel();

    case Constant.START://收到連接命令

        isOpen = true;
        Toast.makeText(MainActivity.this, "客戶端連接上", Toast.LENGTH_LONG)
                .show();
        startCamera(curCameraIndex);

        break;
    case Constant.STOP://收到斷開(kāi)命令

        stopCamera();
        isOpen = false;

        break;
    case Constant.TAKEPHOTO://收到拍照命令

        if (isOpen) {
            camera.takePicture(new ShutterCallback() {

                @Override
                public void onShutter() {

                }
            }, new Camera.PictureCallback() {

                @Override
                public void onPictureTaken(byte[] arg0, Camera arg1) {

                }
            }, new Camera.PictureCallback() {

                @Override
                public void onPictureTaken(byte[] data, Camera camera) {

                    // 向電腦端發(fā)送數(shù)據(jù)
                    int datalen = data.length;
                    if (isOpen) {
                        // 寫(xiě)入頭
                        sendData(new byte[] { (byte) 0xA1 });
                        // 寫(xiě)入數(shù)組長(zhǎng)度
                        sendData(intToByteArray(datalen));
                        // 寫(xiě)入數(shù)據(jù)值
                        sendData(data);
                    }

                    // 重新瀏覽
                    camera.stopPreview();
                    camera.startPreview();
                }
            });

        }

    }
}   

當(dāng)建立連接之后可以向PC端發(fā)送數(shù)據(jù)唇礁,發(fā)送數(shù)據(jù)的方法:

public void sendData(final byte[] data) {
    threadSocket.writeData(data);
}

PC端程序代碼

PC端作為客戶端需要向服務(wù)端發(fā)起連接勾栗。

主函數(shù):

 public class Main {

    private static Socket socket;
    private static OutputStream out;
    private static InputStream in;
    public  static MyFrame frame;
    private static String CMD = "";

    public static void main(String[] args) {
    
        frame = new MyFrame();

        JPanel panel2 = new JPanel();
        panel2.setLayout(new FlowLayout(FlowLayout.CENTER, 10, 0));
        final JButton button = new JButton("連接");
        panel2.add(button);
        button.addActionListener(new ActionListener() {
            @Override
        public void actionPerformed(ActionEvent arg0) {
            new Thread() {
                public void run() {
                        onConnect();
                    };
                }.start();
                button.setEnabled(false);
            }
        });

        JButton button2 = new JButton("斷開(kāi)");
        button2.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent arg0) {

                CMD = Constant.DISCONNECT;
                try {
                    out.flush();
                    out.write(CMD.getBytes());
                    out.flush();                
                } catch (IOException e) {
                
                    e.printStackTrace();
                }
                button.setEnabled(true);
            }
        });
        panel2.add(button2);
    
        JButton button3 = new JButton("拍照");
        button3.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent arg0) {
                CMD = Constant.TAKEPHOTO;
                try {
                    out.flush();
                    out.write(CMD.getBytes());
                    out.flush();                    
                } catch (IOException e) {   
                    e.printStackTrace();
                }           
            }
        });
        panel2.add(button3);

        frame.add(panel2, BorderLayout.SOUTH);
        frame.setResizable(false);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }

    //啟動(dòng)連接時(shí)使用adb發(fā)送系統(tǒng)廣播
    protected static void onConnect() {
        try {
        // adb 指令
            Runtime.getRuntime().exec(
                "adb shell am broadcast -a NotifyServiceStop");
            Thread.sleep(2000);
            Runtime.getRuntime().exec("adb forward tcp:12580 tcp:10086"); // 端口轉(zhuǎn)換
            Thread.sleep(2000);
            Runtime.getRuntime().exec(
                "adb shell am broadcast -a NotifyServiceStart");
            Thread.sleep(3000);
        } catch (Exception e) {
            e.printStackTrace();
        }
        int len = 0;
        int degree = 0;
        try {
            InetAddress serveraddr = null;
            serveraddr = InetAddress.getByName("127.0.0.1");
            System.out.println("TCP 1 " + "正在連接。盏筐。围俘。。");
            socket = new Socket(serveraddr, 12580);
            System.out.println("TCP 2 " + "連接成功 ");
            // 獲取輸入輸出流
            out = new BufferedOutputStream(socket.getOutputStream());
            in  = new BufferedInputStream(socket.getInputStream());
            // 發(fā)送連接命令
            CMD = Constant.CONNECT;
            out.write(CMD.getBytes());
            out.flush();
            boolean flag = true;    
            if (socket.isConnected()) {
                while (flag) {
                    try {
                        int head = in.read();
                    
                        if (head == 0xA0) {
                            byte[] src = new byte[4];
                            len = in.read(src);
                            len = byteArrayToInt(src);
                            if (len > 0) {
                                int cclen = 0;
                                byte[] srcData = new byte[len];
                                while (cclen < len) {
                                    int readlen = in.read(srcData, cclen, len
                                        - cclen);
                                    cclen += readlen;
                                }
                                ImageIcon icon = new ImageIcon(srcData);
                            if (icon != null) {
                                frame.setIcon(icon, degree);
                            }
                        }
                        }else if (head == 0xA1) {
                            byte[] src = new byte[4];
                            len = in.read(src);
                            len = byteArrayToInt(src);
                            if (len > 0) {
                                int cclen = 0;
                                byte[] srcData = new byte[len];
                                while (cclen < len) {
                                    int readlen = in.read(srcData, cclen, len
                                        - cclen);
                                    cclen += readlen;
                                }
                            
                                //保存圖片文件
                                File file = new File("D:\\images\\" + System.currentTimeMillis() + ".jpg");
                                if (!file.exists()) {
                                    file.mkdirs();
                                }
                                                        
                                ImageIcon icon = new ImageIcon(srcData);
                                Image image = icon.getImage();
                                BufferedImage bi = new BufferedImage(image.getWidth(null),image.getHeight(null),BufferedImage.TYPE_INT_RGB);
                                Graphics2D g2d = bi.createGraphics();
                                g2d.drawImage(image, 0, 0, null);
                                g2d.dispose();
                                ImageIO.write(bi,"jpg",file);
                            }
                        }
                    
                    } catch (Exception e) {
                    
                    }

                }
            }
        } catch (Exception e1) {
            System.out.println(" 連接出現(xiàn)異常:連接失敗: " + e1.toString());
        }
    }

// 讀取數(shù)據(jù)線程,當(dāng)點(diǎn)擊連接時(shí)啟動(dòng)
class ReadThread extends Thread {
    InputStream in;
    boolean isReading = true;

    public ReadThread(InputStream inputStream) {
        this.in = inputStream;
    }

    @Override
    public void run() {
        int len = 0;
        int degree = 0;
        while (isReading) {
            try {
                    if (in.read() == 0xA0) {
                        byte[] src = new byte[4];
                        len = in.read(src);
                        len = byteArrayToInt(src);
                    }
                    // System.out.println("數(shù)據(jù)長(zhǎng)度" + len);
                    if (len > 0) {
                        int cclen = 0;
                        byte[] srcData = new byte[len];
                        while (cclen < len) {
                            int readlen = in.read(srcData, cclen, len - cclen);
                            cclen += readlen;
                        }
                        ImageIcon icon = new ImageIcon(srcData);
                        if (icon != null) {
                            frame.setIcon(icon, degree);
                        }
                    }
                } catch (Exception e) {
                    isReading = false;
                }
            }
        }

        public void cancel() {
            isReading = false;
        }
    }

    public static int byteArrayToInt(byte[] b) {
        return b[3] & 0xFF | (b[2] & 0xFF) << 8 | (b[1] & 0xFF) << 16
            | (b[0] & 0xFF) << 24;
    }
}

MyFrame類(lèi)

public class MyFrame extends JFrame {

    private static final long serialVersionUID = 1L;
    public MyPanel panel;

    public MyFrame() {

        // 默認(rèn)的窗體名稱
        this.setTitle("USB連接顯示");

        // 獲得面板的實(shí)例
        panel = new MyPanel();
        this.add(panel);
    
        this.pack();
        this.setVisible(true);
    }

    //設(shè)置圖片
    public void setIcon(ImageIcon incon, int drgree) {  
        panel.setImage(incon, drgree);
    }
}

MyPanel類(lèi)

public class MyPanel extends Panel {

    private static final long serialVersionUID = 1L;
    private Image bufferImage;
    private final Image screenImage = new BufferedImage(800, 600, 2);
    private final Graphics2D screenGraphic = (Graphics2D) screenImage
        .getGraphics();
    int degree = 90;
    private Image backgroundImage = screenImage;

    public MyPanel() {
        // 設(shè)定焦點(diǎn)在本窗體
        setFocusable(true);
        // 設(shè)定初始構(gòu)造時(shí)面板大小,這里先采用圖片的大小
        setPreferredSize(new Dimension(800, 600));
        // 繪制背景
        drawView();
    }

    public void setImage(ImageIcon icon, int degree) {

        //System.out.println("設(shè)置圖片   偏轉(zhuǎn)角度" + degree);
        this.degree = degree;
        backgroundImage = icon.getImage();
        drawView();
        repaint();
    }

    private void drawView() {
        int width  = getWidth();
        int height = getHeight();
    
        int x = width / 2 - backgroundImage.getWidth(null) /2;
        int y = height / 2 - backgroundImage.getHeight(null) / 2;
        screenGraphic.drawImage(backgroundImage, x , y, null);
    }

    @Override
    public void update(Graphics g) {
    
        if (bufferImage == null) {
            bufferImage = this.createImage(this.getWidth(), this.getHeight());
        }
    
        //bufferImage = rotateImage(bufferimage, degree);
    
        Graphics gBuffer = bufferImage.getGraphics();// 獲得圖片緩沖區(qū)的畫(huà)筆
        if (gBuffer != null){
            paint(gBuffer);
        }
        else{
            paint(g);
        }
        gBuffer.dispose();
        g.drawImage(bufferImage, 0, 0, null);
    }

    public void paint(Graphics g) {
    
        g.drawImage(screenImage, 0, 0, null);
    }


    public static BufferedImage rotateImage(final BufferedImage bufferedimage,
        final int degree) {
        int w = bufferedimage.getWidth();
        int h = bufferedimage.getHeight();
        int type = bufferedimage.getColorModel().getTransparency();
        BufferedImage img;
        Graphics2D graphics2d;
        (graphics2d = (img = new BufferedImage(w, h, type))
            .createGraphics()).setRenderingHint(
            RenderingHints.KEY_INTERPOLATION,
            RenderingHints.VALUE_INTERPOLATION_BILINEAR);
        graphics2d.rotate(Math.toRadians(degree), w / 2, h / 2);
        graphics2d.drawImage(bufferedimage, 0, 0, null);
        graphics2d.dispose();
        return img;
    }
}

兩個(gè)工程均用到的Contant類(lèi)

public class Constant {
    public static final String addrIp = "192.168.0.119";
    public static final int addrPort = 56168;
    public static final String CONNECT = "CONNECT";
    public static final String DISCONNECT = "DISCONNECT";
    public static final String TAKEPHOTO = "TAKEPHOTO";
    public static final String START = "START";
    public static final String STOP = "STOP";
}

上述代碼只是簡(jiǎn)單實(shí)現(xiàn)了手機(jī)端與PC端通過(guò)USB線的數(shù)據(jù)傳輸,數(shù)據(jù)的通信過(guò)程與Socket一致界牡。
源碼下載

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末簿寂,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子欢揖,更是在濱河造成了極大的恐慌,老刑警劉巖奋蔚,帶你破解...
    沈念sama閱讀 206,968評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件她混,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡泊碑,警方通過(guò)查閱死者的電腦和手機(jī)坤按,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)馒过,“玉大人臭脓,你說(shuō)我怎么就攤上這事「购觯” “怎么了来累?”我有些...
    開(kāi)封第一講書(shū)人閱讀 153,220評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)窘奏。 經(jīng)常有香客問(wèn)我嘹锁,道長(zhǎng),這世上最難降的妖魔是什么着裹? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,416評(píng)論 1 279
  • 正文 為了忘掉前任领猾,我火速辦了婚禮,結(jié)果婚禮上骇扇,老公的妹妹穿的比我還像新娘摔竿。我一直安慰自己,他們只是感情好少孝,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布继低。 她就那樣靜靜地躺著,像睡著了一般稍走。 火紅的嫁衣襯著肌膚如雪郁季。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,144評(píng)論 1 285
  • 那天钱磅,我揣著相機(jī)與錄音梦裂,去河邊找鬼。 笑死盖淡,一個(gè)胖子當(dāng)著我的面吹牛年柠,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 38,432評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼冗恨,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼答憔!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起掀抹,我...
    開(kāi)封第一講書(shū)人閱讀 37,088評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤虐拓,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后傲武,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體蓉驹,經(jīng)...
    沈念sama閱讀 43,586評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評(píng)論 2 325
  • 正文 我和宋清朗相戀三年揪利,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了态兴。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,137評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡疟位,死狀恐怖瞻润,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情甜刻,我是刑警寧澤绍撞,帶...
    沈念sama閱讀 33,783評(píng)論 4 324
  • 正文 年R本政府宣布,位于F島的核電站得院,受9級(jí)特大地震影響楚午,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜尿招,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評(píng)論 3 307
  • 文/蒙蒙 一矾柜、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧就谜,春花似錦怪蔑、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,333評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至虹统,卻和暖如春弓坞,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背车荔。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,559評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工渡冻, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人忧便。 一個(gè)月前我還...
    沈念sama閱讀 45,595評(píng)論 2 355
  • 正文 我出身青樓族吻,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子超歌,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評(píng)論 2 345