I am attempting to make a an image pre loader. There is an array of low res images and an array of high res images. I create a new image object and run through a loop to preload these images. I then use a line of Jquery to set the background to use a low resolution image until the high resolution object has loaded, and when that loads I use another line of Jquery to switch the background to use this high resolution image.
The problem I am having is that the code skips the low resolution background setting and loads the high res image.
Here is the code:
// Low res image array
var lowres = ["image1lr.jpg", "image2lr.jpg", "image3lr.jpg", "image4lr.jpg"];
// Full res image array
var images = ["image1.jpg", "image2.jpg", "image3.jpg", "image4.jpg"];
// Low res image path
var lowresimagepath = "url(images/rotate-background/low_res/";
// Full res image path
var imagepath = "url(images/rotate-background/";
// Counter
var i = 0;
// Image preloading
for(i=0; i<=images.length; i++)
{
// Create object
imageObj = new Image();
imageObj.src = imagepath + images[i] + ')';
}
//Generate random number
var rannum = Math.floor(Math.random() * images.length);
//Set background image to random low res image
$(".bg_home").css({'background-image': lowresimagepath +lowres[rannum]+')'});
//Once image objects are loaded switch to high res image
imageObj.onLoad= function(){
$(".bg_home").css({'background-image': imagepath + images[rannum] + ')'});
}
The Image objects' src is a css property. It should just be the URL
imageObj.src = imagepath + images[i] + ')'; //Generates "url('whatever');"
//It can't be that, must just be the path.
In my experience image.onLoad isn't very reliable. There are different cases where it doesn't work, e.g. IE or cached images.
I'd take a look at https://github.com/desandro/imagesloaded
I've used that library and it works great.
As for your code, it seems to be rather invalid:
// Low res image array
var lowres = ["image1lr.jpg", "image2lr.jpg", "image3lr.jpg", "image4lr.jpg"];
// Full res image array
var images = ["image1.jpg", "image2.jpg", "image3.jpg", "image4.jpg"];
// Low res image path
var lowresimagepath = "images/rotate-background/low_res/";
// Full res image path
var imagepath = "images/rotate-background/";
//Generate random number
var rannum = Math.floor(Math.random() * images.length);
for(var i = 0; i < images.length; i++) {
var image = new Image();
image.src = imagepath + images[i];
if(i == rannum) {
//Set background image to random low res image
$(".bg_home").css({'background-image': 'url(' + lowresimagepath +lowres[i]+')'});
//Once image objects are loaded switch to high res image
iamge.onLoad= function() {
$(".bg_home").css({'background-image': 'url(' + imagepath + images[i] + ')'});
};
}
}
That's working under the assumption that your idea is to have a a single random image added to your background, while all images are loaded in the background.
You're code has lots of problems, here is a clean version I've made, but its not tested.
(function(){ // prevents name conflicting with other scripts
var BASE_PATH_LOW_RES = "images/rotate-background/low_res/",
BASE_PATH_HIGH_RES = "images/rotate-background/"; // since these are constants its better to use capitalized letters
var lastLoadedIndex = 0, // you must ensure all images are loaded and its hard to preload them in parallel
randomIndex = Math.floor(Math.random() * images.length),
images = [
{low: "image1lr.jpg", high: "image1.jpg"},
{low: "image2lr.jpg", high: "image2.jpg"},
{low: "image3lr.jpg", high: "image3.jpg"},
{low: "image4lr.jpg", high: "image4.jpg"}
];
var onComplete = function() {
$(".bg_home").css({'background-image': 'url(' + BASE_PATH_HIGH_RES + images[randomIndex] + ')'});
}
var loadNext = function(){
if(lastLoadedIndex == images.length) { // all images has been preloaded
onComplete();
} else {
var imgTemp = new Image();
imgTemp.src = BASE_PATH_HIGH_RES + images[lastLoadedIndex++].high;
imgTemp.onLoad = loadNext;
}
}
$(".bg_home")
.css({'background-image': 'url(' + BASE_PATH_LOW_RES + images[randomIndex].low + ')'});
loadNext(); // start to preload every image one after another
})();
Related
I have tried to create simple chrome extension to help myself download manga to ebook.
How it works - i get img sources as a string separated by space from website to extension side and split that into the table.
And now my function attached below should check every single image(page) of manga, redraw it to canvas, and recreate it again to raw img(cause its should be like that for pdfjs).
My problem:
console show its skips to last file
my for loop ends faster than recreate process lasts - it saves 3kb pdf (propably empty
manual saving PDF file from console still not works (file is bigger - +-size of image, but wont starts - shows errors).
function preparedownloadPDF(imagelist){
var page = 0;
console.log(imagelist);
var doc = new jsPDF();
var imageArray = imagelist.split(" ");
console.log(imageArray);
for(var i = 0; i < imageArray.length; i++)
{
if(imageArray[i] != "")
{
pdf.getImgFromUrl(imageArray[i]);
//pdf.generatePDF();
}
}
pdf.saveFile("123.pdf")
}
var pdf = {
page: 0,
img: null,
options: {orientation: 'p', unit: 'mm', format: "custom"},
doc: new jsPDF(this.options),
getImgFromUrl: function(base_url){
this.img = new Image();
this.img.src = base_url;
console.log(this.img.src + " baseurl: "+ base_url)
this.img.onload = function () {
pdf.generatePDF();
};
},
generatePDF: function(){
//redrawing image to canvas, to later recreate this as a BASE64 string(RAW data)
var canvas = document.createElement("canvas");
canvas.width = this.img.width;
canvas.height = this.img.height;
console.log("canvas")
console.log(canvas.width + "x" + canvas.height)
canvas.getContext("2d").drawImage(this.img, 0, 0);
var image = document.createElement("img");
image.src = canvas.toDataURL();
document.body.appendChild(image);
if(this.page++ != 0)
pdf.doc.addPage();
pdf.doc.addImage(this.img, 10, 10);
},
saveFile: function(name){
this.doc.save(name)
this.page = 0;
}
}
Any tips?
#
I not attach code of validation URL,etc. I use as valid phoenix-scans pl website.
I am trying to compress images on client side using JavaScript on some low bandwidth devices and I'm currently stuck in a limbo using the HTML5 File API. I'm new to this, please bear with me if I'm missing something important.
I have some input tags which should ideally open the mobile camera, capture single image, compress and send files to the backend. Although this can be done with a single input field with multiple uploads enabled but I need the multiple image fields to segregate images based on some categories.
Here's the input boxes:
<input type="file" name="file1" id="file1" capture="camera" accept="image/*">
<input type="file" name="file2" id="file2" capture="camera" accept="image/*">...
Here's the image compression logic:
// Takes upload element id ("file1") and a maxSize to resize, ideally on a change event
window.resizePhotos = function(id, maxSize){
var file = document.getElementById(id).files[0];
// Ensuring it's an image
if(file.type.match(/image.*/)) {
// Loading the image
var reader = new FileReader();
reader.onload = function (readerEvent) {
var image = new Image();
image.onload = function (imageEvent) {
// Resizing the image and keeping its aspect ratio
var canvas = document.createElement("canvas"),
max_size = maxSize,
width = image.width,
height = image.height;
if (width > height) {
if (width > max_size) {
height *= max_size / width;
width = max_size;
}
} else {
if (height > max_size) {
width *= max_size / height;
height = max_size;
}
}
canvas.width = width;
canvas.height = height;
canvas.getContext("2d").drawImage(image, 0, 0, width, height);
var dataUrl = canvas.toDataURL("image/jpeg");
var resizedImage = dataURLToBlob(dataUrl);
$.event.trigger({
type: "imageResized",
blob: resizedImage,
url: dataUrl
});
}
image.src = readerEvent.target.result;
}
reader.readAsDataURL(file);
}
};
// Function to convert a canvas to a BLOB
var dataURLToBlob = function(dataURL) {
var BASE64_MARKER = ';base64,';
if (dataURL.indexOf(BASE64_MARKER) == -1) {
var parts = dataURL.split(',');
var contentType = parts[0].split(':')[1];
var raw = parts[1];
return new Blob([raw], {type: contentType});
}
var parts = dataURL.split(BASE64_MARKER);
var contentType = parts[0].split(':')[1];
var raw = window.atob(parts[1]);
var rawLength = raw.length;
var uInt8Array = new Uint8Array(rawLength);
for (var i = 0; i < rawLength; ++i) {
uInt8Array[i] = raw.charCodeAt(i);
}
return new Blob([uInt8Array], {type: contentType});
}
// Handling image resized events
$(document).on("imageResized", function (event) {
if (event.blob && event.url) {
document.getElementById('file1').files[0] = event.url; // --> Tried this, did not work
document.getElementById('file1').files[0].value = (URL || webkitURL).createObjectURL(event.blob); // --> Tried doing this looking at some other answers but did not work
console.log(document.getElementById('file1').files[0]); // Original file is loading fine
console.log(event.url); // Image compression is working correctly and producing the base64 data
}
});
$(window).on("load", function() {
// Resets the value to when navigating away from the page and choosing to upload the same file (extra feature)
$("#file1").on("click touchstart" , function(){
$(this).val("");
});
// Action triggers when user has selected any file
$("#file1").change(function(e) {
resizePhotos("file1", 1024)
});
});
In PHP script, I'd usually try to catch files from the POST request like:
$file1 = $_FILES["file1"]["tmp_name"];
$file2 = $_FILES["file2"]["tmp_name"];
...
But this doesn't work because it looks for the original user selected file at a tmp directory (e.g. the actual temporary file in my case is C:\xampp\tmp\php25CB.tmp )
One thing I've tried is put the input fields outside of the form tags, enabled the click behaviour using a button and created new input field with the modified data within the form like:
var newinput = document.createElement("input");
newinput.type = 'file';
newinput.name = 'file1';
newinput.files[0] = event.url;
document.getElementById('parentdiv').appendChild(newinput);
Needless to say, this had no effect and the PHP script could not identify any file.
Please guide me and suggest any changes required in the JavaScript/PHP script so I can accept the modified file and not the original user uploaded file from the input field.
You can only change a file input value with another list here is how: https://stackoverflow.com/a/52079109/1008999 (also in the example)
Using the FileReader is a waste of time, CPU, Encoding & decoding and RAM...use URL.createObjectURL instead
Don't use canvas.toDataURL... use canvas.toBlob instead
Canvas have bad compression, read earlier comment and see the jsfiddle proff...If you insist on using canvas to try and squeeze the size down then
First try to see if the image is in a reasonable size first
Compare if the pre existing image file.size is smaller than what the canvas.toBlob provides and choose if you want the old or the new one instead.
If resizing the image isn't enough have a look at this solution that change the quality until a desired file size & image aspect have been meet.
Without any testing, this is how i would have refactor your code too:
/**
* #params {File[]} files Array of files to add to the FileList
* #return {FileList}
*/
function fileListItems (files) {
var b = new ClipboardEvent('').clipboardData || new DataTransfer()
for (var i = 0, len = files.length; i<len; i++) b.items.add(files[i])
return b.files
}
// Takes upload element id ("file1") and a maxSize to resize, ideally on a change event
window.resizePhotos = async function resizePhotos (input, maxSize) {
const file = input.files
if (!file || !file.type.match(/image.*/)) return
const image = new Image()
const canvas = document.createElement('canvas')
const max_size = maxSize
image.src = URL.createObjectURL(file)
await image.decode()
let width = image.width
let height = image.height
// Resizing the image and keeping its aspect ratio
if (width > height) {
if (width > max_size) {
height *= max_size / width
width = max_size
}
} else {
if (height > max_size) {
width *= max_size / height
height = max_size
}
}
canvas.width = width
canvas.height = height
canvas.getContext('2d').drawImage(image, 0, 0, width, height)
const resizedImage = await new Promise(rs => canvas.toBlob(rs, 'image/jpeg', 1))
// PS: You might have to disable the event listener as this might case a change event
// and triggering this function over and over in a loop otherwise
input.files = fileListItems([
new File([resizedImage], file.name, { type: resizedImage.type })
])
}
jQuery($ => {
// Resets the value to when navigating away from the page and choosing to upload the same file (extra feature)
$('#file1').on('click touchstart' , function(){
$(this).val('')
})
// Action triggers when user has selected any file
$('#file1').change(function(e) {
resizePhotos(this, 1024)
})
})
Hello I am new to javascript so I apologize if this is silly however, I am creating a generator that displays a .png for each letter of the alphabet. The goal is to overlap and display multiple images inside of a div, with random positions. So far I am able to display images for each letter on top of one another by creating a random z-index, however I can not figure out how to alter the positioning to random for each picture.
I attempted to create a Math.floor random variable called randomThingTwo to alter the top positioning of the images, but this did not work.
Please help!
here is my current code:
var x,y,splitted;
function generate() {
x = document.getElementById("form1");
y = x.elements["message"].value;
var text = [y];
var joined = text.join();
var res = joined.toLowerCase();
var regexp = /[A-z]/g;
splitted = res.match(regexp);
var words = [];
judge();
}
var counter = -1;
function judge() {
if (counter < y.length) {
counter++;
art();
}
}
function art() {
img = new Image(splitted[counter] + '.png');
var picture = document.getElementById("pic");
var img = document.createElement('img');
var randomThing = Math.floor((Math.random() * 10) + 1);
console.log(randomThing);
// var randomThingTwo = Math.floor((Math.random() * 20) + 1);
img.setAttribute("src", splitted[counter]+".png");
img.style.zIndex= randomThing;
img.style.position= "absolute";
// img.style.position.marginTop = randomThingTwo;
img.setAttribute("width", "304");
img.setAttribute("width", "328");
picture = document.getElementById("pic").appendChild(img);
setTimeout(function () {
judge();
}, 100);
}
When setting properties that way, you need to include 'px' afterward, otherwise it doesn't know what units to use with the number you're passing. Try changing the second line to img.style.marginTop = randomThingTwo + 'px';
I have an browse area in which the user browses and enters an image.
I need to know the height and width of the image to limit it.
var img= IWDatacapture.getItem("banners/mobile-banner/mobile-content[1]/main-image");
var params = new Object();
if(img.length==undefined)
{
var savnm = IWDatacapture.getWorkarea() + img.getValue();
params.savnm = savnm;
var server = window.location.hostname;
IWDatacapture.callServer("http://"+server+"/iw-bin/iw_cgi_wrapper.cgi/getFileSize.ipl", params,true);
}
After I make a server call, I didn't understand how to access the image's attributes.
Try something like:
// Get the full image URL:
var img = IWDatacapture.getItem("banners/mobile-banner/mobile-content[1]/main-image");
// Note: I'm not sure if the following will generate the correct URL, but it should be close. Double check the "workarea" part.
var fullImagePath = "/iw/cci/meta/no-injection/iw-mount/" + IWDatacapture.getWorkarea() + img.getValue();
// Then load the image in the browser to get the dimensions:
var image = new Image();
image.onload = function(){
var height = image.height;
var width = image.width;
// Whatever you want to do
}
image.src = fullImagePath;
I'm trying to add images to canvas strictly, but images are added randomly.
What's the problem?
Here is my simple code.
var canvas = new fabric.Canvas("preview");
var imgs = ['bgBottom','bgTop', 'bgLevel', 'bgCircle'];
for (var i=0; i<imgs.length;i++){
var url = imgs[i]+'.png';
fabric.Image.fromURL(url, function (oImg) {
canvas.add(oImg)
})
}
fabric.Image.fromURL loads the image in the background and runs the anonymous function you pass to it once image load is complete which adds it to the canvas. The order that the browser loads the images will vary and you can't rely on it being in a specific order.
Check out this jsfiddle that shows loading an array of images and making sure they're displayed in a set order. This works by adding the image to the canvas before it's loaded; it just doesn't render until the image is available to be displayed.
The code from the jsfiddle:
var SelfLoadingImage = fabric.util.createClass(fabric.Object, {
initialize: function(src) {
this.image = new Image();
this.image.src = src;
this.image.onload = (function() {
this.width = this.image.width;
this.height = this.image.height;
this.loaded = true;
this.setCoords();
this.fire('image:loaded');
canvas.renderAll();
}).bind(this);
},
_render: function(ctx)
{
if (this.loaded) {
ctx.drawImage(this.image, -this.width / 2, -this.height / 2);
}
}
});
var canvas = new fabric.Canvas("preview");
var imgs = [
'http://icons.iconarchive.com/icons/fasticon/ifunny/128/dog-icon.png', // dog
'http://33.media.tumblr.com/avatar_14ee6ada72a4_128.png', // cat
'http://upload.wikimedia.org/wikipedia/commons/b/bc/Nuvola_devices_mouse.png' // mouse
];
for (var i=0; i<imgs.length;i++){
var url = imgs[i];
var img = new SelfLoadingImage(url);
canvas.add(img);
}