Add interface for stretchable image (#314)
* Add interface for stretch image * Add demo for stretch image api * Add stretchable image demp * Update stretchable image test activity. * Revert change for SymbolLayerActivity This reverts commit 22bbb798
This commit is contained in:
@@ -13,6 +13,9 @@ mbgl::style::Image Image::getImage(jni::JNIEnv& env, const jni::Object<Image>& i
|
||||
static auto bufferField = javaClass.GetField<jni::Array<jbyte>>(env, "buffer");
|
||||
static auto nameField = javaClass.GetField<jni::String>(env, "name");
|
||||
static auto sdfField = javaClass.GetField<jni::jboolean>(env, "sdf");
|
||||
static auto contentField = javaClass.GetField<jni::Array<jfloat >>(env, "content");
|
||||
static auto stretchXField = javaClass.GetField<jni::Array<jfloat>>(env, "stretchX");
|
||||
static auto stretchYField = javaClass.GetField<jni::Array<jfloat>>(env, "stretchY");
|
||||
|
||||
auto height = image.Get(env, heightField);
|
||||
auto width = image.Get(env, widthField);
|
||||
@@ -20,7 +23,9 @@ mbgl::style::Image Image::getImage(jni::JNIEnv& env, const jni::Object<Image>& i
|
||||
auto pixels = image.Get(env, bufferField);
|
||||
auto name = jni::Make<std::string>(env, image.Get(env, nameField));
|
||||
auto sdf = (bool) image.Get(env, sdfField);
|
||||
|
||||
auto content = image.Get(env, contentField);
|
||||
auto stretchX = image.Get(env, stretchXField);
|
||||
auto stretchY = image.Get(env, stretchYField);
|
||||
jni::NullCheck(env, pixels.get());
|
||||
std::size_t size = pixels.Length(env);
|
||||
|
||||
@@ -29,8 +34,38 @@ mbgl::style::Image Image::getImage(jni::JNIEnv& env, const jni::Object<Image>& i
|
||||
throw mbgl::util::StyleImageException("Image pixel count mismatch");
|
||||
}
|
||||
|
||||
jni::GetArrayRegion(env, *pixels, 0, size, reinterpret_cast<jbyte*>(premultipliedImage.data.get()));
|
||||
return mbgl::style::Image {name, std::move(premultipliedImage), pixelRatio, sdf};
|
||||
jni::GetArrayRegion(env, *pixels, 0, size,
|
||||
reinterpret_cast<jbyte *>(premultipliedImage.data.get()));
|
||||
|
||||
style::ImageStretches imageStretchesX = {};
|
||||
style::ImageStretches imageStretchesY = {};
|
||||
if (stretchX.get()) {
|
||||
std::size_t sizeX = stretchX.Length(env);
|
||||
for (jni::jsize i = 0; i < sizeX - 1; i += 2) {
|
||||
imageStretchesX.push_back({stretchX.Get(env, i), stretchX.Get(env, i + 1)});
|
||||
}
|
||||
}
|
||||
if (stretchY.get()) {
|
||||
std::size_t sizeY = stretchY.Length(env);
|
||||
for (jni::jsize i = 0; i < sizeY - 1; i += 2) {
|
||||
imageStretchesY.push_back({stretchY.Get(env, i), stretchY.Get(env, i + 1)});
|
||||
}
|
||||
}
|
||||
|
||||
if (content) {
|
||||
const style::ImageContent imageContent = style::ImageContent{content.Get(env, 0),
|
||||
content.Get(env, 1),
|
||||
content.Get(env, 2),
|
||||
content.Get(env, 3)};
|
||||
return mbgl::style::Image{name, std::move(premultipliedImage), pixelRatio, sdf,
|
||||
imageStretchesX,
|
||||
imageStretchesY,
|
||||
std::move(imageContent)};
|
||||
}
|
||||
|
||||
return mbgl::style::Image{name, std::move(premultipliedImage), pixelRatio, sdf,
|
||||
imageStretchesX,
|
||||
imageStretchesY};
|
||||
}
|
||||
|
||||
void Image::registerNative(jni::JNIEnv &env) {
|
||||
|
||||
@@ -10,13 +10,24 @@ public class Image {
|
||||
private final int width;
|
||||
private final int height;
|
||||
private final boolean sdf;
|
||||
private final float[] content;
|
||||
private final float[] stretchX;
|
||||
private final float[] stretchY;
|
||||
|
||||
public Image(byte[] buffer, float pixelRatio, String name, int width, int height, boolean sdf) {
|
||||
this(buffer, pixelRatio, name, width, height, sdf, null, null, null);
|
||||
}
|
||||
|
||||
public Image(byte[] buffer, float pixelRatio, String name, int width, int height, boolean sdf,
|
||||
float[] stretchX, float[] stretchY, float[] content) {
|
||||
this.buffer = buffer;
|
||||
this.pixelRatio = pixelRatio;
|
||||
this.name = name;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.sdf = sdf;
|
||||
this.content = content;
|
||||
this.stretchX = stretchX;
|
||||
this.stretchY = stretchY;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
package com.mapbox.mapboxsdk.maps;
|
||||
|
||||
/**
|
||||
* Describes the image content, e.g. where text can be fit into an image.
|
||||
* <p>
|
||||
* When sizing icons with icon-text-fit,
|
||||
* the icon size will be adjusted so that the this content box fits exactly around the text.
|
||||
*/
|
||||
public final class ImageContent {
|
||||
|
||||
private final float left;
|
||||
private final float top;
|
||||
private final float right;
|
||||
private final float bottom;
|
||||
|
||||
public ImageContent(float left,
|
||||
float top,
|
||||
float right,
|
||||
float bottom) {
|
||||
this.left = left;
|
||||
this.top = top;
|
||||
this.right = right;
|
||||
this.bottom = bottom;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the array for this content, sorted by left, top, right, bottom.
|
||||
*
|
||||
* @return the content array.
|
||||
*/
|
||||
public float[] getContentArray() {
|
||||
float[] array = new float[4];
|
||||
array[0] = left;
|
||||
array[1] = top;
|
||||
array[2] = right;
|
||||
array[3] = bottom;
|
||||
return array;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof ImageContent)) {
|
||||
return false;
|
||||
}
|
||||
ImageContent other = (ImageContent) obj;
|
||||
return this.left == other.left
|
||||
&& this.top == other.top
|
||||
&& this.right == other.right
|
||||
&& this.bottom == other.bottom;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = (left != +0.0f ? Float.floatToIntBits(left) : 0);
|
||||
result = 31 * result + (top != +0.0f ? Float.floatToIntBits(top) : 0);
|
||||
result = 31 * result + (right != +0.0f ? Float.floatToIntBits(right) : 0);
|
||||
result = 31 * result + (bottom != +0.0f ? Float.floatToIntBits(bottom) : 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[ " + "left: " + left + ", " + "top: " + top + ", " + "right: " + right + ", " + "bottom: " + bottom + " ]";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package com.mapbox.mapboxsdk.maps;
|
||||
|
||||
|
||||
/**
|
||||
* Describes the image stretch areas.
|
||||
*/
|
||||
public final class ImageStretches {
|
||||
|
||||
private final float first;
|
||||
private final float second;
|
||||
|
||||
public ImageStretches(float first,
|
||||
float second) {
|
||||
this.first = first;
|
||||
this.second = second;
|
||||
}
|
||||
|
||||
/**
|
||||
* The first stretchable part in pixel units.
|
||||
*/
|
||||
public float getFirst() {
|
||||
return first;
|
||||
}
|
||||
|
||||
/**
|
||||
* The second stretchable part in pixel units.
|
||||
*/
|
||||
public float getSecond() {
|
||||
return second;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof ImageStretches)) {
|
||||
return false;
|
||||
}
|
||||
ImageStretches other = (ImageStretches) obj;
|
||||
return this.first == other.first
|
||||
&& this.second == other.second;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = (first != +0.0f ? Float.floatToIntBits(first) : 0);
|
||||
result = 31 * result + (second != +0.0f ? Float.floatToIntBits(second) : 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[ " + "first: " + first + ", " + "second: " + second + " ]";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -3,12 +3,9 @@ package com.mapbox.mapboxsdk.maps;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.AsyncTask;
|
||||
import androidx.annotation.IntRange;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.StringDef;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.Pair;
|
||||
|
||||
import com.mapbox.mapboxsdk.constants.MapboxConstants;
|
||||
import com.mapbox.mapboxsdk.style.layers.Layer;
|
||||
import com.mapbox.mapboxsdk.style.layers.TransitionOptions;
|
||||
@@ -26,6 +23,11 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import androidx.annotation.IntRange;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.StringDef;
|
||||
|
||||
/**
|
||||
* The proxy object for current map style.
|
||||
* <p>
|
||||
@@ -317,6 +319,20 @@ public class Style {
|
||||
addImage(name, image, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an image to be used in the map's style
|
||||
*
|
||||
* @param name the name of the image
|
||||
* @param image the pre-multiplied Bitmap
|
||||
* @param stretchX image stretch areas for x axix
|
||||
* @param stretchY image stretch areas for y axix
|
||||
* @param content image content for text to fit
|
||||
*/
|
||||
public void addImage(@NonNull String name, @NonNull Bitmap image, @NonNull List<ImageStretches> stretchX,
|
||||
@NonNull List<ImageStretches> stretchY, @Nullable ImageContent content) {
|
||||
addImage(name, image, false, stretchX, stretchY, content);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an drawable to be converted into a bitmap to be used in the map's style
|
||||
*
|
||||
@@ -331,6 +347,26 @@ public class Style {
|
||||
addImage(name, bitmap, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an drawable to be converted into a bitmap to be used in the map's style
|
||||
*
|
||||
* @param name the name of the image
|
||||
* @param drawable the drawable instance to convert
|
||||
* @param stretchX image stretch areas for x axix
|
||||
* @param stretchY image stretch areas for y axix
|
||||
* @param content image content for text to fit
|
||||
*/
|
||||
public void addImage(@NonNull String name, @NonNull Drawable drawable,
|
||||
@NonNull List<ImageStretches> stretchX,
|
||||
@NonNull List<ImageStretches> stretchY,
|
||||
@Nullable ImageContent content) {
|
||||
Bitmap bitmap = BitmapUtils.getBitmapFromDrawable(drawable);
|
||||
if (bitmap == null) {
|
||||
throw new IllegalArgumentException("Provided drawable couldn't be converted to a Bitmap.");
|
||||
}
|
||||
addImage(name, bitmap, false, stretchX, stretchY, content);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an image to be used in the map's style
|
||||
*
|
||||
@@ -343,6 +379,25 @@ public class Style {
|
||||
nativeMap.addImages(new Image[] {toImage(new Builder.ImageWrapper(name, bitmap, sdf))});
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an image to be used in the map's style
|
||||
*
|
||||
* @param name the name of the image
|
||||
* @param bitmap the pre-multiplied Bitmap
|
||||
* @param sdf the flag indicating image is an SDF or template image
|
||||
* @param stretchX image stretch areas for x axix
|
||||
* @param stretchY image stretch areas for y axix
|
||||
* @param content image content for text to fit
|
||||
*/
|
||||
public void addImage(@NonNull final String name, @NonNull Bitmap bitmap, boolean sdf,
|
||||
@NonNull List<ImageStretches> stretchX,
|
||||
@NonNull List<ImageStretches> stretchY,
|
||||
@Nullable ImageContent content) {
|
||||
validateState("addImage");
|
||||
nativeMap.addImages(new Image[] {
|
||||
toImage(new Builder.ImageWrapper(name, bitmap, sdf, stretchX, stretchY, content))});
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an image asynchronously, to be used in the map's style.
|
||||
*
|
||||
@@ -353,6 +408,22 @@ public class Style {
|
||||
addImageAsync(name, image, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an image asynchronously, to be used in the map's style.
|
||||
*
|
||||
* @param name the name of the image
|
||||
* @param image the pre-multiplied Bitmap
|
||||
* @param stretchX image stretch areas for x axix
|
||||
* @param stretchY image stretch areas for y axix
|
||||
* @param content image content for text to fit
|
||||
*/
|
||||
public void addImageAsync(@NonNull String name, @NonNull Bitmap image,
|
||||
@NonNull List<ImageStretches> stretchX,
|
||||
@NonNull List<ImageStretches> stretchY,
|
||||
@Nullable ImageContent content) {
|
||||
addImageAsync(name, image, false, stretchX, stretchY, content);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an drawable asynchronously, to be converted into a bitmap to be used in the map's style.
|
||||
*
|
||||
@@ -367,6 +438,27 @@ public class Style {
|
||||
addImageAsync(name, bitmap, false);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adds an drawable asynchronously, to be converted into a bitmap to be used in the map's style.
|
||||
*
|
||||
* @param name the name of the image
|
||||
* @param drawable the drawable instance to convert
|
||||
* @param stretchX image stretch areas for x axix
|
||||
* @param stretchY image stretch areas for y axix
|
||||
* @param content image content for text to fit
|
||||
*/
|
||||
public void addImageAsync(@NonNull String name, @NonNull Drawable drawable,
|
||||
@NonNull List<ImageStretches> stretchX,
|
||||
@NonNull List<ImageStretches> stretchY,
|
||||
@Nullable ImageContent content) {
|
||||
Bitmap bitmap = BitmapUtils.getBitmapFromDrawable(drawable);
|
||||
if (bitmap == null) {
|
||||
throw new IllegalArgumentException("Provided drawable couldn't be converted to a Bitmap.");
|
||||
}
|
||||
addImageAsync(name, bitmap, false, stretchX, stretchY, content);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an image asynchronously, to be used in the map's style.
|
||||
*
|
||||
@@ -379,6 +471,25 @@ public class Style {
|
||||
new BitmapImageConversionTask(nativeMap).execute(new Builder.ImageWrapper(name, bitmap, sdf));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an image asynchronously, to be used in the map's style.
|
||||
*
|
||||
* @param name the name of the image
|
||||
* @param bitmap the pre-multiplied Bitmap
|
||||
* @param sdf the flag indicating image is an SDF or template image
|
||||
* @param stretchX image stretch areas for x axix
|
||||
* @param stretchY image stretch areas for y axix
|
||||
* @param content image content for text to fit
|
||||
*/
|
||||
public void addImageAsync(@NonNull final String name, @NonNull Bitmap bitmap, boolean sdf,
|
||||
@NonNull List<ImageStretches> stretchX,
|
||||
@NonNull List<ImageStretches> stretchY,
|
||||
@Nullable ImageContent content) {
|
||||
validateState("addImage");
|
||||
new BitmapImageConversionTask(nativeMap)
|
||||
.execute(new Builder.ImageWrapper(name, bitmap, sdf, stretchX, stretchY, content));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds images to be used in the map's style.
|
||||
*
|
||||
@@ -388,6 +499,19 @@ public class Style {
|
||||
addImages(images, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds images to be used in the map's style.
|
||||
*
|
||||
* @param images the map of images to add
|
||||
* @param stretchX image stretch areas for x axix
|
||||
* @param stretchY image stretch areas for y axix
|
||||
* @param content image content for text to fit
|
||||
*/
|
||||
public void addImages(@NonNull HashMap<String, Bitmap> images, @NonNull List<ImageStretches> stretchX,
|
||||
@NonNull List<ImageStretches> stretchY, @Nullable ImageContent content) {
|
||||
addImages(images, false, stretchX, stretchY, content);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds images to be used in the map's style.
|
||||
*
|
||||
@@ -406,6 +530,31 @@ public class Style {
|
||||
nativeMap.addImages(convertedImages);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds images to be used in the map's style.
|
||||
*
|
||||
* @param images the map of images to add
|
||||
* @param sdf the flag indicating image is an SDF or template image
|
||||
* @param stretchX image stretch areas for x axix
|
||||
* @param stretchY image stretch areas for y axix
|
||||
* @param content image content for text to fit
|
||||
*/
|
||||
public void addImages(@NonNull HashMap<String, Bitmap> images, boolean sdf,
|
||||
@NonNull List<ImageStretches> stretchX,
|
||||
@NonNull List<ImageStretches> stretchY,
|
||||
@Nullable ImageContent content) {
|
||||
validateState("addImage");
|
||||
Image[] convertedImages = new Image[images.size()];
|
||||
int index = 0;
|
||||
for (Builder.ImageWrapper imageWrapper
|
||||
: Builder.ImageWrapper.convertToImageArray(images, sdf, stretchX, stretchY, content)) {
|
||||
convertedImages[index] = toImage(imageWrapper);
|
||||
index++;
|
||||
}
|
||||
|
||||
nativeMap.addImages(convertedImages);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds images asynchronously, to be used in the map's style.
|
||||
*
|
||||
@@ -415,6 +564,19 @@ public class Style {
|
||||
addImagesAsync(images, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds images asynchronously, to be used in the map's style.
|
||||
*
|
||||
* @param images the map of images to add
|
||||
* @param stretchX image stretch areas for x axix
|
||||
* @param stretchY image stretch areas for y axix
|
||||
* @param content image content for text to fit
|
||||
*/
|
||||
public void addImagesAsync(@NonNull HashMap<String, Bitmap> images, @NonNull List<ImageStretches> stretchX,
|
||||
@NonNull List<ImageStretches> stretchY, @Nullable ImageContent content) {
|
||||
addImagesAsync(images, false, stretchX, stretchY, content);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds images asynchronously, to be used in the map's style.
|
||||
*
|
||||
@@ -426,6 +588,24 @@ public class Style {
|
||||
new BitmapImageConversionTask(nativeMap).execute(Builder.ImageWrapper.convertToImageArray(images, sdf));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds images asynchronously, to be used in the map's style.
|
||||
*
|
||||
* @param images the map of images to add
|
||||
* @param sdf the flag indicating image is an SDF or template image
|
||||
* @param stretchX image stretch areas for x axix
|
||||
* @param stretchY image stretch areas for y axix
|
||||
* @param content image content for text to fit
|
||||
*/
|
||||
public void addImagesAsync(@NonNull HashMap<String, Bitmap> images, boolean sdf,
|
||||
@NonNull List<ImageStretches> stretchX,
|
||||
@NonNull List<ImageStretches> stretchY,
|
||||
@Nullable ImageContent content) {
|
||||
validateState("addImages");
|
||||
new BitmapImageConversionTask(nativeMap)
|
||||
.execute(Builder.ImageWrapper.convertToImageArray(images, sdf, stretchX, stretchY, content));
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes an image from the map's style.
|
||||
*
|
||||
@@ -830,6 +1010,26 @@ public class Style {
|
||||
return this.withImage(id, bitmap, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Will add the drawable as image when the map style has loaded.
|
||||
*
|
||||
* @param id the id for the image
|
||||
* @param drawable the drawable to be converted and added
|
||||
* @param stretchX image stretch areas for x axix
|
||||
* @param stretchY image stretch areas for y axix
|
||||
* @param content image content for text to fit
|
||||
* @return this
|
||||
*/
|
||||
@NonNull
|
||||
public Builder withImage(@NonNull String id, @NonNull Drawable drawable, @NonNull List<ImageStretches> stretchX,
|
||||
@NonNull List<ImageStretches> stretchY, @Nullable ImageContent content) {
|
||||
Bitmap bitmap = BitmapUtils.getBitmapFromDrawable(drawable);
|
||||
if (bitmap == null) {
|
||||
throw new IllegalArgumentException("Provided drawable couldn't be converted to a Bitmap.");
|
||||
}
|
||||
return this.withImage(id, bitmap, false, stretchX, stretchY, content);
|
||||
}
|
||||
|
||||
/**
|
||||
* Will add the drawables as images when the map style has loaded.
|
||||
*
|
||||
@@ -853,6 +1053,22 @@ public class Style {
|
||||
return this.withImage(id, image, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Will add the image when the map style has loaded.
|
||||
*
|
||||
* @param id the id for the image
|
||||
* @param image the image to be added
|
||||
* @param stretchX image stretch areas for x axix
|
||||
* @param stretchY image stretch areas for y axix
|
||||
* @param content image content for text to fit
|
||||
* @return this
|
||||
*/
|
||||
@NonNull
|
||||
public Builder withImage(@NonNull String id, @NonNull Bitmap image, @NonNull List<ImageStretches> stretchX,
|
||||
@NonNull List<ImageStretches> stretchY, @Nullable ImageContent content) {
|
||||
return this.withImage(id, image, false, stretchX, stretchY, content);
|
||||
}
|
||||
|
||||
/**
|
||||
* Will add the images when the map style has loaded.
|
||||
*
|
||||
@@ -884,6 +1100,29 @@ public class Style {
|
||||
return this.withImage(id, bitmap, sdf);
|
||||
}
|
||||
|
||||
/**
|
||||
* Will add the drawable as image when the map style has loaded.
|
||||
*
|
||||
* @param id the id for the image
|
||||
* @param drawable the drawable to be converted and added
|
||||
* @param sdf the flag indicating image is an SDF or template image
|
||||
* @param stretchX image stretch areas for x axix
|
||||
* @param stretchY image stretch areas for y axix
|
||||
* @param content image content for text to fit
|
||||
* @return this
|
||||
*/
|
||||
@NonNull
|
||||
public Builder withImage(@NonNull String id, @NonNull Drawable drawable, boolean sdf,
|
||||
@NonNull List<ImageStretches> stretchX,
|
||||
@NonNull List<ImageStretches> stretchY,
|
||||
@Nullable ImageContent content) {
|
||||
Bitmap bitmap = BitmapUtils.getBitmapFromDrawable(drawable);
|
||||
if (bitmap == null) {
|
||||
throw new IllegalArgumentException("Provided drawable couldn't be converted to a Bitmap.");
|
||||
}
|
||||
return this.withImage(id, bitmap, sdf, stretchX, stretchY, content);
|
||||
}
|
||||
|
||||
/**
|
||||
* Will add the drawables as images when the map style has loaded.
|
||||
*
|
||||
@@ -917,6 +1156,25 @@ public class Style {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Will add the image when the map style has loaded.
|
||||
*
|
||||
* @param id the id for the image
|
||||
* @param image the image to be added
|
||||
* @param sdf the flag indicating image is an SDF or template image
|
||||
* @param stretchX image stretch areas for x axix
|
||||
* @param stretchY image stretch areas for y axix
|
||||
* @param content image content for text to fit
|
||||
* @return this
|
||||
*/
|
||||
@NonNull
|
||||
public Builder withImage(@NonNull String id, @NonNull Bitmap image, boolean sdf,
|
||||
@NonNull List<ImageStretches> stretchX,
|
||||
@NonNull List<ImageStretches> stretchY, @Nullable ImageContent content) {
|
||||
images.add(new ImageWrapper(id, image, sdf, stretchX, stretchY, content));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Will add the images when the map style has loaded.
|
||||
*
|
||||
@@ -967,11 +1225,22 @@ public class Style {
|
||||
Bitmap bitmap;
|
||||
String id;
|
||||
boolean sdf;
|
||||
List<ImageStretches> stretchX;
|
||||
List<ImageStretches> stretchY;
|
||||
ImageContent content;
|
||||
|
||||
public ImageWrapper(String id, Bitmap bitmap, boolean sdf) {
|
||||
this(id, bitmap, sdf, null, null, null);
|
||||
}
|
||||
|
||||
public ImageWrapper(String id, Bitmap bitmap, boolean sdf, List<ImageStretches> stretchX,
|
||||
List<ImageStretches> stretchY, ImageContent content) {
|
||||
this.id = id;
|
||||
this.bitmap = bitmap;
|
||||
this.sdf = sdf;
|
||||
this.stretchX = stretchX;
|
||||
this.stretchY = stretchY;
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
public Bitmap getBitmap() {
|
||||
@@ -986,6 +1255,18 @@ public class Style {
|
||||
return sdf;
|
||||
}
|
||||
|
||||
public List<ImageStretches> getStretchX() {
|
||||
return stretchX;
|
||||
}
|
||||
|
||||
public List<ImageStretches> getStretchY() {
|
||||
return stretchY;
|
||||
}
|
||||
|
||||
public ImageContent getContent() {
|
||||
return content;
|
||||
}
|
||||
|
||||
public static ImageWrapper[] convertToImageArray(HashMap<String, Bitmap> bitmapHashMap, boolean sdf) {
|
||||
ImageWrapper[] images = new ImageWrapper[bitmapHashMap.size()];
|
||||
List<String> keyList = new ArrayList<>(bitmapHashMap.keySet());
|
||||
@@ -995,6 +1276,19 @@ public class Style {
|
||||
}
|
||||
return images;
|
||||
}
|
||||
|
||||
public static ImageWrapper[] convertToImageArray(HashMap<String, Bitmap> bitmapHashMap, boolean sdf,
|
||||
List<ImageStretches> stretchX,
|
||||
List<ImageStretches> stretchY,
|
||||
ImageContent content) {
|
||||
ImageWrapper[] images = new ImageWrapper[bitmapHashMap.size()];
|
||||
List<String> keyList = new ArrayList<>(bitmapHashMap.keySet());
|
||||
for (int i = 0; i < bitmapHashMap.size(); i++) {
|
||||
String id = keyList.get(i);
|
||||
images[i] = new ImageWrapper(id, bitmapHashMap.get(id), sdf, stretchX, stretchY, content);
|
||||
}
|
||||
return images;
|
||||
}
|
||||
}
|
||||
|
||||
public class LayerWrapper {
|
||||
@@ -1059,6 +1353,24 @@ public class Style {
|
||||
bitmap.copyPixelsToBuffer(buffer);
|
||||
float pixelRatio = (float) bitmap.getDensity() / DisplayMetrics.DENSITY_DEFAULT;
|
||||
|
||||
if (imageWrapper.getStretchX() != null && imageWrapper.getStretchY() != null) {
|
||||
float[] arrayX = new float[imageWrapper.getStretchX().size() * 2];
|
||||
for (int i = 0; i < imageWrapper.getStretchX().size(); i++) {
|
||||
arrayX[i * 2] = imageWrapper.getStretchX().get(i).getFirst();
|
||||
arrayX[i * 2 + 1] = imageWrapper.getStretchX().get(i).getSecond();
|
||||
}
|
||||
|
||||
float[] arrayY = new float[imageWrapper.getStretchY().size() * 2];
|
||||
for (int i = 0; i < imageWrapper.getStretchY().size(); i++) {
|
||||
arrayY[i * 2] = imageWrapper.getStretchY().get(i).getFirst();
|
||||
arrayY[i * 2 + 1] = imageWrapper.getStretchY().get(i).getSecond();
|
||||
}
|
||||
return new Image(buffer.array(), pixelRatio, imageWrapper.id,
|
||||
bitmap.getWidth(), bitmap.getHeight(), imageWrapper.sdf, arrayX, arrayY,
|
||||
imageWrapper.getContent() == null ? null : imageWrapper.getContent().getContentArray()
|
||||
);
|
||||
}
|
||||
|
||||
return new Image(buffer.array(), pixelRatio, imageWrapper.id,
|
||||
bitmap.getWidth(), bitmap.getHeight(), imageWrapper.sdf
|
||||
);
|
||||
|
||||
@@ -1123,6 +1123,18 @@
|
||||
android:name="android.support.PARENT_ACTIVITY"
|
||||
android:value=".activity.FeatureOverviewActivity" />
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".activity.style.StretchableImageActivity"
|
||||
android:description="@string/description_stretchable_image"
|
||||
android:exported="true"
|
||||
android:label="@string/activity_stretchable_image">
|
||||
<meta-data
|
||||
android:name="@string/category"
|
||||
android:value="@string/category_style" />
|
||||
<meta-data
|
||||
android:name="android.support.PARENT_ACTIVITY"
|
||||
android:value=".activity.FeatureOverviewActivity" />
|
||||
</activity>
|
||||
<!-- For Instrumentation tests -->
|
||||
<activity
|
||||
android:name=".activity.style.RuntimeStyleTimingTestActivity"
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
{
|
||||
"type": "FeatureCollection",
|
||||
"features": [
|
||||
{
|
||||
"type": "Feature",
|
||||
"geometry": {
|
||||
"type": "Point",
|
||||
"coordinates": [40, -30]
|
||||
},
|
||||
"properties": {
|
||||
"image-name": "popup-debug",
|
||||
"name": "Line 1\nLine 2\nLine 3"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Feature",
|
||||
"geometry": {
|
||||
"type": "Point",
|
||||
"coordinates": [40, 30]
|
||||
},
|
||||
"properties": {
|
||||
"image-name": "popup",
|
||||
"name": "Line 1\nLine 2\nLine 3"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Feature",
|
||||
"geometry": {
|
||||
"type": "Point",
|
||||
"coordinates": [-40, -30]
|
||||
},
|
||||
"properties": {
|
||||
"image-name": "popup-debug",
|
||||
"name": "One longer line"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Feature",
|
||||
"geometry": {
|
||||
"type": "Point",
|
||||
"coordinates": [-40, 30]
|
||||
},
|
||||
"properties": {
|
||||
"image-name": "popup",
|
||||
"name": "One longer line"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,198 @@
|
||||
package com.mapbox.mapboxsdk.testapp.activity.style;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.mapbox.geojson.Feature;
|
||||
import com.mapbox.geojson.FeatureCollection;
|
||||
import com.mapbox.geojson.Point;
|
||||
import com.mapbox.mapboxsdk.maps.ImageContent;
|
||||
import com.mapbox.mapboxsdk.maps.ImageStretches;
|
||||
import com.mapbox.mapboxsdk.maps.MapView;
|
||||
import com.mapbox.mapboxsdk.maps.MapboxMap;
|
||||
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
|
||||
import com.mapbox.mapboxsdk.maps.Style;
|
||||
import com.mapbox.mapboxsdk.style.layers.SymbolLayer;
|
||||
import com.mapbox.mapboxsdk.style.sources.GeoJsonSource;
|
||||
import com.mapbox.mapboxsdk.testapp.R;
|
||||
import com.mapbox.mapboxsdk.testapp.utils.GeoParseUtil;
|
||||
import com.mapbox.mapboxsdk.utils.BitmapUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import timber.log.Timber;
|
||||
|
||||
import static com.mapbox.mapboxsdk.style.expressions.Expression.get;
|
||||
import static com.mapbox.mapboxsdk.style.layers.Property.ICON_TEXT_FIT_BOTH;
|
||||
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconAllowOverlap;
|
||||
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconImage;
|
||||
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconTextFit;
|
||||
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textAllowOverlap;
|
||||
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textField;
|
||||
|
||||
/**
|
||||
* Test stretchable image as a background for text..
|
||||
*/
|
||||
public class StretchableImageActivity extends AppCompatActivity implements OnMapReadyCallback {
|
||||
private static final String NAME_POPUP = "popup";
|
||||
private static final String NAME_POPUP_DEBUG = "popup-debug";
|
||||
private static final String STRETCH_SOURCE = "STRETCH_SOURCE";
|
||||
private static final String STRETCH_LAYER = "STRETCH_LAYER";
|
||||
private static final String ORIGINAL_SOURCE = "ORIGINAL_SOURCE";
|
||||
private static final String ORIGINAL_LAYER = "ORIGINAL_LAYER";
|
||||
private MapboxMap mapboxMap;
|
||||
private MapView mapView;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_stretchable_image);
|
||||
mapView = findViewById(R.id.mapView);
|
||||
mapView.onCreate(savedInstanceState);
|
||||
mapView.getMapAsync(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMapReady(@NonNull MapboxMap mapboxMap) {
|
||||
this.mapboxMap = mapboxMap;
|
||||
mapboxMap.setStyle(Style.MAPBOX_STREETS, style -> {
|
||||
Bitmap popup = BitmapUtils.getBitmapFromDrawable(getResources().getDrawable(R.drawable.popup));
|
||||
Bitmap popupDebug = BitmapUtils.getBitmapFromDrawable(getResources().getDrawable(R.drawable.popup_debug));
|
||||
|
||||
// The two (blue) columns of pixels that can be stretched horizontally:
|
||||
// - the pixels between x: 25 and x: 55 can be stretched
|
||||
// - the pixels between x: 85 and x: 115 can be stretched.
|
||||
List<ImageStretches> stretchX = new ArrayList<>();
|
||||
stretchX.add(new ImageStretches(25, 55));
|
||||
stretchX.add(new ImageStretches(85, 115));
|
||||
|
||||
// The one (red) row of pixels that can be stretched vertically:
|
||||
// - the pixels between y: 25 and y: 100 can be stretched
|
||||
List<ImageStretches> stretchY = new ArrayList<>();
|
||||
stretchY.add(new ImageStretches(25, 100));
|
||||
|
||||
// This part of the image that can contain text ([x1, y1, x2, y2]):
|
||||
ImageContent content = new ImageContent(25, 25, 115, 100);
|
||||
|
||||
style.addImage(NAME_POPUP, popup, stretchX, stretchY, content);
|
||||
style.addImage(NAME_POPUP_DEBUG, popupDebug, stretchX, stretchY, content);
|
||||
new LoadFeatureTask(StretchableImageActivity.this).execute();
|
||||
});
|
||||
}
|
||||
|
||||
private void onFeatureLoaded(String json) {
|
||||
if (json == null) {
|
||||
Timber.e("json is null.");
|
||||
return;
|
||||
}
|
||||
|
||||
Style style = mapboxMap.getStyle();
|
||||
if (style != null) {
|
||||
FeatureCollection featureCollection = FeatureCollection.fromJson(json);
|
||||
GeoJsonSource stretchSource = new GeoJsonSource(STRETCH_SOURCE, featureCollection);
|
||||
SymbolLayer stretchLayer = new SymbolLayer(STRETCH_LAYER, STRETCH_SOURCE)
|
||||
.withProperties(
|
||||
textField(get("name")),
|
||||
iconImage(get("image-name")),
|
||||
iconAllowOverlap(true),
|
||||
textAllowOverlap(true),
|
||||
iconTextFit(ICON_TEXT_FIT_BOTH));
|
||||
|
||||
// the original, unstretched image for comparison
|
||||
Point point = Point.fromLngLat(-70, 0);
|
||||
Feature feature = Feature.fromGeometry(point);
|
||||
FeatureCollection originalCollection = FeatureCollection.fromFeature(feature);
|
||||
GeoJsonSource originalSource = new GeoJsonSource(ORIGINAL_SOURCE, originalCollection);
|
||||
SymbolLayer originalLayer = new SymbolLayer(ORIGINAL_LAYER, ORIGINAL_SOURCE);
|
||||
|
||||
style.addSource(stretchSource);
|
||||
style.addSource(originalSource);
|
||||
style.addLayer(stretchLayer);
|
||||
style.addLayer(originalLayer);
|
||||
}
|
||||
}
|
||||
|
||||
private static class LoadFeatureTask extends AsyncTask<Void, Integer, String> {
|
||||
|
||||
private WeakReference<StretchableImageActivity> activity;
|
||||
|
||||
private LoadFeatureTask(StretchableImageActivity activity) {
|
||||
this.activity = new WeakReference<>(activity);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String doInBackground(Void... params) {
|
||||
StretchableImageActivity activity = this.activity.get();
|
||||
if (activity != null) {
|
||||
String json = null;
|
||||
try {
|
||||
json = GeoParseUtil.loadStringFromAssets(activity.getApplicationContext(), "stretchable_image.geojson");
|
||||
} catch (IOException exception) {
|
||||
Timber.e(exception, "Could not read feature");
|
||||
}
|
||||
|
||||
return json;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(String json) {
|
||||
super.onPostExecute(json);
|
||||
StretchableImageActivity activity = this.activity.get();
|
||||
if (activity != null) {
|
||||
activity.onFeatureLoaded(json);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void onStart() {
|
||||
super.onStart();
|
||||
mapView.onStart();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
mapView.onResume();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
mapView.onPause();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStop() {
|
||||
super.onStop();
|
||||
mapView.onStop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
mapView.onSaveInstanceState(outState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLowMemory() {
|
||||
super.onLowMemory();
|
||||
mapView.onLowMemory();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
mapView.onDestroy();
|
||||
}
|
||||
|
||||
}
|
||||
BIN
MapboxGLAndroidSDKTestApp/src/main/res/drawable-hdpi/popup.png
Normal file
BIN
MapboxGLAndroidSDKTestApp/src/main/res/drawable-hdpi/popup.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.6 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.9 KiB |
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.mapbox.mapboxsdk.maps.MapView
|
||||
android:id="@id/mapView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:mapbox_cameraZoom="1"/>
|
||||
|
||||
</RelativeLayout>
|
||||
@@ -20,6 +20,7 @@
|
||||
<string name="description_offline">Offline Map example</string>
|
||||
<string name="description_region">Download an offline region.</string>
|
||||
<string name="description_within">Usage of the within expression on a buffered geometry</string>
|
||||
<string name="description_stretchable_image">Usage of the stretchable image as a background for text.</string>
|
||||
<string name="description_update_metadata">Update metadata example</string>
|
||||
<string name="description_offline_region_delete">Delete region example</string>
|
||||
<string name="description_change_resources_cache_path">Change resources cache path example</string>
|
||||
|
||||
@@ -90,4 +90,5 @@
|
||||
<string name="activity_physical_circle">Physical Unit Circle</string>
|
||||
<string name="activity_region">Download region</string>
|
||||
<string name="activity_within">Within expression</string>
|
||||
<string name="activity_stretchable_image">Stretchable Image</string>
|
||||
</resources>
|
||||
Reference in New Issue
Block a user