Image resizing causing slow scrolling - html

I'm loading large images and having the browser resize them. I'm explicitly setting the size.
<img src="http://example.com/image1.jpg" width="240" height="360"/>
There are many such images on the page. Scrolling is very slow and choppy. The Events Timeline in chrome looks something like this when scrolling:
Paint
* Image decode (JPEG)
* Image resize (non-cached)
* Image decode (JPEG)
* Image resize (non-cached)
* ...
Paint
* Image resize (cached)
* Image resize (cached)
* Image resize (cached)
* Image resize (cached)
Paint
* Image decode (JPEG)
* Image resize (non-cached)
* Image decode (JPEG)
* Image resize (non-cached)
* ....
Paint
* Image resize (non-cached)
* Image resize (non-cached)
* Image resize (non-cached)
* Image resize (non-cached)
Paint
* Image decode (JPEG)
* Image resize (cached)
* Image decode (JPEG)
* Image resize (cached)
* ...
etc.
I'm not sure why some of the Paint events include image decoding and others don't, nor why sometimes the resizing is cached and sometimes it is not. I guess it must have to do with new images coming into the view-port.
Is there anything I can do to ensure that I only pay the image resize cost once per image when the page loads, and avoid image resizing during scroll?
(Of course, I understand that the best solution is to avoid browser resizing by loading in an image that is already of the appropriate size. In this case this is not practical.)

This function will permit you to resize an image only once, by replacing it with a new image resized at the desired scale :
function resizeImage(image, maxWidth, maxHeight) {
// Output scale is the minimum of the two possible scales
var scale = Math.min((maxWidth / image.width), (maxHeight / image.height))
// Output canvas
var outputCanvas = document.createElement('canvas')
outputCanvas.width = image.width * scale
outputCanvas.height = image.height * scale
// Draw image content in output canvas
var outputContext = outputCanvas.getContext('2d')
outputContext.drawImage(image, 0, 0, parseInt(image.width * scale), parseInt(image.height * scale))
// Replace image source
image.src = outputCanvas.toDataURL()
}
It takes the image you pass as image parameter, and creates a canvas where it resizes image, and then sets the image.src attribute to the content of the output canvas, using toDataURL().
Images you resize have to be in RELATIVE path (yes it's not cool), or you will have security error due to CORS if not fulfilled.
But you can pass base64 data as src attribute, and it can be easy to do it with AJAX.

Your problem is that you are downloading lots of images at the same time, lots of large images. The rendering of them to differnt sizes other than the orginal will also be slow if there are lots of large images and the users individual ram and processor limitations.
no matter what size you tell the browser to render the image the browser still loads the original image size and then adjusts it on the fly. The large image has to travel down the users internet connection to the browser from the server. by using html attributes all you are doing really is using CSS to change the image size once it has been downloaded.
Your best option would in mho be to create multiple image sizes server side, preferably at the time of creation of the asset rather than on the fly and call the image size closest to your needs. If you create images on the fly using scripts etc keep them on the server to use again later on and reduce load time and server resources.
one last tip is also make sure you are caching. more info here http://betterexplained.com/articles/how-to-optimize-your-site-with-http-caching/

CSS would help here. That would act as a default and may slow down individual load time. To achieve this just do basic css for images. Reference below:
<img src="....." />
For your css you need the following code as an example:
img {
height: 360;
width: 240;
}
Then you could add extra code to have rounded corners, border, or any effects you may want.
To avoid all resizing and this would of course help is to resize images in Photoshop. Then it would just show image and not render each image as different parts of the page are shown.

large image takes more time to load to memory (RAM), even if the images already on memory (RAM) if there is huge memory consumption (too many large images or there is an application that takes large memory on background), invisible (outside of visible area) images get pushed to paging/swap file (on hard drive), so when the images come to visible area, browser would load that from paging/swap with hard drive speed (slow speed).
in this case, if you have many large images on one page, you cannot depend on client side resizing, because it would make your client browsing experience bad.
you should consider to resize your images on server side, either on demand, or pre-resized (thumbnail).
in case of on demand method, you could user Apache's mod_rewrite to point images to a script to resize and image that is beeing requested by your clients browser.
take a look at popular image sharing/hosting site, view a random image and copy its URL, paste it to another tab, and play with the URL by changing/removing some part of the URL.
you can see that they dynamically resize the image on server side.
TLDR: you cannot have smooth scrolling with many large images on a page, either use thumbnails, or get choppy scrolling if you insist on not using thumbnails.
oh, there is one other thing to consider, that is increasing your (and your clients) RAM to handle such memory needs

Related

Using sprite atlases in a multi resolution setup in Cocos2D-x

I've just been able to setup a Cocos2d-x for a multiresolution environment. Ie supporting all/most of the available iPhone screen sizes.
My next step is to scrap the individual files (bunch of pngs) and use sprite atlases (aka sprite sheets) instead.
How does this work in Cocos2D-x? Does anyone have a working sample setup?
Once again, Google and existing documentation (well, I don't think that exists) fail me.
For cocos2d-x v3.5...
The cocos2d-x test classes are always a great place to look to see how things can be done with cocos2d-x.
Check out the AppDelegate.cpp in:
Cocos2d-x/cocos2d-x-3.5/tests/cpp-tests/Classes/AppDelegate.cpp.
In that class the window size is tested to see which set of assets should be loaded. That is part of the issue, deciding which assets to load.
For iOS retina, you can check the size of the screen and then set the content scale factor to either 1.0 for standard resolution or 2.0 for retina resolution.
Unfortunately, cocos2d-x doesn't seem to ever detect certain screen sizes and call Director::getInstanct()->setContentScaleFactor(2.0) for you, so I think we have to do this our self.
I have not tested the impact of setting contentScaleFactor on non-apple devices yet...
Check out the code below. Try running it in your AppDelegate::applicationDidFinishLaunching() method to get an idea of how cocos2d-x sees screen pixels and points; the result is not exactly what I expected. The output below is for an iPhone 5 device.
director->setContentScaleFactor(2);
Size winSizePoints = director->getWinSize();
Size winSizePixels = director->getWinSizeInPixels();
Size visibleSize = director->getVisibleSize();
CCLOG("Content scale factor set to 2.0.");
CCLOG("winSizePoints:%.2f,%.2f", winSizePoints.width, winSizePoints.height);
CCLOG("winSizePixels:%.2f,%.2f", winSizePixels.width, winSizePixels.height);
CCLOG("visibleSize:%.2f,%.2f", visibleSize.width, visibleSize.height);
director->setContentScaleFactor(1);
winSizePoints = director->getWinSize();
winSizePixels = director->getWinSizeInPixels();
visibleSize = director->getVisibleSize();
CCLOG("Content scale factor set to 1.0.");
CCLOG("winSizePoints:%.2f,%.2f", winSizePoints.width, winSizePoints.height);
CCLOG("winSizePixels:%.2f,%.2f", winSizePixels.width, winSizePixels.height);
CCLOG("visibleSize:%.2f,%.2f", visibleSize.width, visibleSize.height);
Output of above code:
Content scale factor set to 2.0.
winSizePoints:1136.00,640.00
winSizePixels:2272.00,1280.00
visibleSize:1136.00,640.00
Content scale factor set to 1.0.
winSizePoints:1136.00,640.00
winSizePixels:1136.00,640.00
visibleSize:1136.00,640.00
So it seems we have to check the the screen size and then choose assets.
One option is to then use code like this to decide which assets to load based on if the screen is retina or not. You could use a similar approach to also loading different size background images to deal with different aspect ratios (more aspect ratios below).
float scaleFactor = CCDirector::getInstance()->getContentScaleFactor();
if (scaleFactor > 1.99)
{
SpriteFrameCache::getInstance()->addSpriteFramesWithFile("spriteSheet-hd.plist", "spriteSheet-hd.png");
}
else
{
SpriteFrameCache::getInstance()->addSpriteFramesWithFile("spriteSheet.png", "spriteSheet.plist");
}
For sprite sheets, I highly recommend Texture Packer. Awesome tool that can create SD and HD sheets and .plist files for you with the press of one button.
If you publish to multiple platforms, you will also want to use the macros to detect the device type and use that information in deciding which assets to load.
e.g.
if (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32)
elif CC_TARGET_PLATFORM == CC_PLATFORM_WP8
elif CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID
elif CC_TARGET_PLATFORM == CC_PLATFORM_IOS
elif CC_TARGET_PLATFORM == CC_PLATFORM_MAC)
endif
Another thing to consider is that on low power CPU and RAM devices, loading large assets might make your frames per second (FPS) go to crap. Or worse, the device might not be able to load the asset or could crash the game. So be sure to test/profile on least common denominator devices that you plan to support.
Aspect Ration is another important issue (landscape width:height).
iPad aspect ratio is 4:3
iPhone 4 is 3:2
iPhone 5 & 6 are 16:9
Android throws in a bunch more width:height ratios.
WP8.1 is 15:9... not sure if others.
The point is that you probably don't want to stretch your backgrounds to get them to fill the screen, or have black bars on the edges where assets are not tall or wide enough.
To deal with this I create background assets that are wider than they need to be going off the right side of the screen. That content looks good but is not vital to convey the meaning of the background. That extra content can be clipped on devices that have narrower aspect ratios, i.e. ipad, and is visible on wider aspect ratio devices, i.e. iPhone 6.
The background images are then scaled up/down to match the screenSize height and retain their aspect ratio.

Twitter Bootstrap Image Gallery - creating automatic thumbnails

I thought the thumbnail component of Bootstrap automatically took an image, and cut out a specific size thumbnail to slap on the site. Either I'm using this feature wrong or this is completely false. Everytime I create class="thumbnail", I just get a slightly smaller version of the photo.
As a photographer, my photos are huge, and the "thumbnails" are taking up half the page! Certainly I could resize everything in Photoshop to a 200X200px size and upload these as thumbnails, but I feel like there must be a beter way of doing this.
I tried in the html itself just putting width="200" and height="200" after img src, but the problem here is that instead of cutting a 200X200 square out of the image, the image was scaled down proportionally using one dimension. I.e., the image fits in a 200X200 square, but rather than filling up the entire square (since that's not the original proportions), it fills up a 200X100 type area.
Can anyone help?
Bootstrap won't resize your images. It is a CSS framework, it can only add styles to your web page but you can't use it to do any backend work, like thumbnails creation. Setting the dimensions in the HTML img tag doesn't resize your image neither, it is still the same image that is sent to the browser. So in order to boost your website performance, you need to think of another solution, you don't want to send huge images through the network if you're only gonna show them with thumbnail size.
What kind of website are you running?
For example, Wordpress automatically handles the thumbnails creation when you upload files through the Media Manager. I'm pretty sure most of the CMS have this functionnality.
If you have a PHP website without a CMS, you could try using a library such as phpthumb, that would require some coding though.
If you have a static HTML website, then you have no other choice but to resize the images manually in Photoshop.
By the way, do you optimize your images too? (compression with tools such as tinypng or jpeg-optimizer
I've got a little code to generate thumb:
public function generateThumb($pathToImage, $pathToThumb, $extension, $maxDim)
{
//Create a new image according to "MimeType"
switch($extension){
case "gif":
$img = imagecreatefromgif("{$pathToImage}");
break;
case "jpeg":
$img = imagecreatefromjpeg("{$pathToImage}");
break;
case "png":
$img = imagecreatefrompng("{$pathToImage}");
break;
}
// load image and get image size
$width = imagesx($img);
$height = imagesy($img);
// calculate thumbnail size, vertical and horizontal orientation
$new_width = ($width > $height) ? $maxDim : floor($width * ( $maxDim / $height ));
$new_height = ($height > $width) ? $maxDim : floor($height * ( $maxDim / $width ));
// create a new temporary image
$tmp_img = imagecreatetruecolor($new_width, $new_height);
// copy and resize old image into new image
imagecopyresized($tmp_img, $img, 0, 0, 0, 0, $new_width, $new_height, $width, $height);
// save thumbnail into a file
imagejpeg($tmp_img, "{$pathToThumb}");
}
I'm sorry, but I can't remember where I found the original script (On SO and other website).
Using that you can generate a thumb each time you add a new image and then use this thumb in your thumbnail preview.
Nop, the Bootstrap will not resize files for You.
Even if You're the only user of the site u can make a file-upload form for yourself. Take a look at Paperclip - it's awesome. And do not forget to protect this form to disallow network users upload some ugly images on your site
Bookstrap is not for resizing api. You can use many of the Image Compression apps that are available.
I would recommend http://shrinkjpeg.com since it does not upload the images to server and compresses them locally in browser.

SWF with multiple "stages"

Is it possible to have a single SWF file with multiple "stages" appearing at different parts of the page and sharing data?
What I'm trying to do requires sharing big amount of data (byteArrays of image data) that cannot be shared through LocalConnections or via JS (very slow) so I'm trying to avoid the "sharing" part and somehow do it in a single SWF. Problem is, those images need to appear on different parts of the page thus I'm stuck.
There is only one Stage in swfs - the Stage is effectively the background; and you cant have more than one background.
"Problem is, those images need to appear on different parts of the page" - why cant you adjust the position of the images?
Use swf 100x100 % of browser window with transparent bg (wmode='transparent'), load images and place them in appropriate position. Main problem how to calculte coordinates for thumbnails... ^)
And flash with transparent bg very slow too...

Get Image src attribute value for HTML5 canvas element

I have been searching - am thinking what I want to do is not possible but thought I would check.
I have a few canvasses on an HTML page as follows: (these are IDs below)
canvasMain - this is going to display
a large version of an image
canvasThumbnail1 - this is going to
display a thumbnail image
canvasThumbnail2 - same as
above...etc
I have it working where I paint the canvasMain with the contents of the thumbnail. The problem is since the canvas is immediate it is copying the pixels as they are over to the canvasMain from canvasThumbnail. This is resulting in an enlarged pixelated image.
What I want to do is click on one of the canvasThumbnails and be able to grab the Image.src property as a string and then pull that into canvasMain instead of actually copying the pixels over from one canvas to another. Essentially just grab the address (local or say on Flickr) from where I can pull in the image. Pulling an image in to a canvas seems to scale it nicely.
From what I have seen I do not think that Image.src value is accessible through the 2d context. I enumerated through its properties and have only found nested objects or native code returns.
I figured that if I clicked on the canvasThumbnail, and then used (this) to get a reference to that canvas element and then grab the 2dcontext of that canvas I may be able to use a property of that context to get a string that represents the value of the Image.src.
Any ideas?
Thanks
Somehow you painted the image onto canvasThumbnail1, presumably from a (high resolution) Image element.
The canvasThumbnail1, or any canvas for that matter, has no memory on things painted on it. So if you paint a large Image onto a tiny canvasThumbnail, the high-resolution data does not exist on that tiny canvas. To get it you must use the original image again, or else you must paint to a larger canvas from the start.
In other words, instead of painting the thumbnail onto the main, you need to repaint Image element (that you used to make the thumbnail) onto the main.

How to capture zoomable image as one high resolution image?

I would like to capture a zoomable image at a high resolution zoomed at 3x. Do you know of a way I can piece this image together without having to do it manually? Here is the image
After using bhups' solution, tweaking outputxand outputy for a good while, I tried something else.
I went back to the object page (in the above example, here), took the thumbnail image URL (http://www.metmuseum.org/Imageshare/ep/regular/DP145931.jpg), replaced regular with zoom and to my surprise got what I presume is the full image, with less effort:
http://www.metmuseum.org/Imageshare/ep/zoom/DP145931.jpg
You can tweak the URL to get the job DONE. Here is the URl for 3x image. http://media.metmuseum.org/mgen/metzoom/zoom3.ms?img=DP145931.jpg&wrapperid=11&outputx=1200&outputy=1601.067378252168&level=1&x=0&y=0&backcolor=0x00000
outputx and outputy are the output image dimensions. level implies the zoom level. and x and y are the top left corner of the selected rectangle.