I am using an open-source web-based viewer in a Vue3 app. The image is not shown until the user clicks a "Open Image" button. It works good.
However, does anyone know why the same image is making two network requests when the "Open Image" button is clicked?
Here's is my minimal reproduction:
sandbox: https://stackblitz.com/edit/vitejs-vite-xxxk9w?file=src/App.vue
App.vue:
<script setup>
import { ref } from 'vue';
import Viewer from './components/Viewer.vue';
const show = ref(false);
</script>
<template>
<div>
<button type="button" @click="show = true">Open Image</button>
<Viewer v-if="show" />
</div>
</template>
Viewer.vue:
<template>
<div ref="osdContainer" style="width: 500px; height: 500px"></div>
</template>
<script setup>
import OpenSeadragon from 'openseadragon';
import { ref, onMounted } from 'vue';
const viewer = ref(null);
const osdContainer = ref(null);
const initViewer = () => {
console.log('init Viewer');
viewer.value = OpenSeadragon({
element: osdContainer.value,
tileSources: {
type: 'image',
url: 'https://ik.imagekit.io/pixstery/users%2F5cnu6iDlTsa5mujH2sKPsBJ8OKH2%2Fposts%2Fportrait-of-arabian-man_jjC2?alt=media&token=64fb0ae4-b0dc-4ead-b22e-292e55de1447&tr=f-auto,pr-true,q-80',
buildPyramid: false,
},
});
};
onMounted(() => {
console.log('mounting..');
initViewer();
});
</script>

OpenSeadragon thinks in tiled image pyramids, where most of the time you access the image metadata (resolution, and the like) and the actual tiles (bitmap data) separately.
Supporting actual images is the outlier in such world, and it's still handled as if image metadata and bitmap data would arrive from separate sources.
The first request you see comes from
getImageInfo()ofImageTileSource, the specialized class for supporting images:and the second request is when the bitmap data is requested in
_loadTile():this part of the code is a generic one,
TiledImage, which is common for everything. And this is a weakness of current(*) OpenSeadragon: the generic code asks for an URL, and not for tile data. So it doesn't matter that theImageTileSourceabove stores the entire image in its_imagefield (and even more (*)), the drawing code never asks for it, it wants and gets an URL, for which it issues a request.getTileUrl()ofTileImageSourceindeed provides that URL without any magics:When mentioning "magic", I can think of usage of
createObjectURL(). Then you would download the image withfetch(), ask forblob(), do thecreateObjectURL(), and use that URL for both theimage.src =line and return it ingetTileUrl().So if you have your own OpenSeadragon copy, it would become something like
and
(*) And why this probably doesn't matter:
levels[]thing in the originalgetTileUrl()(and_buildLevels()at the end of the file).ImageTileSourcealready stores the image and even an entire pyramid created from it, just it's not in use, yet.