- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
我的问题:
如何正确地将图像从 ios swift 客户端应用程序转换并发送到 java 服务器?(不使用大量外部 sdks)
在 swift 中使用哪种类型的套接字(我是 swift 的新手,真的找不到任何合适的套接字)?
请给我一个示例代码,因为我一点也不精通 swift 语法和库。
我的计划的预期结果- ios swift 应用程序应该有效地连接到我的 java 服务器并将视频帧的图像实时发送到它。然后图像应在 Java 服务器机器上转换为 bufferedImage 并作为视频播放!
关于之前提出的问题- 我只找到一个类似的问题,但答案不是很有用。
详情
所以,我在我的 mac 上编写了一个 Java 服务器程序,我想添加一个功能,用户应该能够将实时视频从他的 iPhone(ios 设备)发送到我的 Java 服务器程序。
ios 应用程序是在 xcode 上用 swift 编写的。
为了做到这一点,我在 swift 程序中从视频帧中捕获 CGImage 并将其转换为 UIImage ;然后我将这个 UIImage 转换为 byte[] 数据,如下所示:-
let cgImage:CGImage = context.createCGImage(cameraImage, from:
cameraImage.extent)! //cameraImage is grabbed from video frame
image = UIImage.init(cgImage: cgImage)
let data = UIImageJPEGRepresentation(image, 1.0)
然后使用 SwiftSocket/TCPClient ( https://github.com/swiftsocket/SwiftSocket ) 将此 byte[] 数据发送到我的 Java 服务器运行的 IP 地址和端口
client?.send(data: data!)
这里的 client 是一个 TCPClient 类型的对象,它在 swift xcode 中声明如下:( https://github.com/swiftsocket/SwiftSocket/blob/master/Sources/TCPClient.swift )
client = TCPClient(address: host, port: Int32(port))
client?.connect(timeout: 10)
连接成功,Java 服务器程序生成一个 MobileServer 线程来处理此客户端。 DataInput 和OutputStreams 使用ServerSocket 打开。这是 Java 服务器生成的 MobileServer 线程的 run() 方法(其中“in”是从 ServerSocket 派生的 DataInputStream)
public void run()
{
try{
while(!stop)
{
int count=-1;
count = in.available();
if(count>0) System.out.println("LENGTH="+count);
byte[] arr=new byte[count];
System.out.println("byte="+arr);
in.read(arr);
BufferedImage image=null;
try{
InputStream inn = new ByteArrayInputStream(arr);
image = ImageIO.read(inn);
inn.close();
}catch(Exception f){ f.printStackTrace();}
System.out.println("IMaGE="+image);
if(image!=null)
appendToFile(image);
}
}catch(Exception l){ l.printStackTrace(); }
}
问题是我的 Java 服务器正在接收一些奇怪的字节序列,这些字节序列可能无法正确转换为 BufferedImage,因此在查看文件中存储的“视频”时,我只能看到一条细长的“图像”,而iPhone 捕捉正常。(基本上图像没有正确地从 ios 应用程序传输到我的服务器!)
整个 Swift 程序的 viewController.swift 视频采集是从这个 github 项目派生的(https://github.com/FlexMonkey/LiveCameraFiltering)
编辑- 我已经找出问题并将其作为答案发布,但这仍然只是一种解决方法,因为服务器视频源仍然挂起很多,我不得不降低发送的图像字节数据的质量由 swift 客户。肯定有更好的做事方式,我请求人们分享他们的知识。
最佳答案
因此,我无法找到上述问题的完整且绝对完美的解决方案,但为了任何其他可能偶然发现类似跨语言客户端-服务器程序问题的快速初学者的利益,这是我的两分钱:
上述代码中第一个也是最重要的错误是这一行:
let data = UIImageJPEGRepresentation(image, 1.0)
1) 在这里,我通过将压缩因子设置为 1 将 UIImage 编码为尽可能高的质量。正如我后来检查的那样,这导致创建了计数超过 100000 的字节数组,因此很难通过 TCPClient 套接字轻松快速地发送如此大的数据。
2) 即使TCPClient套接字高效发送了如此大的数组,服务器端的Java DataInputStream也很难一次读取完整的数据。它可能一次只读取小块数据,因此在 Java 服务器端生成的图像是局部的和模糊的。
3)这一行是另一个问题:
count = in.available();
if(count>0) System.out.println("LENGTH="+count);
byte[] arr=new byte[count];
System.out.println("byte="+arr);
in.read(arr);
in.available() 方法可能不会返回客户端发送的数据的完整长度。这会导致读取不完整的字节数据,从而导致读取不完整的图像。
解决方案/解决方法(某种)
我在 swift 客户端的 UIImageJPEGRepresentation() 方法中将压缩因子降低到大约 0.000005,这导致创建长度约为 5000 的字节数组(这是可管理的)
为了避免在服务器端读取不完整数据的问题,我将字节数组转换为 base64String,然后我简单地在该字符串的末尾添加了一个终止字符“%”,在服务器端将标记一个 base64 字符串的结尾。
我将服务器端的 DataInputStream/DataOutputStream 更改为 InputStreamReader/OutputStreamWriter,因为我现在要处理字符/字符串。
Java 服务器的 InputStreamReader 将一次接收一个字符并从中形成一个字符串,直到它遇到终止字符“%”,然后这个 base64 字符串将被转换为字节数组:
imageBytes=javax.xml.bind.DatatypeConverter.parseBase64Binary(str);
//str is a String formed by concatenating characters received by the InputStreamReader
然后将这个 imageBytes 数组转换为 BufferedImage,然后一个接一个地绘制在面板上,从而再现原始的 iPhone 直播视频
修改后的Swift代码(ios客户端)
func captureOutput(_ captureOutput: AVCaptureOutput!, didOutputSampleBuffer sampleBuffer: CMSampleBuffer!, from connection: AVCaptureConnection!)
{
var cameraImage: CIImage
var image: UIImage ;
let pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer)
cameraImage = CIImage(cvPixelBuffer: pixelBuffer!)
let context:CIContext = CIContext.init(options: nil)
let cgImage:CGImage = context.createCGImage(cameraImage, from: cameraImage.extent)!
image = UIImage(cgImage: cgImage)
DispatchQueue.main.async
{
self.imageView.image = image //live video captured from camera streamed to the device's own UIImageView
}
let thumbnail = resizeImage(image: image, targetSize: CGSize.init(width: 400, height: 400)) // snapshot image from camera resized
let data = UIImageJPEGRepresentation(thumbnail,0.000005) //the snapshot image converted into byte data
let base64String = data!.base64EncodedString(options: Data.Base64EncodingOptions(rawValue: 0))
// byte image data is encoded to a base64String
var encodeImg=base64String.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed )
encodeImg = encodeImg! + String("%") // termination char % is added at the end
var sendData = String("0%")
if(live)
{
sendData = encodeImg!
}
client?.send(string: sendData!) //sent as a String using TCPClient socket
}
修改了 MobileServer Thread 类的 Java 服务器端 run() 方法
public void run()
{
try{
boolean access_granted=false;
while(!stop)
{
char chr=(char)in.read();
if(chr!='%') // read and append char by char from the InputStreamReader "in" until it encounters a '%'
str+=Character.toString(chr);
else terminate=true;
if(terminate)
{
if(entry)
{
int a=str.indexOf('&');
int b=str.indexOf('#');
String username=str.substring(0,a);
String password=str.substring((a+1),b);
String ip=str.substring((b+1),str.length());
System.out.println("IP ADDRESS: \""+ ip+"\"");
String usernameA[]=convertToArray(username);
String passwordA[]=convertToArray(password);
String user=decrypt(usernameA,portt);
String pass=decrypt(passwordA,portt);
boolean accessGranted=false;
int response=dbManager.verify_clientLogin(user,pass);
if(response==RegisterInfo.ACCESS_GRANTED) {
System.out.println("access granted");
accessGranted=true;
}
int retInt=-1;
if(accessGranted) retInt=1;
out.write(retInt);
entry=false;
terminate=false;
}
else
{
terminate=false;
try {
// str includes the original single base64String produced by the swift client app which is converted back to a byte array
imageBytes = javax.xml.bind.DatatypeConverter.parseBase64Binary(str);
}catch(ArrayIndexOutOfBoundsException l){ exception=true; }
str="";
if(!exception)
{
//this byte array image data is converted to a image and played on the videoPlayer, and serial images played would be visible as a video stream
vidPlayer.playImage(imageBytes);
ioexcep=false;
}
else exception=false;
}
}
}
}catch(Exception l){ l.printStackTrace(); }
}
关于java - 如何将图像(UIImage)从 SWIFT ios 客户端程序发送到 JAVA 服务器程序?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46011832/
我正在编写一个具有以下签名的 Java 方法。 void Logger(Method method, Object[] args); 如果一个方法(例如 ABC() )调用此方法 Logger,它应该
我是 Java 新手。 我的问题是我的 Java 程序找不到我试图用作的图像文件一个 JButton。 (目前这段代码什么也没做,因为我只是得到了想要的外观第一的)。这是我的主课 代码: packag
好的,今天我在接受采访,我已经编写 Java 代码多年了。采访中说“Java 垃圾收集是一个棘手的问题,我有几个 friend 一直在努力弄清楚。你在这方面做得怎么样?”。她是想骗我吗?还是我的一生都
我的 friend 给了我一个谜语让我解开。它是这样的: There are 100 people. Each one of them, in his turn, does the following
如果我将使用 Java 5 代码的应用程序编译成字节码,生成的 .class 文件是否能够在 Java 1.4 下运行? 如果后者可以工作并且我正在尝试在我的 Java 1.4 应用程序中使用 Jav
有关于why Java doesn't support unsigned types的问题以及一些关于处理无符号类型的问题。我做了一些搜索,似乎 Scala 也不支持无符号数据类型。限制是Java和S
我只是想知道在一个 java 版本中生成的字节码是否可以在其他 java 版本上运行 最佳答案 通常,字节码无需修改即可在 较新 版本的 Java 上运行。它不会在旧版本上运行,除非您使用特殊参数 (
我有一个关于在命令提示符下执行 java 程序的基本问题。 在某些机器上我们需要指定 -cp 。 (类路径)同时执行java程序 (test为java文件名与.class文件存在于同一目录下) jav
我已经阅读 StackOverflow 有一段时间了,现在我才鼓起勇气提出问题。我今年 20 岁,目前在我的家乡(罗马尼亚克卢日-纳波卡)就读 IT 大学。足以介绍:D。 基本上,我有一家提供簿记应用
我有 public JSONObject parseXML(String xml) { JSONObject jsonObject = XML.toJSONObject(xml); r
我已经在 Java 中实现了带有动态类型的简单解释语言。不幸的是我遇到了以下问题。测试时如下代码: def main() { def ks = Map[[1, 2]].keySet()
一直提示输入 1 到 10 的数字 - 结果应将 st、rd、th 和 nd 添加到数字中。编写一个程序,提示用户输入 1 到 10 之间的任意整数,然后以序数形式显示该整数并附加后缀。 public
我有这个 DownloadFile.java 并按预期下载该文件: import java.io.*; import java.net.URL; public class DownloadFile {
我想在 GUI 上添加延迟。我放置了 2 个 for 循环,然后重新绘制了一个标签,但这 2 个 for 循环一个接一个地执行,并且标签被重新绘制到最后一个。 我能做什么? for(int i=0;
我正在对对象 Student 的列表项进行一些测试,但是我更喜欢在 java 类对象中创建硬编码列表,然后从那里提取数据,而不是连接到数据库并在结果集中选择记录。然而,自从我这样做以来已经很长时间了,
我知道对象创建分为三个部分: 声明 实例化 初始化 classA{} classB extends classA{} classA obj = new classB(1,1); 实例化 它必须使用
我有兴趣使用 GPRS 构建车辆跟踪系统。但是,我有一些问题要问以前做过此操作的人: GPRS 是最好的技术吗?人们意识到任何问题吗? 我计划使用 Java/Java EE - 有更好的技术吗? 如果
我可以通过递归方法反转数组,例如:数组={1,2,3,4,5} 数组结果={5,4,3,2,1}但我的结果是相同的数组,我不知道为什么,请帮助我。 public class Recursion { p
有这样的标准方式吗? 包括 Java源代码-测试代码- Ant 或 Maven联合单元持续集成(可能是巡航控制)ClearCase 版本控制工具部署到应用服务器 最后我希望有一个自动构建和集成环境。
我什至不知道这是否可能,我非常怀疑它是否可能,但如果可以,您能告诉我怎么做吗?我只是想知道如何从打印机打印一些文本。 有什么想法吗? 最佳答案 这里有更简单的事情。 import javax.swin
我是一名优秀的程序员,十分优秀!