Coder Social home page Coder Social logo

drmint / litrato Goto Github PK

View Code? Open in Web Editor NEW
85.0 8.0 20.0 3.65 MB

Android photo editing app with various filters and tools. Included advanced features like masking, histogram, color picker, EXIF viewer...

License: MIT License

Java 92.98% RenderScript 7.02%
android-studio image-processing image-editing java android-app android-application gaussian-blur laplacian-filter photo-editing renderscript

litrato's Introduction

LITRATO

DESCRIPTION

The goal of this project is to create an Android app capable of editing photos and saving those changes to the gallery.

Filters and effects:

  • 14 presets to quickly apply a filter (without any parameters).
  • Transformations such as rotation, crop, flip...
  • Essentials tools such as luminosity, contrast, gamma, saturation...
  • More advanced filters that use convolution or blending two or more images.
  • Almost all filters are using RenderScript, which accelerates the calculations.

User interface:

  • The UI is simple and intuitive, with menus, separate interfaces, and the preview of each filter.
  • Dark and light theme.
  • Zoom and scroll: it is possible to zoom on the image using two fingers or with a double tap, and then move around with one finger.

Tools:

  • “Color Picker”, a tool to select a hue directly from the image.
  • "History" gives the user the ability to revert to any prior state of the image.
  • A setting menu where the user can tweak some parameters. Those values are saved on the phone.
  • An menu to view most EXIF values of the image, such as the ISO, f-number or where the photo was taken.
  • Ability to only apply a filter to a part of the image. This "mask" is drawn by the user using its finger.

Load and save:

  • Take or select an image: images can be obtained from the gallery, or directly from the camera.
  • It is possible to save the image in its original resolution, and have a smaller resolution while using the app.

INTERFACE

When the app is first launched, a permission request to access storage is prompted. Then a default image will be displayed. The user can then load an image from his gallery or take a picture by clicking on the top left File icon and modify his personal images. What was simply called "Filters" has been divided in three categories : Presets which are predefined filters that can be applied just be tapping on its miniature, Tools which include all the essential tools to modify an image, and finally Filters. This last one is further divided into four categories: Color, Fancy, Blur and Contour.

At the top, there is also the History button with a clock icon. Using this button, the user can preview and revert to any prior state of the image using a slider. Once the user selected a prior state, he can click on the Confirm button to validate their choice.

Further to the right there is the save button, quick access to 90° counterclockwise and clockwise rotations. Lastly, a dropmenu gives access to Settings and EXIF Viewer. The first one allow the user to change some parameters in the app and the second one is usuful to learn more about the loaded image, such as where it has taken, by what camera...

Back to the main window, the user can zoom on the image using two fingers, and then move around with one finger or two fingers. Double tapping the image will zoom on it, and double tapping again will make the image fit on the screen. Warning : sometimes gesture navigation is disabled depending on the situation. Some functions use the touch as an input, such as Color Picker or Crop.

If the user tap on one of a tool or a filter, a new window will appear prompting them to adjust the filter as they wishes. Once the user is happy with the result, they can click on the Apply button to validate the modification. The bar at the very bottom also shows the name of the active filter/tool. Clicking on the name can toggle on or off the "Filter menu". The number and the disposition of the controls vary according to the filter. Some use the Color Seek bar to select a tint. In this case, the Pick a Color tool also appear on its left. The user can use this tool to select directly on the image the tint they want the work with. At most, a filter can display two seekbars, one colorSeekBar, a switch, and a special menu (currently only used by "Stickers") to display a list of selectable bitmaps.

On the left, two other buttons can appear. The first one is the Masking tool. Clicking on it will bring another window where the user can draw where the filter should be applied on the image. By default, the mask is entirely black, meaning that the filter will be apply nowhere. The user can choose the draw in white or black, the size of the brush, and the view opacity of the mask. This last option is purely visual and doesn't change the mask whatsoever. Let's go back to the Filter menu, the last option at the bottom left is Histogram, a button that will toggle the histogram, a visual representation of the repartition of RGB values. It is overprinted on the image to allow the user to still view what is underneath. The histogram uses logarithm scaling on the Y-axis.

FILTERS

Original image

Auto

Provides two ways to increase the contrast without burning values (burning refers to values getting out of the 0-255 range). The first is by maximizing the range of luminances values of the image. The second is called Dynamic extension, and tries to make the histogram as flat as possible.
  • Switch: choose which way to increase contrast.

Luminosity

Changes how bright or dark the image is. It turns up too much, this will burn the image.
  • Seek bar: the image's brightness (between -100% and 100%).
  • Seek bar 2: the image's gamma value (between -100% and 100%).

Saturation

Changes the saturation of the image.
  • Seek bar: the image's saturation (between 0 and 200%)

Temperature

Makes the image look warmer or colder.
  • Seek bar: the image’s temperature (between -100% and 100%).

Tint

Changes the tint of an image. Makes the images more magenta or green.
  • Seek bar: the image’s tint (between -100% and 100%).

Sharpening

Makes the image look sharper or blurrier.
  • Seek bar: the image’s sharpness (between -100% and 100%).

Colorize

Apply one color and saturation to the entire image.
  • Color seek bar: the color you wish to use.
  • Seek bar: the color’s saturation (between 0% and 100%).

Change Hue

Apply one hue to the entire image but contrary to the Colorize filter, it doesn’t change the saturation of the image.
  • Color seek bar: the color hue you wish to use.

Hue Shift

Shift all hues by a certain amount. This can give interesting results when used moderately.
  • Color seek bar: the color hue you wish to use.
  • Seek bar: shift amount (between -180 and 180 degrees).

Threshold

If the pixel’s luminosity is bellow the threshold, turns it back. Turns it white otherwise.
  • Color seek bar: the color hue you wish to use.
  • Seek bar: shift amount (between -180 and 180 degrees).

Selective Coloring

Turns everything grayscale except for a specific color. If in remove mode (using the Switch), the user can reverse the effect and only remove that color instead of keeping it.
  • Color seek bar: the color hue you wish to use.
  • Seek bar: how far off the color can be (in degrees).
  • Switch: chose between keeping or removing that color.

Add noise

Adds some random noise to the image.
  • Seek bar: the amount of noise (between 0 and 255).
  • Switch: turns the noise greyscale or colored.

Posterize

Reduces the number of distinct colors, also called color quantization.
  • Seek bar: how many possible colors should be kept in each channel (in steps between 2 and 32).
  • Switch: also turns the image greyscale.

Average Blur

Blurs the image by averaging equally all pixels with their neighbors.
  • Seek bar: blur amount (between 1 and 19 pixels).

Gaussian Blur

Blurs the image by using a Gaussian function.
  • Seek bar: blur amount (between 1 and 25 pixels).

Laplacian

Used to highlight all the image’s contours.
  • Seek bar: how much details should be kept(between 1 and 14 pixels).

Directional Blur

Blurs the image horizontally or vertically.
  • Seek bar: blur amount (between 2 and 30 pixels).
  • Switch: horizontal or vertical.

Cartoon

Applies a cartoon effect. This is achieve by reducing the number of color values and highlighting the contours.
  • Seek bar: the black value of the "shading" (everything expect the contours).
  • Seek bar 2: the number of colors.

Sketch

Sketch effect.
  • Seek bar: how thick or narrow the contours should be.
  • Seek bar 2: how much colors should remain.

Crop

Crop the image at the desired size. The area is selected using touch.
  • Switch: how thick or narrow the contours should be.

Flip

Applies a horizontal flip of the image.

Rotation

Applies a rotation to the image.
  • Seek bar: rotation in degrees (between -180 and 180).

Stickers

Allows to put stickers on the image. Touching the screen applies a sticker at that location.
  • Seek bar: size of the sticker in percent (between 10% and 290%)
  • Seek bar: rotation of the sticker in degrees (between -180 and 180)

PACKAGES, CLASSES, AND FUNCTIONS

1 - Packages

At the root folder there are three packages:

  • activities: containing everything related to the activities, the tools to managed the UI, menus etc...
  • filters: all the Classes and Functions that deals with images.
  • tools: other Classes to help with any part of the app.

Each package also as a sub-package named tools. Tools are packages filled with Classes useful for the parent package they're included in.

2 - Activities Package

2.1 - MainActivity Class

This is the core of the app. This Class initializes a lot of variables for other classes such as calling Settings.setDPValuesInPixel, or generating the listeners such as menuButtonListener or menuItemListener. This Class and all the other Activities implements a method named applyColorTheme(). This method is usually called by onCreate but because this activities has an ActionBar, it needs to be called by onCreateOptionsMenu.

2.2 - ExifActivity Class

An activity to view the image EXIF data. EXIF is a meta-data format used by a lot of image formats and even sounds files. It contains most notably the camera model and manufacturer, the exposure, ISO, focal length... Also the GPS coordinates where the image was taken. To display the coordinates, we used the Google Maps API. This API key can be found in res/google_maps_api.xml. When dark theme is enabled, the map uses raw/style_gmap_night.json

2.3 - FiltersActivity Class

An activity used to prompt the user to tweak the filter parameter. This activity can also start a new instance of itself, most notably to create a mask.

2.4 - PreferencesActivity Class

This class is where the user can view and change app's preferences.

2.5 - Tools Package

2.5.1 - History Class

This Class allows to manage the history. It takes an ArrayList of AppliedFilter as attribute. When a filter is applied to an image (and confirmed by the user), it is added to the ArrayList. Then by using goUntilFilter we can get back the image to any prior stage. To achieve this result, this method takes the image and apply all the filters until that state is achieved. This way, we don't have to save a bitmap for each step, and you can reapply the same actions to the image in its original resolution (compared to its loaded resolution which is usually lower to increase reactivity of the UI). removeUntil allows to remove all states following the given state, reverting the history to that state.

2.5.2 - Preference Enum

It is used to ensure the names used are the same throughout the code.

2.5.3 - PreferenceManager Class

This Class is used to save and load preferences on the phone. It also store the default values when the app is first installed. This is where the default values such as

  • DARK_MODE: defines if the color theme should be dark or light.
  • IMPORTED_BMP_SIZE: the maximum size of a loaded image. If the image is rectangular, the longest dimension will be resized to IMPORTED_BMP_SIZE and the otherwill be smaller than IMPORTED_BMP_SIZE. Default: 1000
  • MINIATURE_BMP_SIZE: the size of the miniature used in the filter and preset menu.
  • SAVE_ORIGINAL_RESOLUTION: if true, the history is reapplied to the original image (the image as it was before reducing it to its IMPORTED_BMP_SIZE.)
  • OPEN_HISTOGRAM_BY_DEFAULT: if true, make the histogram visible by default when using a filter.

2.5.4 - Settings Class

This class is where constants and magic numbers are stored. It gives easy access to some settings.

  • MAX_ZOOM_LEVEL: how much the user can zoom on the image. For example: 5f means we can zoom until only 1/5 of the image is displayed. Default 5f.
  • DOUBLE_TAP_ZOOM: how much it zooms on the image when double tapping it. Default 3f.
  • OUTPUT_JPG_QUALITY: The quality of the saved image. 100 means no compression, the lower you go, the higher the compression.
  • SAVE_PATH: the path to Litrato's folder. Photo are not saved there if using the Android MediaStore.
  • SAVE_PATH_ORIGINAL: the path to the subfolder of Litrato where the captured image are saved.
  • Layout related constant such as ITEMS_MARGIN_IN_MENU, PADDING_BETWEEN_MINIATURE_AND_LABEL...
  • FILTER_MASK_NAME and FILTER_ROTATION: because some filter are used in the code, they must have a peculiar name. To ensure this name is the same throughout the code, they are stored there.
  • ACTIVITY_EXTRA_CALLER: when adding extras to a StartActivity's Intent, we must used a string key to transfer information. To ensure this key is the same throughout the code, it is stored there.

2.6 - Ui Package

Those menus are used in the bottom part of the UI, in the MainActivity and also the Stickers filter.

2.6.1 - BottomMenu Class

Those menus are used in the bottom part of the UI, in the MainActivity and also the Stickers filter.

2.6.2 - ColorTheme Class

This class is used to change the color and style of UI elements to reflect the global style. The Dark Mode can be disabled in the Settings to change the style of the app.

2.6.3 - DisplayedFilter Class

A displayed filter is a filter paired with its visual representation.

2.6.4 - ImageViewZoomScroll Class

This class is used to add new functionality to ImageView objects: the ability to zoom and scroll on the image. Zoom and scroll events are handle by the MainActivity class, this class is used to calculate which portion of the image should be displayed. The more we zoom, the smaller this surface. When we scroll, we are moving this surface around.

This surface is a rectangle defined by newHeight, newWidth, and center. If we want to change zoom level, we use the following line, we can use setZoom(float zoom) and we can move the image by using translate(int x, int y).

Using those values, the Class created a transformation Matrix for the displayed image.

Another very useful function in imageViewTouchPointToBmpCoordinates which convert the pixel touched on the imageView to the coordinates of that pixel in image (regardless of zoom and center position).

2.6.5 - ViewTools Class

This Class contains multiple tools useful with views such as the ability to know if a View is visible, or transform DP units into pixels.

3 - Filters Package

3.1 - Filter Class

A Filter is an object that describes which input (colorSeekBar, seekBars, switches etc...) the user has access to. Each Filter instance could be created anywhere in the code, but we decided to do it outside MainActivity, which was already quite full.

At first, there is no link between a Filter instance and its corresponding FilterFunction. In order to create that connection, each Filter instance is given a new FilterInterface object. This interface is used to declare which FilterFunction should be called when applying the filter.

Here's an example to showcase how easily a new filter can be created. Please keep in mind that most filters doesn't use that many options, we have purposely used all of them:

// Create a filter with a name, a category and we can
// declare which sub-function is available to the user.
newFilter = new Filter("Name", Category.CATEGORY_NAME);
newFilter.allowMasking = false;     // true by default
newFilter.allowHistogram = false;   // true by default
// allowScrollZoom is true by default, must be false to use the coordinates of touch events.
newFilter.allowScrollZoom = false;  

// Now, let's define which interface to use and their parameters.
// If we don't call set..., this UI element wont be available.
newFilter.setColorSeekBar();
newFilter.setSeekBar1(seekBar1Min, seekBar1Current, seekBar1Max, "SeekBar 1 Label", "Unit");
newFilter.setSeekBar2(seekBar2Min, seekBar2Current, seekBar2Max, "SeekBar 2 Label", "Unit");
newFilter.setSwitch1(defaultBooleanValue, "Label if true", "Label if false");

// Then we can specify if changing the UI element automatically refresh the image.
newFilter.seekBar1AutoRefresh = false;
newFilter.seekBar2AutoRefresh = false;
newFilter.switch1AutoRefresh = false;

// We can now set two different function, the first one is the one used when using the FilterActivity
// (while tweaking the parameters). The second one is only called when the user click "Apply".
// Filters such as Crop is using this distinction.
newFilter.setFilterPreviewFunction(new FilterPreviewInterface() {
    @Override
    public Bitmap preview(Bitmap bmp, Bitmap maskBmp, Context context, int colorSeekHue, float seekBar, float seekBar2, boolean switch1, Point touchDown, Point touchUp, int selectedMenuItem, Filter filter) {
        FilterFunction.sobel(bmp, seekBar, switch1);
        return null;
    }
});

// If no apply function is provided, the preview function is called instead.
newFilter.setFilterApplyFunction(new FilterApplyInterface() {
    @Override
    public Bitmap apply(Bitmap bmp, Bitmap maskBmp, Context context, int colorSeekHue, float seekBar, float seekBar2, boolean switch1, Point touchDown, Point touchUp, int selectedMenuItem, Filter filter) {
        return maskBmp;
    }
});

// We can create any outside variable that could be used in between the Preview and Apply function.
// Those variables needs to be final.

3.2 - FilterFunction Class

A filter function is a static method of this class. It will always takes in parameter a Bitmap (the image to modify). Most filters can also be tuned by some parameters. Lastly, those that use RenderScript will be given a Context in parameter.

keepOrRemoveAColor is the filter function for the Keep a color and Remove a color filters. It takes a target hue as a parameter. Then, for each pixel, a pixel turns progressively greyer depending on the distance in degrees between its hue and the target hue. In order the accelerate the process, a lookup table (abbreviated to LUT from now on) has been used. Other functions also use LUTs such as linearContrastStretching, histogramEqualization, and hueShift.

gaussianBlur was a difficult function to write. The Gaussian blur operation "can be applied to a two-dimensional image as two independent one-dimensional calculations" (taken from Wikipedia). Thanks to this property, we will be using a one-dimensional kernel. I chose to scale the sigma with the size of the kernel. That way, the Gaussian kernel with always "look the same'' but its resolution will increase with its size. In fact, the kernel will always have values between 1 and 90.

3.3 - FilterFunctionDeprecated Class (Deprecated)

This class is the legacy versions of currently used filters. Functions that uses non-RS convolution are in this class.

3.4 - FilterFunctionIntrinsic Class

This class is the Intrinsic versions of currently used filters. It has been left there to compare our implementations from Android's library's.

3.5 - AppliedFilter Class

This Class was made to implement the history. It is essentially a Filter and all the parameters to apply it (the states of all seekBars, a mask, the state of the switch, the points touchUp and touchDown). It can be used as a recipe to exactly recreate the effect applied by the user. Then, the apply function allows us to apply this AppliedFilter to a bitmap.

3.6 - FilterApply and FilterPreview Interfaces

This FilterApply interface is used to dynamically change the Filter instances apply method. Each filter will call a different FilterFunction static method and using this interface, it is possible for MainActivity to change which one to use. The FilterPreview interface is used in the same way but targets the Preview method instead.

3.7 - Category and BlendType Enums

Category is used to define where one Filter object should be displayed (as a Filter, a Tool, or a Filter). The Blending type defines how two images can be blend together using the applyTexture FilterFunction.

3.8 - Tools Package

3.8.1 - ColorTools Class (Deprecated)

This class implemented all the functions necessary for conversions between RGB and HSV. It is now deprecated as those conversions are done in RenderScript directly.

3.8.2 - ConvolutionTools Class (Deprecated)

This class implemented tools used by any filter that uses convolution without RenderScript. It is now deprecated as all FilterFunctions now use RenderScript based convolution.

3.8.3 - RenderScriptTools Class

The RenderScriptTools implements tools useful for functions that use RS. The applyConvolution3x3RS function applies any 3x3 kernel to any image. However, it uses ScriptIntrinsicConvolve3x3. The applyConvolution function uses our own RenderScript convolution and isn't limited to 3x3 kernel. Actually, the kernel can even be rectangular. The cleanRenderScript function can be called after any RS function to destroy the Script, RenderScript, and a list of Allocation for input(s) and output(s).

4 - RenderScriptTools Class

4.1 - FileInputOutput Class

This class is managing input and output. Loading files, loading resources, creating folders...

4.2 - ImageTools Class

This Class contains useful tools to manipulate images, here are some of them. First to create a bitmap satisfying our expectations (modifying its size or not) with cloneBitmap, createScaledBitmap or toSquare. Then to create the histogram of the bitmap with generateHistogram(Bitmap bmp). It contains also tools to draw on a bitmap drawCircle(final Bitmap bmp, Point center, int radius, int color) to create a mask and drawRectangle(final Bitmap bmp, Point a, Point b, int color, int thickness) to show the cropping area.

4.3 - Point and PointPercentage Classes

The Point Class allows to create a two-dimensional point (two integers) and contains multiple methods to manipulate them : we can copy a point, translate it, and test if two points are equals. Points are mainly used for when the user is interacting with the screen, for example to draw the rectangle when cropping, we need the position of the finger. Then the PointPercentage Class is basically the same but instead of having two integers to make a point, we are having two floats because they are representing the coordinates on their respective axis in percent. PointPercentage is used to apply filters to the full size image. Indeed having the coordinate of the touched pixel in percentage allows to have this touched pixel for any size of the image.

PERFORMANCES

The following test has been performed on a Samsung SM-A105FN, a low spec phone from released in February 2019. This phone has an AnTuTu score of 88.710, 2 GB of RAM, and uses a Samsung Exynos 7 Octa 7884 processor. According to Device Atlas, France still most used phone in 2019 is the iPhone 7 (with 6.89% share) which has an AnTuTu score of 237.890 (+268% compared to the A10).

The last column is the ratio between the processing time for 1 Mpx and 3.6 Mpx. If the process is linear, is should be 360%.

Filter RS HSV 0.185 Mpx 0.750 Mpx 3.00 Mpx % %
Old analog 210 302 506 144 168
Night from day 200 642 1720 321 268
Rotation 23 53 209 230 394
Crop 4 6 14 150 233
Flip 19 20 32 105 160
Stickers 5 6 16 120 267
Luminosity 35 33 155 94 470
Contrast 23 22 49 96 223
Sharpness 22 45 102 205 227
Auto 35 100 361 286 361
Saturation 15 18 35 120 194
Add noise 115 380 1320 330 347
Temperature 14 16 23 114 144
Tint 15 16 22 107 138
Colorize 13 20 37 154 185
Change hue 12 25 45 208 180
Selective coloring 19 30 81 158 270
Hue shift 13 30 71 231 237
Threshold 11 17 30 155 176
Posterize 22 20 54 91 270
Average blur (2px) 21 55 150 262 273
Average blur (20px) 309 1034 5820 335 563
Gaussian blur (2px) 39 62 165 159 266
Gaussian blur (20px) 60 168 507 280 302
Directional blur (20px) 38 69 231 182 335
Laplacian (2px) 68 98 264 144 269
Sobel (2px) 53 102 285 192 279
Sketch 168 288 566 171 197
Cartoon 221 398 1120 180 281
Mask apply 26 62 96 238 155
Histogram 70 72 79 103 110

RS means that the function uses RenderScript. HSV means it uses RGB->HSV->RGB convertions. The durations are in milliseconds. The last two columns are the ratio between 0.185 Mpx and 0.750 Mpx, and the ratio between 0.750 Mpx and 3.00 Mpx respectively. Those values would be 400% if the performance scaled linearly. Also, it is clear that there is a constant time spent on initializing the filter, copying the image, displaying the result, which isn't always dependant on the image size. This is why the first ratio is almost always lower then the second one. In conclusion, at 0.750 Mpx on this phone, for most filters, there is little intrestess in lowering the internal image resolution. The filters that use convolution kernels are expectantly slower than the rest. The Average blur filter is very slow at high kernel size. It is clear that the Gaussian Blur being a separable filter makes a huge difference in performance when compared with the Average blur filter. Also, the Add noise filter is particularly slow despite using RenderScript. This is because it’s generating up to three random numbers for each pixel. It would be much faster—but more complicated—to superpose a pre-fetched noisy layer on top of the image, simmilarly to what we do with the Old analog preset.

Our implementation of the Gaussian blur much slower than ScriptIntrinsicBlur. Because of this, Sobel and Laplacian are also significantly slower.

Furthermore, the images used in a photography app such as this one would probably be those taken by the phone. The Samsung A10 takes pictures with a resolution of 13 Mpx which would make virtually all the filter unusable in real-time. This is why have an interface that uses a smaller version of the images to priorities reactivity, and only applies the filters to the original non-resized image when saving.

MEMORY USAGE

The following test has been performed on the same phone as before. In order to better highlight some behavior, we used a 3 Mpx image.

The program memory usage starts around 75 MB and after one minute of standby. When we load the 3 Mpx image, the memory consumption skyrocketed to about 201 MB. After a little while, the memory usage dropped to 107. The image internally is stored in RGBA-4444 which means that we use 4 bytes to store each pixel. 3 millions * 4 is equals to 12MB. In practice, loading this image resulted in about 3 times this amount. This can be explained because our program stores three copies of the image: the original image, the filtered image, and internally, the imageView stores another copy. When applying a filter (we choose Colorize), the value stay constant at about 300MB after Applying the filter and returning to the Main activity, the memory consumption stays at around 210MB. The second wave was using the Rotate tool. After all those operations, the program stays at 260MB.

The orange portion is the memory allocated to "Graphics". Strangely enough, this amount seems to never go down. We would like to remind the reader that our History doesn't save each step as a bitmap, but as the "recipe" to make recreate the image from the previous state.

Loading a new image reset this "Graphics" portion and also "Native", the blue portion bellow.

BUGS AND LIMITATIONS

  • Landscape mode is not available. We have created a layout_land of Filter, but because of time contraint, we decided to focus on other, more important elements (History was one of them at the time).
  • Convolutions do not correct the pixel values for the border of the image. As such, we can see black borders around the image.
  • When rotating the image, we could have a Crop function that automatically keeps the largest rectangle that fit inside the image.
  • When switching between Light and Dark mode, the icons in Tools aren't recolorize by the theme. It is difficult to say what is causing it. The problem appeared quite recently while creating the BottomMenu Class. As it isn't that much of a problem, we left it as it is for now.
  • Images saved by our program seems to erase most EXIF meta-data.
  • The EXIF value for flash activation seems to not follow the ExifInterface given by Android's library. Some phones and other cameras use seems to use many different values, some of which are not even categories by the library. This result in a lot of false positive by the EXIF Viewer.
  • The Google API key has been made public on our GitHub after committing the file. It is highly discouraged by GitHub and Google Developer's Guide.
  • MainActivity is sharing its AppContext in static manner with BottomMenu Class. This can lead to memory leaks according the Android Studio.
  • We looked a little bit into AsyncTasks as it could greatly improve the speed of the app on older and newer phones.
  • The app is really slow when first launched. From what we understood, this is because RenderScript is "compiling" / "caching" its functions.
  • The app memory consumption seems way higher than its expected consumption. We have to look into that.

litrato's People

Contributors

afournier014 avatar drmint avatar mariondo-projet avatar rodin1997 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

litrato's Issues

Any chance to add new features?

I see there are a few open issues for feature request not having your response. Would you accept new feature requests? I have quite a few ideas of extra features and your app is the only foss one that I know so far as good image editors (it's easy to find galleries and painters, but not editors). Wish you can keep refining this app and don't let it die slowly.

Zoom reset after selecting crop tool

If you're zoomed in on a picture, then select the crop tool, the zoom you previously set is forgotten and you're forced to see the whole picutre.
Please keep the zoom as is after selecting the crop tool, as it would be useful to make small crops on big picture.
Alternatively, allow for zooming and scrolling pictures when cropping.

License and some minors

This is quite a well-documented project if I ever saw one, congrats! And even only skimming the Readme is promising. A few questions however:

  • What license are you using?
  • the tag says "1.0" – but the APK identifies as "1.1"; is that intended?
  • seeing versionName "1.1" together with versionCode 1 looks like the latter was forgotten to increase (but could also mean you just started with "1.1" because noone would trust a .0 release)?
  • as this is an open-source project, wouldn't you rather use an open-source mapping library (OSM?) instead of bringing in proprietary dependencies (here: Google Maps and GSM)?

Thanks in advance for letting me know!

Litrato not recognized as Image Editing app

It seems Image Editing apps can be recognized by Android as such: in sone third party apps you can choose to edit pictures with an external app, which prompts you with a list of selected apps that seemingly hit the Image Editing category.
As an exemple, this is what what i'm prompted with when i chose to edit a picture in Gallery:
20231108_220402

As you can see, Pocket Paint is there, as well as the tools used by ScreenshotTile (a public library of editing tools you probably heard of or even used), but not Litrato.

Would that be possible to make Litrato appear in that menu ?

Can't open an image from my local storage

Using release 1.1 APK, I am unable to open an image from the local storage of my phone.

The app lets me open the gallery viewer and when I select an image it goes back to the Litrato interface but the test image is still present. I have tried to open images from various locations on my phone to no avail.

Clicking on take picture also does not do anything so at the moment I can only edit the test image. The functionality of the application looks awesome, would be very keen to try with my own images.

F-Droid

As one of the only two decent libre Android image editors, it'd be great if Litrato was in the official F-Droid repository. Would you mind adding the app to F-Droid?

Save over original picture

For those who just want a quick crop or editing a screenshot on the go, this would help tremendously, as it would reduce the load of file cleaning in our folders.

So if an activated option could allow us to write the edited picture over the original one, and using the same name, that would be useful :)

Choose where to save picture

Last time i edited a picture i wasn't sure were it was saved on my phone. After some digging i found out they were being saved in /storage/emulated/0/Pictures.

Please let us decide where to save the edited picture. I can see 3 options available:

  1. same folder as original (with some text appended to its name to distinguish it from the original)
  2. choose folder everytime image is saved
  3. default folder (set by user)

If this is a bit much to do in one go, at least tell the user the folder path to where the picture was saved :)

Apply filter, i.e., noise to a particular area

Having the ability to apply filters to a specific area would be great.
I tried with Noise, but you can only paint it on, which is not precise.
Using area to apply filters, like noise and blur would be good

versionCode not increased

it looks like versionCode is never increased before releasing a new version. From the last release's build.gradle:

        versionCode 1
        versionName "1.1"

This is from tag 1.11 – the third release, so I'd expected

        versionCode 3
        versionName "1.11"

instead. Unfortunately, that's not just a cosmetic thing: versionCode is what Android uses internally to tell versions apart. Which means, the newer versions won't be offered for update, as Android thinks they're already installed. And even if force-updated, it will make reporting of issues difficult: which "version 1.1" had the user installed – this one (1.11) or the previous one?

TL;DR: could you please increase versionCode with each release (for technical reasons) – and versionName (to not confuse users 🙊)? Thanks!

Crop selection adjustments

The current behaviour of dragging rectangle for cropping is a little annoying, as you can not stop, correct, adjust once you have begun.

The standard of having the whole area of drawing/picture
Then selecting corners or sides to expand/reduce area works perfectly, as users can adjust and make corrections

In the following image you can see how to different apps use transform (crop) tool:

[BUG] No blur in saved picture

Steps to reproduce

  1. open an image from your gallery
  2. go to filters > blur and apply gaussian blur to the picture
  3. save the image

Actual result

The picture saved in the gallery is not blurred

Expected behaviour

image should be saved with blur

Compiled *Not* For Debug?

Hi there.

This looks amazing, but given the potential access implications after the fact, will there be a version on izzysoft that is not compiled for debugging?

Not asking with any entitlement, or expectation of response, just thought it might be something to up the security profile of it is all.

Keep up the good work!

All filters appear two times

This bug i can't reproduce consistently but it seems this happens when using the app a bit too fast.

The issue is, all filters appear twice in their list. For example, the "Fancy" list only contains 2 filters, but they both appear twice their, as if a second list of the same filters was appended at the end of the Fancy list.

Certificate issue

A scan (see here for details and background) just revealed the APKs at your releases are signed using a debug key. As that has security implications, may I ask you to please switch to a proper release key, and provide the corresponding APK signed with it? Thanks in advance!

Name saved pictures

Sometimes you want the edited picture to have a personalized name. It would ée neat if we had the ability to give a personalized name to these pictures directly from within Litrato.

Maybe optuons to generate preformatted edited picture names would help some users too. Nwt speaking for myself though, and not entirely sure if that feature would be much used.

Edit in Landscape mode

As stated on the main page in Bugs and Limitations:

Landscape mode is not available. We have created a layout_land of Filter, but because of time contraint, we decided to focus on other, more important elements (History was one of them at the time).

Maybe now it is time to finally implement that feature !
Please consider making Litrato work in Landscape mode, as to accomodate for pictures taken in that format. The app would greatly benefit from that-improvmert i think.

Crashes & Slider Issues

An open source photo editing with decent capabilities is wonderful! Understandably, since it is the first release, there are a few issues.

  • Crashes
    This seems to only happen when you press "sharpen" in the tools option. Everything else works fine without crashing the app.

  • Slider Issues
    The slider is extremely off from my touch input, and often when trying to move only a little bit, the full 100% is moved. Moving back is difficult, since it will keep resisting to return back to 100%. Eventually, I can get it to the applied percentage I want.

  • Slow App Responses
    Honestly, every option in the app is slow to respond, though it seems like you're aware of that.

I'm hoping these can be resolved/optimized further in the next release. Sometimes I don't want to pull up my computer to edit a photo, but most photo editing mobile apps are closed source. Having an open source option like this is great.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.