diff --git a/app/src/main/java/io/noties/markwon/app/MarkdownRenderer.java b/app/src/main/java/io/noties/markwon/app/MarkdownRenderer.java index 9bcb8e0f..67585f85 100644 --- a/app/src/main/java/io/noties/markwon/app/MarkdownRenderer.java +++ b/app/src/main/java/io/noties/markwon/app/MarkdownRenderer.java @@ -1,6 +1,7 @@ package io.noties.markwon.app; import android.content.Context; +import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Handler; import android.os.SystemClock; @@ -9,6 +10,8 @@ import android.text.Spanned; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import java.io.InputStream; +import java.util.Collection; import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; @@ -23,7 +26,10 @@ import io.noties.markwon.ext.strikethrough.StrikethroughPlugin; import io.noties.markwon.ext.tables.TablePlugin; import io.noties.markwon.ext.tasklist.TaskListPlugin; import io.noties.markwon.html.HtmlPlugin; +import io.noties.markwon.image.ImageItem; import io.noties.markwon.image.ImagesPlugin; +import io.noties.markwon.image.MediaDecoder; +import io.noties.markwon.image.SchemeHandler; import io.noties.markwon.image.file.FileSchemeHandler; import io.noties.markwon.image.network.OkHttpNetworkSchemeHandler; import io.noties.markwon.syntax.Prism4jTheme; @@ -120,6 +126,29 @@ public class MarkdownRenderer { builder.urlProcessor(urlProcessor); } }) + .usePlugin(new AbstractMarkwonPlugin() { + @Override + public void configure(@NonNull Registry registry) { + registry.require(ImagesPlugin.class, new Action() { + @Override + public void apply(@NonNull ImagesPlugin imagesPlugin) { + imagesPlugin.addMediaDecoder(new MediaDecoder() { + @NonNull + @Override + public Drawable decode(@Nullable String contentType, @NonNull InputStream inputStream) { + return null; + } + + @NonNull + @Override + public Collection supportedTypes() { + return null; + } + }); + } + }); + } + }) .build(); final long start = SystemClock.uptimeMillis(); diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js index eaa57168..27a4dd6b 100644 --- a/docs/.vuepress/config.js +++ b/docs/.vuepress/config.js @@ -62,6 +62,7 @@ module.exports = { '/docs/v4/image/', '/docs/v4/image-glide/', '/docs/v4/image-picasso/', + '/docs/v4/linkify/', '/docs/v4/recycler/', '/docs/v4/recycler-table/', '/docs/v4/syntax-highlight/', diff --git a/docs/docs/v4/core/core-plugin.md b/docs/docs/v4/core/core-plugin.md index 750e3c59..a5002ba8 100644 --- a/docs/docs/v4/core/core-plugin.md +++ b/docs/docs/v4/core/core-plugin.md @@ -108,7 +108,7 @@ which accepts a MovementMethod as an argument. ## OnTextAddedListener Since `4.0.0` `CorePlugin` provides ability to receive text-added event. This can -be useful in order to process raw text (for example to [linkify](/docs/v4/linkify.md) it): +be useful in order to process raw text (for example to [linkify](/docs/v4/linkify/) it): ```java final Markwon markwon = Markwon.builder(context) diff --git a/docs/docs/v4/image/README.md b/docs/docs/v4/image/README.md index 8731af05..b618f999 100644 --- a/docs/docs/v4/image/README.md +++ b/docs/docs/v4/image/README.md @@ -66,7 +66,7 @@ FileSchemeHandler.createWithAssets(context); ``` :::warning -Assets loading will work when your URL will include `android_asset` the the path, +Assets loading will work when your URL will include `android_asset` in the path, for example: `file:///android_asset/image.png` (mind the 3 slashes `///`). If you wish to _assume_ all images without proper scheme to point to assets folder, then you can use [UrlProcessorAndroidAssets](/docs/v4/core/configuration.html#urlprocessorandroidassets) @@ -136,8 +136,9 @@ final Markwon markwon = Markwon.builder(context) @Override public ImageItem handle(@NonNull String raw, @NonNull Uri uri) { + // will handle URLs like `drawable://ic_account_24dp_white` final int resourceId = context.getResources().getIdentifier( - raw.substring("resources://".length()), + raw.substring("drawable://".length()), "drawable", context.getPackageName()); @@ -146,20 +147,66 @@ final Markwon markwon = Markwon.builder(context) // it's important to apply bounds to resulting drawable DrawableUtils.applyIntrinsicBounds(drawable); - + return ImageItem.withResult(drawable); } @NonNull @Override public Collection supportedSchemes() { - return Collections.singleton("resources"); + return Collections.singleton("drawable"); } }); } })) ``` +Otherwise `SchemeHandler` must return an `InputStream` with proper `content-type` information +for further processing by a `MediaDecoder`: + +```java +imagesPlugin.addSchemeHandler(new SchemeHandler() { + @NonNull + @Override + public ImageItem handle(@NonNull String raw, @NonNull Uri uri) { + return ImageItem.withDecodingNeeded("image/png", load(raw)); + } + + @NonNull + private InputStream load(@NonNull String raw) {...} +}); +``` + +## MediaDecoder + +`ImagesPlugin` comes with predefined media-decoders: +* `GifMediaDecoder` adds support for GIF +* `SvgMediaDecoder` adds support for SVG +* `DefaultMediaDecoder` + +:::warning +If you wish to add support for **SVG** or **GIF** you must explicitly add these dependencies +to your project: +* for `SVG`: `com.caverock:androidsvg:1.4` +* for `GIF`: `pl.droidsonroids.gif:android-gif-drawable:1.2.14` + +You can try more recent versions of these libraries, but make sure that they doesn't +introduce any unexpected behavior. +::: + + +### GifMediaDecoder + +### SvgMediaDecoder + +### DefaultMediaDecoder + +## AsyncDrawableScheduler + +## ErrorHandler + +## Placeholder + :::tip If you are using [html](/docs/v4/html/) you do not have to additionally setup images displayed via `` tag, as `HtmlPlugin` automatically uses configured diff --git a/docs/docs/v4/linkify/README.md b/docs/docs/v4/linkify/README.md new file mode 100644 index 00000000..10a96b98 --- /dev/null +++ b/docs/docs/v4/linkify/README.md @@ -0,0 +1,3 @@ +# Linkify + + \ No newline at end of file diff --git a/markwon-image/src/main/java/io/noties/markwon/image/AsyncDrawableLoaderBuilder.java b/markwon-image/src/main/java/io/noties/markwon/image/AsyncDrawableLoaderBuilder.java index 704ebffb..24ce355a 100644 --- a/markwon-image/src/main/java/io/noties/markwon/image/AsyncDrawableLoaderBuilder.java +++ b/markwon-image/src/main/java/io/noties/markwon/image/AsyncDrawableLoaderBuilder.java @@ -43,7 +43,7 @@ class AsyncDrawableLoaderBuilder { addMediaDecoder(GifMediaDecoder.create()); } - defaultMediaDecoder = DefaultImageMediaDecoder.create(); + defaultMediaDecoder = DefaultMediaDecoder.create(); } void executorService(@NonNull ExecutorService executorService) { diff --git a/markwon-image/src/main/java/io/noties/markwon/image/AsyncDrawableLoaderImpl.java b/markwon-image/src/main/java/io/noties/markwon/image/AsyncDrawableLoaderImpl.java index 4428177c..52afc7a3 100644 --- a/markwon-image/src/main/java/io/noties/markwon/image/AsyncDrawableLoaderImpl.java +++ b/markwon-image/src/main/java/io/noties/markwon/image/AsyncDrawableLoaderImpl.java @@ -77,7 +77,7 @@ class AsyncDrawableLoaderImpl extends AsyncDrawableLoader { @NonNull private Future execute(@NonNull final AsyncDrawable asyncDrawable) { - // todo: more efficient DefaultImageMediaDecoder... BitmapFactory.decodeStream is a bit not optimal + // todo: more efficient DefaultMediaDecoder... BitmapFactory.decodeStream is a bit not optimal // for big images for sure. We _could_ introduce internal Drawable that will check for // image bounds (but we will need to cache inputStream in order to inspect and optimize // input image...) diff --git a/markwon-image/src/main/java/io/noties/markwon/image/DefaultImageMediaDecoder.java b/markwon-image/src/main/java/io/noties/markwon/image/DefaultMediaDecoder.java similarity index 79% rename from markwon-image/src/main/java/io/noties/markwon/image/DefaultImageMediaDecoder.java rename to markwon-image/src/main/java/io/noties/markwon/image/DefaultMediaDecoder.java index e820ff45..bdf81e05 100644 --- a/markwon-image/src/main/java/io/noties/markwon/image/DefaultImageMediaDecoder.java +++ b/markwon-image/src/main/java/io/noties/markwon/image/DefaultMediaDecoder.java @@ -19,22 +19,22 @@ import java.util.Collections; * * @since 1.1.0 */ -public class DefaultImageMediaDecoder extends MediaDecoder { +public class DefaultMediaDecoder extends MediaDecoder { @NonNull - public static DefaultImageMediaDecoder create() { - return new DefaultImageMediaDecoder(Resources.getSystem()); + public static DefaultMediaDecoder create() { + return new DefaultMediaDecoder(Resources.getSystem()); } @NonNull - public static DefaultImageMediaDecoder create(@NonNull Resources resources) { - return new DefaultImageMediaDecoder(resources); + public static DefaultMediaDecoder create(@NonNull Resources resources) { + return new DefaultMediaDecoder(resources); } private final Resources resources; @SuppressWarnings("WeakerAccess") - DefaultImageMediaDecoder(Resources resources) { + DefaultMediaDecoder(Resources resources) { this.resources = resources; } diff --git a/markwon-image/src/main/java/io/noties/markwon/image/ImagesPlugin.java b/markwon-image/src/main/java/io/noties/markwon/image/ImagesPlugin.java index 8c02695e..d93ca23d 100644 --- a/markwon-image/src/main/java/io/noties/markwon/image/ImagesPlugin.java +++ b/markwon-image/src/main/java/io/noties/markwon/image/ImagesPlugin.java @@ -111,7 +111,7 @@ public class ImagesPlugin extends AbstractMarkwonPlugin { } /** - * @see DefaultImageMediaDecoder + * @see DefaultMediaDecoder * @see SvgMediaDecoder * @see GifMediaDecoder * @since 4.0.0-SNAPSHOT @@ -123,10 +123,10 @@ public class ImagesPlugin extends AbstractMarkwonPlugin { } /** - * Please note that if not specified a {@link DefaultImageMediaDecoder} will be used. So + * Please note that if not specified a {@link DefaultMediaDecoder} will be used. So * if you need to disable default-image-media-decoder specify here own no-op implementation or null. * - * @see DefaultImageMediaDecoder + * @see DefaultMediaDecoder * @since 4.0.0-SNAPSHOT */ @NonNull