Sharing image generated from html canvas on FB - facebook-javascript-sdk

This one I've been banging my head against for a few weeks now.
Scenario:
Let user generate an image out of layers they select
Convert image to canvas
Share image from canvas on facebook wall using share_open_graph (along with the image, a short text and title will be shared)
I've already had a solution in place using publish_actions but that was recently removed from the API and is no longer available.
I am using js and html for all code handling.
The issue is that I can generate a png image from the canvas but that is saved as base64 and share_open_graph doesn't allow this type of image, it needs a straight forward url such as './example.png'. I have tried using several approaches and with canvas2image, converting and saving image using file-system but all of these fail.
Does anyone have similar scenario and possible solution from April/May 2018 using share_open_graph ?
My current code looks like this - it fails at the image conversion and save to a file (Uncaught (in promise) TypeError: r.existsSync is not a function at n (file-system.js:30)). But I am open to different solutions as this is clearly not working.
html2canvas(original, { width: 1200, height: 628
}).then(function(canvas)
{
fb_image(canvas);
});
var fb_image = function(canvas) {
canvas.setAttribute('id', 'canvas-to-share');
document.getElementById('img-to-share').append(canvas);
fbGenerate.style.display = 'none';
fbPost.style.display = 'block';
var canvas = document.getElementById('canvas-to-share');
var data = canvas.toDataURL('image/png');
var encodedPng = data.substring(data.indexOf(',') + 1, data.length);
var decodedPng = base64.decode(encodedPng);
const buffer = new Buffer(data.split(/,\s*/)[1], 'base64');
pngToJpeg({ quality: 90 })(buffer).then(output =>
fs.writeFile('./image-to-fb.jpeg', output));
var infoText_content = document.createTextNode('Your image is being
posted to facebook...');
infoText.appendChild(infoText_content);
// Posting png from imageToShare to facebook
fbPost.addEventListener('click', function(eve) {
FB.ui(
{
method: 'share_open_graph',
action_type: 'og.shares',
href: 'https:example.com',
action_properties: JSON.stringify({
object: {
'og:url': 'https://example.com',
'og:title': 'My shared image',
'og:description': 'Hey I am sharing on fb!',
'og:image': './image-to-fb.jpeg',
},
}),
},
function(response) {
console.log(response);
}
);
});
};

Related

HERE Maps JS API 3.1.30.17 used in VUE - Error for style group 'non-collision' in Firefox

I've build a simple Here Map using Vue 2 and the JS API in version 3.1.30.17. The map works fine in all browsers except Firefox v102.
This is the error message in Firefox:
Tangram [error]: Error for style group 'non-collision' for tile 20/7/68/41/7 CanvasRenderingContext2D.drawImage: Passed-in canvas is empty: loadTexture#https://js.api.here.com/v3/3.1.30.17/mapsjs-core.js:431:417267
e/sn.addWorker/<#https://js.api.here.com/v3/3.1.30.17/mapsjs-core.js:431:63015
EventListener.handleEvent*e/sn.addWorker#https://js.api.here.com/v3/3.1.30.17/mapsjs-core.js:431:62515
e/value/<#https://js.api.here.com/v3/3.1.30.17/mapsjs-core.js:431:515089
value#https://js.api.here.com/v3/3.1.30.17/mapsjs-core.js:431:515502
value#https://js.api.here.com/v3/3.1.30.17/mapsjs-core.js:431:514847
e/value/this.initializing<#https://js.api.here.com/v3/3.1.30.17/mapsjs-core.js:431:511497
promise callback*value#https://js.api.here.com/v3/3.1.30.17/mapsjs-core.js:431:511472
Ul#https://js.api.here.com/v3/3.1.30.17/mapsjs-core.js:335:441
p.eh#https://js.api.here.com/v3/3.1.30.17/mapsjs-core.js:378:446
p.Ge#https://js.api.here.com/v3/3.1.30.17/mapsjs-core.js:329:436
p.Ge#https://js.api.here.com/v3/3.1.30.17/mapsjs-core.js:376:356
S#https://js.api.here.com/v3/3.1.30.17/mapsjs-core.js:369:214
T.prototype.u#https://js.api.here.com/v3/3.1.30.17/mapsjs-core.js:410:166
T#https://js.api.here.com/v3/3.1.30.17/mapsjs-core.js:401:290
... The error is even bigger
The following method I'm using to init Here Maps inside Vue's mounted:
async initializeHereMap() {
const mapContainer = this.$refs.hereMap;
const H = window.H;
// Initialize the platform object:
this.platform = new H.service.Platform({
apikey: this.apiKey,
});
await this.geocode(this.platform, this.originAddress)
.then(data => this.routingParameters.origin = data[0]);
await this.geocode(this.platform, this.destinationAddress)
.then(data => this.routingParameters.destination = data[0]);
// Obtain the default map types from the platform object
const defaultLayers = this.platform.createDefaultLayers({
lg: window.navigator.language,
});
// Instantiate (and display) a map object:
const map = new H.Map(mapContainer, defaultLayers.vector.normal.map, {
zoom: this.zoom,
center: this.center,
padding: {
top: this.padding,
bottom: this.padding,
left: this.padding,
right: this.padding,
},
});
// create map pins
const mapPinOrigin = this.addMapPin('A', 40);
const mapPinDestination = this.addMapPin('B', 40);
let linestring = new H.geo.LineString();
linestring.pushPoint(this.routingParameters.origin);
linestring.pushPoint(this.routingParameters.destination);
// Create a polyline to display the route:
let routeLine = new H.map.Polyline(linestring, {
linestring,
style: { strokeColor: '#3F80C4', lineWidth: 5 },
});
// Create a marker for the start point:
let startMarker = new H.map.Marker(this.routingParameters.origin, { icon: mapPinOrigin });
// Create a marker for the end point:
let endMarker = new H.map.Marker(this.routingParameters.destination, { icon: mapPinDestination });
// Add the route polyline and the two markers to the map:
map.addObjects([routeLine, startMarker, endMarker]);
// Set the map's viewport to make the whole route visible:
map.getViewModel().setLookAtData({bounds: routeLine.getBoundingBox()});
// add behavior control
if (this.behaviors) new H.mapevents.Behavior(new H.mapevents.MapEvents(map));
// add UI
if (this.controls) H.ui.UI.createDefault(map, defaultLayers);
},
Is there some one facing the same issue and could solved it?
Did you follow this example on: https://developer.here.com/tutorials/how-to-implement-a-web-map-using-vuejs/ ?
Tangram error is related to rendering e.g. when render map objects (like icons, markers, polylines etc.) and map vector tiles.
I don't think so that this issue related to HERE JS Map API.
Because all examples on https://developer.here.com/documentation/examples/maps-js are working well on my FireFox 102.0.1
It could be some map objects like icons or markers etc. are created in some moment but is not finished yet and then try to push onto map? Creating an icon in some asynchron function?
Or in like your code:
await this.geocode(this.platform, this.originAddress)
.then(data => this.routingParameters.origin = data[0]);
You don't know when func geocode will be finished (e.g. due slow internet connectivity)
It could be this command above is not done yet, but your code is already start to run this code:
linestring.pushPoint(this.routingParameters.origin);<-- 'this.routingParameters.origin' could be null
linestring.pushPoint(this.routingParameters.destination);
// Create a polyline to display the route:
let routeLine = new H.map.Polyline(linestring, { <-- Could cause Tangram error because 'linestring' is strange due undefined origin yet!
linestring,
style: { strokeColor: '#3F80C4', lineWidth: 5 },
});
The polyline options is not correct in:
new H.map.Polyline(linestring, {
linestring,
style: { strokeColor: '#3F80C4', lineWidth: 5 },
}
Why in above the 'linestring' is second time in options?
Please follow correct syntax on:
https://developer.here.com/documentation/maps/3.1.31.0/api_reference/H.map.Polyline.html#.Options

How to add image from mobile storage to mapbox-gl?

I've been trying to add an image overlay to mapbox-gl-js on a project that uses Ionic 5 + Vue.js, similar to what Leaflet does, but i cannot get it to work.
The only way that I can get it to work is by following this tutorial, but the image does not fit properly into the polygon. I've also tried this, and I can see when Capacitor requests the image, but it does not load. It works fine on Chrome, but on mobile it does not.
This is the code that I have now:
const { map } = this;
if (map.getLayer(layerId)) {
map.removeLayer(layerId);
}
if (map.getSource(sourceId)) {
map.removeSource(sourceId);
}
map.addSource(sourceId, { ...source, url: Capacitor.convertFileSrc(source.url) });
map.addLayer(layer);
whereas the source and layer objects are like this:
const sourceId = `${talhao.id}-image`;
const layerId = `${talhao.id}-image-${image.id}`;
const bbox = getBoundingBox(talhao);
const source = {
type: "image",
url: image.imagemPng,
coordinates: [
bbox.getNorthWest().toArray(),
bbox.getNorthEast().toArray(),
bbox.getSouthEast().toArray(),
bbox.getSouthWest().toArray()
]
};
const layer = {
id: layerId,
source: sourceId,
type: "raster",
paint: {
"raster-opacity": 0.85
}
};
Any help would be appreciated!
edit: It is worth noticing that I do not think that the image is the problem here, because I use the same image in another part of the screen that I'm working and it loads fine.
Turns out the mapbox-gl-js library had a bug in version 1.x that prevented the image from showing on mobile.
Upgraded to version 2.0.1 and it worked.

Show local image file:///tmp/someimage.jpg

Scenario
I'm contributing for a OSS project that is build on BlazorServerSide and ElectronNET.API Version 9.31.1.
In an Electron window we would like to show images from local storage UI via <img> tag.
What I have tried:
I have tried with:
<img src="file:///home/dani/pictures/someimage.jpg" />
But doesn't work. Image doesn't appear. I have then tried to create electron window with WebSecurity = false, but also doesn't help (images appears as broken on UI):
var browserWindowOptions = new BrowserWindowOptions
{
WebPreferences = new WebPreferences
{
WebSecurity = false,
},
};
Task.Run(async () => await Electron.WindowManager.CreateWindowAsync(
browserWindowOptions,
$"http://localhost:{BridgeSettings.WebPort}/Language/SetCultureByConfig"
));
Finally, as workaround, I'm sending the images as data base64 in img src's attribute, but it looks like a dirty approach.
My Question:
My question is, how can I show on electron window picture files from local storage.
Some irrelevant info:
The open source line where I need assistance.
There are several ways to go about this, so I will try to cover the most relevant use cases. Some of this depends on the context of your project.
Access to local files behave as cross origin requests by default. You could try using the crossorigin=anonymous attribute on your image tag, but doesn't work because your local file system will not be responding with cross origin headers.
Disabling the webSecurity option is a workaround, but is not recommended for security reasons, and will not usually work correctly anyway if your html is not also loaded from the local file system.
Disabling webSecurity will disable the same-origin policy and set allowRunningInsecureContent property to true. In other words, it allows the execution of insecure code from different domains.
https://www.electronjs.org/docs/tutorial/security#5-do-not-disable-websecurity
Here are some methods of working around this issue:
1 - Use the HTML5 File API to load local file resources and provide the ArrayBuffer to ImageData to write the image to a <canvas> .
function loadAsUrl(theFile) {
var reader = new FileReader();
var putCanvas = function(canvas_id) {
return function(loadedEvent) {
var buffer = new Uint8ClampedArray(loadedEvent.target.result);
document.getElementById(canvas_id)
.getContext('2d')
.putImageData(new ImageData(buffer, width, height), 0, 0);
}
}
reader.onload = putCanvas("canvas_id");
reader.readAsArrayBuffer(theFile);
}
1.b - It is also possible to load a file as a data URL. A data URL can be set as source (src) on img elements with JavaScript. Here is a JavaScript function named loadAsUrl() that shows how to load a file as a data URL using the HTML5 file API:
function loadAsUrl(theFile) {
var reader = new FileReader();
reader.onload = function(loadedEvent) {
var image = document.getElementById("theImage");
image.setAttribute("src", loadedEvent.target.result);
}
reader.readAsDataURL(theFile);
}
2 - Use the Node API fs to read the file, and convert it into a base64 encoded data url to embed in the image tag.
Hack - Alternatively you can try loading the image in a BrowserView or <webview>. The former overlays the content of your BrowserWindow while the latter is embedded into the content.
// In the main process.
const { BrowserView, BrowserWindow } = require('electron')
const win = new BrowserWindow({ width: 800, height: 600 })
const view = new BrowserView()
win.setBrowserView(view)
view.setBounds({ x: 0, y: 0, width: 300, height: 300 })
view.webContents.loadURL('file:///home/dani/pictures/someimage.jpg')

How to get remote image height and width in Appcelerator Titanium

I am posting sample code below please any help me
var bb_CoverPageImage = Ti.UI.createImageView({
width : '100%',
image : '',
categoryName : magazinePagesList[i].categoryName,
lengthId : magazinePagesList.length,
});
bb_CoverPageImage.image = L('Site_URL_Images') + magazinePagesList[i].imagePreviewUrl.replace(/\s/g, '%20');
coverScrollView.add(bb_CoverPageImage);
Though you have not mentioned why you need image width/height of remote image, but there can be basically 3 ways to get the width/height of any remote image.
Solution 1:
You can either ask your backend devs to provide you the image width & height as separate parameters.
Solution 2:
You can use Ti.UI.ImageView's load event to wait till your image is loaded & then you can use a code similar like this:
imageview.addEventListener('load', function(e) {
var image = imageview.toBlob();
var h = image.height;
var w = image.width;
});
This method forces that you can get width/height only after the image is loaded in ImageView.
Solution 3:
You can use web-service to download image & get further values:
var client = Ti.Network.createHTTPClient({
onload: function(e) {
var image = this.responseData;
var h = image.height;
var w = image.width;
bb_CoverPageImage.image = image;
},
onerror: function(e) {}
});
client.open("GET", magazinePagesList[i].imagePreviewUrl);
client.send();

KeystoneJS Cloudinary image upload

I am using the latest version of KeystoneJS and have a form working to add a record to the database.
I'm having trouble getting image uploads to work.
My model conatains:
heroImage: { type: Types.CloudinaryImage, autoCleanup : true },
My form includes:
<input type="file" accept="image/*" id="heroImage" name="heroImage_upload" className='field-upload'>
and my middleware for saving the form simply includes:
view.on('post', {action: 'save'}, function(next)
{
var newProperty = new Property.model(req.body);
console.log(newProperty);
newProperty.save(function(err, body)
{});
});
which works great for all field's except the file upload.
I've tried adding:
newProperty.heroImage = req.files['heroImage'];
which leaves heroImage as null.
I also tried creating a cloudinaryImage but this causes an error:
var img = new CloudinaryImage(req.files['heroImage']);
It all works fine when I use the KeystoneJS admin dashboard to upload images. Can someone please explain how I should use the cloudinaryImage field type in my own form?
Thanks
Not sure if this will help, but there is a note at the bottom of the docs:
http://keystonejs.com/docs/database/#fieldtypes-cloudinaryimage
"Remember that if you are uploading images to a CloudinaryImage field using an HTML form, you need to specify enctype="multipart/form-data" in your form tag."
Have you included that in your form?
Update:
So, the following should work, assuming your model is called MyModel, and your form data uses the same object keys as your model. (i.e. the image for your heroImage field should be provided as heroImage in the POST data).
var MyModel = keystone.list('MyModel');
view.on('post', {action: 'save'}, function(next)
{
var item = new MyModel.model();
data = req.body;
item.getUpdateHandler(req).process(data, function(err) {
// Handle error
}
}
Keystone should then handle all the specific cloudinary stuff internally.
Here is a way to do it with cloudinary.v2
untested keystone
cloudinary.v2.uploader.upload(base64_file_data, (err, result) => {
var newMyModel = new MyModel.model(model_data);
newMyModel.image = result;
let updater = newMyModel.getUpdateHandler(req);
updater.process(newMyModel, {
fields: image
}, err => {...})
})
tested mongoose
cloudinary.v2.uploader.upload(base64_file_data, (err, result) => {
var newMyModel = new MyModel.model(model_data);
newMyModel.image = result;
newMyModel.save(err => {...})
})