I am working on creating a module that interfaces with Media for cropping images, and had a question regarding the javascript integration. I have to know when an image is selected, and I've found this in media-browser.js:

Drupal.media.browser.selectionFinalized = function (selectedMedia) {
  // This is intended to be overridden if a callee wants to be triggered
  // when the media selection is finalized from inside the browser.
  // This is used for the file upload form for instance.
};

This sounds like what I need (an event handler for file selection), my question is, how can I override it? I tried the following to no avail:

Drupal.media.browser.selectionFinalized = function(selectedMedia) {
    // My code here
    console.log(selectedMedia);
}

If anyone familiar with this code could let me know, I'd appreciate it.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

JacobSingh’s picture

Hi cocoloco:

This is awesome! The API for the media browser could really use some fixes, so please feel free to suggest changes, but for now, check out the wysiwyg integration for a tip on how to interact.

wysiwyg-media.js

Drupal.media.popups.mediaBrowser(function (mediaFiles) {
        Drupal.wysiwyg.plugins.media.mediaBrowserOnSelect(mediaFiles, instanceId);
      }, settings['global']);

So here it's saying "when someone selects something, call mediaBrowserOnSelect()"

mediaBrowserOnSelect: function (mediaFiles, instanceId) {
    var mediaFile = mediaFiles[0];
    var options = {};
    Drupal.media.popups.mediaStyleSelector(mediaFile, function (formattedMedia) {
      Drupal.wysiwyg.plugins.media.insertMediaFile(mediaFile, formattedMedia.type, formattedMedia.html, formattedMedia.options, Drupal.wysiwyg.instances[instanceId]);
    }, options);

    return;
  },

mediaBrowserOnSelect, launches the "mediaStyleSelector" popup, passing in the mediafile and a callback for what to do when it comes back. This popup contains the place where the user can select large, small, medium, etc and the alt tag.

So the call to load this secondary page is independent of the browser itself. In your case, I don't know what your designs are, but maybe the best solution is actually to just modify that page with an alter to add a "custom" setting for images in the view_mode drop down and then launch a cropping interface?

I'm really excited you're building this! Can you submit some wireframes before you get too knee deep in the code so we all know what's coming down the pike and I can be more helpful?

Thanks,
Jacob

cocoloco’s picture

Jacob,

I'm glad you're excited about this - thanks for all of the work you've put in to the media module. I'm launching a new project on D7 as soon as possible with a heavy focus on ease-of-use and the media handling aspect of D6 just isn't cutting it. This is coming out of necessity, so I'm looking to get a base implementation up ASAP, then refine it as time goes on.

At first, this will only support the Multimedia asset field via a "Media image selector with cropping" widget, where users can configure cropping dimensions on a per-instance basis. Down the road, I want to try to integrate this into the browser to allow cropping on a per-insert basis into a WYSIWYG textarea.

From looking at the code, I was thinking of this as a development strategy (using the widget):

1. User clicks "Select media", then uploads or selects an image.
2. Module JS intercepts the selected image information using the mediaBrowserOnSelect() callback.
3. An interface is created where we can specify the crop dimensions using jCrop. The image is maximized to the maximum available area using jQuery's innerHeight/innerWidth functions and jCrop's box sizing methods for scaling down large images (see attached media-widget-crop.jpg).
4. Image thumbnail is replaced and dynamic preview is shown and Re-crop button is added to edit the crop (see attached media-widget-crop-finished.jpg).
5. Crop data (start x, start y, delta x, delta y) is stored with the field data (which stores it in the _data column of the field's data table).
6. When the image is called, we would need to alter the URL to specify the cropping parameters, such as appending the crop data to the end of the image url (image.jpg?crop=100,100,500,250) since it seems that the only data is passed to the image is the filename and style. I believe the Imagefield Crop module actually made a copy of the image with the cropped dimensions, then ran any Imagecache actions on the copy. As I don't think it would be a good idea to have a bunch of cropped copies of images littering the Media library, we'd need some way of communicating the crop information when loading the image from the URL.

I'm a bit limited with my knowledge of the inner workings of the new Image API and the Media module so I'm not sure if this is the "proper" way of doing this but any input or insight would be appreciated.

This is my start - I'm eager to hear your thoughts.

cocoloco’s picture

Title: media-browser.js Integration Question » Media Image Cropping
Category: support » feature

Actually let me revise - I don't think that appending the cropping params to the image would be a good idea since that can open a security door to overload a CPU by rapidly requesting different crops, so one of three things will probably have to be done:

  1. Make a copy of the image in the library and use that file. Unfortunately this may clutter up the image library unless we can add some sort of flag to these images for them not to display in the browser.
  2. Create a database table that holds cropping info (or use an existing one such as the data column in the media field's table perhaps?) and pass a row identifier with the image. However, I'm not sure if usage records are created when images are inserted through the WYSIWYG editor (seems like params are just included in a JSON object).
  3. Pass a HMAC together with the crop size to verify an approved crop size is being requested from the server.

As I've said, I have limited knowledge with how Media and some of the newer D7 architecture works, so there may be a way that I'm not thinking of.

JacobSingh’s picture

Hmm...

Okay, so from what I understand, we're going to need to store additional meta-data along with each instance. Currently, the media-as-a-field code has been a bit of a neglected step-child from a UX perspective and architecture. I'd like that to change.

http://drupal.org/comment/reply/969284#comment-form

There is some legacy stuff in there. See media_field_schema();

This is actually not even used :( Only the fid field is used. There was an original idea of making media fields overridable on an instance-by-instance basis (hence the "data" blob). I'm not sure this is terribly practical and the case is a little edgy. The title field thing was the same idea.

So cropping definitions seem to belong here. I don't know about field schema altering and if it can even be done. IIRC, widgets aren't allowed to define new fields, so that means you'd need to define a new field type "Media field / cropping". This is kinda crappy because it's just a bunch of wrappers around the existing functions.

We could alternately add another field to the schema like "customizations" or something which could contain stuff like custom crops and... ?

Another approach is to just alter the widget, and do your own storage in a custom table. The danger here is you'd want to be real careful to make sure you stay in sync and delete your data when the field instance data changed...

Of course, you also need to account for the media type so crops only work for images. (although there are video and audio crops, I'd handle these in later aberrations).

Hope that helps a little.

Best,
Jacob.

cocoloco’s picture

Jacob,

I can see the data blob being useful for the field instances. However, the one problem I see is that including an image via WYSIWYG creates a JSON-based placeholder that seems like it has enough information to render an image by itself:

[[{"type":"media","view_mode":"media_large","fid":"6","attributes":{"alt":"","class":"media-image","title":""}}]]

Since this is the case, it seems that no database record is created, and since it has enough information, an image with the correct style could be rendered on demand. Since no database record is created, we would either have to create a table that held all metadata information and update it whenever changes were made in the WYSIWYG browser, introducing syncing issues and AJAX callbacks for in-editor WYSIWYG deletions, etc. (which you noted) or pass this metadata along with the URL when generating the image (which seems like the easier approach). Other than these two options, I'm at a loss on how we would communicate metadata to the image in question.

If we were to add cropping metadata to this, say:

[[{"type":"media","view_mode":"media_large","fid":"6","attributes":{"alt":"","class":"media-image","title":""},"metadata":{"cropping":[100,100,500,250]}}]]

it would translate to:

/sites/default/files/styles/large/public/grass.jpg?metadata=<?php http_build_query($metadata); ?>

Now, we have the information we need for cropping, but then it would make it easy for an attacker to perform a DoS by rapidly requesting random (and non-cached) crops. One way to solve this is to sign the metadata with an HMAC (we could use $drupal_hash_salt). The only downsides I see to this is a long query string appended to the image URL, and an image that isn't cropped if the query string isn't appended.

If anyone has any thoughts regarding this, I'd be eager to hear them.

JacobSingh’s picture

Hmm... good stuff! The DOS angle makes everything a bit harder, however I think this can be mitigated by logging and restricting based on the # of requested crops for a given image over a given time period.

If you say that only 10 derivations of image X can be generated every 24hrs that's more than enough for 99% of use cases, but also stops any DOS.

For the WYSIWYG stuff, I'd just include it with the other attributes. That whole setup is screwy, and needs re-architecting, but I don't see why you couldn't just include it in the attributes like crop=50:100:300:200 or whatever. The code which does the rendering could grab the definition, make the derivative, md5 the crop instructions and then use the md5 as a key for the resulting image. Or make a nice URL of image_50_100_300_200.jpg and just ref that.

How to handle the actual crop is another matter. I guess it would be better to use image_style_alter than to generate it when the json is being built into the object. I know it sounds a little screwy, but maybe we could have an attribute of the field (is this what you were suggesting) that would store the same attributes that go into the WYSIWYG JSON string and use similar rendering functions?

BEst,
J

cocoloco’s picture

Jacob,

I have the images cropping from a URL and verifying with a signature successfully, however I can't figure out how to create and register a javascript plugin for Media. I looked at the wysiwyg-media.js file, but it seems like it's being invoked from the WYSIWYG module's plugin system, not Media's, since it's namespace is Drupal.wysiwyg.plugins.media.

Since there's no up-to-date documentation, can you or someone who's familiar with Media's JS plugin system write a sample basic plugin outline that includes some sort of mediaBrowserOnSelect callback that works with the popup created by the Media widget? It would really help get this module going and also could be a reference for other would-be Media integrators.

Thanks.

JacobSingh’s picture

Yes, we should absolutely do this. I created a node for it, please fill in details if desired.
#972830: Create a sample plugin module to show how to extend the media browser

I won't have time to do that in any decent way for the next 2 weeks at least, so I wrote a very sketchy primer over there.

cocoloco’s picture

Jacob,

Work is continuing on this and as long as you would be able to review and commit the JS patch in #972830: Create a sample plugin module to show how to extend the media browser, I should have a mostly-working cropping module to submit for review by the end of the week.

Thanks for all your help.

-cocoloco

JacobSingh’s picture

Awesome! Really excited to see what comes out of it. I'll take a look at the other patch tomorrow.

Best,
J

rwohleb’s picture

subscribe

cocoloco’s picture

Jacob,

I'm really close, but it seems I've hit a snag. I'm trying to figure out how to save crop information in the field table, but it seems (correct me if I'm wrong) but it doesn't appear that there's the ability to save data in the field's data column yet. The only field element that looks like it's in the form is the "fid" element.

I tried to see if there was a hook that I could use to preprocess the variables before they were saved, and it looks like hook_field_presave would be able to do that job. However, this can only be set on a per-field basis (not a per-widget basis) and I'd hate to create a new field (and consequently, table) when the media field has all the columns it needs to store crop information just fine.

I thought one possible solution would be to also include the data column as a hidden field in the form, just like you did with the fid column (from media_element_process()):

$element['fid'] = array(
    '#type' => 'textfield',
    '#default_value' => $fid,
    '#attributes' => array('class' => array('fid')),
);

// Create a place where we can access and edit the data column
// Transform current data where it's storable in a hidden field
// We'll need $.deparam to unserialize the data in the hidden field
$element['#attached']['js'][] = 'misc/jquery.ba-bbq.js';
// This can be decoded in jQuery like so:
// var data = $.deparam($('.data').val());
// Then updated like so:
// data.crop = {x: 100, y: 100, w: 500, h: 250};
// $('.data').val($.param(data));
$element['data'] = array(
    '#type' => 'hidden',
    '#default_value' => http_build_query($current_data), // $current_data is unserialized
    '#attributes' => array('class' => array('data')),
);

Then you can easily get this with all of the other form data:

// I forget the variable names that get sent back after a form is submitted, however you should get the idea:
parse_str($form['data'], $unserialized_data);

I'm not sure where in the media.module it saves this data to the field table, but if you could let me know, I could make a patch for the media module if you think this is a good approach. On the other hand, if you have a better approach, or if something is already created, I'm eager to hear your thoughts.

JacobSingh’s picture

Heh, now you're seeing what I was talking about in http://drupal.org/comment/reply/969284#comment-3712208

I"d really like to get @effulgentsia's take on this. But outside of that, I think there is little option but to add a more columns to the media field. I put this in IRC, but got no bites yet:

JacobSingh: Hey, I've got a feature request which someone has almost finished to provide cropping in the media module on a per-instance basis.
[07:51am] JacobSingh: Of course, we don't want a "cropping spec" column to go w/ each media field
[07:52am] JacobSingh: Is there a way to alter the schema definition of a field? (ii.e. to add a new column to store this data in)
[07:52am] JacobSingh: Sounds like sketchy territory, but the alternative is a BBOD (Big Blob of Data) tacked on, which also kinda sucks

Does this describe the problem succinctly?

Best,
Jacob

cocoloco’s picture

Jacob,

I think we have everything we need to currently add cropping data to the current schema:

--
-- Table structure for table `field_media`(only relevant columns shown)
--
`field_fid` int(10) unsigned DEFAULT NULL,
`field_title` varchar(255) DEFAULT NULL,
`field_data` longtext,

The existing longtext data column is more than enough room to store a serialized array used for cropping as well as other data, however I guess in D7 they made a push to store any serialized data in BLOBs instead of text-based fields (#690746: Text column type doesn't reliably hold serialized variables). In that case, the data field should be a BLOB anyway to do what I believe it intends to do (hold extra data about a field instance).

Of course I could also make another field type called "Media image w/ cropping" that users can select instead of "Multimedia asset" however it doesn't make much sense to create a whole other database table just to store a bit of metadata, which may be useful to other contributors.

cocoloco’s picture

Jacob,

Follow-up from my previous comment:

Looking through the code, it seems that the existing data field was made exactly for this purpose:

function media_field_schema($field) {
  return array(
    'columns' => array(
      'fid' => array(
        'type' => 'int',
        'unsigned' => TRUE,
        'not null' => FALSE,
      ),
      'title' => array(
        'type' => 'varchar',
        'length' => 255,
        'not null' => FALSE,
      ),
      'data' => array(
        'type' => 'text',
        'not null' => FALSE,
        'size' => 'big',
        'serialize' => TRUE,
        //'description' => 'Used for storing additional information.  Can be harnessed by widgets',
      ),
    ),
    'indexes' => array(
      'fid' => array('fid'),
    ),
  );
}

If that's the case, we just need to convert this to a BLOB field (see linked issue in previous comment) and provide a way that I can line in to update it (such as what is shown in comment #12).

If there is a performance issue with LONGBLOBs (though there shouldn't be any more than with the current LONGTEXT) I would say it would be OK to just use a regular BLOB - I don't think additional data will exceed 64KB (not for crops anyway) and we certainly wouldn't need the 4GB available as a LONGBLOB. MEDIUMBLOB (16MB) would be a good compromise but I don't think we could use that since it is not defined in the core database handler's getFieldTypeMap().

Let me know your thoughts.

effulgentsia’s picture

@cocoloco: If I'm understanding correctly, what you're looking for is how to make the widget add info to $form_state['values'][FIELD_NAME][LANGUAGE_CODE][DELTA]['data']. That way, your module can just deal with widget code, and not have to also create a new field type.

In D6, there was a 'process form values' operation for widgets to do this, but in D7, that's been removed, because the Form API already provides a way to do that, so widgets were made simpler in D7 by delegating more to the Form API.

The FAPI technique is to use #element_validate, and within the element-level validation callback, call form_set_value(). For an example, see options_field_widget_validate().

So you don't need to create a dummy 'data' hidden element. Though I guess you can, if you think that makes sense. Ultimately, it's up to widgets to decide how they want to structure the form. All the field cares about is what ends up in $form_state['values'][FIELD_NAME][LANGUAGE_CODE][DELTA]. Though note, before D7 is released, even that location will be abstracted: #942310: Field form cannot be attached more than once.

I'm not sure where in the media.module it saves this data to the field table

The Field API takes care of that. The field module (in this case, 'media') just defines the columns within hook_field_schema(). Then, when node_save() is called (or if the field is attached to an entity type other than a node, then that entity type's save function), it calls field_attach_insert() or field_attach_update(), and those functions iterate every field in the entity, and issue db queries to get the identified columns from their $form_state['values'] location into the db (calling various hooks in the process to allow for customization).

cocoloco’s picture

@effulgentsia: That did the trick! Thanks for pointing me in the right direction.

vood002’s picture

awesome thread...learned a few things just reading through it once...subscribing, and i'll be happy to test~

cocoloco’s picture

@effulgentsia: Hopefully you have time to share your knowledge regarding the Fields API for one more thing.

I have my cropping widget saving the crop data to the Media field's data column successfully. However, when the field is being displayed, it needs to alter the URL of the image if cropping information exists in the field's data column. Since this is module currently only implements a widget, do I have the power to do this? Or would I need to:

  • Create a field type specifically for image cropping? I've tried not to go down this route, since Media's field table already has all the columns needed for storing cropping metadata, and I'd essentially be creating the same table structure for this new field. However, it seems that hook_field_prepare_view() is perfect for this, although it seems most hook_field_* (with the exception of hook_field_widget_*) calls can only be attached to field modules, and widget-only modules cannot invoke them.
  • Write a formatter and attach it to the Media field somehow?
  • Ask the Media module to provide a hook somewhere?

If you could point me in the right direction, I'd appreciate it.

effulgentsia’s picture

Version: 7.x-1.0-beta1 » 7.x-1.x-dev
Write a formatter and attach it to the Media field somehow?

This would be the way most in line with how Field API is intended to be used. Field types define how the data is stored. Widgets define how the field is edited. And formatters define how the field is displayed. So, if you're providing a new way to display a media field, then a new formatter is appropriate.

However, the challenge with media is the way media field formatters relate to media entity view modes and file field formatters. The challenge comes from media not being a simple field, but being an entity to which the administrator can add more fields. For example, suppose your Article node type has a media field. On the Manage Display page for the Article type, a formatter you can apply to your Media field is "Small". What this does is then renders the referenced media entity with a "Small" view mode. On the Manage Display page for the Image/Audio/Video media types, you can configure how to display these types "Small", and it is here that you set the formatter for the underlying File field. For example, you might decide to use the "File Style: small" formatter, and this is handled not by the Media module, but by the Styles module. Additionally, your Media entity may have other fields like Tags or Description, so this is where you can decide how to display those other fields when your media field is displayed as "Small".

Additionally, the Styles module provides another level of abstraction, so that its formatters can work well across different types of files. For example, the "File Style: small" formatter is applied to a File field, but the file itself can be an image, a video, an audio, etc., and the formatter needs do the right thing based on the type of file.

So, there's two levels of abstraction. Media field formatters are abstractions for handling that media entities may contain fields in addition to the underlying file field. And File field formatters provided by the Styles module are abstractions for handling that how you display a file depends on its type.

So, you can plug in at one of three levels:

  1. Have your module define a Styles container/preset/style. See Media: Youtube for an example.
  2. Have your module define a direct File field formatter without using Styles.
  3. Have your module define a Media field formatter that doesn't bother with displaying other fields that the media entity might have.

Normally, I'd suggest #1 above, but the Styles module is currently undergoing significant refactoring between the 1.x and 2.x branches, but Media module does not yet work with the 2.x branch. So, you might want to go with #3 above as a short term solution, and then do #1 once Styles 2.x settles down and works with Media.

Ask the Media module to provide a hook somewhere?

There is the hook_field_attach_view_alter() hook, which might give you a quick way to do what you want, pending the ability to integrate properly with Styles.

pcambra’s picture

suscribe

cocoloco’s picture

I've been busy with deadlines but am still working on this, and got it to the point where it will show the cropped image in the default display, and I'm still working on have it render a style using the cropped image. Will provide more updates soon.

nicolas.antoniazzi’s picture

subscibe

KubriK’s picture

Subscribing

mansspams’s picture

subscibe

Sol Roth’s picture

Subscribe - I'm very interested in this

cocoloco’s picture

I wanted to give everybody an update on this since it's been a little while since I've made any noteworthy news to this, however now that Styles 2.x is pretty well ironed out, it helps since last time I was heavily working on this, a rewrite was still being worked on.

In that time, I've been doing some thinking about the approach I took before, and I think it can be improved. This is because there are two parts to the Media module - 1) attaching media images as a field and 2) attaching media images inline in the WYSIWYG editor. Both of these have drastically different cropping metadata handling, since the field can store it in the database, however inline would require storing cropping metadata in the embedded JSON code. It has been my intention to store cropping metadata on an instance-by-instance basis so that we don't have duplicates of images in the library, all with different crops, which IMHO would be a mess.

As stated before, with a couple of tweaks to the Media module, I was able to store (and display) crops for field-based Media images and tweaked it to store this metadata in the database.

Then I got thinking, since we have this never-used-before metadata option, why should this be limited to crop data? Since implementing the metadata was the hard part, why wouldn't we add the ability to also specify vertical/horizontal flipping, rotation, or even specify ImageCache Action presets to image instances via this metadata system, in addition of the crop data? I feel like it may be a good idea to make this an instance-by-instance image filter system, so we can have something like (this would be an inline example, formatted for easier reading):

[[ { "attributes" : { "class" : "media-image",
	    "height" : "209",
	    "width" : "262"
	  },
	  "process" : {
	  	"crop" : {
	  	  "x" : 0,
	  	  "y" : 10,
	  	  "w" : 209,
	  	  "h" : 262
	  	},
	  	"flip" : ["horizontal"],
	  	"actions" : ["my_imagecache_action_preset"]
	  },
	  "fid" : "3",
 	  "type" : "media",
	  "view_mode" : "media_large"
} ]]

This is a pretty intensive use of this, however this snippet would crop the image, flip it horizontally, and run a custom ImageCache Actions preset on it (the backend would cache the images so this instance would only be generated once).

The only difference between the inline implementation of this versus the field implementation is that the process directives are stored in JSON vs. the database. It would be great to have a nice GUI that people can use to specify all of these directives (like WordPress uses), however that would have to come after we got the actual implementation working.

I'd like to know your thoughts on this, or if anyone has any ideas.

Thanks,
cocoloco

JacobSingh’s picture

@cocoloco:

This is fantastic stuff. You just nailed it. That's totally the vision I have as well. It's complicated to organize it correctly though... There is a 'data' attribute in media fields which I intended to use for stuff like that as well as overrides of media fields (so you could use a different caption in one area of the site than another for the same file). This field is not even used now and is kinda commented in the code :(

The problem with fields is that it creates DB entries, and therefor needs to be thoughtout. Once you add it, it's hard to move / remove. I think that having this additional "data" attribute in the media field is at first blush the way to do this. However: I'm a little concerned about chucking all of this code into the media module itself. The goal of Media is as vague as the name, but roughly it should provide a framework for handling files, metadata for files and interfaces to access files. If we start having code in media like "If it smells like an image, show these fields, and format the image this way, but if it smells like a video, do something else, etc" we've kinda failed. (Hence the impossible to understand styles abstractions).

I'm not sure this comment is helpful, but I agree with your general vision.

- We should unify the instance level attributes of WYSIWYG and media fields so they don't have duplicate code.
- Cropping is awesome, I'd actually like to see another module for this though until we determine that it is so general use that it belongs in the main media module. media_transforms or media_images might work? And then add APIs to media to call module_invoke_all('something_to_do_with_transforms'); So that we don't have code in media that determines what these fields are, how they are displayed, etc.

Does that make ANY sense? I know this is really meta stuff. Thanks for your contribution! A LOT of people are eagerly awaiting your work here.

cocoloco’s picture

Jacob,

Again, thank you for all of your continued hard work on the Media module. I do agree that this should be a separate module that provides extended functionality (as you said, media_transforms or media_images or something...) and should be easily extensible for other effects/filters. It seems that this will heavily rely on using the styles_alter hooks or formatters to apply the effects (something that effulgentsia was trying to tell me a long time ago - before Styles 7.x-2.x came out) but didn't sink in until a lot later). Edit: I didn't see your note about the module_invoke hook, however that can be an option as well.

Media is a complex module, and it took awhile for all the things I originally learned about it through going through the code to sink in. Additionally, it took a bit of working with D7 and Styles for everything to make sense.

When trying to get this to work before, I did do some hacking to use the field data column that you provided in Media, which I used to store the serialized metadata. However, at that time, I didn't understand the difference/relationship between field formatters and image styles.

I agree, code shouldn't be duplicated at all where possible. I would like the related part of the JSON structure (when used inline) to essentially match the corresponding array structure (when used as a field) so we can essentially pass either one to the same function that creates and caches the filtered image.

The only problem I see is that, when used inline, it will have to translate some part of the JSON string into an image URL, and that URL could be quite long. Additionally, the URL would have to be signed so that people can't bring down a server by rapidly requesting different parameters (I've already coded a solution to this problem).

It's not the most elegant solution, however another solution to be only allow authenticated users to request image formats via URL (since we need this for previewing in WYSIWYG) and then, on node save, parse the body and save the inline images/params into a database. For instance if your body is:

<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam felis nibh, porta et pulvinar ut, iaculis non velit. [[{"attributes":{"class":"media-image","height":"209","width":"262"},"process":{"crop":{"x":0,"y":10,"w":209,"h":262},"flip":["horizontal"],"actions":["my_imagecache_action_preset"]},"fid":"3","type":"media","view_mode":"media_large"}]]Curabitur gravida, tellus in scelerisque accumsan, sem felis rhoncus ipsum, vel dapibus dui enim in ipsum. Nam nec molestie quam. Suspendisse sed nulla tellus, ut volutpat metus.</p>

It would find and parse the media tags on node save (while still allowing the WYSIWYG to render it via a URL). It would go ahead and insert it into a database table (sample SQL call, ignore the data serialization - it could just as easily be serialize()'d instead of JSON):

INSERT INTO media_image_inline (nid, fid, field, delta, metadata) VALUES (1, 3, body, 0, '[{"process":{"crop":{"x":0,"y":10,"w":209,"h":262},"flip":["horizontal"],"actions":["my_imagecache_action_preset"]}]');

Which would return an identifier (for this example, say 255), which we can use to call the image. So instead of calling:

http://example.com/sites/default/files/styles/media_large/public/my_image.jpg?crop=0,10,209,262&flip=horizontal&actions=my_imagecache_action_preset&sig=033292b555545793d62faa6073bc6545

we can use:

http://example.com/sites/default/files/styles/media_large/public/my_image.jpg?mfid=255

Then, every time a node is saved, we can update this table. We wouldn't have to rely on tracking via JavaScript since the WYSIWYG could still request the params via GET (as in the long example above) since the user was logged in and they would have the proper permission to.

I thought of this while writing this response so I may not have thought it through, but on the surface it seems like it may be a possible solution (hopefully what I wrote makes sense).

-cocoloco

cocoloco’s picture

I'm going to be working as much as I can in my free time on making the above specs a reality as a separate add-on module to Media. As soon as I have enough code to release a full project that can be reviewed, I will post the project details here.

Thanks for your input and interest in this.

cocoloco’s picture

Title: Media Image Cropping » Media Image Transformations (formerly Cropping)
cocoloco’s picture

Title: Media Image Transformations (formerly Cropping) » Media Image Transform (formerly Cropping)

Just so people can follow along with the development of this project if they are interested, I've started an experimental project at http://drupal.org/sandbox/cocoloco/1090384. Once it is mature enough for others to test, I will submit it for review.

Andreas Radloff’s picture

Looking forward to an alpha! Any idea when?

dddbbb’s picture

sub

sebish’s picture

Subscribe. Seems to be a great tool!

cocoloco’s picture

I'm looking to have an alpha in May/June - unfortunately this takes some changes to the Media module, which I am in the process of branching so I can make integration improvements.

Andreas Radloff’s picture

Sorry, only works with image fields, got a bit over-excited :)

Just wanted to let enyone following this know I found an alternative module for croping media, released yesterday. Haven't tried it though....
http://drupal.org/project/manual-crop

mstrelan’s picture

Subscribe. Unfortunately manual-crop only works with Image fields and not the Media module. Apart from that it seems awesome.

Hopiu’s picture

Subscribe.

shadybar’s picture

Subscribe.

bmx269’s picture

This is an important feature for me as well. With the sandbox module, I do not see where you crop the images. Am I missing something?

lsolesen’s picture

+1

cocoloco’s picture

Just an update - I'm making decent headway on this - it will need some patches to media and styles in the meantime but should have something ready for testing in the next couple weeks.

dddbbb’s picture

Bring it on :)

dmsmidt’s picture

looking forward to it +1

cocoloco’s picture

I've made a preview of the initial functionality for the Media Image Transform module - can you please take a look at the video and let me know your thoughts?

http://bit.ly/mitransform

I'd like to hear your feedback. Thanks.

bmx269’s picture

Looks awesome. Can't wait to use it on a site.

good_man’s picture

subscribe

camdarley’s picture

Subscribe! Thanks for your work!

lsolesen’s picture

Looked through your video, and it looks very, very promising. This will be an important module.

lsolesen’s picture

What is the status for this module?

arthurf’s picture

Version: 7.x-1.x-dev » 7.x-2.x-dev

I'm bumping this to 2.x so we can make sure this functionality will work on the more modern version.

cocoloco’s picture

I've been incredibly busy lately however I would like to help integrating this into 2.x (or at the least make sure it will be eas(ier) to integrate into 2.x). I also have diffs of changes that I had to make to 1.x to make what you see in the video work properly.

Feel free to message me if you need anything - I'll follow up shortly.

bryancasler’s picture

subscribe

drzraf’s picture

Would you want to post your patches so we can see how they can be rerolled and tested on 7.x-2.x ?

cocoloco’s picture

drzraf,

Please note that the last thing this has been tested on is media-7.x-1.0-beta4 that I had to make the attached changes to and this project still has a long way to go. However, it should work in Chrome with the code found here: http://drupal.org/sandbox/cocoloco/1090384. Since I'm short on time, I'll attach a previously-sent e-mail on the subject (please ignore references to the repo since you won't need it since it's just a copy of media-7.x-1.0-beta4 with the attached patch applied):

I'm currently looking to minimize the amount of changes required to the Media module - currently this requires a change to the createTag function of wysiwyg-media.js that parses the transform key in the JSON tag. Altering this function in Media for this purpose is unacceptable since it would have no use for other modules; consequently, this functionality should be in the Media Image Transform module. I've tried to put this functionality in MIT's attach() function, however since Media's attach function gets called first, it parses the tags and strips the transform data. The solution I am working on involves having the WYSIWYG editor generate an ID for each image and maintain it's own tag map of IDs to transform data, which it will attach to the JSON tags on detach(). I've created a new branch that will incorporate this internal tag map, so for the time being, please clone from the master branch to test. Once I remove this functionality from the wysiwyg-media.js file, essentially the only change left (at this point in time, at least) will be adding an alter function to allow other modules to modify the settings array (which I think other modules could benefit from).

Just a reminder - please try this with Chrome or Firefox - I think Safari has some problems and I didn't even try to test on IE (I wanted to keep my morale up). Additionally, it only works with TinyMCE - not CKEditor support as of yet.

Please let me know if there is any other way I can help or if you have any questions.

drzraf’s picture

FileSize
1.25 KB

Looking at the video, it seems awsome !
I just tried it, so here are some notes from a quick look:

* the wysiwyg icon attempt to appear on the button-bar but there the icon is a broken link, that the corresponding HTML:
<img alt="" src="//" class="mceIcon">

* I also have errors related to paths.
In fact media_image_transform_get_absolute_path tries to manually guess the path of the file.
In my case, I Rewrite / to /drupal with Apache so that function does not works and it would be painful to reimplements every kinds of trickery to grab the correct path.
The stream_wrappers are here for that reason and the value returned by image_style_path() is a "real" path which should be sufficient by itself even if it is prefixed by "public:///" (see the attached patch)

* I have another error which is related to image copy in styles/ but I still have to dig it.

* I would be fine with libraries not being bundled in the module (when it is considered stable).
The use of library - drush - ... make very easy to keep all libraries into /sites/all/libraries/.

other than that, thank you for your work !!

drzraf’s picture

Forgot to say, the following snippet in media_image_transform_preview

  $style = 'large';
  if (isset($_GET['styles'])) {
    $style = $_GET['styles'];
  }

seems wrong.
You probably want to test $_GET['style'] rather than $_GET['styles'] as is specified this parameter in js/plugins/wysiwyg/media_image_transform_tinymce.js

That's probably one of the reasons of the unknown failure mentioned in the above comment.

We should probably test if styles=media_original and default $styles to NULL (still in media_image_transform_preview) so that we can use the original file path as a source when no specific style has been requested.

dddbbb’s picture

+1 for libraries not being bundled with the module.

drzraf’s picture

js/plugins/wysiwyg/media_image_transform_tinymce.js initializeOverlayContent should be stricter.

Eg externals image in the code, like the following:
<img id="mit_img_0" border="0" data-mce-src="http://my.ph/to.bmp" src="http://my.ph/to.bmp">
=> styleMatches == null
So it bugs the JS on styleMatches[1].

bryancasler’s picture

This module was released in December.

http://drupal.org/project/media_crop

I've posted an issue about combining efforts #1420664: Duplicate module in the works

HnLn’s picture

Not sure (didn't read the whole thread in detail) but isn't this a duplicate of http://drupal.org/project/imagecrop ? Imagecrop already integrates well with media.

Devin Carlson’s picture

Status: Active » Fixed

I'm marking this as fixed because, as #61 and #62 mention, a small number of transformation/crop modules have now been released and are quite stable.

Additional problems with integrating transformations/crop tools with Media should be filed as separate issues.

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.

bryancasler’s picture

Just adding this great comparison of the different solutions available right now.

Comparison of image cropping and resizing modules