How long does Image.prefetch actually cache the image? - image

When testing on the iOS Simulator I seem to be downloading the image every time the app is opened. Is this the intended behavior?
The three images are prefetched initially, and the cache is used whenever I reference that URI but as soon as I reload the app everything seems to reset.
Here are some snippets of how I'm using it inside my component.
prefetchImages(images) {
let p = [];
images.map((url) => {
p.push(Image.prefetch(url).then(() => {
console.log('image prefetched:', url);
}));
});
return Promise.all(p);
}
this.prefetchImages([
'http://domain.com/myimg1.jpg',
'http://domain.com/myimg2.jpg'
])).then((a) => {
console.log('all images have been prefetched');
});
I would just like to know whether or not the images are meant to be cached even after the app is relaunched.
Ideally I'd like to download some assets once and have them persist to disk for a sensible period.
Does Image.prefetch check HTTP Status Codes behind the scenes? I'm not sure how to log network requests through the simulator to see. I wonder if it receives a 304 Not Modified when the app is relaunched, or whether it's always 200. Any help appreciated.

Related

React native app loads url images slowly when opened the first time or when all data cleared

I have a react native app where in the home page I need to fetch the settings and then set the image as banner as per the response of settings. Until the settings is fetched, I use local image to display as banner.
My problem here is that when I install the app for the first time, after the settings are fetched it takes quite some time (3-4 seconds for the image to load, images are of some 300 kbs, they're jepeg if it matters). I tried firing onLoadStart and onLoadEnd in the Image component and logging the statements. They have quite some time lag between them. It only occurs on the first time only/or when I clear all data from settings in memory. The next time I launch the app the image seems to have only some 10s miliseconds between the onLoadStart and onLoadEnd and images show up without any delay.
SOme code snippets are:
<ImageBackground
defaultSource={require('../../assets/homebanner.jpg')}
onLoadStart={() => { console.log('loading started'); }}
onLoadEnd={() => { console.log('loaded'); this.setState({ bannerImageLoaded: true }) }}
source={this.state.settingsLoaded && this.state.bannerImageLoaded
? { uri: this.state.settings.bannerImageUrl }
: require('../../assets/homebanner.jpg')}
style={{ height: width / 2.5, width: width }} />
Here I have used defaultSource hoping that it would load before the uri image is actually loaded but this doesnt seem to make any difference. I also tried, setting a state variable bannerImageLoaded as true at the onLoadEnd event and applied logic as seen in the code.
Still, it does not make any difference and there are a blank white boxes at the very first load of the app which makes it look bad. How can I manage this??
I have heard about react-native-fast-image but dont want to use it as once the app is installed, it doesnt show any trouble the second time.
Please guide me through this.

Xamarin - how to reset image cache for a specific image

In my Xamarin app I upload a new "user profile" image on the server, then I try to update the image with the new version of the image (Noticed that the image uri is the still the same).
There is an image cache provided by Xamarin, I need to invalidate it to force the image to reload from the server. But it seems that the Image cache cannot be invalidated ! I find no solution !
I have try several solutions, but find no way ! Even when I restart the application I get the old version of the image.
I have try some stuffs like this :
(MediaImageSource as UriImageSource).CacheValidity = new TimeSpan(-1);
FFImageLoading.Forms.CachedImage.InvalidateCache(MediaImageSource, FFImageLoading.Cache.CacheType.All, true);
FFImageLoading.ImageService.Instance.InvalidateCacheAsync(FFImageLoading.Cache.CacheType.All);
But nothing work, any idea is welcome ? Thx
I do the following:
// this.Img is the FFImageLoading.CachedImage in my view
var source = this.Img.Source as FileImageSource;
// Reset cache using the global instance (the key is the file name, I assume it is the uri for UriImageSource)
await ImageService.Instance.InvalidateCacheEntryAsync( source.File, CacheType.All, true );
// Reassign the image source (since the binding has not changed per se, the UI may miss the change otherwise)
this.Img.Source = new FileImageSource(...);
This reloads the image and FFImageLoading even does a nice fade animation when it changes.
There is actually a static method in CachedImage that accepts any kid of ImageSource, so there is no need to guess the key:
FFImageLoading.Forms.CachedImage.InvalidateCache(myImageSource, CacheType.All, true);

Preloading HTML5 video keeps connection opened

I am working in a web application that provides some (html5 compatible) videos to the user. I am using videojs to show those videos with the "preload" attribute set to "auto".
I am aware that browsers usually only load a portion of the video and that is ok for me. The problem is that it keeps the connection opened with the backend (spring-boot) that is dispatching the video by writing to the OutputStream:
while ((read = input.read(buffer)) > 0) {
output.write(buffer, 0, read); // once video is preloaded, it keeps waiting here
output.flush();
}
After 1 min, if the user doesn't hit the play button, it throws a ClientAbortedException: java.net.SocketTimeoutException.
Is there any way to make the browser close the connection once the preload has finished? (Note that for our system, it is important to close the InputStream as soon as possible if it is not being used).
Yes, I agree. This is an issue.
The sugestion below only will work if you are using playlist and segments, like HLS and DASH.
If you are playing static files (vod) and its segments are cached on the browser's cache, you can restart the player using a set timeout function and reload all settings again, replacing the preload attribute with "none", on the ready event. So, you can control the cache in seconds that you want.
var stopcache = true;
// when ready, cache segments by 5 seconds and restart player
player.on('ready',function(){
setTimeout(function() {
if (stopcache) {
stopcache = false; // avoid repeat
player.preload('none'); // or false if API allows
player.autoplay(false);
player.src('');
player.src({
type:'application/x-mpegURL',
src:'//example.com/hls/stream.m3u8'
});
}
}, 5000);
});
// avoid player reload if user played the file
player.on('play',function(){ stopcache = false; });
This is just a sugestion, I didn't try it but I believe that it will work because the playlist and segments are cached by the browser (vod). I use the same technique when playing live videos, reloading the url when user press play after pause, forcing the player starts from the actual live segment.

Node.js: image resizing without ImageMagick

I'm developing a web app on Node.js (+ express 4) where users can set their profile image by uploading it to the server. We already limit the file mimetype and max filesize, so the user can't upload more than 200KB png or jpeg images.
The problem is we'd like to resize (serverside) the uploaded image resolution to 200x200 to improve page loading and saving space on disk. After some research, all answers pointed to using any module based on ImageMagick or GraphicsMagick.
However, having to install ImageMagick/GraphicsMagick to do a simple image resizing seems too overkill for me, so, is there any other solution other than this for Node.js?
Edit: I've changed the accepted solution to sharp as the previous solution (lwip) is no longer maintained. Thanks for all your feedback!
I would vote for sharp:
sharp('input.jpg')
.resize(200, 200)
.toFile('ouput.jpg', function(err) {
// output.jpg is a 200 pixels wide and 200 pixels high image
// containing a scaled and cropped version of input.jpg
});
It's fast, typically 6x faster than the fastest imagemagick-based node bindings, and runs in very little memory, perhaps 10x less. sharp links to the libvips image library directly, there is no shelling out to an external program, and the library itself is faster and more efficient than *magick at this task. It supports useful things like stream, buffer and filesystem input and output, colour management, transparency, promises, overlays, WebP, SVG, and more.
As of sharp 0.20, npm will automatically download complete pre-compiled binaries on most platforms, so there's no need for node-gyp. Just enter:
npm install sharp
or:
yarn add sharp
And off you go.
I have recently started developing an image processing module for NodeJS without any runtime dependencies (read why). It's still at early stages, but already usable.
What you are asking for would be done as follows:
image.resize(200, 200, function(err, image){
// encode resized image to jpeg and get a Buffer object
image.toBuffer('jpg', function(err, buffer){
// save buffer to disk / send over network / etc.
});
});
More info at the module's Github repo.
Take a look at lwip : https://github.com/EyalAr/lwip
Very simple and easy to use
npm install lwip
and then in your node code,
// obtain an image object:
require('lwip').open('image.jpg', function(err, image){
// check err...
// define a batch of manipulations and save to disk as JPEG:
image.batch()
.scale(0.75) // scale to 75%
.rotate(45, 'white') // rotate 45degs clockwise (white fill)
.crop(200) // crop a 200X200 square from center
.blur(5) // Gaussian blur with SD=5
.writeFile('output.jpg', function(err){
// check err...
// done.
});
});
I have successfully implemented this in my file uploader and it works like a charm.
There is a good image manipulation library written entirely in JavaScript, without dependencies to any other libraries, Jimp. https://github.com/oliver-moran/jimp
Example usage:
var Jimp = require("jimp");
// open a file called "lenna.png"
Jimp.read("lenna.png", function (err, lenna) {
if (err) throw err;
lenna.resize(256, 256) // resize
.quality(60) // set JPEG quality
.write("lena-small.jpg"); // save
});
sharp has enjoyed some popularity recently, but it’s the same idea as *Magick bindings.
However, having to install ImageMagick/GraphicsMagick to do a simple image resizing seems too overkill for me
Image resizing is anything but simple. The JPEG format is particularly complex, and there are several ways to scale graphics with results of varying quality, few of them easily implemented. Image processing libraries exist to do this job, so if there’s no other reason why you can’t install them, go for it.
According to images-manipulation-performance, Canvas is 2.3 times faster than ImageMagick.
Sample results:
Library
Imges per Second
Minimum Free Memory
sharp.js
9.501
929Mb
canvas.js
8.246
578Mb
gm.js
4.433
791Mb
gm-imagemagic.js
3.654
804Mb
lwip.js
1.203
54Mb
jimp.js
0.445
82Mb
If you don't need a large image, you can resize it on the client side before uploading it:
Reading files in JavaScript using the File APIs
Image resizing client-side with javascript before upload to the server
Many users might have a good picture of themselves from a smartphone, and many of them are over 200kB. Note that client-provided data is not to be trusted, so server-side checks still apply.
I was using lwip (as previously suggested by arvind) but switched to png-crop. It seems to work a little faster for me (Win 8.1 x64, Node v0.12.7). The code in the repo looks incredibly lightweight, and operationally it's simple to use.
var pngcrop = require('png-crop');
var config = {left: 10, top: 100, height: 150, width: 150};
pngcrop.crop('cats.png','cats-cropped.png',config);
Of course, it'll only do png files...
Sharp work very well and is easy to use with streams, work like a charm, but you need to compile it with the node version, this is a downside to it.
I was using Sharp for image processing, with an image from an AWS S3 bucket and worked perfectly, but I had to use another module. GM didn't work for me, but Jimp worked very good!
You have to pay attention to the path of the written picture, it might give you some errors if you start the path with a "/".
This is how I used Jimp in nodeJS:
const imageUrl = `SOME_URL`;
let imgExported = 'EXPORTED_PIC.png';
Jimp.read(imageUrl)
.then(image => {
image
.resize(X, Y)
.write(`tmp/`+ imgExported, err => {
if(err)
console.error('Write error: ', err);
else { ... // don't forget to put a callback() } }
});
Also watch out for the order of execution, put a callback so other things don't happen when you don't want to. Tried using "await" for the Jimp.read() but it didn't do the job well.
You can do this using jimp (node_module)
Local Write:
Jimp.read(path) // this can be url or local location
.then(image=> {
image
.resize(size, Jimp.AUTO) // jimp.AUTO automatically sets the width so that the image doesnot looks odd
.write('path-to-save');
})
.catch(err => {
console.log(err);
});
To upload to s3 or where ever you like.
Jimp.read(urls) // this can be url or local location
.then(image=> {
image
.resize(size, Jimp.AUTO) // jimp.AUTO automatically sets the width so that the image doesnot looks odd
.getBase64(Jimp.AUTO, (err, res) => {
const buf = new Buffer(
res.replace(/^data:image\/\w+;base64,/, ""),
"base64"
);
var data = {
Key: key,
Bucket: bucket,
Body: body,
ContentEncoding: "base64",
ContentType: "image/jpeg"
};
s3.putObject(data, function(err, data) {
if (err) {
throw err;
} else {
console.log("succesfully uploaded the image!");
}
});
});
})
.catch(err => {
console.log(err);
});
I like resize-img library for its simplicity.
const fs = require('fs');
const resizeImg = require('resize-img');
(async () => {
const image = fs.readFileSync('unicorn.png');
const newImage = await resizeImg(image, { width: 128, height: 128 });
fs.writeFileSync('unicorn-128x128.png', newImage);
})();
Implemented image resize using Google Drive API v3. This method is recommended for Google Apps Script to insert images into Google Sheets.
Algorithm:
Upload image to the Google Drive folder.
Get image thumbnail public URL.
Replace 'resize' parameter in the URL with necessary width and/or height. (Default thumbnail size is 220px).
Download resized thumbnail from the Google Drive.
See example here:
https://github.com/dobromyslov/google-drive-utils/blob/511c44c2c48862b47c60038423b7f71bf1d28f49/src/index.ts#L150
And beware of GDrive quotas:
queries per day: 1000000000
queries per 100 sec per user: 1000
queries per 100 sec: 10000

PhantomJS Render Page Fonts

I am using PhantomJS to take screenshots of webpages.
I have seen other posts about problems with #font-face, but the fonts on my pages are rendering correctly. The only issue I am having is that each time I take a screenshot, the fonts show slightly differently from the previous screenshot. So although they are rendering correctly, they are inconsistent in their appearance on the screenshot.
I have tried a number of fixes, most based around the assumption that it is something to do with the screenshot being taken before the page is ready, but this doesn't seem to be the issue. For example, I have delayed the screenshot being taken so that the font has time to load, and be rendered, but this doesn't solve the problem.
I have tried binding to various page events, but again, no luck.
I have attached screenshots to show the difference. The problem is, I need the rendered screenshot to be accurate in the context of what I am using it for.
As a note, I have tried CasperJS as well (knowing that it is based on PhantomJS so not expecting it to be any different).
Have you tired watching the DOM for font related events? You can also try taking a screenshot every X seconds, producing a moment-moment overview (note that this will produce a lot of empty and duplicate images. If that's a problem, try simply setting a min file size or checking to see if two files have the same size).
var page = require('webpage').create();
page.open("http://www.slashdot.org", function (status) {
phantom.exit();
});
var i = 0;
setInterval(function() {
i += 1;
page.render("/tmp/screenshots/screenshot-" + i + ".png");
}, 50);
You can delay your screenshot using the following method :
var page = new WebPage();
page.open('http://stackoverflow.com/', function (status) {
just_wait();
});
function just_wait() {
setTimeout(function() {
page.render('screenshot.png');
phantom.exit();
}, 2000);
}
Here, your screenshot is taken 2000ms after your page is loaded.
Set the delay accordingly to allow the page to completely load all resources.

Resources