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());
}
}
/**
* 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))};
}
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;
}
Original image:
Has crop, has sticker at default scale and location:
Result:
[{"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}]
Has crop, has sticker with some rotation:
Result:
[{"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}]
Has everything, crop, stickers, filter, adjustments.
Result:
[{"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}]