I'm using expo to build a cross-platform application. In my app, I have a screen where user can select images or videos to upload.
When I use expo-image-picker to select image it gives me an object which its uri starts with file:/// and I can use this uri to display the image.
When I use expo-image-picker-multiple to select multiple images it gives me objects and the uri starts with asset-library:// and I can't use this uri to display the content of it nor send it to server.
How can I convert this asset-library:// to file://? What keyword should I use to get better results when doing google search on this problem or which tool should I use? I can't really find a proper solution to this one. This occurs on IOS devices.
Thanks!
[EDIT]
here is my code
var assetUri = 'asset-library://....'
var tempDir = `${FileSystem.cacheDirectory}${Math.random().toString(36).substring(7)}.jpg`
FileSystem.copyAsync({
from: assetUri,
to: tempDir
})
try {
var assetResult = await FileSystem.readAsStringAsync(tempDir, {
encoding: FileSystem.EncodingType.UTF8
})
console.log(assetResult)
}
catch(e) {
console.log(e)
}
File 'file:///var/mobile/Containers/Data/Application/0E-FC42-4630-B3C7-537D5EFB7D1F/Library/Caches/ExponentExperienceData/ichardexpohong/gwmke.jpg' could not be read.
I wanted only the filename so i used
let filename= result.assets[0].uri.split('/')[result.assets[0].uri.split('/').length-1]
so maybe if the path after both asset-library and file:// are the same you can use
take away the asset-library:// then replace it with file://
let uri='file://' + object.uri.split('asset-library://')[1]
hope it helps
Related
I'm making mobile app with React-Native and i wanna get data from my API.But my API's datas , databases has html tags (you can see them in images which i shared) and some character codes because there are also Turkish characters.I already was using this API from my web site and there was no problem but when i try to get data to my react native app , it is getting data as a plain text as you see in my images.How can i get this datas without problem
It's called HTML entity. This is the code that works on browser (not on your case)
var decodeEntities = (function() {
// this prevents any overhead from creating the object each time
var element = document.createElement('div');
function decodeHTMLEntities (str) {
if(str && typeof str === 'string') {
// strip script/html tags
str = str.replace(/<script[^>]*>([\S\s]*?)<\/script>/gmi, '');
str = str.replace(/<\/?\w(?:[^"'>]|"[^"]*"|'[^']*')*>/gmi, '');
element.innerHTML = str;
str = element.textContent;
element.textContent = '';
}
return str;
}
return decodeHTMLEntities;
})();
The code are copied from here HTML Entity Decode
But it only works on the browser because the browser are automatically translate the characters for you.
I don't think passing around unserialized data like this is a good idea. You might want to encode data in server side using url encode or something then decode it in the react-native side
Reference
https://www.w3schools.com/charsets/ref_utf_punctuation.asp
Actually i solved it with this : https://github.com/archriss/react-native-render-html
Thanks
My intent:
I want my app to upload images to S3. If image already exists, server should record a reference to existing image rather than asking for an upload of another copy.
How I imagine that works:
Hash image data
Send hash to server with request for signed url (to upload to AWS S3)
If hash matches something already stored, reference it and tell app
Initial thoughts:
Use imageEditor.cropImage to get image into ImageStore, which will give me an appropriate uri. Then use getBase64ForTag(uri, success, failure) to retrieve base64 data for a hash calculation.
The problem:
According to the answer on this question, this process is not efficient in the least. The usual solution would be to use native methods, as described in the answer to this question, however I do not want to eject my Expo app for this feature.
My Question:
Is there a better way to hash image data? Or more fundamentally, is there a better way of ensuring that identical images are not duplicated in S3 storage?
EDIT 2020-10-21 :
The library updated itself, and you should now call:
_hashImage = async (imageUri) => {
return await FileSystem.getInfoAsync(imageUri, { md5: true } );
}
ORIGINAL:
It turns out that Expo provides this out of the box.
Expo.FileSystem.getInfoAsync
myImageHashFunction = async (imageUri) => {
let fsInfo = await Expo.FileSystem.getInfoAsync(imageUri, [{ md5: true }] )
console.log(fsInfo.md5)
}
If you are still looking for a solution:
This is how I got it working - create a base64 of the image and then create a hash of it.
import * as FileSystem from 'expo-file-system';
import * as Crypto from 'expo-crypto';
let info = await FileSystem.readAsStringAsync(imageUri,
{ encoding: FileSystem.EncodingType.Base64 });
const hashData = await Crypto.digestStringAsync (
Crypto.CryptoDigestAlgorithm.MD5,
info
)
I'm building an app with titanium and I would like to save in the phone, the user's profile picture. In my login function, after the API response, I tried to do :
Ti.App.Properties.setString("user_picture_name", res.profil_picture);
var image_to_save = Ti.UI.createImageView({image:img_url}).toImage();
var picture = Ti.Filesystem.getFile(Ti.Filesystem.applicationDataDirectory, res.profil_picture); //As name, the same as the one in DB
picture.write(image_to_save);
And in the view in which I want to display the image :
var f = Ti.Filesystem.getFile(Ti.Filesystem.applicationDataDirectory,Ti.App.Properties.getString("user_picture_name") );
var image = Ti.UI.createImageView({
image:f.read(),
width:200,
height:100,
top:20
});
main_container.add(image);
But the image doesn't appears. Could someone help me ?
Thanks a lot :)
There are 2 issues with your code:
1 - You cannot use toImage() method unless your image view is rendered on UI stack or simply on display. Rather you should use toBlob() method.
2 - Point no. 1 will also not work the way you are using because you cannot directly use toBlob() method until or unless the image from the url is completely loaded, means until it's shown on image view. To check when the image is loaded, use Ti.UI.ImageView onload event
But, there's another better approach to do such type of tasks.
Since you have the image url from your Login API response, you can use this url to fetch image from http client call like this:
function fetchImage() {
var xhr = Ti.Network.createHTTPClient({
onerror : function() {
alert('Error fetching profile image');
},
onload : function() {
// this.responseData holds the binary data fetched from url
var image_to_save = this.responseData;
//As name, the same as the one in DB
var picture = Ti.Filesystem.getFile(Ti.Filesystem.applicationDataDirectory, res.profil_picture);
picture.write(image_to_save);
Ti.App.Properties.setString("user_picture_name", res.profil_picture);
image_to_save = null;
}
});
xhr.open("GET", img_url);
xhr.send();
}
You don't need to manually cache remote images, because
Remote images are cached automatically on the iOS platform and, since
Release 3.1.0, on the Android platform.
[see docs here & credit to Fokke Zandbergen]
Just use the remote image url in your UI, at first access Titanium will download and cache it for you; next accesses to the same image url will actually be on the automatically cached version on local device (no code is best code)
Hth.
I have several html templates I require to "compile" and convert to base64 format. By compile I mean injecting JS and CSS inline, and then converting it to base64 format.
I tried gulp-base64 but that only works for images in CSS. Any ideas?
Edit: I just got an idea that maybe I could use gulp-foreach to process each file individually and then use a Buffer to convert each file's content's to base64 format. I know I could do something like:
> console.log(new Buffer("Hello World").toString('base64'));
SGVsbG8gV29ybGQ=
> console.log(new Buffer("SGVsbG8gV29ybGQ=", 'base64').toString('ascii'))
Hello World
But I'm not really sure how to do it since I don't understand quite well how file streams (I think it's called vinyl) work yet in gulp. Any help would be greatly appreciated.
I found your question while looking for a solution to the same problem. Your suggestion to use gulp-foreach led me to a solution, although I didn't use that package:
// import the appropriate plugins
//
const each = require('gulp-each');
const htmlToJs = require('gulp-html-to-js');
// I'm compiling a couple of small PDF files
//
gulp.task('compile:pdf', () =>
gulp.src('./files/**/*.pdf')
// use gulp-each to iterate over the files & convert the
// files to a base64-encoded data URL
//
.pipe(each((content, file, callback) => {
const output = `data:application/pdf;base64,${new Buffer(content).toString('base64')}`;
// the first arg in this callback is the error; the second
// is the content to pass along via the stream
//
callback(null, output)
}))
// use gulp-html-to-js to convert the data URL to a JS module
// which can be imported
//
.pipe(htmlToJs())
// and set the destination...
//
.pipe(gulp.dest('./client/modules/helpers/files'))
);
The end result is a JS file with contents that look like this:
'use strict';
module.exports = 'data:application/pdf;base64,... base64 encoded string...';
I've been trying to send data from my background page to a content script in my chrome extension. i can't seem to get it to work. I've read a few posts online but they're not really clear and seem quite high level. I've got managed to get the oauth working using the Oauth contacts example on the Chrome samples. The authentication works, i can get the data and display it in an html page by opening a new tab.
I want to send this data to a content script.
i'm having a lot of trouble with this and would really appreciate if someone could outline the explicit steps you need to follow to send data from a bg page to a content script or even better some code. Any takers?
the code for my background page is below (i've excluded the oauth paramaeters and other )
` function onContacts(text, xhr) {
contacts = [];
var data = JSON.parse(text);
var realdata = data.contacts;
for (var i = 0, person; person = realdata.person[i]; i++) {
var contact = {
'name' : person['name'],
'emails' : person['email']
};
contacts.push(contact); //this array "contacts" is read by the
contacts.html page when opened in a new tab
}
chrome.tabs.create({ 'url' : 'contacts.html'}); sending data to new tab
//chrome.tabs.executeScript(null,{file: "contentscript.js"});
may be this may work?
};
function getContacts() {
oauth.authorize(function() {
console.log("on authorize");
setIcon();
var url = "http://mydataurl/";
oauth.sendSignedRequest(url, onContacts);
});
};
chrome.browserAction.onClicked.addListener(getContacts);`
As i'm not quite sure how to get the data into the content script i wont bother posting the multiple versions of my failed content scripts. if I could just get a sample on how to request the "contacts" array from my content script, and how to send the data from the bg page, that would be great!
You have two options getting the data into the content script:
Using Tab API:
http://code.google.com/chrome/extensions/tabs.html#method-executeScript
Using Messaging:
http://code.google.com/chrome/extensions/messaging.html
Using Tab API
I usually use this approach when my extension will just be used once in a while, for example, setting the image as my desktop wallpaper. People don't set a wallpaper every second, or every minute. They usually do it once a week or even day. So I just inject a content script to that page. It is pretty easy to do so, you can either do it by file or code as explained in the documentation:
chrome.tabs.executeScript(tab.id, {file: 'inject_this.js'}, function() {
console.log('Successfully injected script into the page');
});
Using Messaging
If you are constantly need information from your websites, it would be better to use messaging. There are two types of messaging, Long-lived and Single-requests. Your content script (that you define in the manifest) can listen for extension requests:
chrome.extension.onRequest.addListener(function(request, sender, sendResponse) {
if (request.method == 'ping')
sendResponse({ data: 'pong' });
else
sendResponse({});
});
And your background page could send a message to that content script through messaging. As shown below, it will get the currently selected tab and send a request to that page.
chrome.tabs.getSelected(null, function(tab) {
chrome.tabs.sendRequest(tab.id, {method: 'ping'}, function(response) {
console.log(response.data);
});
});
Depends on your extension which method to use. I have used both. For an extension that will be used like every second, every time, I use Messaging (Long-Lived). For an extension that will not be used every time, then you don't need the content script in every single page, you can just use the Tab API executeScript because it will just inject a content script whenever you need to.
Hope that helps! Do a search on Stackoverflow, there are many answers to content scripts and background pages.
To follow on Mohamed's point.
If you want to pass data from the background script to the content script at initialisation, you can generate another simple script that contains only JSON and execute it beforehand.
Is that what you are looking for?
Otherwise, you will need to use the message passing interface
In the background page:
// Subscribe to onVisited event, so that injectSite() is called once at every pageload.
chrome.history.onVisited.addListener(injectSite);
function injectSite(data) {
// get custom configuration for this URL in the background page.
var site_conf = getSiteConfiguration(data.url);
if (site_conf)
{
chrome.tabs.executeScript({ code: 'PARAMS = ' + JSON.stringify(site_conf) + ';' });
chrome.tabs.executeScript({ file: 'site_injection.js' });
}
}
In the content script page (site_injection.js)
// read config directly from background
console.log(PARAM.whatever);
I thought I'd update this answer for current and future readers.
According to the Chrome API, chrome.extension.onRequest is "[d]eprecated since Chrome 33. Please use runtime.onMessage."
See this tutorial from the Chrome API for code examples on the messaging API.
Also, there are similar (newer) SO posts, such as this one, which are more relevant for the time being.