PeterStaev / nativescript-photo-editor

🎨 Easily edit an image in your NativeScript app (crop, draw, etc)
Apache License 2.0
47 stars 15 forks source link

Edited Photo Quality #8

Closed throwingdarts closed 5 years ago

throwingdarts commented 5 years ago

If I load an image smaller than the device (say 300px), edit the image and then save a new image the new image edits are of very poor quality. They look "pixelated" as if the image edits have been stretched. If the image loaded is larger than the device (modal window) it looks fine.

I am wondering if this is because of the "stretching" of the image in the photo editor and how the added text and lines are embedded/saved in the image?

Below is a before and after example. Any ideas?

abigail_6223 2067vzsmsl

PeterStaev commented 5 years ago

Hey @throwingdarts , currently the plugin works so that it "stretches" the source image so that it matches the device screen. Then after the edits are made the new image will be basically the size of the screen. For example if the image width is 600px, device screen is 300px, result image will be 300px.

throwingdarts commented 5 years ago

Ok, the example was from me resizing the image back to its original size before I saved it. I guess I just won't do that. Lol. Thanks again. Great plugin!

NatanijelVasic commented 5 years ago

I don't quite understand one thing about this behaviour.

Let's say I load an image that is 1000px by 1000px, draw over it, and then display the resulting imageSource in a view. The quality is exactly the same as it was before. However, my debug log shows very different values:

original_image_source_height: 1000px original_image_source_width: 1000px original_image_source_height: 310px original_image_source_width: 310px

There should be a drastic drop in quality, but there isn't. Also, when I upload my original and edited images to my server, it's only then that I can see the difference: the edited image is now much lower quality.

Do you know what's going on here? Any help would be greatly appreciated!

Nat :)

PeterStaev commented 5 years ago

Hey @NatanijelVasic , like I explained in my previous comment above, by design the editor automatically resizes the image so that it matches the screen size. So in your example 1000x1000, I guess your device width is 310. So it squeezes those 1000 into 310 and keeps aspect ratio. Since the image is a square it makes height also 310px.

NatanijelVasic commented 5 years ago

Hello :) I appreciate the very quick response!

I understand that it re-scales the images, but why is this downscaling not visible in my view after I finish editing the image (after I exit the plugin)? I expect to see a pixelated 310x310 image, but I actually see a very high quality image with all the edits present (e.g. the draw feature).

(By the way, i really like the plugin! Thanks!!)

PeterStaev commented 5 years ago

The only way to view pixelation is if you zoom the image beyond the screen size. Just think of this - you have a 1000x1000 image that gets displayed on a 500x310 screen. If you keep the aspects the image will get made into a 310x310 image. So that 1 device pixel corresponds to exactly 1 pixel on the image. So even after the editor finishes if you view the image on the same device it will look pixel perfect since the 1:1 ratio of device and image pixels. Now, if you try to open the edited and original image on a 1000x620 screen for example you will see the pixelation, because then 1 edited image pixel will have to be displayed in 2 device pixels, while the original image is large enough to again be displayed in a 1:1 ratio.

Hope this explains it :)

throwingdarts commented 5 years ago

This can definitely be problematic but I am not clear on a resolution. Maybe if there were parameters of some kind that allowed control over how the image is resized in the editor and if the loaded image is then larger than the device incorporate a zoom feature that zoomed not only the image but the additions the user makes (line widths and font size) accordingly.

NatanijelVasic commented 5 years ago

I think I have worked out what is going on. Ok, so now i'm going to use actual figures (the ones above were approximate).

  1. I am using an iPhone X emulator, which has a 1125 x 2436 screen in "actual" pixels.
  2. In my photo library, I have a square photo which is 1000x1000 in actual pixels.
  3. I use the image-picker plugin to load that photo in my view. I then log originalImage.width and originalImage.height, and I get the output 1000x1000 pixels, as expected
  4. I now load that image into the photo-editor plugin, and I draw over it (no cropping)
  5. When I finish, I load the edited image into my view, and the editImage.width and editImage.height are 375x375, even though my device width is 1125.

Since, 3*375 = 1125, this suggests the following conclusions:

Now this is not a problem at all if the edited image is just to stay in my view

if you view the image on the same device it will look pixel perfect

However, other parts of my program rely on the measured values. Since the pixel values are measured in different units for each image (original and edited), it is probably the reason why the quality of the two images is SO different on my database.

So, I need to find a way to change the height and width properties of the edited image (multiply them by the screen multiplier), without changing the actual image information.

PeterStaev commented 5 years ago

This can definitely be problematic but I am not clear on a resolution. Maybe if there were parameters of some kind that allowed control over how the image is resized in the editor and if the loaded image is then larger than the device incorporate a zoom feature that zoomed not only the image but the additions the user makes (line widths and font size) accordingly.

This is not an easy task as it sounds - imagine you have the image zoomed out so it fits the screen, approximately half the size of the original one. If user decides to draw/text at this stage, this means that you need to actually draw 2x the actual line/text width. And this is just one of the cases... I guess it might be possible, but currently don't have the resources to commit to such a big change.

throwingdarts commented 5 years ago

This can definitely be problematic but I am not clear on a resolution. Maybe if there were parameters of some kind that allowed control over how the image is resized in the editor and if the loaded image is then larger than the device incorporate a zoom feature that zoomed not only the image but the additions the user makes (line widths and font size) accordingly.

This is not an easy task as it sounds - imagine you have the image zoomed out so it fits the screen, approximately half the size of the original one. If user decides to draw/text at this stage, this means that you need to actually draw 2x the actual line/text width. And this is just one of the cases... I guess it might be possible, but currently don't have the resources to commit to such a big change.

Yeah, I understand. Thanks.

throwingdarts commented 5 years ago

So, I need to find a way to change the height and width properties of the edited image (multiply them by the screen multiplier), without changing the actual image information.

@NatanijelVasic - I actually tried a similar approach but the end results were the sample images in my original post. If your image is larger than your device the result is better than the other way around. When you have to start stretching the edited image the quality suffers quickly.

NatanijelVasic commented 5 years ago

@throwingdarts How did you modify the height and width properties of an ImageSource? Because the values are read-only

throwingdarts commented 5 years ago

@NatanijelVasic I used the nativescript bitmap factory plugin.

See this solution for example code.

NatanijelVasic commented 5 years ago

I am using this plugin. It think it is bitmap-factory that actually decreases the quality ( as a result of getting DIP values from the editor plugin instead of real pixel values ). However, from what I have found after many experiments, it seems like things get even more complicated:

We can compensate for create() and resizeHeight(), since we get get the screen multiplier of the device, but unfortunately, we cannot compensate for the insert() function unless we could magically edit the readonly height and width properties of imageSource

NatanijelVasic commented 5 years ago

To simplify things, let's ignore bitmapfactoy's resizeHeight() function, so that we don't get confused talking about consecutive resizings form two different plugins. This is what will happen if we edit our image and then use bitmapfactory. px = actual pixel units DIP = device independent units

I have attached the output of these operation (slightly different dimensions, but same principle. Also, most of the image is white, it's not the webpage): 8008482889351

throwingdarts commented 5 years ago

@NatanijelVasic How about BitmapFactory.create(3000px, 3000px)?

NatanijelVasic commented 5 years ago

@throwingdarts Why would that help? That would just mean more white space.

throwingdarts commented 5 years ago

@NatanijelVasic Was just thinking (in theory I guess) that if the insert function translates/divides by the scale then how you might increase the size before the translation.

NatanijelVasic commented 5 years ago

@throwingdarts No matter what size we create, the image part will be the same absolute size. The scale factor discrepancy comes from the DIP to px mix-up

throwingdarts commented 5 years ago

I think I am following you now. The editImage after editing would need to be 3000x3000 for my theory to be relevant which of course can't be because it is dictated by the editor container (device) size. It's a shame the photo editor has to changes the absolute size after editing.

NatanijelVasic commented 5 years ago

I think for most practical purposes, the editor's resizing is not a big issue, since most devices have hi-res screens these days. The bigger problem is bitmap-factory's pixel unit inconsistency (https://github.com/mkloubert/nativescript-bitmap-factory/issues/22)