Entries Tagged as 'code'

Dynamically resizing text in Flash to fit a container

Earlier this year I ran into an interesting problem. I was generating images of thought bubbles randomly appearing in a Flash movie containing people’s messages they’ve entered in a web form. It was a nice interactive display. The trouble was that people inevitably would write thoughts of varying lengths, and either the short ones looked swamped by the bubble, or the long one’s over ran:

Bubbles overlapping

So, how could I determine the length and adjust the text size appropriately? After spending sometime attempting to use a variety of formulas I thought of a different approach: Firstly, start with the text size extremely large, say size 50. Then, check if it breaks the boundary of the bubble, if it does, drop the size by 2 points. Now does it break the boundary? If it does, drop the size… and so on until the text fits.

The result is neat thought bubbles with well sized text populating them:

Bubbles neatly sized

I’ve stripped the Actionscript 2 code out of my application by means of example, though it won’t run out of the box:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
//Generate a bubble
function generateBubble() {
	//Duplicate the bubble dummy
	bubbleDummy.duplicateMovieClip ("bubble" + intDepth, getNextHighestDepth());
	//And select it
	objBubble = get("bubble" + intDepth);
 
	//Substitute in the response as dynamic text
	objBubble.txtResponse.text 	= loadResponseObj["response"+intResponse];
 
	//Set up the TextFormat
	myTextFormat = new TextFormat();
	myTextFormat.font = "my font";
	myTextFormat.size = 50;
 
	objBubble.txtResponse.embedFonts = true;
 
	//Autosize the dynamic text field
	objBubble.txtResponse.setTextFormat(myTextFormat);
	objBubble.txtResponse.autoSize = "left";
 
	while ( objBubble.txtResponse._height > 140 ) { 	// the text field is taller than the bubble
		myTextFormat.size -= 2; 			// shrink the font size by 2
		objBubble.txtResponse.setTextFormat(myTextFormat);
		objBubble.txtResponse.autoSize = "left";	// and resize the box...
	}
 
	//Set the backing the same height as the text field
	objBubble.backing._height = objBubble.txtResponse._height + 40;
 
	//Keep our records tidy
	intResponse ++;
	intDepth ++;
}

Obviously this solution is an iterative loop, so I’d like to hear if there are more elegant solutions.

Cropped thumbnails in attachment_fu using mini_magick

I’m in the process of building a ruby on rails application that allows people to upload images. The application then takes these images and creates a series of thumbnails that are used throughout the site.

Having opted to use attachment_fu and mini_magick as my respective file upload plugin and image processor, I found an excellent post by Khamsouk Souvanlasy explaining how to create the upload form using AJAX.

The difficultly came when I wanted to make one of the custom thumbnails measure 100px x 100px, and crop the source image appropriately:

Example of ratio cropping

Thankfully Andy Croll had written how he patched attachment_fu to enable it to do just that, only using ImageScience as it’s image processor.

Therefore, I’ve extended this patch to allow you to use a ! flag to create an aspect ratio cropped image, using mini_magick as your processor.

Step 1

Modify attachment_fu/lib/geometry.rb, as suggested by Andy in cropped thumbnails in attachment_fu using imagescience. This ensures the ! flag is interpretted correctly in attachment_fu.

Step 2

Modify the resize_image function of attachment_fu/processors/mini_magick_processor.rb:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
def resize_image(img, size)
  size = size.first if size.is_a?(Array) && size.length == 1
  if size.is_a?(Fixnum) || (size.is_a?(Array) && size.first.is_a?(Fixnum))
    if size.is_a?(Fixnum)
      size = [size, size]
      img.resize(size.join('x'))
    else
      img.resize(size.join('x') + '!')
    end
  else
    n_size = [img[:width], img[:height]] / size.to_s
    if size.ends_with? "!"
      aspect = n_size[0].to_f / n_size[1].to_f
      ih, iw = img[:height], img[:width]
      w, h = (ih * aspect), (iw / aspect)
      w = [iw, w].min.to_i
      h = [ih, h].min.to_i
      if ih > h
        shave_off =  ((ih - h) / 2).round
        img.shave("0x#{shave_off}")
      end
      if iw > w
        shave_off = ((iw - w ) / 2).round
        img.shave("#{shave_off}x0")
      end
      img.resize(size.to_s)
    else
      img.resize(size.to_s)
    end
    self.temp_path = img
  end
end

Step 3

Modify your model, using the new ! flag to force a cropped aspect ratio:

has_attachment  :storage => :file_system,
                :max_size => 2.megabytes,
                :thumbnails => { :thumb => '100x100!', :medium => '470x470' },
                :processor => :MiniMagick

I think this is an excellent solution. Thanks to everyone I’ve link to here, they’ve done the real work!