I currently have a function in PHP called img(), that takes at least two arguments, as such:
print img("foo.jpg", 100);
That would return something like this:
<img src='/cache/foo_XXXXX.jpg' width='100' height='76' />
So, the function takes the arguments, resize the original file and save it as a cached file on the server and return the image tag. Obviously, if the cached version already exists, it just returns it and saves the processing for the next time.
Now, this works perfectly in 99 cases out of 100, but for some sites there are pages which are quite image-heavy, and since the cached versions of the image is expired after X number of days, the img() functions needs to recreate 50+ high resolution images to small thumbnails, and loading such a page takes several seconds and that's not acceptable.
So my idea is to separate this. So doing this:
print img("foo.jpg", 100);
would return this:
<img src='img.php?ARGUMENTS' width='?' height='?' />
Which means that the img() function doesn't actually handle the file at all, but rather output HTML that tells the browser to get the image from a PHP script rather than a static image file on the server.
Now, the "ARGUMENT" part would of course contain all the information that img.php needs to deal with the file in the same way that img() has dealt with it - perhaps a serialized string version of all the arguments to the function?
But the problem is the width/height values of the image tag! Since processing is moved outside the scope of the current script, it has no idea how large the resulting image would be, right? I obviously can't wait for img.php to complete and return it. I am using imagemagick for the processing (so the second argument can be 100, "50%", "<40" and whatnot) and perhaps there is a way to "dryrun" it with imagemagick - i.e. having imagemagick return the resulting size of a specific file using a specific command?
How would you solve this?
You have the list of all images somewhere in database, right? You can add the fields for width and height and calculate scaled width and height while generating HTML. You could also add thumbnails width and height into database as well.
Related
I have used the construct <img src="http://yoursite.com/image.php?request_id=XXXX">
and it works well to serve images that may need some preprocessing. However, if image.php requires a lot of arguments, the src can become very clumsy. Therefore I thought of wrapping image.php into a function, and bundling it to my content page with include_once "image.php".
The strategy, however, produces the dreaded "Cannot modify header information" error. I believe this is because there is already output on the page, before the img is referenced. Does that mean that it is impossible to output an image src by function rather than by GET a separate file?
This will not work because you are sending two different types of contents in one response, one is text/html and the other for example image/jpeg. Here is my suggestion: have a function that accepts all the arguments you need to render the image and have this function save it somewhere on the disk (cache/images for example) the function should then return the path to this image so you can put it in you src.
I'm building a site that depends on bookmarklets. These bookmarklets pull the URL and a couple of other elements. However, I need to select 1 image from the page the user bookmarks. Currently I'm trying to use the PHP Simple HTML DOM Parser http://simplehtmldom.sourceforge.net/
It pulls the HTML as expected, and returns the tags as expected. However, I want to take this a step further and only return images with a min width of 40px. I know about the function getimagesize() but from what I understand, this is resource heavy. Is there a better method available to pre-process the image and achieve the results I'm looking for?
Thanks!
First check if the image HTML tag has a width attribute. If it's above 40, skip over it. As Matthew mentioned, it will get false positives where people sized down a large image to 40px wide, but that's no big deal; the point of this step is to quickly weed out the first dozen or so images that are obviously too big.
Once the script catches an image that SAYS it's under 40px wide, check the header information to deduce a general width based on the size of the file. This is faster than getimagesize because you don't have to download the image to get the info.
function get_image_kb($path) {
$headers = get_headers($path);
$len = explode(" ",$headers[6]);
return $len[1];
}
$imageKb = get_image_kb('test1.jpg');
// I'm going to gander 40x80 is about 2000kb
$cutoffSize = 2000;
if ($imageKb < $cutoffSize) {
// this is the one!
}
else {
// it was a phoney, keep scraping
}
Setting it at 2000kb will also let through images that are 100x30, which isn't good.
However, at this point, you've weeded out most of the huge 800kb files that would really slow you down, and because we know it's under 2kb, it's not too taxing to test this one with getimagesize() to get an accurate width.
You can tweak the process depending on how picky you are for the 40px mark, as usual higher accuracy takes more time, and vice versa.
On my server, I have three files per image.
A thumbnail file, which is cropped to 128 by 128.
A small file, which I aspect fit to a max of 160 by 240.
A large file, which I aspect fit to a max of 960 by 540.
My method for returning these URLs to three20's gallery looks like this:
- (NSString*)URLForVersion:(TTPhotoVersion)version {
switch (version) {
case TTPhotoVersionLarge:
return _urlLarge;
case TTPhotoVersionMedium:
return _urlSmall;
case TTPhotoVersionSmall:
return _urlSmall;
case TTPhotoVersionThumbnail:
return _urlThumb;
default:
return nil;
}
}
After having logged when these various values are called, the following happens:
When the thumbnail page loads, only thumbnails are called (as expected)
When an image is tapped, the thumbnail appears, and not the small image.
After that thumbnail appears, the large image is loaded directly (without the small image being displayed).
What I desire to happen is the following
This is the same (thumbnails load as expected on the main page)
When the image is tapped, the small image is loaded first
Then after that, the large image is loaded.
Or, the following
Thumbnails
Straight to large image.
The problem with the thumb, is that I crop it so it is a square.
This means that when a thumbnail image is displayed in the main viewer (after thumb was tapped), it is oversized, and when the large image loads, it immediately scales down to fit.
That looks really bad, and to me, it would make far more sense if it loaded the thumbs in the thumbnail view, and then the small image followed by the large image in the detail view.
Does anyone have any suggestions on how to fix this?
Is the best way simply to make the thumbs the same aspect ratio?
I would appreciate any advice on this issue
Looking at the three20 source I can see that TTPhotoView loads the preview image using the following logic:
- (BOOL)loadPreview:(BOOL)fromNetwork {
if (![self loadVersion:TTPhotoVersionLarge fromNetwork:NO]) {
if (![self loadVersion:TTPhotoVersionSmall fromNetwork:NO]) {
if (![self loadVersion:TTPhotoVersionThumbnail fromNetwork:fromNetwork]) {
return NO;
}
}
}
return YES;
}
The problem is that as your small image is on the server and not locally the code skips the image and uses the Thumbnail for the preview.
I would suggest that your best solution would be to edit the thumbnails so that they have the same aspect ratio as the large images. This is what the developer of this class seems to have expected!
I think you have three ways to go here:
modify the actual loadPreview implementation from TTPhotoView so that it implements the logic you want (i.e., allowing loading the small version from the network);
subclass TTPhotoView and override loadPreview to the same effect as above;
pre-cache the small versions of your photos; i.e, modify/subclass TTThumbView so that when TTPhotoVersionThumbnail is set, it pre-caches the TTPhotoVersionSmall version; in this case, being the image already present locally, loadPreview will find it without needing to go out for the network; as an aside, you might do the pre-caching at any time that you see fit for your app; to pre-cache the image you would create a TTButton with the proper URL (this will both deal with the TTURLRequest and the cache for you);
otherwise, you could do the crop on-the-fly from the small version to the thumbnail version by using this UIImage category; in this case you should also tweak the way your TTThumbView is drawn by overriding its imageForCurrentState method so that the cropping is applied when necessary. Again, either you modify directly TTThumbView or you subclass it; alternatively, you can define layoutSubviews in your photo view controller and modify there each of the TTThumbViews you have:
- (void)layoutSubviews {
[super layoutSubviews];
for (NSInteger i = 0; i < _thumbViews.count; ++i) {
TTThumbView* tv = [_thumbViews objectAtIndex:i];
[tv contentForCurrentState].image = <cropped image>;
If you prefer not using the private method contentForCurrentState, you could simply do:
[tv addSubview:<cropped image>];
As you can see, each option will have its pros and cons; 1 and 2 are the easiest to implement, but the small version will be loaded from the network so it could add some delay; the same holds true for 4, although the approach is different; 3 gives you the most responsive implementation (no additional delay from the network, since you pre-cache), but it is possibly the most complex solution to implement (either you download the image and cache it yourself, or use TTButton to do that for you, which is kind of not very "clean").
Anyway, hope it helps.
Last week I converted my page img src values from pointing at image files to using a PHP script to serve up the images. The primary reason was to accommodate both files and database BLOBs as the actual source.
Now when a user goes to a page, sometimes images show and sometimes not. If not, and the page is refreshed\reloaded, then the image appears. When images do not appear, sometimes it is an image the user has already accessed previously today.
I am stumped.
Here is the img tag:
<img src="../somedir/image_script.php?i=1234">
The image_script.php file figures out where to get the image from, then finishes up with:
header("Content-type: image/jpeg");
if($from_db){
print $image_blob;
} else {
$im = imagecreatefromjpeg($image_file);
imagejpeg($im,null,100);
imagedestroy($im)
}
I am using PHP 5.2.8 on IIS 6 using FastCGI. There are no cache headers on the image_script.php file nor on the directory it is in. Currently 99.9% of the images are file based, so I do not know if there is a difference in result between db-based and file-based images. When I go directly to image_script.php in my browser it returns the requested image (i=????) 100% of the time.
a> Any clue as to why the hit and miss with images being displayed? and,
b> what would be a proper way to actually cache the images served up by the PHP script? (they are very static)
Scott
Hmm. Can't tell for sure, but maybe your imagecreatefromjpeg is occasionally running out of memory? In that case, you'd serve an error message out as JPEG data and never see it, right?
Incidentally, wouldn't just grabbing the image file in as a string and shovelling it out without going through imagecreatefromjpeg/imagejpeg/imagedestroy be more efficient? It looks like you're reading a JPEG file, creating an internal PHP memory image from it, then reconverting it to a JPEG (at hefty 100% quality) then serving that data out, when you could simply read the JPEG file data in and print it, like you do from the database.
What happens if you do, say...
...
} else {
header ('Content-length: ' .filesize($image_file));
readfile ($image_file);
}
I would like to generate a dynamic image from a script, and then have it load to the browser without being persistent on the server.
However, I cannot call this by setting the image's src="script.php", since that would require running the script that just generated the page and its data all over again, just to get the final data that will generate the graph.
Is there a way to do this that is similar to setting image's src="script.php", but which is called from within another script, and just sends the image without saving it? I need access to the data that is used in the generation of the markup, in order to create this dynamic image.
Or, if not, what is the easiest way to destroy the image once the page is loaded? a quick ajax call?
Is there any way to cache certain data for some limited time frame in order for it to be available to some other script?
Any ideas would be greatly appreciated, as I'm having a really hard time finding the right solution to this...
Thanks!
You can inline the image into a <img> tag if you need to.
Like
<?php
$final_image_data; // Your image data, generated by GD
$base64_data = base64_encode($final_image_data);
echo "<img src=\"data:image/png;base64,{$base64_data}\" ... />";
?>
That should work on all modern browsers, and IE8. Doesn't work well with some email clients tho (Outlook, for one).
Also, another solution I found is to store the image in a session variable which is then called from a php script in the image tag. This would allow a user specific image to be served, and then removed from memory by the script... This also avoids messy img src="" tags...
Hopefully that is helpful to someone.
Use a rewrite rule.
RewriteRule ^magicimage.jpg$ /myscript.php
Then simply echo your image data from gd, instead of writing it to disk -- which is as simple as not providing a filename to the appropriate image*() function
myscript.php
<?php
$im = imagecreatetruecolor($w, $h);
//...do gd stuff...
header('Content-type: image/jpeg');
//this outputs the content directly to the browser
//without creating a temporary file or anything
imagejpeg($im);
And finally, utilize the above
display.php
<img src="magicimage.jpg">