Jump to content
GreenSock

Search In
  • More options...
Find results that contain...
Find results in...
skiller

TransformManager & cropped images

Recommended Posts

Hi there,

 

I've spent a good part of the last few weeks trying to use the TransformManager for an application that not only scales, rotates, and moves images, but also crops them. I find the moving, rotating and scaling part compellingly easy to achieve with the TransformManager, but it doesn't seem to be suitable for moving, rotating and scaling cropmasks, too.

 

The requirements:

 

  • [*:2a6p5l9k] There is a layer with an arbitrary number of images and text elements (RichText) that are created on the fly by the user[*:2a6p5l9k] above that layer there's another layer that partially obscures the image/text layer (a kind of mask/template – but not a clip mask, since the parts "masked out" still "shine through" the mask)[*:2a6p5l9k] yet on top of that is a layer that contains control elements for the images/textitems that must not be obscured by the mask/template layer[*:2a6p5l9k] images are to be scaled, rotated, moved and cropped on the fly[*:2a6p5l9k] it should be possible to grab the items even if they're mostly obscured by the template/mask layer --> the handles and borders of selected items must appear "above" the template, even if the corresponding image is "below" the template/mask[*:2a6p5l9k] images must be scaleable/croppable in-place even if they're mostly "under" the template/mask

 

The setup:

  • [*:2a6p5l9k] The TransformManager sits atop the template layer and governs placeholder elements ("proxies"), which are created along with each text item/image and added to the TM[*:2a6p5l9k] the TransformItems relate to the transparent proxies, changes in dimensions, position, and scale are updated to the corresponding image/text (through Flex's commitProperties/invalidateDisplayList mechanisms)[*:2a6p5l9k] image items are their own clipmasks, i.e. masking and clipping is achieved through negative positioning of the image inside the image box element[*:2a6p5l9k] TransformManager operates in two modes: SCALE_NORMAL has image scale, move, and rotate as a whole, SCALE_WIDTH_AND_HEIGHT should keep the image in place, preserve/freeze the scaling, lock rotation, and only move the crop mask within the boundaries of the image

 

The problems:

  • [*:2a6p5l9k] TransformManager removes and adds TransformItems when switching their scale mode between scaling and cropping, resulting in the current item to be forced out of its ongoing modification[*:2a6p5l9k] the crop mask should be confined to the image, i.e. "scaling" and moving the image mask must not lead to a situation where part of the mask are outside of the image --> the TransformManagers bounding box remains unrotated, leading to undesired mask bleeding for rotated images and actually rendering the TM's bounds mechanism unusable[*:2a6p5l9k] TransformManager uses x/y + width/height as well as transform matrices to manipulate the TransformItems, making it very hard to simply "listen" to changes in the desired properties (sometimes dragging handles results only in a modified transform matrix, Matrix doesn't implement IEventDispatcher, though, leaving you with the only option to listen for frame events)

 

The possible solutions:

  • [*:2a6p5l9k]TransformManager should support bounding boxes that are not just unrotated rectangles, allowing for easy crop mask confinement inside of an image's area[*:2a6p5l9k]TransformManager/TransformItem should emit events when the transform matrix changes[*:2a6p5l9k]maybe even a full-fledged cropping mechanism out of the box? *wink wink wink*

 

 

Thoughts are welcome, because I'm really stuck here. A colleague talked me into buying this pile of… monolithic code that I'm having a really hard time with. Hey, it costs three hundred bucks – I expect it to behave well then. Get me right, the TransformManager goes great lengths in the right direction, but it stops short. Or do you think it's not suitable for that purpose and I should get a refund?

 

 

Best regards

Constantin

Link to comment
Share on other sites

Ha. "pile of… monolithic code"...ouch. Well, I'm sorry to hear about the frustration. I'd be happy to issue a full refund if that's what you prefer, but I suspect the cropping thing isn't quite as impossible as it may seem. I'm running out to a meeting but I'll try to get back here later with a more full response. Stand by...

Link to comment
Share on other sites

Thanks for the reply.

 

The cropping should not be that hard, especially in Flex, where you can quite easily use Flex's own cropping mechanisms in its components (so there's no need to juggle masks like in an earlier approach I've tried).

 

I'm basically switching from normal scale mode to width/height scale mode when the crop mode is activated because I don't want any scaling to occur (maybe I should try to simply lock scaling…), but I find it peculiarly hard to track and translate the right set of modifications, and when switching back to normal scale mode there are unwanted transform matrix modifications that ruin my calculations by occuring too early. But I suspect I still haven't grasped the intricacies of TM to their full extent.

 

Initially, the TransformManager was suggested to make the scaling and cropping easy. Now I find myself sifting through the code, trying to grasp what happens when (and why), which calculations to stop and which modifications to allow. And, to be honest, the intensive use of generic objects doesn't make debugging easier. I'd rather have Value objects that I can subclass and put breakpoints into.

 

Right now I've resorted to monkey patching the TransformManager, but is definitely not pretty. Maybe we can find a solution together, and if it suits the TransformManager well we could look for ways to blend that functionality into it.

 

Looking forward to your suggestions…

 

 

Best regards

Constantin

Link to comment
Share on other sites

Yeah, it's not as difficult as you might think. I've whipped together a little example class that should help you a lot, but I need to finish a few tweaks and then I should be able to send it your way on Monday sometime, okay? Stand by...

 

(by the way, it is absolutely essential to use the Matrices to do the transformations because that's the only way to accommodate multiple selections and potential skewing that can happen. In terms of getting notified when various things change, that should be as simple as listening for SCALE, ROTATE, and MOVE events. And I realize it may look "monolithic" and complex inside the classes, but I assure you that building a tool like TransformManager is a much, much bigger undertaking than most developers initially suspect and there are tons of little "gotchas" that need to be wrestled through. Hopefully when I send you the example on Monday you'll feel better about the investment in the tool. If not, the refund offer still stands.)

Link to comment
Share on other sites

Alright, I've whipped together a "Crop" class (and matching FlexCrop for Flex apps) that will hopefully help you. As of today, it is included in the download .zip for TransformManager (AS3). To see an interactive example of its capabilities, just go to http://www.greensock.com/transformmanageras3/#crop (that .fla file is in the "examples" directory of the .zip too)

 

It started out pretty simple actually, but I went a little crazy adding features and configuration options to the class for convenience :)

 

If nothing else, I hope it at least serves as a jumping-off point for you to build your own customized TransformManager-based cropping tool. I added a bunch of ASDoc comments in the code to help explain how it works.

 

I'd love to hear what you think.

 

Enjoy.

Link to comment
Share on other sites

Thanks, great! You're a Wiz. :)

 

A little different than I would've envisioned, but works like a charm. And to have this functionality *within* the TransformManager definitely reduces coupling.

 

 

Best regards

Constantin

Link to comment
Share on other sites

Hi there,

 

I had written an elaborate forum post about how I wished the cropping would work which I couldn't post because the forum wasn't reachable, but it turned out you did it anyway. Thanks again for your efforts.

 

I just wanted to assure you that your efforts are very well valued, and the TransformManager is a great piece of code, and with the latest addition it has become even better. ;-)

 

 

Best regards

Constantin

Link to comment
Share on other sites

I had written an elaborate forum post about how I wished the cropping would work which I couldn't post because the forum wasn't reachable, but it turned out you did it anyway. Thanks again for your efforts.

 

I just wanted to assure you that your efforts are very well valued, and the TransformManager is a great piece of code, and with the latest addition it has become even better. ;-)

Great! Glad to hear it. Thanks for getting back to me. Good luck with your project.

Link to comment
Share on other sites

Sorry for being a pain in the arse, but I'd like to suggest a few additions. While inspecting the code and the newly added cropping features, it turns out that I've already been down that road (which I don't mean in a diminishing way, your efforts are well appreciated!).

 

It turned out, though, that there are a few requirements that still need to be met, especially that the crop selection must not exceed the image's bounds – something I found impossible to achieve without drilling holes into the TransformManager/TransformItem (which - per se - is okay and covered by the license, but it would still feel more natural as a TM/TI functionality).

 

I assume the TransformManager's bounds are thought to restrict the movement of managed items within the limits of a "canvas", hence it merely accepts an unrotated rectangle relative to the TransformManager's space as bounds parameter. So what I have to do is monkey patch the TransformItem in a way that I can check if it is inside of the image bounds first before I allow it to move its handles – which results in a very undesired dependency and strong coupling between the TransformItem and the target object.

 

How about enhancing the TransformManager in a way that it respects rotated retangles as well? Or even better: keep the current TransformManager "canvas" bounds and allow for TransformItems to have their own boundaries? That would make the TransformManager/TransformItem a black box again.

 

So here's the desired enhancement/workflow:

A TransformItem should accept an arbitrary UIComponent as a bounds parameter of its own, using its bounds and rotation to restrict its own and its handles' movement.

 

So basically, I have a Flex component that is equivalent to the image's clip mask (undesired image portions are clipped through Flex's own clipping mechanism, i.e. clipAndEnableScrolling). When in crop mode, the image will stay in place, rotation is locked and scaling is forbidden.

I have no problem with setting the component's image position back to its fixed position after it has been moved by the TransformManager/TransformItem – that's the easy part. The tricky part is restricting the item to the confines of the image, since the crop mask should never exceed the image (which it does with the TransformManager/TransformItem/Crop classes in their current form).

 

Let me know what you think.

 

 

Best regards

Constantin

Link to comment
Share on other sites

Gosh, you are really hard to please :)

 

This is definitely a more complicated task to accomplish well and you're actually the first person who has ever requested this kind of bounds functionality (not that it's a bad suggestion, just one that's very uncommon thus far). Bounds enforcement is pretty tricky to do "right" especially with multiple selections. Given the lack of interest from others, I'm reluctant to burn all the hours it would take to implement this (my schedule is extremely packed as it is). If you'd like to book some of my time to add this feature, shoot me an e-mail or Private Message here in the forums and we'll talk timeline, budget, etc. Otherwise, if you'd like to tackle it yourself, the easiest (but not technically the smoothest) way to do it might be to record the target's transform.matrix and then create a listener for SCALE, ROTATE, and MOVE events. In that method, you could analyze whether or not the object exceeded the bounds (your rotated bounds) and if so, revert the transform.matrix to that one you recorded. If not, record that latest transform.matrix (basically you always have the last iteration so that you can revert). Don't forget to update() the TransformItem if you revert so that it calibrates things.

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×