MarkdownImageRenderer for Gemini,ChatGPT,Grok
通称:画G、英名「MIRG」
目的:Webから、Gemini,ChatGPT,GrokでマークダウンURLの画像を閲覧する
使用手順:①Tampermonkeyのプラグインを インストール
②「MIRGインストール」を押して、スクリプトインストールを行う(またはTampermonkeyで、以下のコードを保存)
③各サイトで画像が表示できるか確認してください!※Gemini,ChatGPTは癖があるのででにくいです。Studio AI用はコチラ
Tampermonkeyが良く分からない人はコチラの下部の解説を参考に
詳しくは下部へ
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 |
// ==UserScript==
// @name Markdown Image Renderer for Gemini, ChatGPT, Grok
// @namespace https://greasyfork.org/ja/scripts/556280
// @license MIT
// @version 2.0
// @description Gemini,ChatGPT,GrokのチャットでMarkdown画像を表示します。画像クリックで単一のサブウィンドウに表示(上書き)します。
// @author FoeverPWA
// @match https://gemini.google.com/app/*
// @match https://chatgpt.com/*
// @match https://grok.com/*
// @grant GM_xmlhttpRequest
// ==/UserScript==
(function () {
'use strict';
console.log("🚀 Markdown Image Renderer v1.8 (Grok対応): Script loaded.");
function fetchImageAsDataURL(url, callback) {
GM_xmlhttpRequest({
method: 'GET',
url: url,
responseType: 'blob',
onload: function (response) {
if (response.status >= 200 && response.status < 300) {
callback(response.response);
} else {
console.error(`❌ [Fetch] HTTP Error ${response.status} for: ${url}`);
callback(null);
}
},
onerror: (error) => {
console.error(`❌ [Fetch] Network Error for: ${url}`, error);
callback(null);
}
});
}
/**
* 指定された要素を、指定されたURLの画像に置き換えます。
* @param {HTMLElement} targetElement - 置き換え対象のDOM要素 (<a>タグなど)
* @param {string} imageUrl - 表示する画像のURL
*/
function replaceElementWithImage(targetElement, imageUrl) {
if (!targetElement.parentNode || targetElement.dataset.imageProcessed) return;
targetElement.dataset.imageProcessed = 'true';
const altText = imageUrl.split('/').pop().split('.')[0] || 'image';
const uniqueId = 'img-placeholder-' + Date.now() + Math.random().toString(36).substring(2);
const placeholder = document.createElement('img');
placeholder.id = uniqueId;
placeholder.alt = altText + ' (loading...)';
placeholder.style.cssText = "max-width: 100%; height: auto; border-radius: 8px; display: block; background-color:#f0f0f0; min-height: 50px; cursor: pointer;";
placeholder.addEventListener('click', () => {
window.open(imageUrl, 'imagePreviewWindow');
});
const preWrapper = document.createElement('pre');
preWrapper.setAttribute('contenteditable', 'false');
preWrapper.style.cssText = "margin: 0; padding: 0; background: transparent; border: none; font-family: inherit; white-space: pre-wrap; display: block;";
preWrapper.appendChild(placeholder);
// ReactなどのフレームワークがDOMを管理している場合、要素を完全に削除(replaceChild)すると
// "The node to be removed is not a child of this node" エラーが発生することがあります。
// そのため、元の要素は削除せずに非表示にし、その直後に画像プレビューを挿入します。
targetElement.style.display = 'none';
targetElement.parentNode.insertBefore(preWrapper, targetElement.nextSibling);
fetchImageAsDataURL(imageUrl, (blob) => {
const imgElement = document.getElementById(uniqueId);
if (imgElement) {
if (blob) {
imgElement.src = URL.createObjectURL(blob);
imgElement.alt = altText;
} else {
imgElement.alt = `[画像読み込み失敗] ${altText}`;
imgElement.style.border = "1px dashed #ccc";
imgElement.style.padding = "10px";
imgElement.style.cursor = 'default';
}
}
});
}
let debounceTimer;
const debouncedProcessor = () => {
// --- ステージ1: Gemini専用 - Google検索リンクを逆変換 ---
// Geminiは特殊なので全体から検索
document.querySelectorAll('a[href*="google.com/search?q="]').forEach(link => {
if (link.dataset.imageProcessed) return;
try {
const searchUrl = new URL(link.href);
const originalUrl = searchUrl.searchParams.get('q');
if (originalUrl && /\.(avif|webp|png|jpg|jpeg|gif|svg)$/i.test(originalUrl)) {
console.log(`✅ [Gemini] Found Google search link. Reversing to image: ${originalUrl}`);
replaceElementWithImage(link, originalUrl);
}
} catch (e) {
// URL解析エラーは無視
}
});
// ChatGPT, Grok対応のセレクター
const targetSelector = '.model-response-text, p.break-words';
document.querySelectorAll(targetSelector).forEach(container => {
// --- ステージ2: Grok形式の画像リンクを変換 ---
container.querySelectorAll('a[href][target="_blank"]').forEach(link => {
if (link.dataset.imageProcessed) return;
const href = link.href;
// 画像ファイル拡張子で判定
if (/\.(avif|webp|png|jpg|jpeg|gif|svg)$/i.test(href)) {
console.log(`✅ [Grok] Found image link. Converting to image: ${href}`);
replaceElementWithImage(link, href);
}
});
// --- ステージ3: 残っているMarkdownテキストを処理 (フォールバック) ---
const walker = document.createTreeWalker(container, NodeFilter.SHOW_TEXT);
while (walker.nextNode()) {
const node = walker.currentNode;
if (!node.parentElement || node.parentElement.closest('[data-image-processed="true"]')) continue;
// 改善された正規表現: 閉じ括弧 ')' を含まない、またはエスケープされた括弧を許容する簡易的な対応
// より厳密なパースが必要な場合はライブラリ推奨だが、UserScriptとしてはこれで十分
const markdownImageRegex = /!\[[^\]]*\]\(([^)]+)\)/;
const match = node.textContent.match(markdownImageRegex);
if (match) {
const imageUrl = match[1];
console.log(`✅ [Markdown] Found raw markdown text. Converting to image: ${imageUrl}`);
replaceElementWithImage(node.parentElement, imageUrl);
}
}
});
};
const observer = new MutationObserver(() => {
clearTimeout(debounceTimer);
debounceTimer = setTimeout(debouncedProcessor, 250);
});
console.log("👀 DOM Observer started.");
observer.observe(document.body, { childList: true, subtree: true });
})();
|
Geminiの画像出力プロンプト例
運がいいと画像がでます(動作不安定)
画像URLと宣言するとうまくいかない気がします。画像の文字列と言い換える
以下のように創作をするけど画像表示ルールを先に確定してからの方がスムーズです(面倒ならPWAでOK)
最終的に<pre>タグで囲ってというとでる事象が多い
「形式で」とか
「<pre></pre>形式で」というと出やすい
うまくいくとこんな感じ、このあと好きなプロンプトをぶち込みましょう(画像ルールの部分はなしでOK)

以下のようにホワイトリストに画像があるサイトを入れる「netlify.app」が、いれなくても許可するか判断させる画面でドメインを許可すればOK

うまくいかないばあい:対象のサイトのみの広告ブロックを止める、いろいろ試す(preタグ使ったり、外したり)
こちらのプロンプト・画像は以下の提供でお送りしました。ありがとうございます。
個人的シコキャラ置き場様
https://rentry.co/ar6e9t2n
その他のツール
AI Studioで自動音声読み上げ(VOICEVOX)が欲しい!
通称:スタ自ボ
https://rentry.co/x9fw82o3
Wikiのプロンプトまとめ等をみながら、プロンプトだけを即コピーしたい人用に作成しました
通称:即コピ
https://rentry.co/8772bcnh
Google AI Studio に直接画像を出したい!
通称:MIR(スタ画)
https://rentry.co/3bnuvgwu