Need an idea

77 views
Skip to first unread message

Alan Hoffmeister

unread,
May 21, 2012, 7:58:47 PM5/21/12
to expre...@googlegroups.com
Hello there!

I need some ideia to make this work , I need to generate a thumbnail
from an image inside the view, and return an unique id to insert into
the <img> tag.
In PHP I was using this in the view:

<img src="<?php resize($image, 'crop', 200, 200) ?>" alt="Hello world!" />

This way, the RESIZE function would crop $image, cache it and return
the full URL for the cropper image, and a possible output would be
like:

<img src="/thumbs/hnd13ud01fd028f084ru" alt="Hello world!" />

But I don't know how I can do this if I can't use async inside the views!

Any ideas?

--
Att,
Alan Hoffmeister

Kevin Sakhuja

unread,
May 21, 2012, 8:11:39 PM5/21/12
to expre...@googlegroups.com, expre...@googlegroups.com
Client side resize?
http://adeelejaz.com/blog/resize-images-on-fly-using-jquery/

Best,
Kevin
> --
> You received this message because you are subscribed to the Google Groups "Express" group.
> To post to this group, send email to expre...@googlegroups.com.
> To unsubscribe from this group, send email to express-js+...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/express-js?hl=en.
>

Alan Hoffmeister

unread,
May 21, 2012, 8:16:12 PM5/21/12
to expre...@googlegroups.com
Bad idea..
If my client have an album of 500 photos, each photo > than 2MP, man,
that's a ruge bandwidth for 150x150pixel squares :)
--
Att,
Alan Hoffmeister


2012/5/21 Kevin Sakhuja <kevin....@gmail.com>:

Rajesh Kumar Jha

unread,
May 21, 2012, 10:24:03 PM5/21/12
to expre...@googlegroups.com
use image magik module.
With regards
Er. Rajesh Kumar Jha
Software Engineer
mail : rkjha.it.in@gmail.com
Ph : +91-9560034877,7428444177

Ryan Schmidt

unread,
May 21, 2012, 10:40:37 PM5/21/12
to expre...@googlegroups.com
Yes obviously, use ImageMagick or some other utility that can resize images. I don't think that's his question. He's asking how to structure his code. PHP allowed you to mix PHP into your HTML and it would Just Work (for certain values of Just Work) but that kind of (if you'll pardon the expression) haphazard coding isn't really supported in Node.

You should have been doing this in PHP too, but in Node and Express certainly, you're going to be separating your presentation from your logic. That means in the logic (i.e. a JavaScript file, probably in an Express route), you'll be gathering data, and in the presentation (i.e. a Jade template) you'll be displaying that data. Looking at your PHP:

<img src="<?php resize($image, 'crop', 200, 200) ?>" alt="Hello world!" />

And the example output:

<img src="/thumbs/hnd13ud01fd028f084ru" alt="Hello world!" />

I'm not sure from this code snippet whether $image is a path to an image file on your server's disk or an in-memory PHP GD image reference or what, but whatever it is, it's part of the data of your page. Another part of your data is a URL path to a thumbnail version of that image. So in the logic (in your route), you'll get $image from wherever you get it, and you'll generate a thumbnail from it if you haven't already done so before (storing that information wherever you like: database, filesystem, whatever's comfortable for you). You send the URL of the thumbnail, along with its size and alt tag and whatever else, into the view when you render it. Then in the view you access those variables that were passed in. Any basic Express tutorial should be able to show you the specifics of how to pass variables from a route handler to a template.


On May 21, 2012, at 21:24, Rajesh Kumar Jha wrote:

> use image magik module.

Edmund von der Burg

unread,
May 22, 2012, 4:45:38 AM5/22/12
to expre...@googlegroups.com
On 22 May 2012 00:58, Alan Hoffmeister <alanhof...@gmail.com> wrote:
> Hello there!
>
> I need some ideia to make this work , I need to generate a thumbnail
> from an image inside the view, and return an unique id to insert into
> the <img> tag.
> In PHP I was using this in the view:
>
> <img src="<?php resize($image, 'crop', 200, 200) ?>" alt="Hello world!" />

We have a similar problem with the code that we are working on, with
the added complication that the images need to be used by others at
sizes that they choose. Full details:
http://popit-dev.tumblr.com/post/23222464702/proposal-handling-images-in-the-api

The solution we're tending towards is that the url to the image points
at a resizing proxy, which will load the original image, resize it,
cache it and then return it. This moves the problem from template time
to image serving time which is much easier to handle in the code.

We'll probably look for existing solutions or code our own in the next
couple of weeks. Hopefully releasing it as an express middleware.

Yours,
Edmund.

> This way, the RESIZE function would crop $image, cache it and return
> the full URL for the cropper image, and a possible output would be
> like:
>
> <img src="/thumbs/hnd13ud01fd028f084ru" alt="Hello world!" />
>
> But I don't know how I can do this if I can't use async inside the views!
>
> Any ideas?
>
> --
> Att,
> Alan Hoffmeister
>

Alan Hoffmeister

unread,
May 22, 2012, 8:16:03 AM5/22/12
to expre...@googlegroups.com
@Ryan, our team know how to handle the logic before the template
engine, the complication is that we are building an online CMS, and
the user will have access to the HTML only, that's why we can't have
hard coded or predefined sizes in the core, the user can create his
own template.

@Edmund, yep, we have the same problem :) I don't know how you planned
to use your resizing proxy, as long as I know, you will need to send
the dimensions with the URL, something like:
http://images.mysite.com/ondfou32hfujfj/200/400 but that isn't an
alternative for us.

One solution we found was force the user to create an "image schema"
on the admin interface, this way:

1) The user register a new schmea by submitting a form with the
values: 200 x 300, centered crop
2) The system save this new schema on the database and return an
unique ID for it, let's say: 2k9u8l
3) Now the user will have an relation with the schemas and it's IDs
4) The user implement the ID on the view: <img src="{{ image(file,
'2k9u8l') }}" />
5) The output would be something like <img
src="/image/2k9u8l/theuserimage.png" />
6) This way the system know what is the image and what to do with it
by consulting the database for this image schema.

Pros: This way we wouldn't have resizing parameters on the url,
ensuring maximum system protection agains resizing flood.

Cons: A whole new admin panel to build and it will be a lot more
dificult for users to implement and understand...

--
Att,
Alan Hoffmeister


2012/5/22 Edmund von der Burg <ev...@ecclestoad.co.uk>:

Martin Wawrusch

unread,
May 22, 2012, 8:49:55 AM5/22/12
to expre...@googlegroups.com
Out of curiosity, why is 
alternative for us."

not an alternative for you? An URL schema similar to this one solves so many problems:

.../images/yourimageslug-150x150.jpg

This resolves to the image, and you an do all kind of fancy there, including etag, caching, temporary redirects to a placeholder while the image is resized and so on. It does not require async in views, and it scales easily.

Alan Hoffmeister

unread,
May 22, 2012, 11:05:57 AM5/22/12
to expre...@googlegroups.com
@Martin, solves lots of problems, but a big one appears: resizing flood attack.
I can creade some batch script that touch URLs from
"images/yourimageslug-1x1.jpg" to
"images/yourimageslug-9999x9999.jpg".

If your server wont blow up from the heavy load of converting an image
over 100 millions times, you can say good bye to your credit card on
the Amazon S3.

--
Att,
Alan Hoffmeister


2012/5/22 Martin Wawrusch <mar...@wawrusch.com>:

Paul Vencill

unread,
May 22, 2012, 11:08:05 AM5/22/12
to expre...@googlegroups.com
@Alan,

Sure, if you don't do any input validation or throttling at all... 

Alan Hoffmeister

unread,
May 22, 2012, 11:13:46 AM5/22/12
to expre...@googlegroups.com
@Paul, what kind of validation? Limit the size? That's not an option
for us, we can't limit the user.. Throttling? Quite not simple.. Have
multiple attackers and your throttling won't help..

--
Att,
Alan Hoffmeister


2012/5/22 Paul Vencill <paul.v...@gmail.com>:

Martin Wawrusch

unread,
May 22, 2012, 11:14:02 AM5/22/12
to expre...@googlegroups.com
add an additional, single use token on top of it. 
Only allow resize with first use of token, all other requests are redirected to the cached copy if exists. Resize automatically pushes to S3. so only traffic charges then. Use 1 year expiration date.
 Validate your input for reasonably values.

Alan Hoffmeister

unread,
May 22, 2012, 11:46:09 AM5/22/12
to expre...@googlegroups.com
@Martin, the use of "first use token" wouldn't lead to the same
problem? Async in the view?

Martin Wawrusch

unread,
May 22, 2012, 11:54:06 AM5/22/12
to expre...@googlegroups.com
ah now I get the real problem.

What you need to do in express is to invoke the async function before you render the view, something like this:

app.get '/route...', function (err,...) {
   here you make your async call to either the token generator, or if you are bold, your image resizer,
      and in the result callback from this function you render the view and pass the results of the previous request.

I have posted a sample gist (in coffeescript :-) that shows this here: https://gist.github.com/2769923

Alan Hoffmeister

unread,
May 23, 2012, 8:26:17 AM5/23/12
to expre...@googlegroups.com
@Martin that's too much work for such a simple thing :-)
If I can't use callbacks right inside view helpers by any means, I
think I'll keep my idea of "image schemas".

Martin Wawrusch

unread,
May 23, 2012, 8:43:21 AM5/23/12
to expre...@googlegroups.com
You keep a lot of people busy on two mailing lists for such a simple thing :-) 
Anyways, good luck with this and let us know about the final implementation.

Sugarstack

unread,
May 23, 2012, 10:00:36 AM5/23/12
to expre...@googlegroups.com
This is how I tackled this:

I have a helper that generates the html for an img tag. It has params for width, height. The url is constructed like: 'someimg.jpg?w=75&h=75&key=A89fds'. The key is a unique generated string that relates to the image-name & w/h params. This prevents people overloading your server with lots of diff. sized images (because the key will no longer match).

I then have a middleware before my static that checks for these w/h/k params in urls & calcs whether the key is correct. It then serves up the resized image if its on disk, or uses graphicsmagick to resize the requested image and then serves that. Any errors, etc. cause the req to be passed to the standard static middleware.

Works pretty well, and i've had no problems with it yet. Usage in templates looks like this:

// eg.jade
.user
    .thumb!= img('profilepic.jpg', 150, 150)

which is pretty clean.

Generates this:
<div class="user">
    <div class="thumb"><img src="profilepic.jpg?w=150&h=150&k=U8wdsa9"></div>
</div>

Anand George

unread,
May 23, 2012, 12:26:10 PM5/23/12
to expre...@googlegroups.com
My 2 cents... could we use socket.io as a back channel to pass information to the server that would otherwise have been sent using the url... and therefore prevent any misuse. Moreover information after processing can be sent back via the socket for updating the view. 

--
You received this message because you are subscribed to the Google Groups "Express" group.
To view this discussion on the web visit https://groups.google.com/d/msg/express-js/-/4hPIxtRRmgYJ.

Alan Hoffmeister

unread,
May 27, 2012, 12:36:18 PM5/27/12
to expre...@googlegroups.com
Hey guyz!

I think that I found my answer!

1) Register an dinamic helper:

md5 = require('crypto').createHash 'md5'
app.locals.use (req, res) ->
    app.locals.crop = (image, width, height) ->
        res.crops = new Object if !res.crops
        key = 
md5.update(image + width + height).digest 'hex'
        res.crops[key] =
            image : image
            width : width
            height: heitght
        return "/my-serize-proxy/#{key}"

2) Now we can call crop inside the view:

<img src="{{crop(image, 200, 300)}}" />

3) When the system finished parsing the view, we use a callback to catch all images that we need to store in the database, so the resizing proxy will receive that hash key and query the image and dimensions inside the db.

app.get '/gallery', (req, res) ->
    res.render 'gallery.html', (err, html) ->
        console.log err if err
        if res.crops
            for crop in res.crops
                #here we will save all crops in the database

        #When we are winished we the crops, we can answer the HTML to the client
        res.send html

4) Now is just implement the resiging proxy and query the db for the key in /my-sesizing-proxy/:key and you will know what image and dimensions you'll need to use!

Ta-da! Resizing without dimensions params in the URL!
 
--
Att,
Alan Hoffmeister


2012/5/23 Anand George <mranan...@gmail.com>
Reply all
Reply to author
Forward
0 new messages