モジュール:File clip
表示
このモジュールはアルファ版です。現在、挙動や仕様などをテストしています。機能の追加や変更の提案も歓迎します。 |
このモジュールはテンプレートスタイルを使用しています: |
画像やPDFファイルのトリミング表示を行います。このモジュールは{{File clip}}の実装を置き換える目的で作成されました。
現時点では{{File clip/sandbox}}が当モジュールのラッパーテンプレートになっており、Template:File clip/testcasesにて動作テストを行っています。
使い方
[編集]{{#invoke:File clip|呼び出す関数名|ファイル名|width=表示サイズ(横幅)|その他のオプション ... }}
呼び出す関数名にthumbを指定するとサムネイル形式で表示し、nothumbを指定するとフレームなしの形式で表示します。
ファイル名と表示サイズの指定は省略できません。
ファイル名を指定する際に名前空間プレフィックス(ファイル:やFile:など)を付ける必要はありません。
|width=
には表示する際の横幅をピクセル単位で指定します。指定する値は数値のみとし、単位は付けないでください。
その他のオプションには以下の指定が可能です。
|t=
,|r=
,|b=
,|l=
- それぞれ切り抜く上部分、右部分、下部分、左部分の大きさを百分率で指定します。指定する値は0以上100未満の数値のみとし、%は付けないでください。省略した場合は0を指定した場合と同じになります。|w=
,|h=
- それぞれ元のファイルの横幅・縦幅をピクセル単位で指定します。指定する値は数値のみとし、単位は付けないでください。省略した場合はScribuntoのファイルメタデータを利用して横幅・縦幅を自動的に取得しますが、これを行うと高負荷構文解析関数使用回数のカウンタが増加します。|w=
と|h=
の両方を指定することにより、これを回避することができます。|align=
- ファイルの表示位置を指定します。指定可能な値と省略時の挙動については[[ファイル:ファイル名|...]]による画像の表示と同様です。詳細についてはthumb形式の場合はHelp:画像の表示#thumbを、nothumb形式の場合はHelp:画像の表示#配置指定をご覧ください。|caption=
(あるいは|c=
) - キャプションを指定します。省略時はファイル名が使われます。|alt=
- キャプションとは別にimg要素のalt属性の値を設定する場合は指定します。空文字列を指定することもできます。|page=
- ファイル形式がDjVuやPDFの場合に、表示するページの番号を指定します。省略すると1ページ目を表示します。|link=
- 画像をクリックした際のリンクを変更することができます(空文字列も指定可能)。CC BYなど、ファイルのライセンスが帰属表示を求めている場合は、このオプションを使わないでください。詳しくはHelp:画像の表示#画像リンクをご覧ください。
使用例
[編集]コード
{{#invoke:File clip|thumb|Wikipedia Logo 1.0.png|width=200|align=left|t=0|r=25|b=70|l=35|caption=2003年から2010年まで使われていたウィキペディアのロゴの一部分}}
表示
require('strict')
local function showImage(filename, caption, options)
--[=[
画像を表示するウィキテキスト構文を生成して返す
filename: ファイル名(文字列型、必須)
caption(): 画像のキャプション(文字列型、省略可)
options: その他のオプション(テーブル型、省略可)
]=]--
if type(filename) ~= 'string' or filename == '' then
error('ファイル名が正しく指定されていません。', 2)
end
local t = { filename }
if options then
for k, v in pairs(options) do
table.insert(
t,
(type(k) == 'string') and mw.ustring.format('%s=%s', k, v) or v
)
end
end
if caption then table.insert(t, caption) end
return mw.ustring.format('[[File:%s]]', table.concat(t, '|'))
end
local function isValign(value)
for _, v in ipairs({'baseline', 'sub', 'super', 'top', 'text-top',
'middle', 'bottom', 'text-bottom'}) do
if v == value then return true end
end
return false
end
--------------------------------------------------------------------------------
-- fileClipクラス
--
-- fileClipをテーブルのメタテーブルに設定することで、
-- そのテーブルはfileClipクラスのインスタンスであるかのように振る舞う
--------------------------------------------------------------------------------
local fileClip = {}
fileClip.__index = fileClip
function fileClip:_setError(message)
self._error = mw.html.create('strong')
:addClass('error')
:wikitext('エラー:' .. message)
return self
end
function fileClip._new(args)
local obj = {}
setmetatable(obj, fileClip)
-- 配置指定
obj._align = args.align
if not args[1] then
return obj:_setError('ファイル名が指定されていません。')
end
-- 表示サイズ(横幅)
obj._width = tonumber(args.width)
if not obj._width then
obj._width = 200
return obj:_setError('表示サイズが指定されていません。')
end
-- 切り抜き範囲(百分率)
-- 指定省略時は0%
local crop_top = tonumber(args[2] or args.t) or 0
local crop_right = tonumber(args[3] or args.r) or 0
local crop_bottom = tonumber(args[4] or args.b) or 0
local crop_left = tonumber(args[5] or args.l) or 0
-- 画像の表示範囲(百分率)を計算
-- 縦方向・横方向のどちらか一方でも0%以下ならエラー
local v_rest = 100 - (crop_top + crop_bottom)
local h_rest = 100 - (crop_right + crop_left)
if v_rest <= 0 then
return (h_rest <= 0)
and obj:_setError('縦方向・横方向ともに100%以上切り取っています。')
or obj:_setError('縦方向に100%以上切り取っています。')
end
if h_rest <= 0 then
return obj:_setError('横方向に100%以上切り取っています。')
end
-- ファイルページのタイトルオブジェクト
local filepage = mw.title.new(args[1], 'ファイル')
-- ファイル名(名前空間プレフィックスを含まない)
obj._filename = filepage.text
-- 元の画像の横幅・縦幅
-- 画像の横幅・縦幅はファイルメタデータを参照すれば取得可能だが、
-- ファイルメタデータを取得する処理は高負荷である。
-- 横幅・縦幅の両方が手動で指定されている場合は、それを使用し、
-- ファイルメタデータの取得を避ける。
local orig_width, orig_height
if args.w and args.h then
orig_width = tonumber(args.w)
orig_height = tonumber(args.h)
else
local filemetadata = filepage.file -- 高負荷
if not filemetadata.exists then
return obj:_setError(
mw.ustring.format('[[:File:%s]]は存在しません。', obj._filename)
)
end
if string.find(filemetadata.mimeType, 'image/', 1, true) ~= 1
and filemetadata.mimeType ~= 'application/pdf' then
return obj:_setError(
mw.ustring.format(
'[[:File:%s]]([[MIMEタイプ]]: %s)は切り抜き表示に対応していません。',
obj._filename,
filemetadata.mimeType
)
)
end
local page = tonumber(args.page)
if page and page > 1 and filemetadata.pages then
filemetadata = filemetadata.pages[page]
end
orig_width = filemetadata.width
orig_height = filemetadata.height
end
-- 切り抜き画像の表示サイズ(縦幅)を計算
obj._height = math.floor(
(obj._width * orig_height * v_rest) /
(orig_width * h_rest)
)
-- 画像を拡大後、上方向および左方向に何pxずらせばよいか計算
obj._shift_up = math.floor(
(obj._width * orig_height * crop_top) /
(orig_width * h_rest)
)
obj._shift_left = math.floor((obj._width * crop_left) / h_rest)
-- 画像のキャプション
-- 指定省略時は指定されたファイル名(名前空間プレフィックスを含まない)
obj._caption = args[6] or args.c or args.caption or obj._filename
-- 拡大後の画像の横幅、その他のオプション
obj._image_options = {
math.floor((obj._width * 100) / h_rest) .. 'px',
alt = args.alt,
link = args.link,
page = args.page,
class = args.class,
lang = args.lang
}
return obj
end
function fileClip:thumb()
local center = mw.html.create('div'):addClass('center')
local thumb = mw.html.create('div')
if self._align == 'center' or self._align == 'none' then
thumb:addClass('thumb fileclip-thumb tnone')
elseif self._align == 'left' then
thumb:addClass('thumb fileclip-thumb tleft')
else
thumb:addClass('thumb fileclip-thumb tright')
end
local thumbinner = mw.html.create('div')
:addClass('thumbinner fileclip-thumbinner')
:css('width', (self._width + 2) .. 'px')
if self._error then
thumb:node(thumbinner:node(self._error))
return (self._align == 'center') and center:node(thumb) or thumb
end
local clipper = mw.html.create('div')
:addClass('fileclip-clipper thumbimage')
:css({ width = self._width .. 'px', height = self._height .. 'px' })
:cssText('position: relative; overflow: hidden;')
local shifting = mw.html.create('div')
:addClass('fileclip-shifting')
:css({ top = -self._shift_up .. 'px', left = -self._shift_left .. 'px' })
:cssText('position: absolute;')
:wikitext(showImage(self._filename, nil, self._image_options))
clipper:node(shifting)
local thumbcaption = mw.html.create('div'):addClass('thumbcaption')
local magnify = mw.html.create('div')
:addClass('magnify fileclip-magnify')
:wikitext(
showImage(
'Scissors icon black.svg',
'拡大',
{ 'text-top|16px', link = 'File:' .. self._filename }
)
)
thumbcaption:node(magnify):wikitext(self._caption)
thumb:node(thumbinner:node(clipper):node(thumbcaption))
return (self._align == 'center') and center:node(thumb) or thumb
end
function fileClip:nothumb()
if self._error then return self._error end
local center = mw.html.create('div'):addClass('center')
local aligndiv
local clipper = mw.html.create('span')
:addClass('fileclip-clipper')
:css({ width = (self._width .. 'px'), height = (self._height .. 'px') })
:cssText('position: relative; overflow: hidden; display: inline-block;')
if self._align == 'center' or self._align == 'none' then
aligndiv = mw.html.create('div'):addClass('floatnone')
elseif self._align == 'right' or self._align == 'left' then
aligndiv = mw.html.create('div'):addClass('float' .. self._align)
elseif self._align and isValign(self._align) then
clipper:css({ ['vertical-align'] = self._align })
else
clipper:css('vertical-align', 'middle')
end
local shifting = mw.html.create('span')
:addClass('fileclip-shifting')
:css({ top = -self._shift_up .. 'px', left = -self._shift_left .. 'px' })
:cssText('position: absolute;')
:wikitext(showImage(self._filename, self._caption, self._image_options))
clipper:node(shifting)
if not aligndiv then return clipper end
aligndiv:node(clipper)
return (self._align == 'center') and center:node(aligndiv) or aligndiv
end
local getArgs
local function _main(mode, frame)
if not getArgs then getArgs = require('モジュール:Arguments').getArgs end
local args = getArgs(frame, {
valueFunc = function (key, value)
-- alt引数とlink引数については、省略した場合と
-- 空文字列を指定した場合を区別する
if value then
value = mw.text.trim(value)
end
if value == '' and key ~= 'alt' and key ~= 'link' then
return nil
end
return value
end,
wrappers = { 'Template:File clip', 'Template:File clip2' }
})
local thumb = fileClip._new(args)
thumb._export = thumb[mode]
return frame:extensionTag{
name = 'templatestyles',
args = { src = 'File clip/styles.css' }
}
.. tostring(thumb:_export())
.. '[[Category:切り抜き画像]]'
end
local p = {
thumb = function(frame) return _main('thumb', frame) end,
nothumb = function(frame) return _main('nothumb', frame) end
}
return p