Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How do I crop a full-hd image to a resolution that doesn’t fit on the device? #28

Closed
0x1ad2 opened this issue Dec 23, 2015 · 17 comments
Closed

Comments

@0x1ad2
Copy link

0x1ad2 commented Dec 23, 2015

At first sorry for my vague question I'm going to make it more clear.

The final result I want to achieve is sharing (using ngCordova social sharing plugin) an image that has a resolution of 851 x 315 (facebook cover image).

  • I shoot a photo through my Samsung Galaxy S4 (the resolution of the image is/will be 1080 x 1920)

- I accept the image as you need to do that on android (the resolution of the image still is 1080 x 1920)

- I open up the cropper (currently using https://github.com/JrSchild/jr-crop) I set the options to be 851 x 315

The cropper doesn't have the set dimensions because it can't, because the device resolution is too small.
How could I crop a full-hd picture crop it to 851 x 315 and still be able to work with the picture.

To show what the desired result will be I tried the same in Twitter (for iPhone tough), here I'm going to set the image as a new header image that's (1500 x 500).

@asturur
Copy link

asturur commented Dec 23, 2015

I was checking here
https://github.com/JrSchild/jr-crop/blob/master/dist/jr-crop.js#L76

        if (selectAspectRatio > imgAspectRatio) {
          this.scale = this.last_scale = this.options.width / this.imgWidth;
        } else {
          this.scale = this.last_scale = this.options.height / this.imgHeight;
        }

Probably the image is 1080x1920 with the exif rotation flag for the phone orientation.

In your case it may be ( i'm completley noob about both this scaler and ionic framework ) that swapping this if condition would help you. scaling by height will make your picture looks ok on the cropper.

I think that when the image have different orientation other than the screen, you should add some additional check:

        isOrientationSame = ((selectAspectRatio >= 1 && imgAspectRatio >=1) || (selectAspectRatio < 1 && imgAspectRatio <1));

        if (selectAspectRatio > imgAspectRatio) {
          if (isOrientationSame) {
            this.scale = this.last_scale = this.options.width / this.imgWidth;
          } else {
            this.scale = this.last_scale = this.options.height / this.imgHeight;
          }
        } else {
          if (isOrientationSame) {
            this.scale = this.last_scale = this.options.height / this.imgHeight;
          } else {
            this.scale = this.last_scale = this.options.width / this.imgWidth;
          }
        }

I have no chance or time to check if this works. But i think is a quick try for you or at least a hint for the good direction.

@JrSchild
Copy link
Owner

Hi Dennis,

I am aware of this situation and the way this could be handled definitely needs to improve. It's too vague right now and was initially only meant for square images. To answer your question in #24, yes this is part of the roadmap.

What I think you could do for now is scale down the proportions (851 x 315) down to the screensize. So manually retrieve the screenwidth and scale them down.

Let's say the screenwidth = 320 you would end up doing:
height = (851 / screenwidth) * 315 = 118

If you set width: 320 and height: 118 it might just work.

@asturur
Copy link

asturur commented Dec 23, 2015

Ok @0x1ad2 i just tried :)

@0x1ad2
Copy link
Author

0x1ad2 commented Dec 23, 2015

@asturur thanks for looking into it, I've tried to used the screen orientation check and just simple reversing the current statement but both doesn't seem to work.

@JrSchild thanks for the confirmation and explanation why it's not build in on default. I could scale down the proportions (I currently do) but after cropping the image is put on canvas, edited and exported so If I put in on a 320 x 118 canvas it will export as 320 x 118 not as 851 x 315.

Do you guys know any other good crop plugin that has the ability to deal with the aspect ratio.

@JrSchild
Copy link
Owner

@0x1ad2 Did you try it out? I'm 99% sure it won't ;). It will export the image in the highest possible resolution.

@0x1ad2
Copy link
Author

0x1ad2 commented Dec 23, 2015

@JrSchild I've been working on the app for a couple of weeks now so yeah of course I did try it out ;)
here's a code snipped from my code base, don't mind the options (I've used @akreienbring his PR-code).

     $jrCrop.crop({
            url: "data:image/jpeg;base64," + imageData,
            width: canvasWidth,
            title: '',
            cancelText: 'Annuleren',
            chooseText: 'Uitsnijden',
            allowRotation: true,
            buttonLocation: 'header',
        }).then(function (canvas) {
            $rootScope.latestShot = canvas.toDataURL();
            $state.go('tab.blur');
        }

As you can see I'm exporting the canvas using the toDataURL method.

@JrSchild
Copy link
Owner

You'll also need to set the height in this case. Just try this with my latest version:

options = {
  url: "data:image/jpeg;base64," + imageData,
  width: 320,
  height: 118,
  title: '',
  cancelText: 'Annuleren',
  chooseText: 'Uitsnijden'
}

I just tried it out myself. The resolution of the image will be biggest possible within those proportions, that has always been my intention.

@0x1ad2
Copy link
Author

0x1ad2 commented Dec 23, 2015

It's also not working I removed the height on purpose some seconds ago, forgot to put it back in.
It was

 height: canvasHeight

And my dimensions where

var canvasWidth = 320;
var canvasHeight = 315;

I will use your dimensions and show the result to you

@JrSchild
Copy link
Owner

In your case you will want to calculate the sizes for your screen:

var width = window.innerWidth * 0.9; // Add a small margin or something.

options.width = width;
options.height = ~~((851 / width) * 315)

@JrSchild
Copy link
Owner

My bad, messed up the calculation. Should be this:

var width = window.innerWidth * 0.9; // slight margin
$jrCrop.crop({
  url: image,
  width: width,
  height: ~~((width / 851) * 315)
})

ios simulator screen shot 23 dec 2015 16 29 19

ios simulator screen shot 23 dec 2015 16 29 31

1450884565764

@0x1ad2
Copy link
Author

0x1ad2 commented Dec 23, 2015

@JrSchild thanks for that I'm going to try it right now, I said "I will use your dimensions and show the result to you" but I can't get the result due to a to long base64 dataURL. Any tips for handling those, what would you advice?

@JrSchild
Copy link
Owner

It's much better to retrieve the url to the file and use that instead of base64 data.

-Edit; Oh you mean for the results. Yes check the examples folder. It uses a .toBlob polyfill, currently from blueimp. There's a branch that shims it internally but I haven't had the chance to test it on Android yet.

If you would like to show the result in the DOM it's best to turn it into a BLOB and then retrieve a blob URL.

@0x1ad2
Copy link
Author

0x1ad2 commented Dec 23, 2015

@JrSchild I tried your code and the cropper is working fine for now.

It's producing the following image

But after that I'm putting it on canvas again for some image manipulation added some background overlays and text objects using Fabric.js.

And if I export it after that I'll end up with this

  • the only solution I've got in mind is to load the full image and make it horizontal scrollable but that causes laggy/buggy UI

@JrSchild
Copy link
Owner

Okay you're getting there.

So the resulting image of jr-crop will be the maximum possible resolution in those proportions, it could be bigger or smaller than your target size. First of all, scaling this is logic you probably want to do on the server with proper tools like image-magick, or sharp. Browsers are a) not very good at this with quality, b) slow when using other algorithms. I have already experimented with this, resulting in really bad performance.

What I thought of is that because you are cropping an image on a smaller screen, the result can never be exactly 851 x 315 when you scale it down (or up). You might want to round the height up (height: Math.ceil((width / 851) * 315)) and then manually scale the image to a width of 851px, then remove the excess pixels by placing it on a canvas of 851 x 315 (or cropping with your much better server-tools).

Your example probably went wrong because you are assuming specific measurements when you place it on another canvas. So if you would really like to do the scaling on the client you should place it with context.drawImage with sWidth: 851 and sHeight: null (sx and sy are 0 obviously)

-Edit: Excuse me dWidth and dHeight.

Note that when you draw it on another canvas you don't need to get its contents first. Just draw the whole thing. destinationContext.drawImage(canvas, 0, 0, 851, null);

@JrSchild
Copy link
Owner

JrSchild commented Jan 5, 2016

I'm assuming it's fixed. Feel free to comment here if you have further questions regarding your issue.

@JrSchild JrSchild closed this as completed Jan 5, 2016
@0x1ad2
Copy link
Author

0x1ad2 commented Jan 6, 2016

Ja het is opgelost, bedankt voor je hulp!

2016-01-05 15:49 GMT+01:00 Joram Ruitenschild [email protected]:

I'm assuming it's fixed. Feel free to comment here if you have further
questions regarding your issue.


Reply to this email directly or view it on GitHub
#28 (comment).

Met positieve groet,

Dennis Bruijn
Full-stack Web Developer

http://nl.linkedin.com/in/dbbruijn

http://goog_1423228033

@JrSchild
Copy link
Owner

JrSchild commented Jan 6, 2016

Top! Graag gedaan

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants