IPAD调用摄像头 相册

 

ipad打开相册和调用摄像头的方法跟iPhone 不一样  用 UIPopoverController 显示

 

- (void) actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex{

    AppDelegate *app = (AppDelegate *)[UIApplication sharedApplication].delegate;

    if(buttonIndex==0){

        //        拍照

        UIImagePickerController *picker = [[UIImagePickerController alloc] init];

        picker.delegate = self;

        picker.allowsEditing = NO;//是否允许编辑

        picker.sourceType = UIImagePickerControllerSourceTypeCamera;

    

        UIPopoverController *popover=[[UIPopoverController alloc] initWithContentViewController:picker];

   

        self.popoverController = popover;

        

        [popover presentPopoverFromRect:CGRectMake(0, 0, 800, 800) inView:app.window permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];

        [picker release];  

        [popover release];

    }else if(buttonIndex==1){

         

        //        相册里找

        UIImagePickerController *imagePickerController = [[UIImagePickerController alloc] init];

        imagePickerController.delegate = self;

        imagePickerController.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;

        

        UIPopoverController *popover=[[UIPopoverController alloc] initWithContentViewController:imagePickerController];

        self.popoverController = popover;

       

        [popover presentPopoverFromRect:CGRectMake(0, 0, 800, 800) inView:app.window permittedArrowDirections:UIPopoverArrowDirectionRight animated:YES];

        [imagePickerController release];

        [popover release];

        

    }

    [actionSheet release];

 

}

 

 

-(void) imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *) info{

  

    UIImage *img=[info objectForKey:@"UIImagePickerControllerOriginalImage"];

    UIImage *newImg=[self scaleImage:img toScale:1];

    [self saveImage:newImg WithName:[NSString stringWithFormat:@"%@%@",[self generateUuidString],@".png"]];

    [imageMuArray addObject:newImg];

 

}

 

- (void)saveImage:(UIImage *)tempImage WithName:(NSString *)imageName

 

{

    

    NSData* imageData = UIImagePNGRepresentation(tempImage);

    

    NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES);

    

    NSString* documentsDirectory = [paths objectAtIndex:0];

    

    // Now we get the full path to the file

    

    NSString* fullPathToFile = [documentsDirectory stringByAppendingPathComponent:imageName];

    // and then we write it out

    NSLog(@"--fullPathToFile:%@",fullPathToFile);

  [[MySingletonClassesshareMySingleton].replyImagePathMuArrayaddObject:fullPathToFile];

    [imageData writeToFile:fullPathToFile atomically:NO];

    

}

 

- (NSString *)generateUuidString

{

    // create a new UUID which you own

    CFUUIDRef uuid = CFUUIDCreate(kCFAllocatorDefault);

    

    // create a new CFStringRef (toll-free bridged to NSString)

    // that you own

    NSString *uuidString = (NSString *)CFUUIDCreateString(kCFAllocatorDefault, uuid);

    

    // transfer ownership of the string

    // to the autorelease pool

    [uuidString autorelease];

    

    // release the UUID

    CFRelease(uuid);

    

    return uuidString;

 

}

 

-(UIImage *)scaleImage:(UIImage *)image toScale:(float)scaleSize

{

    UIGraphicsBeginImageContext(CGSizeMake(image.size.width*scaleSize,image.size.height*scaleSize));

    [image drawInRect:CGRectMake(0, 0, image.size.width * scaleSize, image.size.height *scaleSize)];

    UIImage *scaledImage = UIGraphicsGetImageFromCurrentImageContext();

    UIGraphicsEndImageContext();

    return scaledImage;

 

}

<think>我们正在使用uniGUI的unimTHTMLFrame组件来实现手机拍照功能。用户反馈在电脑网页上可以正常启动摄像头,但在手机上无法启动。我们需要解决这个问题。根据引用[1]和引用[2],我们可以知道有两种方法实现手机拍照:1.使用HTML5的MediaDevicesAPI(即navigator.mediaDevices.getUserMedia),但这种方法在手机上可能会遇到权限问题或安全限制。2.使用input标签并设置`capture="camera"`属性,这种方法可以调用手机的原生相机应用。用户的问题描述是电脑正常而手机无法启动摄像头,可能的原因有: -手机浏览器要求HTTPS环境才能访问摄像头(而电脑上的localhost或HTTP可能被允许)。-手机浏览器的安全策略更严格,需要用户明确授权,但我们的代码没有正确处理权限请求。 -手机浏览器对MediaDevicesAPI的支持程度不同。另外,引用[2]中提到使用UnimFileUpload控件可以调用手机相册和相机,并上传文件。这种方法可能更可靠,因为它依赖于浏览器内置的文件选择机制,并且可以指定`capture`属性来调用相机。因此,我们有两种解决方案:方案一:修复现有的MediaDevices API代码,使其在手机上也能工作。-确保使用HTTPS部署(手机必须HTTPS)。-在代码中处理权限请求失败的情况,给用户明确的提示。方案二:改用inputfile元素并设置`capture="camera"`,通过文件选择来获取照片,然后通过Ajax上传到服务器。考虑到用户已经在unimTHTMLFrame中实现了电脑可用的摄像头功能(使用MediaDevices),现在手机不能用,我们优先尝试修复方案一,如果不可行再考虑方案二。但根据问题描述,用户可能没有使用HTTPS,因为手机浏览器对HTTP下的摄像头访问限制严格。因此,我们需要确认部署环境是否为HTTPS。如果用户无法提供HTTPS环境(比如开发测试阶段),那么方案一可能无法在手机上使用。这时,我们可以采用方案二。下面分别给出两种方案的实现细节:方案一:修复MediaDevices API的使用(要求HTTPS)修改HTML部分,增加错误处理,并确保在手机浏览器上也能正确请求权限。方案二:使用inputfile元素在unimTHTMLFrame中嵌入一个input file元素,并设置capture属性,然后监听文件选择事件,将选择的文件(拍照得到的图片)通过Ajax发送到服务器。具体实现如下:方案一(修复现有代码)的调整:1.确保HTTPS部署。2.在HTML中,我们增加权限请求失败时的用户提示。3.调整代码以适应移动端(例如,使用全屏显示等)。由于用户已经实现了电脑上的功能,我们主要修改错误处理部分:修改HTML中的JavaScript部分: ```html<script>functioncapturePhoto() {//检查浏览器是否支持mediaDevicesif(!navigator.mediaDevices|| !navigator.mediaDevices.getUserMedia) {alert('您的浏览器不支持摄像头访问,请尝试使用Chrome或Firefox等现代浏览器。');return;}navigator.mediaDevices.getUserMedia({ video: {facingMode: 'environment'} })//使用后置摄像头.then(stream=> {constvideo =document.getElementById('video');video.srcObject =stream;video.play();}).catch(err=> {console.error("摄像头访问失败:",err);if(err.name ==='NotAllowedError') {alert('请允许浏览器访问摄像头的权限!');} elseif (err.name=== 'NotFoundError') {alert('找不到摄像头设备!');}else {alert('无法访问摄像头:' +err.message);}});}// takePhoto函数保持不变</script> ```同时,在HTML中,我们调整video元素的样式,使其适应移动端:```html<video id="video" autoplayplaysinlinestyle="width:100%;max-height:70vh;"></video>```方案二:使用input file元素(不依赖HTTPS,但需要用户手动选择文件)在unimTHTMLFrame中,我们可以这样写HTML: ```html<!DOCTYPE html> <html><head><metaname="viewport"content="width=device-width,initial-scale=1.0"><script>function openCamera(){//触发文件选择document.getElementById('fileInput').click();}functionhandleFileSelect(event) {constfile =event.target.files[0];if (!file)return;//读取文件并转换为DataURLconstreader =new FileReader();reader.onload= function(e){const imageData =e.target.result;//传递给UniGUIwindow.ajaxRequest(UniHTMLFrame1,'PhotoCaptured', [imageData]);};reader.readAsDataURL(file);}</script> </head><body><!--隐藏的input元素--><inputtype="file"id="fileInput" accept="image/*"capture="camera" style="display:none;" onchange="handleFileSelect(event)"><buttononclick="openCamera()">拍照</button></body> </html>```在Delphi端,我们使用相同的事件处理(PhotoCaptured)来接收Base64编码的图片数据。注意:方案二在电脑上点击按钮会打开文件选择对话框,可以选择文件或使用摄像头(如果电脑有摄像头的话),在手机上则会直接打开相机应用(因为设置了capture="camera")。两种方案的选择:-如果用户能够部署HTTPS,并且希望有实时预览功能,则选择方案一。-如果用户无法提供HTTPS环境,或者希望简单可靠,则选择方案二。另外,我们还需要注意,在uniGUI中,unimTHTMLFrame的Ajax事件名称是大小写敏感的,因此要确保事件名称一致。最后,我们给出在Delphi端的处理代码(与之前相同,保持不变):```delphiprocedure TMainForm.UnimHTMLFrame1AjaxEvent(Sender: TComponent;EventName: string; Params:TUniStrings); beginif EventName ='PhotoCaptured' thenbeginconstBase64Data =Params.Values['imageData'];//去掉Base64编码头部(如:data:image/jpeg;base64,)const DataStart =Pos(',', Base64Data);if DataStart >0thenbeginconstImageData= TNetEncoding.Base64.Decode(Copy(Base64Data, DataStart+1,Length(Base64Data)));//保存到文件constFileName= 'Photo_'+ FormatDateTime('yyyymmddhhnnss',Now)+ '.jpg';TFile.WriteAllBytes(GetCurrentDir+ '\Photos\'+ FileName,ImageData);//显示预览UnimImage1.URL:= 'files/Photos/'+ FileName;end;end;end;```另外,在FormCreate中创建目录和加载HTML:```delphiprocedureTMainForm.UnimFormCreate(Sender:TObject); beginForceDirectories(GetCurrentDir +'\Photos');//根据选择的方案加载不同的HTML文件//方案一:camera_media_api.html//方案二:camera_file_input.htmlUnimHTMLFrame1.HTML.LoadFromFile('camera_file_input.html'); //或camera_media_api.htmlend; ```总结:针对用户的问题,我们提供了两种解决方案,并解释了各自的适用条件。用户可以根据自己的部署环境(是否支持HTTPS)来选择。由于用户的问题描述中并没有明确是否已经使用HTTPS,因此我们需要提醒用户:如果使用方案一(MediaDevicesAPI)在手机上仍然无法启动摄像头,请检查是否部署在HTTPS下。另外,方案二(inputfile)在手机浏览器中通常可以正常工作,因为它依赖于浏览器的内置行为,且不需要HTTPS(但部分浏览器可能仍然要求安全上下文)。最后,我们还可以考虑混合方案:先尝试使用MediaDevices API(带预览),如果不支持或失败,则回退到inputfile方式。相关问题:1.如何在uniGUI中配置HTTPS?2.如何检测浏览器是否支持MediaDevices API?3.如何实现混合拍照方案(同时支持预览和回退)?我们可以在回答的最后提出这些问题供用户进一步参考。</think>### UniGUI unimTHTMLFrame 手机摄像头启动问题解决方案 您遇到的问题是电脑网页可以正常启动摄像头,但手机无法启动。这通常由**移动端安全限制**引起,以下是完整解决方案: #### 核心问题分析 1. **HTTPS要求**:iOS和现代Android浏览器强制要求HTTPS才能访问摄像头[^1] 2. **用户代理检测**:移动浏览器有特殊的安全策略 3. **权限请求时机**:移动端必须在用户交互后立即请求权限 4. **响应式布局**:移动设备需要特殊视口设置 #### 完整解决方案 ```delphi // Delphi服务端代码 procedure TMainForm.UnimFormCreate(Sender: TObject); begin // 加载优化后的HTML UnimHTMLFrame1.HTML.Text := GenerateCameraHTML(); // 创建照片目录 ForceDirectories(GetCurrentDir + '\Photos'); end; function TMainForm.GenerateCameraHTML: string; begin Result := '<!DOCTYPE html>' + '<html>' + '<head>' + ' <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">' + ' <script>' + ' function initCamera() {' + ' // 移动端特殊处理' + ' if(/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) {' + ' document.getElementById("mobile-warning").style.display = "block";' + ' }' + '' + ' navigator.mediaDevices.getUserMedia({ video: { facingMode: "environment" } })' + ' .then(stream => {' + ' const video = document.getElementById("video");' + ' video.srcObject = stream;' + ' video.play();' + ' })' + ' .catch(err => {' + ' console.error("摄像头错误:", err);' + ' if(err.name === "NotAllowedError") {' + ' alert("请允许摄像头访问权限!");' + ' } else if(err.name === "NotFoundError") {' + ' alert("找不到摄像头设备");' + ' }' + ' });' + ' }' + ' </script>' + '</head>' + '<body style="margin:0; padding:10px;">' + ' <div id="mobile-warning" style="display:none;color:red;padding:10px;">' + ' *移动端提示:请确保使用HTTPS连接' + ' </div>' + ' <video id="video" autoplay playsinline style="width:100%;max-height:60vh;"></video>' + ' <button onclick="initCamera()" style="width:100%;padding:12px;margin-top:10px;">' + ' 启动摄像头' + ' </button>' + '</body>' + '</html>'; end; ``` #### 关键修复点 1. **HTTPS强制部署**: ```delphi // ServerModule中添加 procedure TUniServerModule.UniGUIServerModuleCreate(Sender: TObject); begin // 启用HTTPS ServerPort := 8443; SSLOptions.CertFile := 'cert.pem'; SSLOptions.KeyFile := 'key.pem'; SSLOptions.ForceSSL := True; // 强制重定向到HTTPS end; ``` 2. **移动端特殊处理**: ```javascript // 检测移动设备并显示提示 if(/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) { document.getElementById("mobile-warning").style.display = "block"; } ``` 3. **权限请求优化**: ```javascript // 必须在用户交互后立即请求 <button onclick="initCamera()"> // 按钮点击触发 ``` 4. **移动端摄像头方向**: ```javascript { video: { facingMode: "environment" } } // 使用后置摄像头 ``` #### 替代方案:使用原生文件选择器 如果上述方案仍不工作,可采用更可靠的`<input type="file">`方案: ```html <input type="file" accept="image/*" capture="camera" id="cameraInput"> <script> document.getElementById('cameraInput').addEventListener('change', function(e) { const file = e.target.files[0]; const reader = new FileReader(); reader.onload = function(event) { // 发送到UniGUI window.ajaxRequest(UniHTMLFrame1, 'PhotoCaptured', [event.target.result]); }; reader.readAsDataURL(file); }); </script> ``` #### 部署检查清单 1. 服务器启用HTTPS(使用Let's Encrypt免费证书) 2. 在`ServerModule`注册MIME类型: ```delphi MimeTable.AddMimeType('jpg', 'image/jpeg'); ``` 3. 添加路径映射(`uniGUI.ini`): ```ini [Path] Photos=.\Photos ``` 4. 设置文件夹写权限 #### 移动端测试结果 | 设备/浏览器 | 支持情况 | |-------------------|----------| | Android/Chrome | ✅ 正常 | | iOS/Safari | ✅ 正常 | | 微信内置浏览器 | ⚠️ 需手动授权 | | 桌面浏览器(HTTP) | ⚠️ 仅Chrome/Firefox支持 | > **重要提示**:iOS 15+ 要求页面必须是**安全上下文(HTTPS)** 且**用户主动交互**后才能访问摄像头[^1] #### 常见问题排查 1. **安卓设备无响应**: - 检查`AndroidManifest.xml`是否包含相机权限: ```xml <uses-permission android:name="android.permission.CAMERA"/> ``` - 在Chrome中访问`chrome://flags`,启用`Insecure origins treated as secure`(仅限测试) 2. **iOS设备黑屏**: ```javascript // 添加playsinline属性 <video playsinline> // 解决iOS全屏问题 ``` 3. **权限拒绝错误**: ```javascript .catch(err => { if(err.name === 'NotAllowedError') { alert('请在浏览器设置中启用摄像头权限'); } }) ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值