B4J Code Snippet Image to JPEG byte array with resize/quality options

Discussion in 'B4J Code Snippets' started by OliverA, Apr 11, 2018.

  1. OliverA

    OliverA Well-Known Member Licensed User

    Due to @Erel's comment below, I've rewritten this in pure B4X basic. The new version should work with B4A, B4J and B4i. New version (that should be used) can be found here https://www.b4x.com/android/forum/t...byte-array-with-resize-quality-options.91774/.
    Code:
    ' Converts image to JPEG a byte array of the resulting JPEG. Ability to resize and adjust JPEG quality.
    ' Negative width and height values = %, such that -50 = 50% and -200 = 200%
    ' Positive width and height values = pixel dimensions
    ' If one value (either width or height) are 0, then the other value is proportionally
    '  calculated from the first.
    ' If both width and height are 0 or -100, no resizing takes place
    ' If quality = -1, use Java's default quality
    Sub ImageToJPEGByteArray(aImage As Image, width As Int, height As Int, quality As Int) As Byte()
       
    Dim jo As JavaObject = Me
       
    Return jo.RunMethod("imageToJPEGByteArray"Array As Object (aImage, width, height, quality))
    End Sub
    Code:
    #if Java
    import java.awt.image.BufferedImage;
    import java.awt.geom.AffineTransform;
    import java.awt.Graphics2D;

    import java.io.ByteArrayOutputStream;
    import java.io.IOException;
    import java.io.OutputStream;

    import java.util.Iterator;
    import java.util.Locale;

    import javafx.scene.image.Image;
    import javafx.embed.swing.SwingFXUtils;

    import javax.imageio.IIOImage;
    import javax.imageio.ImageIO;
    import javax.imageio.ImageWriteParam;
    import javax.imageio.ImageWriter;
    import javax.imageio.plugins.jpeg.JPEGImageWriteParam;
    import javax.imageio.stream.ImageOutputStream;

    // Image resizing
    // https://stackoverflow.com/a/4205711
    // https://stackoverflow.com/questions/21540378/convert-javafx-image-to-bufferedimage
    // https://stackoverflow.com/a/13605411
    // https://www.mkyong.com/java/how-to-convert-bufferedimage-to-byte-in-java/
    // JPEG quality
    // https://www.b4x.com/android/forum/threads/solved-how-to-create-jpeg-output-stream.83830/#post-531280
    // http://www.java2s.com/Code/Java/2D-Graphics-GUI/WritesanimagetoanoutputstreamasaJPEGfileTheJPEGqualitycanbespecifiedinpercent.htm


    // Converts image to JPEG a byte array of the resulting JPEG. Ability to resize and adjust JPEG quality.
    // Negative width and height values = %, such that -50 = 50% and -200 = 200%
    // Positive width and height values = pixel dimensions
    // If one value (either width or height) are 0, then the other value is proportionally
    //  calculated from the first.
    // If both width and height are 0 or -100, no resizing takes place
    // If quality = -1, use Java's default quality
    public static byte[] imageToJPEGByteArray(Image aImage, int width, int height, int qualityPercent) throws IOException {
       byte[] imageBytes = new byte[0];
     
       if ((qualityPercent < -1) || (qualityPercent > 100)) {
          throw new IllegalArgumentException("Quality out of bounds!");
        }
       float quality = qualityPercent / 100f;
     
       double oldWidth = aImage.getWidth();
       double oldHeight = aImage.getHeight();
       if (oldWidth == 0 || oldHeight == 0) {
           throw new IllegalArgumentException("Source image with 0 width and/or height!");
       }
     
       boolean resize = true;
       if ((width == 0 && height == 0) || (width == -100 && height == -100)) resize = false;

       BufferedImage destImage;
       if (resize) {
           double newWidth = (double) width;
           double newHeight = (double) height;
           // Calculate new dimensions
           if (newWidth < 0) newWidth = -1 * oldWidth * newWidth / 100;
           if (newHeight < 0) newHeight = -1 * oldHeight * newHeight / 100;
           if (newWidth == 0) newWidth = oldWidth * newHeight / oldHeight; 
           if (newHeight == 0) newHeight = oldHeight * newWidth / oldWidth;
           // Convert JavaFX image to BufferedImage and transform according to new dimensions
           destImage = new BufferedImage((int) newWidth, (int) newHeight, BufferedImage.TYPE_INT_RGB);
           BufferedImage srcImage = SwingFXUtils.fromFXImage(aImage, null);
           Graphics2D g = destImage.createGraphics();
           AffineTransform at = AffineTransform.getScaleInstance(newWidth/oldWidth, newHeight/oldHeight);
           g.drawRenderedImage(srcImage, at);
           g.dispose();
       } else {
           destImage = SwingFXUtils.fromFXImage(aImage, null);
       }
     
       // Output JPEG byte array
       ByteArrayOutputStream baos = new ByteArrayOutputStream();
     
       if(qualityPercent != -1) {
           // Start to create JPEG with quality option
           ImageWriter writer = null;
           Iterator iter = ImageIO.getImageWritersByFormatName("jpg");
           if (iter.hasNext()) {
             writer = (ImageWriter) iter.next();
           }
           ImageOutputStream ios = ImageIO.createImageOutputStream(baos);
           writer.setOutput(ios); 
           ImageWriteParam iwparam = new JPEGImageWriteParam(Locale.getDefault());
           iwparam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
           iwparam.setCompressionQuality(quality);
           writer.write(null, new IIOImage(destImage, null, null), iwparam);
           ios.flush();
           writer.dispose();
           ios.close();
           // Done creating JPEG with quality option
       } else {
           // This one line below created a JPEG file without quality option
           ImageIO.write(destImage, "jpg", baos);
       }
     
       baos.flush();
       imageBytes = baos.toByteArray();
       baos.close();
     
       // Done
       return imageBytes; 
    }

    #End If
    Example
    Code:
    Dim bImage As Image
    bImage.Initialize(
    File.DirAssets, "b.png")
    Dim c() As Byte = ImageToJPEGByteArray(bImage, -50050)
    'https://www.b4x.com/android/forum/threads/b4x-bytes-to-file.70111/#content
    BytesToFile(File.DirApp, "b.jpg", c)
    Resources used:
    Image resizing
    https://stackoverflow.com/a/4205711
    https://stackoverflow.com/questions/21540378/convert-javafx-image-to-bufferedimage
    https://stackoverflow.com/a/13605411
    https://www.mkyong.com/java/how-to-convert-bufferedimage-to-byte-in-java/

    JPEG quality
    https://www.b4x.com/android/forum/threads/solved-how-to-create-jpeg-output-stream.83830/#post-531280
    http://www.java2s.com/Code/Java/2D-Graphics-GUI/WritesanimagetoanoutputstreamasaJPEGfileTheJPEGqualitycanbespecifiedinpercent.htm
     
    Last edited: Apr 11, 2018
    moster67, rboeck, inakigarm and 2 others like this.
  2. Erel

    Erel Administrator Staff Member Licensed User

    ellpopeb4a and MarkusR like this.
  3. OliverA

    OliverA Well-Known Member Licensed User

  4. moster67

    moster67 Expert Licensed User

    @OliverA: Many thanks for the java-code you provided - it was a life-saver for a library I am wrapping. Thanks!
     
Loading...
  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice