├── webapp ├── main.js ├── manifest.json ├── cameraApp.html ├── cameraRemoteApi.js └── cameraApp.js ├── .gitattributes ├── README.md └── .gitignore /webapp/main.js: -------------------------------------------------------------------------------- 1 | chrome.app.runtime.onLaunched.addListener(function() 2 | { 3 | /* 4 | * Create Web app windows w 680 x 480 5 | */ 6 | chrome.app.window.create('cameraApp.html', { 7 | width: 480, 8 | height: 854 9 | }); 10 | }); 11 | -------------------------------------------------------------------------------- /webapp/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "manifest_version": 2, 3 | "name": "Camera Remote API", 4 | "description": "Camera Remote API", 5 | "version": "1", 6 | "minimum_chrome_version": "23", 7 | "app": { 8 | "background": { 9 | "scripts": ["main.js"] 10 | } 11 | }, 12 | "permissions": [ 13 | "http://*/", 14 | "experimental", 15 | {"socket": ["udp-send-to", "udp-bind", "udp-multicast-membership"]} 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | *.sln merge=union 7 | *.csproj merge=union 8 | *.vbproj merge=union 9 | *.fsproj merge=union 10 | *.dbproj merge=union 11 | 12 | # Standard to msysgit 13 | *.doc diff=astextplain 14 | *.DOC diff=astextplain 15 | *.docx diff=astextplain 16 | *.DOCX diff=astextplain 17 | *.dot diff=astextplain 18 | *.DOT diff=astextplain 19 | *.pdf diff=astextplain 20 | *.PDF diff=astextplain 21 | *.rtf diff=astextplain 22 | *.RTF diff=astextplain 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Camera-Remote-API 2 | ================= 3 | 4 | NOW support Liveview!! and please try it. 5 | 6 | to start Livewview 7 | * for NEX-5R, call "startRecMode" and call "startLiveview" 8 | * for HDR-AS15, call "startLiveview" 9 | 10 | ---- 11 | 12 | Control Sony Device via Camera Remote API 13 | 14 | This is Web app sample implementation that controls Sony Device via [Camera Remote API](http://developer.sony.com/develop/cameras/). 15 | 16 | for this sample, Web app may not find Device IP address and service end point. IP address and serivce end point are used as the fixed. the device discovery will be supported later. 17 | 18 | ### How to run 19 | * please start WiFi on your Sony Deivce and connect your PC. 20 | * start Chrome web browser w/ "disable-web-security". this will allow Web app to use "Cross domain XHR". 21 | > chrome.exe --disable-web-security 22 | * or install this web app as chrome web app 23 | > setting -> tool -> extension function -> enable developer mode and select "webapp" directory by "install unpackaged extension function". 24 | * Select "Device Name" if you can find your deivce in the list 25 | * if not, please enter your Sony deivce's Service end point url 26 | * select "Action Name" if you can find the action in the list 27 | * if not, please enter your action on JSON message box. 28 | * push "Send Action". 29 | * you will be able to control Sony deivce w/ JSON message. 30 | 31 | ### To Do List 32 | * make JavaScript lib of Camera Remote API 33 | * add SSDP for the device discovery 34 | * add more actions. 35 | * more rich UI 36 | 37 | License 38 | ---------- 39 | Copyright © 2014 Naoyuki Sato(naoyuki.sato@gmail.com) 40 | Licensed under the [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) 41 | -------------------------------------------------------------------------------- /webapp/cameraApp.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Sony Camera Remote API 4 | 5 | 6 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 34 | 35 | 36 | 37 | 40 | 41 |
Device
Name: 31 | 33 |
Action List URL: 38 | 39 |
42 |
43 | 44 | 45 | 46 | 47 | 51 | 52 | 53 | 54 | 57 | 58 | 59 | 60 | 63 | 64 |
Action
Action Name: 48 | 50 |
Parames: 55 | 56 |
ID: 61 | 62 |
65 | 66 |
67 | 68 | 69 | 70 | 71 | 74 | 75 | 76 | 77 | 80 | 81 |
Response
Parames 72 | 73 |
ID: 78 | 79 |
82 |
83 | Image 84 |
85 |
86 | 87 |
88 | 89 | 90 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ################# 2 | ## Eclipse 3 | ################# 4 | 5 | *.pydevproject 6 | .project 7 | .metadata 8 | bin/ 9 | tmp/ 10 | *.tmp 11 | *.bak 12 | *.swp 13 | *~.nib 14 | local.properties 15 | .classpath 16 | .settings/ 17 | .loadpath 18 | 19 | # External tool builders 20 | .externalToolBuilders/ 21 | 22 | # Locally stored "Eclipse launch configurations" 23 | *.launch 24 | 25 | # CDT-specific 26 | .cproject 27 | 28 | # PDT-specific 29 | .buildpath 30 | 31 | 32 | ################# 33 | ## Visual Studio 34 | ################# 35 | 36 | ## Ignore Visual Studio temporary files, build results, and 37 | ## files generated by popular Visual Studio add-ons. 38 | 39 | # User-specific files 40 | *.suo 41 | *.user 42 | *.sln.docstates 43 | 44 | # Build results 45 | 46 | [Dd]ebug/ 47 | [Rr]elease/ 48 | x64/ 49 | build/ 50 | [Bb]in/ 51 | [Oo]bj/ 52 | 53 | # MSTest test Results 54 | [Tt]est[Rr]esult*/ 55 | [Bb]uild[Ll]og.* 56 | 57 | *_i.c 58 | *_p.c 59 | *.ilk 60 | *.meta 61 | *.obj 62 | *.pch 63 | *.pdb 64 | *.pgc 65 | *.pgd 66 | *.rsp 67 | *.sbr 68 | *.tlb 69 | *.tli 70 | *.tlh 71 | *.tmp 72 | *.tmp_proj 73 | *.log 74 | *.vspscc 75 | *.vssscc 76 | .builds 77 | *.pidb 78 | *.log 79 | *.scc 80 | 81 | # Visual C++ cache files 82 | ipch/ 83 | *.aps 84 | *.ncb 85 | *.opensdf 86 | *.sdf 87 | *.cachefile 88 | 89 | # Visual Studio profiler 90 | *.psess 91 | *.vsp 92 | *.vspx 93 | 94 | # Guidance Automation Toolkit 95 | *.gpState 96 | 97 | # ReSharper is a .NET coding add-in 98 | _ReSharper*/ 99 | *.[Rr]e[Ss]harper 100 | 101 | # TeamCity is a build add-in 102 | _TeamCity* 103 | 104 | # DotCover is a Code Coverage Tool 105 | *.dotCover 106 | 107 | # NCrunch 108 | *.ncrunch* 109 | .*crunch*.local.xml 110 | 111 | # Installshield output folder 112 | [Ee]xpress/ 113 | 114 | # DocProject is a documentation generator add-in 115 | DocProject/buildhelp/ 116 | DocProject/Help/*.HxT 117 | DocProject/Help/*.HxC 118 | DocProject/Help/*.hhc 119 | DocProject/Help/*.hhk 120 | DocProject/Help/*.hhp 121 | DocProject/Help/Html2 122 | DocProject/Help/html 123 | 124 | # Click-Once directory 125 | publish/ 126 | 127 | # Publish Web Output 128 | *.Publish.xml 129 | *.pubxml 130 | 131 | # NuGet Packages Directory 132 | ## TODO: If you have NuGet Package Restore enabled, uncomment the next line 133 | #packages/ 134 | 135 | # Windows Azure Build Output 136 | csx 137 | *.build.csdef 138 | 139 | # Windows Store app package directory 140 | AppPackages/ 141 | 142 | # Others 143 | sql/ 144 | *.Cache 145 | ClientBin/ 146 | [Ss]tyle[Cc]op.* 147 | ~$* 148 | *~ 149 | *.dbmdl 150 | *.[Pp]ublish.xml 151 | *.pfx 152 | *.publishsettings 153 | 154 | # RIA/Silverlight projects 155 | Generated_Code/ 156 | 157 | # Backup & report files from converting an old project file to a newer 158 | # Visual Studio version. Backup files are not needed, because we have git ;-) 159 | _UpgradeReport_Files/ 160 | Backup*/ 161 | UpgradeLog*.XML 162 | UpgradeLog*.htm 163 | 164 | # SQL Server files 165 | App_Data/*.mdf 166 | App_Data/*.ldf 167 | 168 | ############# 169 | ## Windows detritus 170 | ############# 171 | 172 | # Windows image file caches 173 | Thumbs.db 174 | ehthumbs.db 175 | 176 | # Folder config file 177 | Desktop.ini 178 | 179 | # Recycle Bin used on file shares 180 | $RECYCLE.BIN/ 181 | 182 | # Mac crap 183 | .DS_Store 184 | 185 | 186 | ############# 187 | ## Python 188 | ############# 189 | 190 | *.py[co] 191 | 192 | # Packages 193 | *.egg 194 | *.egg-info 195 | dist/ 196 | build/ 197 | eggs/ 198 | parts/ 199 | var/ 200 | sdist/ 201 | develop-eggs/ 202 | .installed.cfg 203 | 204 | # Installer logs 205 | pip-log.txt 206 | 207 | # Unit test / coverage reports 208 | .coverage 209 | .tox 210 | 211 | #Translations 212 | *.mo 213 | 214 | #Mr Developer 215 | .mr.developer.cfg 216 | -------------------------------------------------------------------------------- /webapp/cameraRemoteApi.js: -------------------------------------------------------------------------------- 1 | function CameraRemoteAPI(actionListUrl) { 2 | this.methods = [ 3 | "getShootMode", 4 | "getSupportedShootMode", 5 | "getAvailableShootMode", 6 | "actTakePicture", 7 | "awaitTakePicture", 8 | "startMovieRec", 9 | "stopMovieRec", 10 | "startAudioRec", 11 | "stopAudioRec", 12 | "startLiveview", 13 | "startLiveviewWithSize", 14 | "stopLiveview", 15 | "actZoom", 16 | "setSelfTimer", 17 | "getSelfTimer", 18 | "getSupportedSelfTimer", 19 | "getAvailableSelfTimer", 20 | "setPostviewImageSize", 21 | "getPostviewImageSize", 22 | "getSupportedPostviewImageSize", 23 | "getAvailablePostviewImageSize", 24 | "getEvent", "startRecMode", 25 | "stopRecMode", 26 | "getAvailableApiList", 27 | "getApplicationInfo", 28 | "getVersions", 29 | "getMethodTypes" 30 | ]; 31 | this.service = "/camera"; 32 | this.version = "\"1.0\""; 33 | 34 | this.actionListUrl = actionListUrl; 35 | 36 | for(var i = 0; i < this.methods.length; i++) { 37 | this[this.methods[i]] = (function(j) { 38 | return function (params, successCallback, errorCallback) { 39 | this.num = j; 40 | this.endPointUrl = this.actionListUrl + this.service; 41 | 42 | //var id = Math.round(new Date().getTime()); 43 | var id = 1; 44 | 45 | var message = "{ \"method\": " + "\"" + this.methods[this.num] + "\", \"params\": " + params + "," + "\"id\": " + id + ", \"version\": " + this.version + "}"; 46 | console.log(message); 47 | console.log(this.endPointUrl); 48 | 49 | var xhr = new XMLHttpRequest(); 50 | xhr.onreadystatechange = function() { 51 | if (xhr.readyState === 4 && xhr.status === 200) { 52 | console.log(xhr.responseText); 53 | var response = JSON.parse(xhr.responseText); 54 | successCallback(response.id, response.result); 55 | } 56 | }; 57 | xhr.open('POST', this.endPointUrl, true); 58 | xhr.setRequestHeader('Content-Type', 'application/json'); 59 | xhr.send(message); 60 | 61 | return id; 62 | }; 63 | })(i); 64 | } 65 | }; 66 | 67 | CameraRemoteAPI.prototype.setActionListUrl = function(actionListUrl) { 68 | this.actionListUrl = actionListUrl; 69 | }; 70 | 71 | var CRA_LIVEVIEW_MAX_RECEIVE_SIZE = 500000; 72 | var CRA_LIVEVIEW_COMMON_HEADER_SIZE = 8; 73 | var CRA_LIVEVIEW_PLAYLOAD_HEADER_SIZE = 128; 74 | 75 | CameraRemoteAPI.prototype.getLiveviewData = function(targetUrl, dataCallback) { 76 | var headerDecode = false; 77 | var offset = 0; 78 | var self = arguments.callee; 79 | 80 | var xhr = new XMLHttpRequest(); 81 | xhr.open('GET', targetUrl, true); 82 | xhr.overrideMimeType('text\/plain; charset=x-user-defined'); 83 | xhr.onreadystatechange = function() { 84 | if (xhr.readyState == 3) { 85 | if(xhr.response.length >= CRA_LIVEVIEW_MAX_RECEIVE_SIZE) { 86 | console.log('finish'); 87 | xhr.abort(); 88 | //this[getLiveviewData](targetUrl, dataCallback); 89 | self(targetUrl, dataCallback); 90 | } 91 | 92 | if(xhr.response.length >= (CRA_LIVEVIEW_COMMON_HEADER_SIZE + CRA_LIVEVIEW_PLAYLOAD_HEADER_SIZE+offset)) { 93 | if(headerDecode == false) { 94 | var startByte = (xhr.responseText.charCodeAt(offset + 0) & 0xff); 95 | var playLoadType = xhr.responseText.charCodeAt(offset + 1) & 0xff; 96 | var sequenceNumber = (xhr.responseText.charCodeAt(offset + 2) & 0xff) << 8; 97 | sequenceNumber += (xhr.responseText.charCodeAt(offset + 3) & 0xff); 98 | var timeStamp = (xhr.responseText.charCodeAt(offset + 4) & 0xff) << 24; 99 | timeStamp += (xhr.responseText.charCodeAt(offset + 5) & 0xff) << 16; 100 | timeStamp += (xhr.responseText.charCodeAt(offset + 6) & 0xff) << 8; 101 | timeStamp += (xhr.responseText.charCodeAt(offset + 7) & 0xff); 102 | var startCode = [(xhr.responseText.charCodeAt(offset + 8) & 0xff), (xhr.responseText.charCodeAt(offset + 9) & 0xff), (xhr.responseText.charCodeAt(offset + 10) & 0xff), (xhr.responseText.charCodeAt(offset + 11) & 0xff)]; 103 | var jpegSize = ((xhr.responseText.charCodeAt(offset + 12) & 0xff) * (256 * 256)); 104 | jpegSize += ((xhr.responseText.charCodeAt(offset + 13) & 0xff) * 256); 105 | jpegSize += ((xhr.responseText.charCodeAt(offset + 14) & 0xff)); 106 | var paddingSize = xhr.responseText.charCodeAt(offset + 15) & 0xff; 107 | 108 | console.log('startByte: ' + (startByte).toString(16)); 109 | 110 | console.log('playLoadType: ' + (playLoadType).toString(16)); 111 | console.log('startCode: ' + (startCode[0]).toString(16) + (startCode[1]).toString(16) + (startCode[2]).toString(16) + (startCode[3]).toString(16)); 112 | 113 | console.log('jpegSize: ' + (jpegSize).toString(16)); 114 | console.log('paddingSize: ' + (paddingSize).toString(16)); 115 | } 116 | 117 | if(xhr.response.length >= (CRA_LIVEVIEW_COMMON_HEADER_SIZE + CRA_LIVEVIEW_PLAYLOAD_HEADER_SIZE + jpegSize + offset)) { 118 | binary = ''; 119 | for (var i = (CRA_LIVEVIEW_COMMON_HEADER_SIZE + CRA_LIVEVIEW_PLAYLOAD_HEADER_SIZE + offset), len = (CRA_LIVEVIEW_COMMON_HEADER_SIZE + CRA_LIVEVIEW_PLAYLOAD_HEADER_SIZE + offset)+jpegSize; i < len; ++i) { 120 | binary += String.fromCharCode(xhr.responseText.charCodeAt(i) & 0xff); 121 | } 122 | 123 | var base64 = window.btoa(binary); 124 | if (base64.length > 0 && base64[0] == "/") { 125 | //document.getElementById('shoot-image').src = "data:image/jpeg;base64," + base64; 126 | dataCallback(base64); 127 | offset = CRA_LIVEVIEW_COMMON_HEADER_SIZE + CRA_LIVEVIEW_PLAYLOAD_HEADER_SIZE + offset + jpegSize + paddingSize; 128 | headerDecode = false; 129 | return; 130 | } else { 131 | console.log('What is this?'); 132 | xhr.abort(); 133 | return; 134 | } 135 | } 136 | return; 137 | } 138 | } 139 | }; 140 | xhr.send(); 141 | }; 142 | 143 | -------------------------------------------------------------------------------- /webapp/cameraApp.js: -------------------------------------------------------------------------------- 1 | var devInfo = [ 2 | {name:"NEX-5R", url: "http://192.168.122.1:8080/sony"}, 3 | {name:"HDR-AS15", url: "http://10.0.0.1:10000/sony"} 4 | ]; 5 | 6 | var actions = [ 7 | {method:"startRecMode", params:'[]'}, 8 | {method:"setPostviewImageSize", params:'["2M"]'}, 9 | {method:"actTakePicture", params:'[]'}, 10 | {method:"awaitTakePicture", params:'[]'}, 11 | {method:"startLiveview", params:'[]'}, 12 | {method:"stopLiveview", params:'[]'}, 13 | {method:"startMovieRec", params:'[]'}, 14 | {method:"stopMovieRec", params:'[]'} 15 | ]; 16 | 17 | /* 18 | * This function will be called when this js is loaded. 19 | */ 20 | window.addEventListener("load", function() { 21 | console.log("--- Camera Remote API application starts ---"); 22 | console.log("User Agent: " + navigator.userAgent); 23 | console.log("App Version: " + window.navigator.appVersion.toLowerCase()); 24 | 25 | // Init CameraRemoteAPI 26 | var camera = new CameraRemoteAPI(); 27 | 28 | // Init deivce name input 29 | var device = document.getElementById("device-name"); 30 | device.length = devInfo.length; 31 | for (var i = 0; i < devInfo.length; i++) 32 | { 33 | device.options[i].value = i; 34 | device.options[i].text = devInfo[i].name; 35 | } 36 | device.addEventListener('change', function() { 37 | console.log("-- Change Device ---"); 38 | var device = document.getElementById("device-name"); 39 | console.log(device.value); 40 | var i = device.value; 41 | 42 | document.getElementById("action-list-url").value = devInfo[i].url; 43 | }); 44 | var event = document.createEvent( "MouseEvents" ); 45 | event.initEvent("change", false, true); 46 | device.dispatchEvent(event); 47 | 48 | 49 | // Init action list 50 | var select = document.getElementById("actions"); 51 | select.length = actions.length; 52 | for (var i = 0; i < actions.length; i++) 53 | { 54 | select.options[i].value = i; 55 | select.options[i].text = actions[i].method; 56 | } 57 | select.addEventListener('change', function() { 58 | console.log("-- Change Action ---"); 59 | var action = document.getElementById("actions").value; 60 | console.log(action); 61 | 62 | var params = document.getElementById("action-parames"); 63 | params.value = actions[action].params; 64 | }); 65 | var event = document.createEvent( "MouseEvents" ); 66 | event.initEvent("change", false, true); 67 | select.dispatchEvent(event); 68 | 69 | document.getElementById("send-json-message").onclick = function(){ 70 | console.log("--- Send Message ---") 71 | var actionListUrl = document.getElementById("action-list-url").value; 72 | var action = document.getElementById("actions").value; 73 | 74 | console.log("action list url: " + actionListUrl); 75 | console.log("action : " + action); 76 | console.log(actions[action].method); 77 | 78 | camera.setActionListUrl(actionListUrl); 79 | var id = camera[actions[action].method](actions[action].params, 80 | // success callback 81 | function(id, response) { 82 | console.log("--- success response ---") 83 | console.log("method: " + actions[action].method); 84 | console.log("id: " + id); 85 | console.log(response); 86 | document.getElementById("response-id").value = id; 87 | document.getElementById("response-parames").value = response; 88 | // capture still picture 89 | if(actions[action].method == "actTakePicture") { 90 | console.log("--- actTakePicture ---"); 91 | LoadImage(response); 92 | } else if(actions[action].method == "startLiveview") { 93 | camera.getLiveviewData(response, function(base64Data) { 94 | document.getElementById('shoot-image').src = "data:image/jpeg;base64," + base64Data; 95 | }); 96 | } 97 | }, 98 | // error callback 99 | function(id, error){ 100 | console.log("--- error response ---") 101 | console.log("id: " + id); 102 | console.log(error); 103 | } 104 | ); 105 | document.getElementById("action-id").value = id; 106 | }; 107 | }); 108 | 109 | /* 110 | var CRA_LIVEVIEW_MAX_RECEIVE_SIZE = 1000000; 111 | var CRA_LIVEVIEW_COMMON_HEADER_SIZE = 8; 112 | var CRA_LIVEVIEW_PLAYLOAD_HEADER_SIZE = 128; 113 | 114 | var GetLiveviewData = function(targetUrl, dataCallback) { 115 | var offset = 0; 116 | var headerDecode = false; 117 | 118 | var xhr = new XMLHttpRequest(); 119 | xhr.open('GET', targetUrl, true); 120 | xhr.overrideMimeType('text\/plain; charset=x-user-defined'); 121 | xhr.onreadystatechange = function() { 122 | if (xhr.readyState == 3) { 123 | if(xhr.response.length >= CRA_LIVEVIEW_MAX_RECEIVE_SIZE) { 124 | console.log('finish'); 125 | xhr.abort(); 126 | GetLiveviewData(targetUrl, dataCallback); 127 | } 128 | 129 | if(xhr.response.length >= (CRA_LIVEVIEW_COMMON_HEADER_SIZE + CRA_LIVEVIEW_PLAYLOAD_HEADER_SIZE+offset)) { 130 | if(headerDecode == false) { 131 | var startByte = (xhr.responseText.charCodeAt(offset + 0) & 0xff); 132 | var playLoadType = xhr.responseText.charCodeAt(offset + 1) & 0xff; 133 | var sequenceNumber = (xhr.responseText.charCodeAt(offset + 2) & 0xff) << 8; 134 | sequenceNumber += (xhr.responseText.charCodeAt(offset + 3) & 0xff); 135 | var timeStamp = (xhr.responseText.charCodeAt(offset + 4) & 0xff) << 24; 136 | timeStamp += (xhr.responseText.charCodeAt(offset + 5) & 0xff) << 16; 137 | timeStamp += (xhr.responseText.charCodeAt(offset + 6) & 0xff) << 8; 138 | timeStamp += (xhr.responseText.charCodeAt(offset + 7) & 0xff); 139 | var startCode = [(xhr.responseText.charCodeAt(offset + 8) & 0xff), (xhr.responseText.charCodeAt(offset + 9) & 0xff), (xhr.responseText.charCodeAt(offset + 10) & 0xff), (xhr.responseText.charCodeAt(offset + 11) & 0xff)]; 140 | var jpegSize = ((xhr.responseText.charCodeAt(offset + 12) & 0xff) * (256 * 256)); 141 | jpegSize += ((xhr.responseText.charCodeAt(offset + 13) & 0xff) * 256); 142 | jpegSize += ((xhr.responseText.charCodeAt(offset + 14) & 0xff)); 143 | var paddingSize = xhr.responseText.charCodeAt(offset + 15) & 0xff; 144 | 145 | console.log('startByte: ' + (startByte).toString(16)); 146 | 147 | console.log('playLoadType: ' + (playLoadType).toString(16)); 148 | console.log('startCode: ' + (startCode[0]).toString(16) + (startCode[1]).toString(16) + (startCode[2]).toString(16) + (startCode[3]).toString(16)); 149 | 150 | console.log('jpegSize: ' + (jpegSize).toString(16)); 151 | console.log('paddingSize: ' + (paddingSize).toString(16)); 152 | } 153 | 154 | if(xhr.response.length >= (CRA_LIVEVIEW_COMMON_HEADER_SIZE + CRA_LIVEVIEW_PLAYLOAD_HEADER_SIZE + jpegSize + offset)) { 155 | binary = ''; 156 | for (var i = (CRA_LIVEVIEW_COMMON_HEADER_SIZE + CRA_LIVEVIEW_PLAYLOAD_HEADER_SIZE + offset), len = (CRA_LIVEVIEW_COMMON_HEADER_SIZE + CRA_LIVEVIEW_PLAYLOAD_HEADER_SIZE + offset)+jpegSize; i < len; ++i) { 157 | binary += String.fromCharCode(xhr.responseText.charCodeAt(i) & 0xff); 158 | } 159 | 160 | var base64 = window.btoa(binary); 161 | if (base64.length > 0 && base64[0] == "/") { 162 | //document.getElementById('shoot-image').src = "data:image/jpeg;base64," + base64; 163 | dataCallback(base64); 164 | offset = CRA_LIVEVIEW_COMMON_HEADER_SIZE + CRA_LIVEVIEW_PLAYLOAD_HEADER_SIZE + offset + jpegSize + paddingSize; 165 | headerDecode = false; 166 | return; 167 | } else { 168 | console.log('What is this?'); 169 | xhr.abort(); 170 | return; 171 | } 172 | } 173 | return; 174 | } 175 | } 176 | }; 177 | xhr.send(); 178 | } 179 | */ 180 | 181 | 182 | var LoadImage = function(url) 183 | { 184 | console.log("--- LoadImage ----"); 185 | console.log("url: " + url); 186 | 187 | var userAgent = window.navigator.userAgent.toLowerCase(); 188 | // Android Apk 189 | if(userAgent.indexOf('android') != -1) { 190 | var img = document.getElementById("shoot-image"); 191 | img.src = url; 192 | } else { // Chromw Web app 193 | var xhr = new XMLHttpRequest(); 194 | xhr.open('GET', url, true); 195 | xhr.responseType = 'blob'; 196 | 197 | xhr.onreadystatechange = function() { 198 | if (xhr.readyState == 4 && xhr.status == 200) { 199 | var blob = xhr.response; 200 | var img = document.getElementById("shoot-image"); 201 | img.src = window.URL.createObjectURL(blob); 202 | } 203 | }; 204 | xhr.send(); 205 | } 206 | }; 207 | --------------------------------------------------------------------------------