MiniMagick, and processing thumbnails...

I have a requirement that can't be that outrageous....

I want to be able to upload an image, and have multiple thumbnails be
created for each. Then, I want to post process each image (the main
image plus the thumbnails) to add borders. The trick is that the
borders need to be different for each image. I thought I could use
the after_resize handler, but when I try to add a border to the passed
image, the other images are also affected by this call. It seems to
work like this:

- create the main image
- call after_resize
- (DO MY STUFF)

This modified image is now the basis for the thumbnails. Therefore,
the after_resize gets called with an image that already has a border
attached. I think this is wrong...

I've ended up doing this after the main photo model has been saved:

[ @photo.public_filename, @photo.public_filename( :thumb ),
@photo.public_filename( :medium ),
@photo.public_filename( :large )].each do |path|
          path = "#{RAILS_ROOT}/public/#{path}"
          file = MiniMagick::Image.from_file( path )
          file.combine_options do |i|
            i.gravity 'center'
            i.bordercolor 'black'
            i.border 1
            i.bordercolor 'white'
            i.border 10
          end
          file.write( path )
        end

Ick Ick Ick.

Can anyone offer a better way of adding custom borders to each image?

Would it be possible to do this strictly via CSS? Adding a special
class to the image as it comes out and just applying the needed
border? You could do the border as a background on a div that
surrounds the image if the border is graphical rather than solid or
dashed. It would make for alot less server side work, and the border
would be cached after the first load saving you some bandwidth in the
process.

Would it be possible to do this strictly via CSS? Adding a special
class to the image as it comes out and just applying the needed
border?

+ 1

I agree, it would be better to do this with CSS. However, I'm having
a heck of a time trying to get the right incantation. The issue I ran
into that basically drove me nuts was that the div surrounding the
image was expanding to the width of the container div, making the
border too large. I would work if I didn't specify a specific size
for the container div, but then the images wouldn't line up into
columns, which looked pretty awful.

Anyone have any sample CSS that would work in this situation? I'll
take another crack at it today, but some practical examples would be
nice. :slight_smile:

Send me the HTML but here are some simple examples:

<div class="borderImg">
<img src="bob" />
</div>

.borderImg IMG {border:2px solid #000000;}

OR

<img src="bob" class="borderImg" />
IMG.borderImg {border:2px solid #000000;}

OR

<div class="borderImg">
<img src="bob" />
</div>

.borderImg {background:url(bobBorder) top left no-repeat
#FFFFFF;padding:2px;}

(Leave padding so you can see the border around the IMG then you won't
need any height and width on the div)

If you are having problems with divs - you can try a span instead -
divs are block level and always expand width-wise to the size of their
container, spans are inline elements. You can also place a float:left
or float:right on the div to make it inline, but you would then need
to add an addition div below the element to clear the float -

<div class="borderImg">
<img src="bob" />
</div>
<div class="spacer">&nbsp;</div>
.borderImg {background:url(bobBorder) top left no-repeat
#FFFFFF;padding:2px;float:left;}
.spacer {clear:both;height:0px;line-height:0px;font-size:0px;}

hopefully that helps.

<div class="content"><img src="image.jpg"></div>

So in the CSS it could be something like:

.content img
{
  border:1px solid #ccc;
  padding:3px;
  margin:6px;
  background-color:#f9f9f9;
}

Ah! I hadn't thought of using the background to create the border.
That's exactly what I was looking for. Here's what I ended up with,
with a little prototype to center the images in their respective
boxes:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://
www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<script src='prototype.js'></script>
<style type='text/css'>
  body {
    background-color: black;
  }
  .content {
    height: 250px;
    width: 250px;
    float: left;
    border: 1px solid red; /* for illustrative purposes */
  }
  .content img
  {
    border:10px solid white;
    padding:1px;
    background-color:black;
  }
</style>
<script type='text/javascript'>
  window.onload = function() {
      $$( '.content img' ).each( function( image ) {
          if( image.tagName == "IMG" ) {
            marginLeft = ( ( image.up().getWidth() - image.getWidth() -
6 ) / 2 ) + 'px'
          marginTop = ( ( image.up().getHeight() - image.getHeight() -
6 ) / 2 ) + 'px'
            image.setStyle( { 'marginLeft' : marginLeft, 'marginTop' :
marginTop } );
          }
      } );
  }
</script>
</head>
<body>
  <div class='content'><img src='landscape.jpg'/></div>
  <div class='content'><img src='landscape.jpg'/></div>
  <div class='content'><img src='portrait.jpg'/></div>
  <div class='content'><img src='landscape.jpg'/></div>
</body>
</html>

Works exactly as I wanted.

Thanks guys!