功能需求:
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一致界牡。
源碼下載