Related
I'd like to duplicate an image on a first slide to another slide using Google Slide App Scripts.
For this, I get the data inside this image as a blob before inserting the blob in the next slide. The issue is that even when I set top, left, width and height values, I don't understand how I can keep the same scale (in my case I've cropped the image).
This is my code:
function myFunction() {
var slides = SlidesApp.getActivePresentation().getSlides();
var blop, width, height;
slides[0].getImages().forEach(function(image){
if(image.getTitle() == "image") {
blop = image.getBlob()
left = image.getLeft()
top = image.getTop()
width = image.getWidth()
height = image.getHeight()
}
});
slides[1].insertImage(blop, left, top, width, height)
}
You can see how it looks here:
https://docs.google.com/presentation/d/1LlyHNbjcANWspPvJZedW9vgx9c9JHRD-kWOvXkwrDNo/edit?usp=sharing (viewer mode)
When I try to apply transformation the result is really different...
Modification points:
Unfortunately, in the current stage, it seems that at Slides Service and Slides API, the crop of image cannot be used. This has already been reported. Ref So, I thought that in your situation, it might be required to duplicate the image including the crop information.
In your script, insertImage(blobSource, left, top, width, height) is used. In this case, blob is the original image. By this, the crop information is not included. I thought that this might be the reason of your issue.
In this case, I would like to propose to use insertImage(image). The document of this method says as follows.
Inserts a copy of the provided Image on the page.
When above points are reflected to your script, it becomes as follows.
Modified script:
function myFunction() {
var slides = SlidesApp.getActivePresentation().getSlides();
slides[0].getImages().forEach(function(image){
if(image.getTitle() == "image") {
slides[1].refreshSlide();
slides[1].insertImage(image);
slides[1].refreshSlide();
}
});
}
Result:
When above modified script is used for your sample Google Slides, the following result is obtained.
When I tested this modified script, I noticed an important point. When this script is used, it seems that refreshSlide might be required to be used. Because I confirmed that when refreshSlide is not used, the image without including the crop and coordinate information is copied.
And also, In my environment, at most cases, the script worked fine. But, I noticed that when I tested several times, even when refreshSlide is used, there is the case that the image without including the crop and coordinate information is copied. So I thought that insertImage(image) might have a bug.
If in your environment, you have the same situation, how about reporting this to Google issue tracker? Ref
References:
insertImage(blobSource, left, top, width, height)
insertImage(image)
refreshSlide()
Note that I'm not asking how to make a div the size of the "window" or "viewport" for which there are plenty of existing questions.
I have a web page of some height and width, and I'd like to add an empty, top-level div (i.e., not one containing the rest of the page) with a size exactly equal to the page's height and width. In practice, I also want it to be at least the size of the viewport.
I know I can do a one-time calculation of the height and width in JavaScript:
var height = Math.max(document.body.scrollHeight,
document.documentElement.clientHeight);
var width = Math.max(document.body.scrollWidth,
document.documentElement.clientWidth);
But this value can change based on images loading, or AJAX, or whatever other dynamic stuff is going on in the page. I'd like some way of locking the size of the div at the full page size so it resizes dynamically and on-demand.
I have tried something like the following:
function resetFakeBg() {
// Need to reset the fake background to notice if the page shrank.
fakeBg.style.height = 0;
fakeBg.style.width = 0;
// Get the full page size.
var pageHeight = Math.max(document.body.scrollHeight,
document.documentElement.clientHeight);
var pageWidth = Math.max(document.body.scrollWidth,
document.documentElement.clientWidth);
// Reset the fake background to the full page size.
fakeBg.style.height = pageHeight + 'px';
fakeBg.style.width = pageWidth + 'px';
}
// Create the fake background element.
fakeBg = setFakeBgStyle(document.createElement('div'));
document.body.appendChild(fakeBg);
// Keep resizing the fake background every second.
size_checker_interval = setInterval(resetFakeBg, 1000);
Limitations
This is for a Chrome extension, and I'd like to limit my modification of the page to adding this single div. This means that adding CSS to modify the height and width of the html and/or body tags is undesirable because it might have side-effects on the way the rest of the page is rendered.
In addition, I do not want to wrap the existing page in the div because that has the potential to break some websites. Imagine, for example, a site styled with the CSS selector body > div. I'd like my extension to break as few websites as possible.
WHY OH WHY WOULD I NEED TO DO THIS?
Because some people like to hold their answers hostage until they're satisfied that I have a Really Good Reason™ for wanting to do this:
This is for an accessibility-focused Chrome extension that applies a CSS filter across an entire page. Recent versions of Chrome (>= 45) do not apply CSS filters to backgrounds specified on the <html> or <body> tag. As a result, I have chosen to work around this limitation by copying the page's background onto a div with a very negative z-index value, so that it can be affected by the page-wide CSS filter. For this strategy to work, the div needs to exactly imitate the way the page background would appear to a user—by being the exact size of the document (and no larger) and at least filling the viewport.
setInterval() is your best friend in cases like this where you want the .height() and .width() of an element to be asynchronously specified all the time to something that can be dynamicly altered by user input and DOM tree changes. It is what I dub as a "page sniffer", and arguably, works better than $(document).ready if you are working in multiple languages (PHP, XML, JavaScript).
Working Example
You should get away with setting the width and height in the window resize function, you might wanna add it in a load function as well, when all data/images are loaded.
just add width=100%
e.g;-
Hello World
I think you must do it like this:
...
<body>
<script>
function height()
{var height = Math.max(document.body.scrollHeight,
document.documentElement.clientHeight);}
function width()
{var width = Math.max(document.body.scrollWidth,
document.documentElement.clientWidth);}
</script>
<div height="height()" width="width()">
</div>
</body>
...
I have a simple code to set the height of one column, id="colLeft" to the height of another column, id="colRight", with no padding or borders:
<script type="text/javascript">
var colLeft = document.getElementById("colLeft");
var colRight = document.getElementById("colRight");
colLeft.style.height = colRight.offsetHeight + "px";
</script>
This code works fine on desktop and iPad, but on my android phone the results are rather unpredictable. Sometimes colLeft is much longer, sometimes colRight, and sometimes it works the way it should. I have tried it on two browsers with the same results.
I have also tried it inside window.onload=function(){...} which gave slightly less variance in the results, but is still not perfect.
Thanks for any help.
You can read a bit about offsetHeight here. The important thing to note is that if the content is larger than the viewable area the browser might do funny things with non-scrolling elements. Because this is a phone browser, I am guessing that the issue is that it is miscalculating the column height because it doesn't deal with scrolling elements correctly.
How do you set the height of the first column? If it has a valid height set in the style sheet you could easily do something like this:
colLeft.style.height = colRight.style.height;
If that doesn't work, you may need to set the column height based on the browser window size with something like:
colLeft.style.height = colRight.style.height = (window.innerHeight - 10) + "px";
Or something similar.
I'm trying to build an image gallery in Safari that mimics the iPad photo app. It works perfectly, except that once I load more than 6MB or so worth of images either by adding them to the DOM or creating new Image objects, new images either stop loading or the browser crashes. This problem is widespread enough (with everyone else hitting up against the same limit) that I've ruled out my Javascript code as the culprit.
Given that you can stream much more than a few MB in a element or through the in-browser media player, this limit seems unnecessary, and there should be some kind of workaround available. Perhaps by freeing up memory or something else.
I also came across this reference for UIWebView.
"JavaScript allocations are also limited to 10 MB. Safari raises an exception if you exceed this limit on the total memory allocation for JavaScript."
Which matches what I'm seeing fairly well. Is it possible to deallocate objects in Javascript, or does Safari/UIWebView keep a running total and never lets go? Alternately, is there any workaround to load in data another way that doesn't eat up this 10MB?
Update: I think there's an even easier way to do this, depending on your application. Instead of having multiple images, if you simply have one <img> element or Image object (or maybe two, like a 'this' image and a 'next' image if you need animations or transitions) and simply update the .src, .width, .height and so on, you should never get near the 10MB limit. If you wanted to do a carousel application, you'd have to use smaller placeholders first. You might find this technique might be easier to implement.
I think I may actually have found a work-around to this.
Basically, you'll need to do some deeper image management and explicitly shrink any image you don't need. You'd normally do this by using document.removeChild(divMyImageContainer) or $("myimagecontainer").empty() or what have you, but on Mobile Safari this does absolutely nothing; the browser simply never deallocates the memory.
Instead, you need to update the image itself so it takes up very little memory; and you can do that by changing the image's src attribute. The quickest way I know of to do that is to use a data URL. So instead of saying this:
myImage.src="/path/to/image.png"
...say this instead:
myImage.src="data:image/gif;base64,AN_ENCODED_IMAGE_DATA_STRING"
Below is a test to demonstrate it working. In my tests, my large 750KB image would eventually kill the browser and halt all JS exectution. But after resetting src, I"ve been able to load in instances of the image over 170 times. An explanation of how the code works is below as well.
var strImagePath = "http://path/to/your/gigantic/image.jpg";
var arrImages = [];
var imgActiveImage = null
var strNullImage = "data:image/gif;base64,R0lGODlhEAAOALMAAOazToeHh0tLS/7LZv/0jvb29t/f3//Ub//ge8WSLf/rhf/3kdbW1mxsbP//mf///yH5BAAAAAAALAAAAAAQAA4AAARe8L1Ekyky67QZ1hLnjM5UUde0ECwLJoExKcppV0aCcGCmTIHEIUEqjgaORCMxIC6e0CcguWw6aFjsVMkkIr7g77ZKPJjPZqIyd7sJAgVGoEGv2xsBxqNgYPj/gAwXEQA7";
var intTimesViewed = 1;
var divCounter = document.createElement('h1');
document.body.appendChild(divCounter);
var shrinkImages = function() {
var imgStoredImage;
for (var i = arrImages.length - 1; i >= 0; i--) {
imgStoredImage = arrImages[i];
if (imgStoredImage !== imgActiveImage) {
imgStoredImage.src = strNullImage;
}
}
};
var waitAndReload = function() {
this.onload = null;
setTimeout(loadNextImage,2500);
};
var loadNextImage = function() {
var imgImage = new Image();
imgImage.onload = waitAndReload;
document.body.appendChild(imgImage);
imgImage.src = strImagePath + "?" + (Math.random() * 9007199254740992);
imgActiveImage = imgImage;
shrinkImages()
arrImages.push(imgImage);
divCounter.innerHTML = intTimesViewed++;
};
loadNextImage()
This code was written to test my solution, so you'll have to figure out how to apply it to your own code. The code comes in three parts, which I will explain below, but the only really important part is imgStoredImage.src = strNullImage;
loadNextImage() simply loads a new image and calls shrinkImages(). It also assigns an onload event which is used to begin the process of loading another image (bug: I should be clearing this event later, but I'm not).
waitAndReload() is only here to allow the image time to show up on the screen. Mobile Safari is pretty slow and displaying big images, so it needs time after the image has loaded to paint the screen.
shrinkImages() goes through all previously loaded images (except the active one) and changes the .src to the dataurl address.
I'm using a file-folder image for the dataurl here (it was the first dataurl image I could find). I'm using it simply so you can see the script working. You'll probably want to use a transparent gif instead, so use this data url string instead: data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==
The 6.5MB(iPad) / 10MB(iPhone) download limits are calculated based on the number of image elements used to set an image through its src property. Mobile safari doesn't seem to differentiate images loaded from cache or via the network. It also doesn't matter whether the image is injected into the dom or not.
The second part to the solution is that mobile safari seems to be able to load an unlimited number of images via the "background-image" css property.
This proof of concept uses a pool of precacher's which set the background-image properties once successfully downloaded. I know that it's not optimal and doesn't return the used Image downloader to the pool but i'm sure you get the idea :)
The idea is adapted from Rob Laplaca's original canvas workaround http://roblaplaca.com/blog/2010/05/05/ipad-safari-image-limit-workaround/
<!DOCTYPE html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>iPad maximum number of images test</title>
<script type="text/javascript">
var precache = [
new Image(),
new Image(),
new Image(),
new Image()
];
function setImage(precache, item, waiting) {
precache.onload = function () {
item.img.style.backgroundImage = 'url(' + item.url + ')';
if (waiting.length > 0) {
setImage(precache, waiting.shift(), waiting);
}
};
precache.src = item.url;
}
window.onload = function () {
var total = 50,
url = 'http://www.roblaplaca.com/examples/ipadImageLoading/1500.jpg',
queue = [],
versionUrl,
imageSize = 0.5,
mb,
img;
for (var i = 0; i < total; i++) {
mb = document.createElement('div');
mb.innerHTML = ((i + 1) * imageSize) + 'mb';
mb.style.fontSize = '2em';
mb.style.fontWeight = 'bold';
img = new Image();
img.width = 1000;
img.height = 730;
img.style.width = '1000px';
img.style.height = '730px';
img.style.display = 'block';
document.body.appendChild(mb);
document.body.appendChild(img);
queue.push({
img: img,
url: url + '?ver=' + (i + +new Date())
});
}
//
for (var p = 0; p < precache.length; p++) {
if (queue.length > 0) {
setImage(precache[p], queue.shift(), queue);
}
}
};
</script>
</head>
<body>
<p>Loading (roughly half MB) images with the <strong>img tag</strong></p>
</body>
</html>
So far I've had luck using <div> tags instead of <img> tags and setting the image as the div's background-image.
All in all, it's crazy. If the user is making an affirmative request for more image content, then there's no reason why Safari shouldn't allow you to load it.
I've had luck starting with the suggestion of Steve Simitzis, and Andrew.
My project:
PhoneGap-based app with 6 main sections, and about 45 subsections which have a jquery cycle gallery of between 2 and 7 images, each 640 x 440 (215+ images altogether). At first I was using ajax to load page fragments, but I've since switched to a one-page site, with all sections hidden until needed.
Initially, after going through about 20 galleries, I was getting memory warning 1, then 2, then the crash.
After making all the images into divs with the image applied as a background, I could get through more galleries (about 35) in the app before a crash, but after going to previously visited galleries, it would eventually fail.
The solution that seems to be working for me, is to store the background image URL in the div's title attribute, and setting all of the background images to be a blank gif. With 215+ images, I wanted to keep the url someplace in the html for sake of ease and quick reference.
When a subnavigation button is pressed, I rewrite the css background image to the correct source which is contained in the div's title tag, for ONLY the gallery that is showing. This saved me from having to do any fancy javascript to store the correct source image.
var newUrl = $(this).attr('title');
$(this).css('background-image', 'url('+newUrl+')');
When a new subnavigation button is pressed, I rewrite the background image of the last gallery divs to be blank gifs. So, aside from interface gfx, I only have 2-7 images 'active' at all times. With anything else I add that contains images, I just use this "ondemand" technique to swap the title with the background-image.
Now it seems I can use the app indefinitely with no crashes. Don't know if this will help anyone else, and it may not be the most elegant solution, but it provided a fix for me.
On a rails app, I was lazy loading hundreds of mid-size photos (infinite scroll) and inevitably hit the 10Mb limit on the iphone. I tried loading the graphics into a canvas (new Image, src=, then Image.onload) but still hit the same limit. I also tried replacing the img src and removing it (when it went out of viewable area) but still no cigar. In the end, switching out all the img tags w/ div's w/ the photo as background did the trick.
$.ajax({
url:"/listings/"+id+"/big",
async:true,
cache:true,
success:function(data, textStatus, XMLHttpRequest) {
// detect iOS
if (navigator.userAgent.match(/iPhone/i) || navigator.userAgent.match(/iPod/i) || navigator.userAgent.match(/iPad/i)) {
// load html into data
data = $(data);
// replace img w/ div w/ css bg
data.find(".images img").each(function() {
var src = $(this).attr("src").replace(/\s/g,"%20");
var div = $("<div>");
div.css({width:"432px",height:"288px",background:"transparent url("+src+") no-repeat"});
$(this).parent().append(div);
$(this).remove();
});
// remove graphic w/ dynamic dimensions
data.find(".logo").remove();
}
// append element to the page
page.append(data);
}
});
I can now load well over 40Mb of photos on one page w/o hitting the wall. I encountered an odd issue, though, with some of the css background graphics failing to show up. A quick js thread fixed that. Set the div's css bg property every 3 sec's.
setInterval(function() {
$(".big_box .images div.img").each(function() {
$(this).css({background:$(this).css("background")});
});
}, 3000);
You can see this in action at http://fotodeck.com. Check it out on your iphone/ipad.
I was unable to find a solution for this. Here are a couple of methods I tried, and all of them failed:
Simply changed the background of a DIV using div.style.backgroundImage = "url("+base64+")"
Changed the .src of an image using img.src = base64
Removed the old and added the new image using removeChild( document.getElementById("img") ); document.body.appendChild( newImg )
The same as above but with a random height on the new image
Removing and adding the image as a HTML5 canvas object. Also doesn't work, since a new Image(); has to be created, see *
On launch, created a new Image() object, let's call it container. Displayed the image as <canvas>, every time the image changed, I would change container's .src and redraw the canvas using ctx.drawImage( container, 0,0 ).
The sames as the previous, but without actually redrawing the canvas. Simply changing the Image() object's src uses up memory.
A strange thing I noticed: The bug occurs even if the image isn't displayed! For example, when doing this:
var newImg = new Image( 1024, 750 );
newImg.src = newString; // A long base64 string
Every 5 seconds, and nothing else, no loading or displaying the image, of course wrapped up in an object, also crashes the memory after some time!
I encountered an out of memory with Javascript on the iPad when we were trying to refresh an image very often, like every couple of seconds. It was a bug to refresh that often, but Safari crashed out to the home screen. Once I got the refresh timing under control, the web app functioned fine. It seemed as if the Javascript engine couldn't keep up with garbage collection quickly enough to discard all the old images.
There are issues with memory and the way to solve this problem is very simple. 1) Put all your thumbnails in canvas. You will be creating a lot of new Image objects and drawing them into canvas, but if your thumbnail are very small you should be fine. For the container where you will be displaying the real size image, create only one Image object and reuse this object and make sure to also draw it into a canvas. So, every time a user clicks the thumbnail, you will update your main Image object. Do not insert IMG tags in the page. Insert CANVAS tags instead with the correct width and height of the thumbnails and the main display container. iPad will cry foul if you insert too many IMG tags. So, avoid them!!! Insert only canvas. You can then find the canvas object from the page and get the context. So every time the user clicks a thumbnail, you will get the src of the main image (real size image) and draw it to the main canvas, reusing the main Image object and the firing the events. Clearing the events every time at the beginning.
mainDisplayImage.onload = null;
mainDisplayImage.onerror = null;
...
mainDisplayImage.onload = function() { ... Draw it to main canvas }
mainDisplayImage.onerror = function() { ... Draw the error.gif to main canvas }
mainDisplayImage.src = imgsrc_string_url;
I have create 200 thumbnails and each is like 15kb. The real images are like 1 MB each.
I also had similar problems while rendering large lists of images on iPhones.
In my case displaying even 50 images in the list was enough to either crash the browser or occasionally the entire operating system. For some reason any images rendered onto the page weren't garbage collected, even when pooling and recycling just a few onscreen DOM elements or using the images as background-image property. Even displaying the images directly as Data-URIs is enough to count towards the limit.
The solution ended up being rather simple - using position: absolute on the list items allows them to be garbage collected fast enough to not run into a memory limit. This still involved on having only about 20-30 images in the DOM at any moment, creating and removing the item's DOM nodes by scroll positon finally did the trick.
It seems it's particularily dependent on having webkit-transform':'scale3d() applied to any ancestor of the images in the DOM. Relatively flowing a very tall DOM and rendering it on the GPU pisses off a memory leak in webkit renderer, I guess?
I'm running in a similar issue in Chrome too, developing an extension that loads images in the same page (the popup, actually) replacing old images with new ones.
The memory used by the old images (removed from the DOM) is never freed, consuming all the PC memory in a short time.
Have tried various tricks with CSS, without success.
Using hardware with less memory than a PC, like the iPad, this problem arises earlier, naturally.
I filed a bug with jQuery as jQuery trys to handle memory leaks...so I'd consider this a bug. Hopefully the team can come up with some concise and clever way of handling this problem in Mobile Safari soon.
http://dev.jquery.com/ticket/6944#preview
Are there any documents/tutorials on how to clip or cut a large image so that the user only sees a small portion of this image? Let's say the source image is 10 frames of animation, stacked end-on-end so that it's really wide. What could I do with Javascript to only display 1 arbitrary frame of animation at a time?
I've looked into this "CSS Spriting" technique but I don't think I can use that here. The source image is produced dynamically from the server; I won't know the total length, or the size of each frame, until it comes back from the server. I'm hoping that I can do something like:
var image = getElementByID('some-id');
image.src = pathToReallyLongImage;
// Any way to do this?!
image.width = cellWidth;
image.offset = cellWidth * imageNumber;
This can be done by enclosing your image in a "viewport" div. Set a width and height on the div (according to your needs), then set position: relative and overflow: hidden on it. Absolutely position your image inside of it and change the position to change which portions are displayed.
To display a 30x40 section of an image starting at (10,20):
<style type="text/css">
div.viewport {
overflow: hidden;
position: relative;
}
img.clipped {
display: block;
position: absolute;
}
</style>
<script type="text/javascript">
function setViewport(img, x, y, width, height) {
img.style.left = "-" + x + "px";
img.style.top = "-" + y + "px";
if (width !== undefined) {
img.parentNode.style.width = width + "px";
img.parentNode.style.height = height + "px";
}
}
setViewport(document.getElementsByTagName("img")[0], 10, 20, 30, 40);
</script>
<div class="viewport">
<img class="clipped" src="/images/clipped.png" alt="Clipped image"/>
</div>
The common CSS properties are associated with classes so that you can have multiple viewports / clipped images on your page. The setViewport(…) function can be called at any time to change what part of the image is displayed.
In answer to :
Alas, JavaScript simply isn't capable of extracting the properties of the image you'd require to do something like this. However, there may be salvation in the form of the HTML element combined with a bit of server-side scripting.
...
< ? (open php)
$large_image = 'path/to/large_image';
$full_w = imagesx($large_image);
$full_h = imagesy($large_image);
(close php) ? >
This can be done in Javascript, just google a bit :
var newimage = new Image();
newimage.src = document.getElementById('background').src;
var height = newimage.height;
var width = newimage.width;
This generates a new image from an existing one and captures this way in java script the original height and width properties of the original image (not the one id'ed as background.
In answer to :
The width/height properties of the document's image object are read only. If you could change them, however, you would only squish the frames, not cut the frames up like you desire. The kind of image manipulation you want can not be done with client-side javascript. I suggest cutting the images up on the server, or overlay a div on the image to hide the parts you do not wish to display.
...
var newimage = new Image();
newimage.src = document.getElementById('background').src;
var height = newimage.height;
var width = newimage.width;
newimage.style.height = '200px';
newimage.style.width = '200px';
newimage.height = '200px';
newimage.width = '200px';
and if wanted :
newimage.setAttribute('height','200px');
The doubled newimage.style.height and newimage.height is needed in certain circumstances in order to make sure that a IE will understand in time that the image is resized (you are going to render the thing immediately after, and the internal IE processing is too slow for that.)
Thanks for the above script I altered and implemented on http://morethanvoice.net/m1/reader13.php (right click menu... mouseover zoom lent) correct even in IE , but as you will notice the on mousemove image processing is too fast for the old styled IE, renders the position but only once the image. In any case any good idea is welcome.
Thanks to all for your attention, hope that the above codes can help someone...
Claudio Klemp
http://morethanvoice.net/m1/reader13.php
CSS also defines a style for clipping. See the clip property in the CSS specs.
The width/height properties of the document's image object are read only. If you could change them, however, you would only squish the frames, not cut the frames up like you desire. The kind of image manipulation you want can not be done with client-side javascript. I suggest cutting the images up on the server, or overlay a div on the image to hide the parts you do not wish to display.
What spriting does is essentially position a absolutely-positioned DIV inside another DIV that has overflow:hidden. You can do the same, all you need to do is resize the outer DIV depending on the size of each frame of the larger image. You can do that in code easily.
You can just set the inner DIV's style:
left: (your x-position = 0 or a negative integer * frame width)px
Most JavaScript Frameworks make this quite easy.
Alas, JavaScript simply isn't capable of extracting the properties of the image you'd require to do something like this. However, there may be salvation in the form of the HTML <canvas> element combined with a bit of server-side scripting.
PHP code to go about extracting the width and height of the really large image:
<?php
$large_image = 'path/to/large_image';
$full_w = imagesx($large_image);
$full_h = imagesy($large_image);
?>
From here, you'd then load the image into a <canvas> element, an example of which is documented here. Now, my theory was that you may be able to extract pixel data from a <canvas> element; assuming that you can, you would simply make sure to have some form of definite divider between the frames of the large image and then search for it within the canvas. Let's say you found the divider 110 pixels from the left of the image; you would then know that each "frame" was 110 pixels wide, and you've already got the full width stored in a PHP variable, so deciphering how much image you're working with would be a breeze.
The only speculative aspect to this method is whether or not JavaScript is capable of extracting color data from a specified location within an image loaded into a <canvas> element; if this is possible, then what you're trying to accomplish is entirely feasible.
I suppose you want to take a thumbnail for your image. You can use ImageThumbnail.js that created from prototype library in this way:
<script type="text/javascript" src="prototype.js"></script>
<script type="text/javascript" src="ImageThumbnail.js"></script>
<input type="file" id="photo">
<img src="empty.gif" id="thumbnail" width="80" height="0">
<script type="text/javascript">
<!--
new Image.Thumbnail('thumbnail', 'photo');
//-->
</script>
for more information
try use haxcv library haxcv js by simple functions
go to https://docs.haxcv.org/Methods/cutImage to read more about his library
var Pixels = _("img").cutImage (x , y , width , height );
_("img").src (Pixels.src);
// return cut image
but try to include library first