getPublicStorage(“Pictures”) lists no files

后端 未结 1 689
执念已碎
执念已碎 2020-12-11 13:54

Calling

File picturesDir = Services.get(StorageService.class)
            .flatMap(s -> s.getPublicStorage(\"Pictures\"))
            .orElseThrow(() -&g         


        
1条回答
  •  不思量自难忘°
    2020-12-11 14:31

    As discussed previously in this question, on mobile there is no Swing or AWT, so once you have a JavaFX image, to retrieve it you can't use SwingFXUtils.

    The solution proposed in the mentioned question works on Android as you can easily get the File. On iOS, on the contrary, the file is located in the gallery and the current Charm Down PicturesService doesn't access the gallery.

    Instead of modifying that service (with native code like this one), the idea to get a byteArray from the JavaFX Image that you can send to a web service is based on two steps:

    • Get the image pixels as a byte array
    • Encode the byte array into a string.

    If you check the iOS implementation for PicturesService::takePhoto, the image from the iOS native layer is sent to the JavaFX layer via Base64 encoding and decoding.

    Solution 1

    This code snippet works for me:

    // Take a photo and add image to imageView
    Button button = new Button("Take Photo");
    button.setOnAction(e ->
        Services.get(PicturesService.class)
            .ifPresent(s -> s.takePhoto(false).ifPresent(imageView::setImage)));
    
    // Encode image
    imageView.imageProperty().addListener((obs, ov, image) -> {
        if (image != null) {
            // 1. image to byte array
            PixelReader pixelReader = image.getPixelReader();
            int width = (int) image.getWidth(); 
            int height = (int) image.getHeight(); 
            byte[] buffer = new byte[width * height * 4]; 
            pixelReader.getPixels(0, 0, width, height, PixelFormat.getByteBgraInstance(), buffer, 0, width * 4); 
    
            // 2. Encode to String
            String encoded = Base64.getEncoder().encodeToString(buffer);
    
            // 3. send string...
        }
    } 
    

    You can check the process works by reversing these steps and creating an image out of the encoded string:

    byte[] imageBytes = Base64.getDecoder().decode(encoded.getBytes(StandardCharsets.UTF_8));
    
    WritablePixelFormat wf = PixelFormat.getByteBgraInstance();
    WritableImage writableImage = new WritableImage(width, height);
    PixelWriter pixelWriter = writableImage.getPixelWriter();
    pixelWriter.setPixels(0, 0, width, height, wf, imageBytes, 0, width * 4);
    
    imageView.setImage(writableImage);
    

    Solution 2

    If you want to transform the byte array from PixelReader::getPixels into a BufferedImage, that won't work: the byte arrays are different.

    So you need to use something that the buffered image will be able to process.

    Having a look at the SwingFXUtils implementation, it uses an int array instead.

    So this is another possibility:

    // Take a photo and add image to imageView
    Button button = new Button("Take Photo");
    button.setOnAction(e ->
        Services.get(PicturesService.class)
            .ifPresent(s -> s.takePhoto(false).ifPresent(imageView::setImage)));
    
    // Encode image
    imageView.imageProperty().addListener((obs, ov, image) -> {
        if (image != null) {
            // 1. image to int array
            PixelReader pixelReader = image.getPixelReader();
            int width = (int) image.getWidth(); 
            int height = (int) image.getHeight(); 
            int[] data = new int[width * height]; 
            pixelReader.getPixels(0, 0, width, height, PixelFormat.getIntArgbPreInstance(), data, 0, width); 
    
            // 2. int array to byte array
            ByteBuffer byteBuffer = ByteBuffer.allocate(data.length * 4);        
            IntBuffer intBuffer = byteBuffer.asIntBuffer();
            intBuffer.put(data);
    
    
            // 3. Encode to String
            String encoded = Base64.getEncoder().encodeToString(byteBuffer.array());
    
            // 4. send string...
        }
    } 
    

    Now you will have to decode the string, get the int array and create the buffered image:

    // 1. Decode string
    byte[] imageBytes = Base64.getDecoder().decode(encoded.getBytes(StandardCharsets.UTF_8));
    
    // 2. get int array
    ByteBuffer byteBuffer2 = ByteBuffer.wrap(imageBytes);
    IntBuffer intBuffer2 = byteBuffer2.asIntBuffer();
    int[] imageData = new int[intBuffer2.limit()];
    intBuffer2.get(imageData);
    
    // 3. create buffered image
    BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
    bufferedImage.setRGB(0, 0, width, height, imageData, 0, width);
    

    0 讨论(0)
提交回复
热议问题