Bulk conversion of embedded image tiddlers into _canonical_uri tiddlers

<$let
    tids={{{ [all[tiddlers]!is[system]!is[shadow]search:text[.png]enlist-input[]format:titlelist[]join[ ]] }}}
	imgfile="\.(jpg|png|gif)$"
	rb="]]"
	img="[img["
	imgs={{{ [<tids>get[text]split<rb>] :map[split<img>last[]] +[regexp<imgfile>format:titlelist[]join[ ]] }}}
    img-tids={{{ [enlist<imgs>] }}}
    img-tid-title={{{ [<img-tids>split[/]last[]]   }}}
>
<$button>
<$action-sendmessage $message="tm-new-tiddler" title=<<img-tid-title>>  _canonical_uri=<<img>> label=""/>
New Tiddler
</$button>

</$let>

I have many images stored in tiddlers in [img[]] format. I am trying to convert those images in [img[]] format to separate image tiddlers with _canonical_uri field. But my code is not working. Can someone help

Intuitively it looks like you miss a loop (<$list> widget) somewhere between computing your img-tids variable and trying to split each image name in img-tid-title.

Fred

I haven’t really tested this since I don’t use [img[]] constructions in any of my wikis, but perhaps it can get you started:

<$let
	imgfile="\.(jpg|png|gif)"
	rb="]]"
	img="[img["
>
<$button>New Tiddlers
<$list filter="[all[tiddlers]!is[system]!is[shadow]search:text:regexp<imgfile>]" variable="tid">
<$list filter="[<tid>get[text]split<rb>] :map[split<img>butfirst[]] +[regexp<imgfile>!is[tiddler]]" variable="imgs">
	<$action-createtiddler
		$basetitle={{{ [<imgs>split[/]last[]] }}}
		_canonical_uri=<<imgs>>
		type=`image/${ [<imgs>split[.]last[]] }$`
		label="">
	<$action-listops $field="output" $subfilter="[<createTiddler-title>]" /> 
	</$action-createtiddler>
</$list>
</$list>
</$button>
</$let>

Some notes:

  • I don’t seen any particular benefit to using the format:titlelist[]join[ ] + enlist combination here (and also note that, in your original variable definitions, you have an unnecessary enlist-input[] in tids= and would need enlist<tids> in imgs=).
  • +[regexp<imgfile>!is[tiddler]] in the second $list means that the button will only create a new image tiddler if you don’t already have a tiddler by that title. This should prevent you from overwriting/duplicating anything.
  • I used $action-createtiddler in place of <$action-sendmessage $message="tm-new-tiddler" so the newly-created tiddlers won’t be immediately added to your story river (which seemed likely to cause problems if you have more than a few!)
  • I added the type= line to programmatically add an appropriate type field based on the image file suffix. Without the correct tiddler type, _canonical_uri won’t be handled correctly.
  • I also added the <$action-listops $field="output" $subfilter="[<createTiddler-title>]" />, which adds each newly-created title to the output field of the tiddler where you use this button.
    • This will let you use, for example, <<list-links "[enlist{!!output}]">> to get a quick list of all the image tiddlers you’ve just added.
    • If you don’t need this list, you can replace
>
	<$action-listops $field="output" $subfilter="[<createTiddler-title>]" /> 
	</$action-createtiddler>

in the above code with />

1 Like

This is working. Thank you @etardiff for the solution. Always a helping hand for us. If possible, can you suggest a way to remove those [img[]] format images and replace it with transclusion of these newly created image tiddlers?

Here’s a second button — use it after you’ve created your image tiddlers, and remember to back up your wiki first! It may be rather slow if you have a lot of images since it’s checking all your image tiddlers against all tiddlers that contain an image.

<$let
	imgfile="\.(jpg|png|gif)"
	images={{{ [all[tiddlers]!is[system]] :filter[get[type]prefix[image/]] +[format:titlelist[]join[ ]] }}}
>
<$button> Convert
<$list filter="[all[tiddlers]!is[system]!is[shadow]search:text:regexp<imgfile>]">
<$list filter="[enlist<images>]" variable="image">
<$let
	old=`[img[${ [<image>get[_canonical_uri]] }$]]`
	new=`{{$(image)$}}`
>
	<$action-setfield text={{{ [{!!text}search-replace:g<old>,<new>] }}} />
</$let>
</$list>
</$list>
</$button>
</$let>
2 Likes

Thank you @etardiff
Its working as expected.

@etardiff how else are you using images in your wikis.
Transclusion of image tiddlers with _canonical_uri fields ?

No, I don’t really use _canonical_uri tiddlers, either. I tend to agree with Springer and Scott in this recent thread:

Most of my tiddlers (and nearly all the ones where I use images) are rendered through view templates, so I generally store URLs/local filepaths in fields on the associated tiddler and use constructions like <$image source={{!!field}} /> or <$list filter="[enlist{!!field}]" variable=path><$image source=<<path>> /></$list> to display them programmatically.

1 Like

These can be done with _canonical_uri field also right ?
That is also just another field, but attached to type-image/png etc…
Are you trying to avoid type-image/png like tiddlers ? Any disadvantage of using type-image/png tiddlers ?

Yes, you can also transclude image tiddlers into an $image widget — and that’s a major advantage of this approach. If I decide to change my data structure in the future, all I have to do is change the <$image source= value in my template.

But like Scott, I’d like to keep my tiddler count (and my wiki file size) as low as possible; I’d prefer not to make a separate tiddler just to hold a single field value, since that tiddler will come with its own field set full of metadata I don’t actually need. And like Springer, I endeavor to keep all the information relevant to a single tiddler in that tiddler, so the context is always obvious. I think Charlie put it very well here:

@etardiff i was testing the use of image widget instead of the transclusion of image tiddlers. But I want to list the image widgets used in a particular tiddlers for use in an template. How to construct a filter for listing these image widgets ?

Could you give me some sample code? Generally, I’d say your $image widgets should already be in a template, and if you need once-off images in a particular tiddler, use [img[...]] or transclude the image tiddler, unless you need to set attributes that only work with $image. This is also why I prefer to keep any file paths in tiddler fields rather than hardcoded in the text — that way, they’re easy to retrieve to a filter.

But if you do need to extract only the image widgets (or only their sources)? from a tiddler’s text field, you’re going to need the same general techniques I used to find [img[...]] paths:

  • split or splitregexp on a string adjacent to the content you’re looking for (e.g., <$image source= if you’re looking for a hardcoded file path)
  • use search or regexp to narrow down to just the strings that contain your target text
  • split again or use trim or removeprefix/removesuffix to remove unwanted text

Purpose for that separate template is for my cards UI
as shown in the screenshots in this post. Is it possible to step by step build and save a filter into the text field of a state tiddler using select widget - #11 by arunnbabu81

I have one or more image widgets in some of my tiddlers. I want to list those images and display them in this cards UI

Tiddler text

<$image source="tiddler_name" />


Tiddler text

<$image source="tiddler_name" />

Above is the construct of such tiddlers

Can you share a screenshot or demo wiki for a tiddler in which such templates are used to display the images along with the text. I am finding it difficult to fully understand this concept.

Here’s a quick demo of two possible templates, both using the <<currentTiddler>>'s fields:

  1. all image paths given in the images field, one path per line
  2. all image paths found in any field with the img prefix

Image fields demo.tid (983 Bytes)


(screenshot only shows the preview for the first technique)

For this use-case, with text interspersed between the images, I’d probably recommend doing something like this:

Tiddler text

<$image source={{!!img1}} />

Tiddler text

<$image source={{!!img2}} />

With field content:

img1: tiddler_name
img2: tiddler2_name

This would let you use the filter I demo’d in technique #2, above, to get just the images from a particular tiddler:

[<currentTiddler>fields[]prefix[img]] :map[<..currentTiddler>get<currentTiddler>]

Or to get the contents of all the img... fields on all your tiddlers:

[fields[]prefix[img]] :map:flat[all[tiddlers]!is[draft]get{!!title}] +[unique[]]

This should be more efficient than extracting just the image sources from amidst your other text.

But if you need to keep the image sources in the text field (as you have them in your sample code), try this, untested:

[{!!text}split[<$image source="]butfirst[]] :map[split["]first[]]

Or to get all the images from all your text fields:

[all[tiddlers]!is[draft]search:text[<$image source="]get[text]] :map:flat[split[<$image source="]butfirst[]] :map:flat[split["]first[]]

You can of course replace all[tiddlers] with whatever subset of tiddlers you want to search. If you have a lot of tiddlers, this may be rather slow.

1 Like

Thank you @etardiff for sharing. I will look into it and try to incorporate these ideas into my workflow. It’s late here, I will give feedback once I have a concrete idea in the coming days.

@etardiff
I am inclined to using separate tiddlers for images. I will explain why.

  1. Most of my images are radiological images of CT or MRI. It would be useful to have a description for such images in a separate field (may be called label ) so that I can display the description along with the images when they are used in other tiddlers with the help of a custom image widget.
  2. Also I plan to add some keywords to each images in another field may be called keywords so that I can retrieve and compare images with similar keywords using a custom image widget.

So I have use with separate image tiddlers and extra fields within those image tiddlers.

But sometimes I would like to have multiple related images within a single image tiddler. Is it be possible to use multiple image urls or file-paths in the _canonical_uri field of a single image tiddler? If not, may be I should use a separate field called images to store urls or file path of multiple images. How to make my custom image widget display images from that field called images. Discussion regarding that custom image widget is here - How to create a custom image widget - #2 by buggyj

Do you have any tips or suggestions regarding these. Although custom widgets functionality is there is the core since 5.3.0, I hardly see any topics related to that here in the forum to learn from except for the link widget related discussion.

And I see you have good reasons for doing so! Your needs aren’t going to be the same as mine; it’s nice that TW can accommodate both of us.

No, I don’t believe it is.

I’ve noticed the same lack, but I’m afraid I haven’t done much with widget remapping myself — partly for lack of examples, partly because outside of a few specific instances in which you want to change the global behavior of a wikitext shortcut for a widget, I don’t generally see the benefit of using widgets over macros/procedures/template transclusions, which are typically more flexible and easier to type. IMO, the link widget is one of the few counterexamples; it’s easy to imagine that you might want to redefine some attributes of the link widget without having to use the longer $link form every time. But for images, I’d personally lean towards using a custom procedure (say, <<img "Image.jpg">>) in place of [img[Image.jpg]], or a transclusion template in place of a transcluded image tiddler (e.g. {{Image.jpg|i}} instead of {{Image.jpg}}.