Some versions of Firefox and Safari do not view images whose format has been converted with the "Change File Format" action properly. This appears to be because they do not like, for example, a jpeg file which has a .png extension. This problem seems to occur even more if the converted file has been a PDF document - see #366373: PDF support ( i.e. convert PDF to JPG support).
To fix this, I have written a module (currently called imagecache_rename), which it might be worth considering incorporating into imagecache_coloractions. The principle is to make a converted file (say example.jpg, which has been converted to png) available from:
imagecache_rename/presetname/files/example.jpg.png
and for formatters to use this URL to get at the image. Thus a png file has the right ending.
This is acheived by
1. Creating a new menu item
$items[file_directory_path() .'/imagecache_rename'] = array(
'page callback' => 'imagecache_rename_cache',
'access callback' => TRUE,
'type' => MENU_CALLBACK,
);
2. Creating a callback function strips off the last extension, and then
function imagecache_rename_cache() {
$args = func_get_args();
// Strip the last extension off the $filename, and then
// retrieve from imagecache as usual
$filename = array_pop($args);
$filename_parts = pathinfo($filename);
array_push($args, $filename_parts['filename']);
call_user_func_array('imagecache_cache', $args);
}
3. Overriding CCK formatters so that they link images to URLs like imagecache_rename/presetname/files/example.jpg.png rather than imagecache/presetname/files/example.jpg . This is demonstrated in the attached imagecache_rename.module file.
The third step could simply be achieved by overriding theme_imagecache() in a theme file. This might be a better approach, as it avoids creating two sets of theme functions, as the approach at (3) does.
If you think this is worth trying to incorporate into imagecache_coloractions, I'd be happy to try rolling a patch. This would involve cleaning up the very rough code (much borrowed from imagecache).
Comment | File | Size | Author |
---|---|---|---|
imagecache_rename.info.txt | 229 bytes | egfrith | |
imagecache_rename.module.txt | 14.04 KB | egfrith |
Comments
Comment #1
egfrith CreditAttribution: egfrith commentedP.S. Note that I haven't written the code for private files.
Comment #2
dman CreditAttribution: dman commentedFair enough, that hack was improper, and bordering on illegal, I know :-)
It just seemed to work anyway in the browsers I tested at the time, but it made me feel dirty.
Hm.
This approach is certainly a move in the right direction but it doesn't feel holistic enough. There are any number of other things out there that may make assumptions about imagecache naming schemes that would have to be tweaked individually. Overriding formatter callback functions (though logical/inevitable) makes using this a lot tricker than before, IMO.
Thinking about it freshly (a year since I put the hack in) I'd possibly approach it with a subtle little .htaccess rewrite in the file dir itself. Basically content-negotiation at the file-level.
Leaving everything else as it is...
if file.jpg does not exist in imagecache/profilename/files/ folder,
see if file.jpg.png does, and sned a 301 to that real file.
This will (should) give browsers enough to go on, while being transparent to all callers.
So, three lines of .htaccess (although I can't invent that OTTOMH right now)
In leu of htaccess, we can get the same effect using hook_menu - that's how imagecache works now anyway. Less efficient though.
OR - a full though possibly chunkier solution - dig at imagecache_url() (or whatever that function is called) and insert a hook callback so I can change the imagecache pathnames on the fly. Most well-behaved other modules that leverage imagecache should be going through that. IIRC
Comment #3
egfrith CreditAttribution: egfrith commentedThanks for your reply. I thought that your hack was pretty good actually!
I agree that the idea of setting up a new menu item is by no means elegant, though I've some queries about some of your points:
The proposed module/patch doesn't remove any imagecache files - you would still be able to see imagecache/profilename/files/fred.jpg, as well as being able to see imagecache_rename/profilename/files/fred.jpg.png
The formatter callback functions don't need to be overridden - it could be left to the user to modify theme_imagecache(). This would probably be safer than overriding formatters, and would make people more aware of how the code worked - which would probably be a good thing if things started to go wrong.
I can't quite see how this would work, and I'm not convinced of its advantages. Supposing file.jpg is actually a png file, I think we still need to either override formatters or theme functions to get the browser to ask for imagecache/profilename/files/file.jpg.png (as discussed above). As you say, it is less efficient, requiring two requests per image. And it wouldn't work for sites where rewrite rules aren't enabled. That said, we don't introduce the nasty imagecache_rename path.
Also shouldn't the rewrite rule be for file.jpg.png to file.jpg ?
Before doing that, I think it would be worth checking out the D7 image code. As we're in code freeze, it's probably too late to get any such API change in. It would be good for any solution we come up with now to more-or-less work in D7 - though having said that I haven't checked out my current hack in D7!
Comment #4
dman CreditAttribution: dman commentedYeah, but I'd rather see a configurable solution that works out-of-the-box.
? Then someone has been evil like have, and is introducing confusion like I have. :=}
Two requests to the browser are no problem because that's not two data transfers, just header negotiation. Two Apache requests are much more lightweight than a Drupal bootstrap.
I'm pretty sure imagecache just won't work on a system that doesn't already have rewrites in place. Not going to let IIS users bother me.
I'd have to try this out on a platfom or two to see if it really gels together. I'm uncomfortable about multiplying factors here - by introducing a whole new storage area and behaviour here. I'd hope for a more transparent fix - a fallback that just happens - but am not sure it exists.
I'll have to have a play and a think
Comment #5
egfrith CreditAttribution: egfrith commentedI agree, an out of the box solution would be best.
I'm still not convinced by the approach, but I'd be interested to see how you get on - though if I don't come back for a while it might be because subscriptions don't seem to be working for me any more.
Comment #6
sartogo CreditAttribution: sartogo commentedegfrith, I found a small bug in your code. You are retrieving the file format two times, once in
and then in line 142, which I changed to the following:
With the change your module works great! Thanks for the effort, the ability to have the correct extension is a must have for IE6 and the pngfix scripts!
--Alex Sartogo
Hot Sauce Studios
Comment #7
dman CreditAttribution: dman commentedTrue, I hadn't considered the effect this thing has on pngfix.
Re the patch/fix/module.
I appreciate and understand the effort, and I'm sorry it takes so much work to work around.
My gut feeling is that something so small should not take so much code to change, although approaching it as a drop-in pluggable rewrite module was ... appropriate.
I'm thinking there is a simpler, tidier fix out there, but I'm not sure what it is.
If it was a 3-line option we could patch into the appropriate place in imagecache itself, then maybe these three pages could get trimmed.
Comment #8
stephthegeek CreditAttribution: stephthegeek commentedThe current behaviour (not updating the file extension) also causes issues with PDFs in the Print module. Subscribing.
Comment #9
adamo CreditAttribution: adamo commentedsubscribing
Comment #10
gooddesignusa CreditAttribution: gooddesignusa commentedsubscribing
Comment #11
dman CreditAttribution: dman commentedrenaming
Comment #12
ezra-g CreditAttribution: ezra-g commentedAnother potential approach that doesn't require creating a new module and could a file with the change extension such as:
Original file:
sites/default/files/foo.png
File with type changed:
sites/default/files/imagecache/[preset-name]/foo.jpg
1) Use hook_menu_alter() to alter the imagecache menu callback, pointing it to a new function such as imagecache_coloractions_cache() rather than imagecache_cache().
2) At this callback check if the requested path contains an ImageCache preset defined by imagecache_coloractions that changes a file extension
3) If the path does not refer to such a preset, return imagecache_cache() with the default parameters. If it does contain such a preset, rename the file extension requested in the path per the preset (eg, png.jpg)
4) return imagecache_cache() with the altered file path, so we know which source file we want to serve
This could take care of making the altered file available at that path, but not *rendering* images to use this path. There are lots of places that imagecache paths to images are generated. As egfrith points out, we'd have to chance that on the display side of things, such as in CCK formatters and in the Insert module. Luckily, Insert makes this possible for us with hook_alter_styles, which lets imagecache_coloractions() define its own insert style that could use the altered path with new file extension. However, we'd probably want to also alter imagecache_create_url, which doesn't seem to have a drupal_alter() implementation in it or around it in the codeflow within ImageCache, so this part would probably require a patch to imagecache.
Comment #13
Gabriel R. CreditAttribution: Gabriel R. commentedActually, you don't need to rename the files.
What you need is to serve the right mime type.
Do that by creating the appropriate .htaccess file in the preset folder when it's created.
Elegant enough? :-)
Comment #14
thsutton CreditAttribution: thsutton commentedThe point in #13 is correct -- the best solution is to serve the right MIME type. The following code will create a
.htaccess
within each pre-set directory that forces the MIME type iff theimagecache_convert
action is used.I've put it right after the block that uses
mkdir
inimagecache.module
.Comment #15
ak CreditAttribution: ak commentedIs this code/solution usable for drupal 7.x?
Comment #16
fietserwinAFAIK, the image system does serve the right mime type. It certainly does so in D7 and I thought it currently does as well in D6. But I would have to sort that out to be sure.
Are there still (relatively modern versions of) browsers around that do have problems with this?
Comment #17
brenda003This is an active problem in the current version of IE.
Comment #18
amagdy CreditAttribution: amagdy commentedThere is a problem with this from multiple browsers. (IE on windows 7 fro example)
Comment #19
askibinski CreditAttribution: askibinski at Merge commentedThis is a major problem which breaks the display of images JPG converted to PNG on IE up to version 11 (Edge does respect the mime type).
IMO, this fact cannot be ignored by saying "MIME type should respected by the browser" because of the very large market share of these versions of IE.
Comment #20
fietserwinIt's not something we can easily change, nor do we have to, IE11 works fine and as far as I remember it has done so as of IE7. ..
Comment #21
fietserwinUnless someone comes with proof that it does not work with IE7+ AND with a patch or at least a rather complete outline of how to change this, We are not going to change this. BTW: D8 has solved this in core.
Comment #22
dman CreditAttribution: dman as a volunteer and at Sparks Interactive commentedNice to hear that (after these number of years) the D8 image processing has a solution for this! Bravo!
Comment #23
fietserwinTo make this happen, changes had to be made to the image style processing and theming, something that for us, effect suppliers, is nearly impossible in D7 without overtaking the whole image style processing (dumping core, not extending it).
But because the responsive image module (in core in D8) needed this, it was pushed through, see #2330899: Allow image effects to change the MIME type + extension, add a "convert" image effect.
Comment #24
askibinski CreditAttribution: askibinski at Merge commentedIf anyone has an issue with broken images in IE9,10,11, please check if you added the nosniff header (part of drupal 7.40 release) in .htaccess. This is the reason why my images as described above in #19 were broken.
details: http://blog.merge.nl/drupal-broken-images-convert-png-extension-nosniff-...
Comment #25
fietserwinGood catch and explaining why this issue popped up again.
Comment #26
Anonymous (not verified) CreditAttribution: Anonymous commented@askibinski thanks for passing on this blog post, super helpful. It's worth noting that the fix for D7 in that article seems to amount to a minor core hack (altering the new .htaccess from drupal 7.40), and the author notes that he doesn't know whether or not that could be a security issue.
Comment #27
Anonymous (not verified) CreditAttribution: Anonymous commentedMore on the security risk of tampering with the new "nosniff" header: https://www.drupal.org/node/462950, especially https://www.drupal.org/node/462950#comment-3108928 and https://www.drupal.org/node/462950#comment-9456773
Comment #28
fietserwinOops, now I got myself caught by this IE problem. Instead of removing the nosniff header I added this to the .htaccess:
The rule can be generated but I am not sure if we can and want to change the .htaccess. So should we do something and what?
generate:
- generate and add these lines to .htaccess on adding a convert format effect to a style
- update function (+ releasing new version) to add this for existing styles with a convert format effect.
- if we generate: .htaccess in root, public or even create our own in public/styles?
or just warn:
- status report: warn to add these lines for all format changing styles.
- warn on adding a change format effect to a style.
- update function to warn for existing styles.
Note: we don't have to act on private files, they are always served by Drupal and already get the correct Content-Type header (based on content not extension).
Comment #29
dman CreditAttribution: dman as a volunteer commentedDrastic but clever.
The most self-contained and least weird answer seems to be to put this sort of approach into public://styles/rotated-polaroid/.htaccess itself.
That could (I guess) be something done by the image preset 'save' action every time the preset is edited. It *is* legal and clean enough for a preset to write to the filesystem inside that directory, but it would not have permissions to do that at a higher level.
I'd hope there would be an Apache way to just set-header for the contents of a directory without a rewrite?
Comment #30
fietserwinUnfortunately, within an .htaccess the directives Directory, DirectoryMatch, Location and LocationMatch are not allowed, that would certainly have been much easier to read and understand.
I also thought about adding it to that level, but then it would be deleted on a flush. But, if we can hook into an AFTER-flush event that would be OK. I will have a look into that. It would make the .htaccess even simpler, just:
ForceType image/png
Comment #31
fietserwinhook_image_style_flush is called AFTER deleting the directory, so we can use that to recreate the directory and place an .htaccess in it. I am going to write code that will do so, but will do so in a follow-up issue.
Comment #32
Jelle_SFor anyone who's looking for the follow-up, you can find it here: #2664020: IE fails to display images whose extension and Content-Type header do not match the actual image type
Comment #33
fietserwinAlso being a child issue of this one ... :)
Comment #34
tanius CreditAttribution: tanius commentedGood that this is solved in D8 now. For D7, I found just another workaround:
You can use module
filefield_paths
to rename files using your target file extension on upload. When only using image styles (with the file type convert action) for actually serving the image, browsers will always get images where file extension and file type match. The downsides are that the original image stored on the server can have an image type differing from the file extension, since conversion happens when applying image styles.That said, the clean solution for D7 seems to me an option that would convert the file type and change the file extension on upload. Since the image is not in use by then, the missing mechanism to inform other parts of Drupal about a filename change is not an issue. It will however store the image original in the converted format, so won't fit use cases that want to also preserve the uploaded version. But it would be technically clean … . Nothing for the scope of imagecache_actions though.
Comment #35
fietserwinThat wouldn't work if you have multiple image styles converting to different image formats or leaving the format unchanged. Changing all images to png because you have a rotated thumbnail and want the corners to be transparent won't make your website especially fast ...
The solution as made for IE will do for D7.
Comment #36
dman CreditAttribution: dman as a volunteer and at Sparks Interactive commentedThanks for the update on D8 progress.
(sorry, yeah it's old now, but just wanted to tag the issue relationship)