vxh.viet
2/9/2018 - 8:32 AM

[DOCUMENT] Image data to JSON

Image Data to JSON:

Convert Sticker data to JSON

    private void saveStickerData(Matrix m, Sticker sticker, int fullsizeImageWidth, int fullsizeImageHeight) {
        //these data need to be saved to server so we can reproduced this image later

    // sticker.getWidth() and sticker.getHeight() are the actual width and height of the sticker image. Multiply 
    // them with the current scale we will get the sticker's current width and height.
        float scaledStickerWidth = MatrixUtil.getMatrixScale(m) * sticker.getWidth();
        float scaledStickerHeight = MatrixUtil.getMatrixScale(m) * sticker.getHeight();

        //shift to center, don't ask me why, ask iOS
        float stickerCenterX = MatrixUtil.getMatrixValue(m, Matrix.MTRANS_X) + scaledStickerWidth / 2; // Matrix.MTRANS_X is the current X of the sticker 
        float stickerCenterY = MatrixUtil.getMatrixValue(m, Matrix.MTRANS_Y) + scaledStickerHeight / 2;

    // calculate the sticker's current X and Y based on the image's actual width and height.
        float stickerPosXRatio = stickerCenterX / fullsizeImageWidth;
        float stickerPosYRatio = stickerCenterY / fullsizeImageHeight;
        Timber.d("saveStickerData(): DEBUG_SAVE_STICKER sticker posXRatio: %f --- posYRatio: %f", stickerPosXRatio, stickerPosYRatio);

    // calculate the ratio between sticker's current width and the image's actual width.
        float stickerWidthRatio = scaledStickerWidth / fullsizeImageWidth;
        Timber.d("saveStickerData(): DEBUG_SAVE_STICKER sticker width ratio: %f", stickerWidthRatio);

    // current sticker angle
        float stickerAngle = MatrixUtil.getMatrixAngle(m);
        Timber.d("saveStickerData(): DEBUG_SAVE_STICKER sticker angle: %f \n---------------------------------", stickerAngle);

    // current sticker drawable's position (sticker variants)
        List<Integer> drawableResList = ((MyDrawableSticker) sticker).getDrawableResList();

        ImageStickerData imageStickerData = new ImageStickerData.Builder()
                .setType(BaseStickerData.Type.IMAGE)
                .setPosXRatio(stickerPosXRatio)
                .setPosYRatio(stickerPosYRatio)
                .setWidthRatio(stickerWidthRatio)
                .setAngle(stickerAngle)
                .setDrawableResList(drawableResList)
                .build();

        mStickerDataList.add(imageStickerData);

        //check logic for text sticker
        if (sticker instanceof MyTextSticker) {
            Timber.d("saveStickerData(): DEBUG_SAVE_STICKER text: \"%s\"", ((MyTextSticker) sticker).getText());
        }
    }

Convert Crop data to JSON

    /**
     * Save and reproduce crop data.
     * The goal is to map the crop rect to the image or using the image's left top corner as the coordinate for the crop rect.
     * Firstly, we will need to un-rotate the image so that we can easily calculate the distance of crop rect's corners to the
     * image's top and left sides.
     * Then we compute the ratio of said distances to the image's width and height.
     * Save those ratio and the current angle.
     */
    private void saveCropData() {
        //Get the current image and and crop corners
        float[] currentCropCorners = RectUtils.getCornersFromRect(mGestureCropImageView.getCropRect());
        float[] currentImageCorners = mGestureCropImageView.getCurrentImageCornersWithoutPadding();

        //Un-rotate those points. We can simply use the default (0,0) as pivot point,
        //but in order to prevent any problem that could occur because of different screen sizes,
        //we use the image's center as pivot point. (UNTESTED on different devices yet).
        RectF imageRect = RectUtils.trapToRect(currentImageCorners);
        Matrix m = new Matrix();
        m.setRotate(-mGestureCropImageView.getCurrentAngle(), imageRect.centerX(), imageRect.centerY());
        m.mapPoints(currentImageCorners);
        m.mapPoints(currentCropCorners);

        //Calculate the distance of crop rect's corners to the image's top and left sides and
        //then calculate the ratio of these distances to the image's width and height.
        float[] currentImageSize = RectUtils.getRectSidesFromCorners(currentImageCorners);

        float[] cropRectRatio = {
                (currentCropCorners[0] - currentImageCorners[0]) / currentImageSize[0],
                (currentCropCorners[1] - currentImageCorners[1]) / currentImageSize[1],
                (currentCropCorners[2] - currentImageCorners[0]) / currentImageSize[0],
                (currentCropCorners[3] - currentImageCorners[1]) / currentImageSize[1],
                (currentCropCorners[4] - currentImageCorners[0]) / currentImageSize[0],
                (currentCropCorners[5] - currentImageCorners[1]) / currentImageSize[1],
                (currentCropCorners[6] - currentImageCorners[0]) / currentImageSize[0],
                (currentCropCorners[7] - currentImageCorners[1]) / currentImageSize[1]
        };
        Timber.d("saveCropData(): DEBUG_SAVE_CROP ratio: %s", Arrays.toString(cropRectRatio));
        Timber.d("saveCropData(): DEBUG_SAVE_CROP angle: %s", mGestureCropImageView.getCurrentAngle());
        mCropData = new CropData(mGestureCropImageView.getCurrentAngle(), cropRectRatio);
    }
    
    /**
     * Gets a float array of two lengths representing a rectangles width and height
     * The order of the corners in the input float array is:
     * 0------->1
     * ^        |
     * |        |
     * |        v
     * 3<-------2
     *
     * @param corners the float array of corners (8 floats)
     * @return the float array of width and height (2 floats)
     */
    public static float[] getRectSidesFromCorners(float[] corners) {
        return new float[]{(float) Math.sqrt(Math.pow(corners[0] - corners[2], 2) + Math.pow(corners[1] - corners[3], 2)),
                (float) Math.sqrt(Math.pow(corners[2] - corners[4], 2) + Math.pow(corners[3] - corners[5], 2))};
    }

Convert Filter and other Adjustments to JSON:

public void convertFilterAndAdjustmentData() {
        try {
            if (ImageState.INSTANCE.getLUTFilterName() != LUTFilter.DEFAULT_LUT_FILTER) { // LUTFilter.DEFAULT_LUT_FILTER = "filter_lut_original.png"
                mFilterJSONObj = JSONGenerator.convertFilterDataToJSON();
            }

            if (ImageState.INSTANCE.getContrastValue() != Contrast.DEFAULT_VALUE) { // Contrast.DEFAULT_VALUE = 1.0f
                mContrastJSONObj = JSONGenerator.convertContrastDataToJSON();
            }

            if (ImageState.INSTANCE.getBrightnessValue() != Brightness.DEFAULT_VALUE) { // Brightness.DEFAULT_VALUE = 0.0f
                mBrightnessJSONObj = JSONGenerator.convertBrightnessDataToJSON();
            }

            if (ImageState.INSTANCE.getSaturationValue() != Saturation.DEFAULT_VALUE) { // Saturation.DEFAULT_VALUE = 1.0f
                mSaturationJSONObj = JSONGenerator.convertSaturationDataToJSON();
            }

            if (ImageState.INSTANCE.getExposureValue() != Exposure.DEFAULT_VALUE) { // Exposure.DEFAULT_VALUE = 0.0f
                mExposureJSONObj = JSONGenerator.convertExposureDataToJSON();
            }
        } catch (JSONException e) {
            Timber.d("convertFilterAndAdjustmentData(): DEBUG_GEN_JSON exception: %s", e.getMessage());
        }
    }

Sample convertFilterDataToJSON() and convertContrastDataToJSON(), other functions should be similar:

    public static JSONObject convertFilterDataToJSON() throws JSONException {
        JSONObject filterObj = new JSONObject();

        //exclude file's extension
        String lut = ImageState.INSTANCE.getLUTFilterName();
        String lutName = lut.substring(0, lut.length() - 4);

        filterObj.put("filterName", lutName);
        filterObj.put("identifier", "LUTFilter");

        LogUtil.logLongString("DEBUG_GEN_JSON", filterObj.toString());
        return filterObj;
    }
    public static JSONObject convertContrastDataToJSON() throws JSONException {
        JSONObject contrastObj = new JSONObject();
        contrastObj.put("minValue", Contrast.MIN_VALUE); // Contrast.MIN_VALUE = 0.5f
        contrastObj.put("maxValue", Contrast.MAX_VALUE); // Contrast.MAX_VALUE = 3.0f
        contrastObj.put("identifier", "ContrastFilter");
        contrastObj.put("type", "contrast");
        contrastObj.put("value", ImageState.INSTANCE.getContrastValue());

        LogUtil.logLongString("DEBUG_GEN_JSON", contrastObj.toString());
        return contrastObj;
    }

Sample data for testing:

Original image:

Sample 1:

Has crop, has sticker at default scale and location:

Result:

Output JSON:

[{"filterName":"filter_lut_09","identifier":"LUTFilter"},{"package_name":"Activity Homerun","identifier":"sticker_package","stickers":[{"type":"image","x":0.1875,"y":0.2652892470359802,"width":0.375,"angle":-0,"variants":[{"image_name":"sticker_set_homerun_player"},{"image_name":"sticker_set_homerun_out_the_park"},{"image_name":"sticker_set_homerun_strike"}]},{"type":"image","x":0.71875,"y":0.8050307631492615,"width":0.5625,"angle":-0,"variants":[{"image_name":"sticker_set_homerun_1st_place"},{"image_name":"sticker_set_homerun_cup"},{"image_name":"sticker_set_homerun_podium"},{"image_name":"sticker_set_homerun_podium_home_run"}]}]},{"identifier":"crop","corners":[0,0,0.7164633870124817,0,0.7164633870124817,0.6943089365959167,0,0.6943089365959167],"angle":-0}]

Sample 2:

Has crop, has sticker with some rotation:

Result:

Output JSON:

[{"filterName":"filter_lut_09","identifier":"LUTFilter"},{"package_name":"Activity Homerun","identifier":"sticker_package","stickers":[{"type":"image","x":0.71875,"y":0.8050307631492615,"width":0.5625,"angle":-0,"variants":[{"image_name":"sticker_set_homerun_1st_place"},{"image_name":"sticker_set_homerun_cup"},{"image_name":"sticker_set_homerun_podium"},{"image_name":"sticker_set_homerun_podium_home_run"}]},{"type":"image","x":0.06243792548775673,"y":0.5109825134277344,"width":0.5808231830596924,"angle":-25.033145904541016,"variants":[{"image_name":"sticker_set_homerun_player"},{"image_name":"sticker_set_homerun_out_the_park"},{"image_name":"sticker_set_homerun_strike"}]}]},{"identifier":"crop","corners":[0.23272357881069183,0.3886178731918335,1,0.3886178731918335,1,1,0.23272357881069183,1],"angle":-0}]

Sample 3:

Has everything, crop, stickers, filter, adjustments.

Result:

Output JSON:

[{"filterName":"filter_lut_33","identifier":"LUTFilter"},{"package_name":"Activity Homerun","identifier":"sticker_package","stickers":[{"type":"image","x":0.1201624646782875,"y":0.370637446641922,"width":0.5732861161231995,"angle":-8.675870895385742,"variants":[{"image_name":"sticker_set_homerun_player"},{"image_name":"sticker_set_homerun_out_the_park"},{"image_name":"sticker_set_homerun_strike"}]},{"type":"image","x":0.6102254390716553,"y":0.8597456216812134,"width":0.4760517477989197,"angle":-19.779979705810547,"variants":[{"image_name":"sticker_set_homerun_cup"},{"image_name":"sticker_set_homerun_podium"},{"image_name":"sticker_set_homerun_podium_home_run"},{"image_name":"sticker_set_homerun_1st_place"}]}]},{"identifier":"crop","corners":[1.121048626373522E-5,0.37952759861946106,0.6964569687843323,0.11014603823423386,0.7902231812477112,0.7307376265525818,0.09377742558717728,1.0001192092895508],"angle":13.590322494506836},{"minValue":0.5,"maxValue":3,"identifier":"ContrastFilter","type":"contrast","value":0.8711583614349365},{"minValue":-0.5,"maxValue":0.5,"identifier":"BrightnessFilter","type":"brightness","value":0.15721040964126587},{"minValue":0,"maxValue":2,"identifier":"SaturationFilter","type":"saturation","value":0.7990543842315674},{"minValue":-2.5,"maxValue":2.5,"identifier":"ExposureFilter","type":"exposure","value":-0.508274257183075}]