LosslessJpgCrop icon indicating copy to clipboard operation
LosslessJpgCrop copied to clipboard

An added `Stretch` and an `Unrestrained Crop` Tools Complete the App

Open rajibando opened this issue 1 year ago • 9 comments

Thank you for this app. The tiny size is a bonus.

With an Unrestrained Crop and a Stretch tools this app becomes a complete crude perspective correction tool.

Requesting a complete Spherical, Cylindrical, Conical and other distortions arising out of the positioning of the mobile phone w.r.t. the subject and frame of photography would be a tall ask for a tiny, tidy app. So not asked.

rajibando avatar Dec 13 '24 00:12 rajibando

From https://github.com/k3b/LosslessJpgCrop

Note: This app is focused on lossless JPEG image manipulation, so issues that propose additional features (e.g. support for other file formats, add resize-support or adding text to images) are out of scope.

k3b avatar Dec 14 '24 11:12 k3b

Your position and viewpoint is appreciated. Acknowledged.

Literally, only one extra is requested. You already have a crop. Please make it an Unrestrained Crop, adding a Stretch Tool is just opposite of Crop and complements it.

If the app can't be altered on principle, then another app would do immense good to us users.

Best wishes.

rajibando avatar Dec 14 '24 11:12 rajibando

my app can only do what the underlying lib can do

  • sourcecode of the lib https://github.com/facebookincubator/spectrum/network
  • documentation of the lib api https://libspectrum.io/docs/transcoding_images_for_upload

Can you give me a java coding example that adds "Stretch" an image?

k3b avatar Dec 14 '24 12:12 k3b

Your project is built around preserving image quality while performing basic operations, as indicated by its reliance on lossless manipulation tools and libraries like libjpeg.

To implement stretching functionality, you can extend the existing framework by integrating an additional library, such as Java ImageIO or imgscalr. These libraries allow transformations like scaling with high-quality resampling. However, note that "stretching" inherently modifies pixel aspect ratios, making it lossy.

An example sample code snippet using Java's BufferedImage to add stretching:

import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;
 
public class ImageStretch {
    public static void main(String[] args) throws Exception {
        File input = new File("input.jpg");
        BufferedImage originalImage = ImageIO.read(input);

        int newWidth = originalImage.getWidth() * 2; // Example stretch factor
        int newHeight = originalImage.getHeight();

        BufferedImage stretchedImage = new BufferedImage(newWidth, newHeight, originalImage.getType());
        Graphics2D g2d = stretchedImage.createGraphics();
        g2d.drawImage(originalImage, 0, 0, newWidth, newHeight, null);
        g2d.dispose();

        ImageIO.write(stretchedImage, "jpg", new File("stretched.jpg"));
    }
}

For auto-straightening image after an unrestrained crop, the indicative example code could be looked into:

import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;

public class AutoStraightenCrop {
    public static void main(String[] args) throws Exception {
        File inputFile = new File("input.jpg");
        BufferedImage originalImage = ImageIO.read(inputFile);

        // Coordinates of the free-form crop area (example values)
        int cropX = 100, cropY = 50, cropWidth = 200, cropHeight = 150;

        // Crop the free-form area
        BufferedImage croppedImage = originalImage.getSubimage(cropX, cropY, cropWidth, cropHeight);

        // Auto-straighten: Make rectangular by padding
        int rectWidth = Math.max(cropWidth, cropHeight);
        int rectHeight = rectWidth; // Ensure a square for simplicity
        BufferedImage straightenedImage = new BufferedImage(rectWidth, rectHeight, originalImage.getType());
        Graphics2D g2d = straightenedImage.createGraphics();

        // Center cropped image within the new rectangle
        int xOffset = (rectWidth - cropWidth) / 2;
        int yOffset = (rectHeight - cropHeight) / 2;
        g2d.setColor(Color.WHITE); // Background color for padding
        g2d.fillRect(0, 0, rectWidth, rectHeight);
        g2d.drawImage(croppedImage, xOffset, yOffset, null);
        g2d.dispose();

        // Save the output
        ImageIO.write(straightenedImage, "jpg", new File("output.jpg"));
    }
}

I just tried to assist you. I am not a professional programmer, but a physicist. I don't study coding in details.

Hope you might have been assisted. I am trying to assist you in the way I can to help you meet my objective of a simple app with the crudest form of perspective correction by unrestrained crop and stretch.

Another request: Please re-open the issue. Together we shall try to solve the issue, I will try to assist as much as possible.

rajibando avatar Dec 14 '24 13:12 rajibando

Thanks for the infos.

unfortunately android does not support

import java.awt.*

I reopen the ticket. maybe there is somebody else who wants to add these features to the android app

k3b avatar Dec 14 '24 13:12 k3b

... I reopen the ticket. maybe there is somebody else who wants to add these features to the android app

Thank you, K3B. You are a very rational and conscientious individual who can step out of own shoes and into others'. Very rare and precious qualities for the Social Contract to be upheld and made robust.

I guess Android does not support the java.awt package because it relies on its own framework for graphics and image processing. I guess we can achieve similar functionality using Android's Bitmap class for image manipulation and the Canvas class for drawing.

Here could be an approx adapted approach for Android:

Replace BufferedImage with Bitmap.
Use Canvas to draw the cropped image onto a padded Bitmap.

Android-compatible code-snippet:

import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Rect;

public Bitmap autoStraightenCrop(Bitmap originalImage, int cropX, int cropY, int cropWidth, int cropHeight) {
    // Crop the free-form area
    Bitmap croppedBitmap = Bitmap.createBitmap(originalImage, cropX, cropY, cropWidth, cropHeight);

    // Determine dimensions for the rectangular output
    int rectWidth = Math.max(cropWidth, cropHeight);
    int rectHeight = rectWidth; // Ensure a square for simplicity

    // Create a new bitmap with the target dimensions
    Bitmap straightenedBitmap = Bitmap.createBitmap(rectWidth, rectHeight, originalImage.getConfig());
    Canvas canvas = new Canvas(straightenedBitmap);

    // Fill with white background
    canvas.drawColor(Color.WHITE);

    // Center the cropped image in the new rectangle
    int xOffset = (rectWidth - cropWidth) / 2;
    int yOffset = (rectHeight - cropHeight) / 2;
    canvas.drawBitmap(croppedBitmap, xOffset, yOffset, null);

    return straightenedBitmap;
}

rajibando avatar Dec 14 '24 14:12 rajibando

I assume that you used ChatGPT to generate the java examples.

Since LosslessJpgCrop is focused on "lossless jpg" image manipulation it may be more apropriate to create a new tiny tool ImageStretch that works similar to llcrop.

k3b avatar Dec 14 '24 14:12 k3b

You aren't my only friend :)

I have some other friends who try to help me. I don't ask personal questions to them.

Let us have this app out. I am sure the app will do great. I will speak justly about this new app of yours in the F-Droid forum.

Please rename the new app jpgLosslessFixer, keeping the naming consistent with the objective of your earlier app. Or OptimaljpgFixer. Your choice. One insight: when you crop an image, you lose info, which you treat as unwanted. So you decide the name and planning, whether to stretch or shrink.

Please understand that instead of stretch if you shrink the opposite side then the image doesn't suffer approximation-induced losses owing to stretching. However, the image will still suffer losses owing to pixel (info) dropping resulting from shrinkage.

I have already said that I could only assist you. My other friends aren't competent in Android programming.

You please also set a price for your nifty apps. At least, I will buy them. I have paid 10 times the minimum support price to the NetGuard creator, though I don't believe in donations.

I believe interpersonal accountability is best maintained by an exchange of value. The donation model kills that value and encourages unwanted elements to creep into the ecosystem.

rajibando avatar Dec 14 '24 14:12 rajibando

Nearly two months have passed. Any info/updates on this app?

rajibando avatar Feb 10 '25 06:02 rajibando