MediaLibraryPickerField with image size constraints

Topics: Core, Customizing Orchard, Writing modules
Developer
Jan 24, 2014 at 7:01 PM
Edited Jan 24, 2014 at 7:14 PM
I would like to display a field that only displays Images (which can be done presently)
But I want to enforce that the image selected is of a specified height and width.

I'm creating a MediaLibraryImagePickerField for my own use, but I wanted to know what other people thought.

Since the MediaLibraryPickerField is meant to display all types of Media. I can't easily see an way to modify the MediaLibraryPickerField to add an additional setting that would only affect an Image like that.

Image
Jan 24, 2014 at 7:21 PM
My initial thought is that the only reason you want the height and width constrained on input is because you only want the image displayed on the website using a particular width and height. But, now we have media profiles and a resize image filter that can easily take any image and display it as a certain height and width on the website.

Given the new Media Processing Module I'm just not so sure we need such constraints anyway.


Regards,

Dave
Developer
Jan 24, 2014 at 11:43 PM
Thanks for the comment.
I keep on going back and forth about how my users workflow should go.
Jan 25, 2014 at 12:37 AM
Agree with David, only thing missing is documentation on how to use and extend media profiles
Developer
Jan 25, 2014 at 8:43 PM
Edited Jan 25, 2014 at 8:48 PM
After a bit more thought, I had my aha moment.

The problem is I have an "auto-cropper" that my content writers use currently to chop one image into three different sizes, problem is the sizes are in different aspect ratios, and they are sometimes not happy with the result of one size or another.

I was seeking a way to migrate to 1.7's Media Library & Profiles, but I somehow had to solve that problem at the same time.

I realized my approach was wrong.

In the end I created
  1. One MediaPickerField that is required (Primary)
  2. Three MediaPickerFields that are optional (Large, Medium, Small)
  3. Three Media Profiles to match the desired Large Medium and Small output.
My users are then required to specify Primary, but if they don't like how it appears, they can then specify the optional "Sized" field with an alternatively edited image.

Works like a charm.
Thanks for the sounding board.

Except I think I need a clone button in the Media Library or a Save As in the Image Editor
Developer
Jan 25, 2014 at 8:45 PM
@CSADNT, It wasn't that bad after reading the code for another filter.
I was able to provide myself with a CropFilter that I plan on sending back in a pull request at some point.
I'm just not sure how useful it is.
namespace Orchard.MediaProcessing.Providers.Filters {
    public class CropFilter : IImageFilterProvider {
        public CropFilter() {
            T = NullLocalizer.Instance;
        }

        public Localizer T { get; set; }

        public void Describe(DescribeFilterContext describe) {
            describe.For("Transform", T("Transform"), T("Transform"))
                .Element("Crop", T("Crop"), T("Crop using x1, y1, x2, y2."),
                         ApplyFilter,
                         DisplayFilter,
                         "CropFilter"
                );
        }

        public void ApplyFilter(FilterContext context) {
            float x1 = context.State.X1;
            float y1 = context.State.Y1;
            float x2 = context.State.X2;
            float y2 = context.State.Y2;

            var result = new MemoryStream();
            if (context.Media.CanSeek) {
                context.Media.Seek(0, SeekOrigin.Begin);
            }

            var settings = new ResizeSettings {
                CropTopLeft = new PointF(x1, y1),
                CropBottomRight = new PointF(x2, y2)
            };

            ImageBuilder.Current.Build(context.Media, result, settings, true);
            context.Media = result;
        }

        public LocalizedString DisplayFilter(FilterContext context) {
            return T("Crop to x1:{0} y1:{1} x2:{2} y2:{3}", context.State.X1, context.State.Y1, context.State.X2, context.State.Y2);
        }
    }

    public class CropFilterForms : IFormProvider {
        protected dynamic Shape { get; set; }
        public Localizer T { get; set; }

        public CropFilterForms(
            IShapeFactory shapeFactory) {
            Shape = shapeFactory;
            T = NullLocalizer.Instance;
        }

        public void Describe(DescribeContext context) {
            Func<IShapeFactory, object> form =
                shape => {
                    var f = Shape.Form(
                        Id: "ImageCropFilter",
                        _X1: Shape.Textbox(
                            Id: "x1", Name: "X1",
                            Title: T("X1"),
                            Value: 0,
                            Description: T("The X Position of the 1st point."),
                            Classes: new[] {"text small"}),
                        _Y1: Shape.Textbox(
                            Id: "y1", Name: "Y1",
                            Title: T("Y1"),
                            Value: 0,
                            Description: T("The Y Position of the 1st point."),
                            Classes: new[] {"text small"}),
                        _X2: Shape.Textbox(
                            Id: "x2", Name: "X2",
                            Title: T("X2"),
                            Value: 0,
                            Description: T("The X Position of the 2nd point."),
                            Classes: new[] {"text small"}),
                        _Y2: Shape.Textbox(
                            Id: "y2", Name: "Y2",
                            Title: T("Y2"),
                            Value: 0,
                            Description: T("The Y Position of the 2nd point."),
                            Classes: new[] {"text small"})
                        );

                    return f;
                };

            context.Form("CropFilter", form);
        }
    }
}