local p = {}
local getArgs = require('Module:Arguments').getArgs
local mString = require('Module:String')
-- 辅助函数:分割字符串(使用 Module:String)
local function splitString(str, pattern, reg)
if not str or str == '' then
return {count = 0}
end
-- 使用 Module:String 的 split 函数
local result = mString.split(str, pattern, not reg) -- Module:String 的第三个参数是 no_pattern,与 reg 相反
result.count = #result
return result
end
-- 辅助函数:解析图片文件扩展名
local function getFileExtension(filename)
if not filename then return nil end
return filename:match(".+%.(%a+)$")
end
-- 主函数
function p._main(frame, args)
local output = {}
local charaList = {}
local charaOrder = {} -- 存储雪碧图中角色的顺序
-- 处理charas参数(雪碧图模式)
if args.charas then
local charaInfo = splitString(args.charas, ",")
local start = tonumber(args.start) or 1
for i = 1, charaInfo.count do
local charaData = charaInfo[i]
-- 解析页面名和显示名
local page, chara
local equalPos = string.find(charaData, "=")
if equalPos and equalPos > 0 then
page = string.sub(charaData, 1, equalPos - 1)
chara = string.sub(charaData, equalPos + 1)
else
page = charaData
chara = charaData
end
-- 计算尺寸和位置
local width = tonumber(args.width) or 1
local height = tonumber(args.height) or 1
local size = tonumber(args.size) or 0
local scale = tonumber(args.scale) or 1
local targetSize = tonumber(args.targetSize) or width
local fitWidth = tonumber(args.fitWidth) or 0
local fitHeight = tonumber(args.fitHeight) or 0
local offsetX = tonumber(args.offsetX) or 0
local offsetY = tonumber(args.offsetY) or 0
local actualScale = scale * (targetSize / width)
local imgWidth = math.floor(width * actualScale + fitWidth)
local imgHeight = math.floor(height * actualScale + fitHeight)
local xPos = math.floor((width + offsetX) * (start + i - 2) * actualScale)
local yPos = 0
if offsetY and offsetY ~= 0 and mw.title.getCurrentTitle().fullText == page then
yPos = math.floor((height + offsetY) * (start + i - 2) * actualScale)
end
-- 构建image-clip模板调用
local imageClipArgs = {
img = args.image or '',
['宽'] = math.floor(size * actualScale),
width = math.floor(size * actualScale),
wd = imgWidth,
ht = imgHeight,
x = xPos,
y = yPos,
link = page,
['img-css'] = 'vertical-align:initial;border-radius:' .. (args.radius or '0') .. ';' .. (args.imgContainerStyle or '')
}
-- 构建HTML
local itemHtml = {}
table.insert(itemHtml, '<li style="float:left; margin:0 5px; text-align:center; list-style:none; ')
table.insert(itemHtml, args.blockStyle or '')
table.insert(itemHtml, '">')
if args.class then
table.insert(itemHtml, '<div class="')
table.insert(itemHtml, args.class)
table.insert(itemHtml, '">')
end
-- 使用frame:expandTemplate调用image-clip模板
local imageClipCall = frame:expandTemplate{
title = 'image-clip',
args = imageClipArgs
}
table.insert(itemHtml, imageClipCall)
if args.class then
table.insert(itemHtml, '</div>')
end
table.insert(itemHtml, '<br />[[')
table.insert(itemHtml, page)
table.insert(itemHtml, '|')
table.insert(itemHtml, chara)
table.insert(itemHtml, ']]</li>')
local htmlString = table.concat(itemHtml)
charaList[chara] = htmlString
table.insert(charaOrder, htmlString) -- 保持雪碧图中角色的顺序
end
end
-- 处理匿名参数(顺序指定)
local orderList = {}
local i = 1
while args[i] do
local value = args[i]
i = i + 1
-- 检查是否为占位符
if value == "@space" and args[i] then
-- 处理空白占位符
local nextValue = args[i]
i = i + 1
local parts = splitString(nextValue, ",")
if parts.count >= 2 then
local imageFile = parts[1]
local pageName = parts[2]
local displayName = parts[3] or pageName
-- 构建空白占位符HTML
local itemHtml = {}
table.insert(itemHtml, '<li style="float:left; margin:0 5px; text-align:center; list-style:none; ')
table.insert(itemHtml, args.blockStyle or '')
table.insert(itemHtml, '">')
table.insert(itemHtml, '[[')
table.insert(itemHtml, pageName)
table.insert(itemHtml, '|')
if args.class then
table.insert(itemHtml, '<span class="')
table.insert(itemHtml, args.class)
table.insert(itemHtml, '">')
end
table.insert(itemHtml, '<span style="display:inline-block; width:')
table.insert(itemHtml, tonumber(args.width) or 0)
table.insert(itemHtml, 'px; height:')
table.insert(itemHtml, tonumber(args.height) or 0)
table.insert(itemHtml, 'px;">')
table.insert(itemHtml, '</span>')
if args.class then
table.insert(itemHtml, '</span>')
end
table.insert(itemHtml, ']]<br />[[')
table.insert(itemHtml, pageName)
table.insert(itemHtml, '|')
table.insert(itemHtml, displayName)
table.insert(itemHtml, ']]</li>')
table.insert(orderList, table.concat(itemHtml))
end
else
-- 检查是否为角色名(在charaList中存在)
if charaList[value] then
table.insert(orderList, charaList[value])
else
-- 尝试解析为单独图片格式
local parts = splitString(value, ",")
if parts.count >= 2 then
local imageFile = parts[1]
local pageName = parts[2]
local displayName = parts[3] or pageName
-- 检查是否为有效图片
local isValidImage = false
if imageFile ~= "@space" then
local ext = getFileExtension(imageFile)
if ext and string.find("jpg,jpeg,png,gif,svg,webp", ext:lower()) then
isValidImage = true
end
end
-- 计算尺寸
local width = tonumber(args.width) or 0
local height = tonumber(args.height) or 0
local scale = tonumber(args.scale) or 1
local targetSize = tonumber(args.targetSize) or width
local fitWidth = tonumber(args.fitWidth) or 0
local fitHeight = tonumber(args.fitHeight) or 0
local actualScale = scale * (targetSize / width)
local containerWidth = math.floor(width * actualScale + fitWidth)
local containerHeight = math.floor(height * actualScale + fitHeight)
local imgWidth = math.floor(width * actualScale + fitWidth)
-- 构建HTML
local itemHtml = {}
table.insert(itemHtml, '<li style="float:left; margin:0 5px; text-align:center; list-style:none; ')
table.insert(itemHtml, args.blockStyle or '')
table.insert(itemHtml, '">')
table.insert(itemHtml, '[[')
table.insert(itemHtml, pageName)
table.insert(itemHtml, '|')
if args.class then
table.insert(itemHtml, '<span class="')
table.insert(itemHtml, args.class)
table.insert(itemHtml, '">')
end
table.insert(itemHtml, '<span style="display:inline-block; width:')
table.insert(itemHtml, containerWidth)
table.insert(itemHtml, 'px; height:')
table.insert(itemHtml, containerHeight)
table.insert(itemHtml, 'px; ')
table.insert(itemHtml, args.imgContainerStyle or '')
table.insert(itemHtml, '">')
if isValidImage then
-- 使用filepath解析器函数获取完整文件路径
local filepath = frame:callParserFunction{
name = 'filepath',
args = {imageFile}
}
-- 使用frame:callParserFunction调用#img
local imgCall = frame:callParserFunction{
name = '#img',
args = {
filepath,
'style=width:' .. imgWidth .. 'px; float:left;'
}
}
table.insert(itemHtml, tostring(imgCall))
end
table.insert(itemHtml, '</span>')
if args.class then
table.insert(itemHtml, '</span>')
end
table.insert(itemHtml, ']]<br />[[')
table.insert(itemHtml, pageName)
table.insert(itemHtml, '|')
table.insert(itemHtml, displayName)
table.insert(itemHtml, ']]</li>')
table.insert(orderList, table.concat(itemHtml))
end
end
end
end
-- 处理add参数(额外添加的角色)
i = 1
local addList = {}
while args['add' .. i] do
local value = args['add' .. i]
i = i + 1
local parts = splitString(value, ",")
if parts.count >= 2 then
local imageFile = parts[1]
local pageName = parts[2]
local displayName = parts[3] or pageName
-- 检查是否为有效图片
local isValidImage = false
if imageFile ~= "@space" then
local ext = getFileExtension(imageFile)
if ext and string.find("jpg,jpeg,png,gif,svg,webp", ext:lower()) then
isValidImage = true
end
end
-- 计算尺寸
local width = tonumber(args.width) or 0
local height = tonumber(args.height) or 0
local scale = tonumber(args.scale) or 1
local targetSize = tonumber(args.targetSize) or width
local fitWidth = tonumber(args.fitWidth) or 0
local fitHeight = tonumber(args.fitHeight) or 0
local actualScale = scale * (targetSize / width)
local containerWidth = math.floor(width * actualScale + fitWidth)
local containerHeight = math.floor(height * actualScale + fitHeight)
local imgWidth = math.floor(width * actualScale + fitWidth)
-- 构建HTML
local itemHtml = {}
table.insert(itemHtml, '<li style="float:left; margin:0 5px; text-align:center; list-style:none; ')
table.insert(itemHtml, args.blockStyle or '')
table.insert(itemHtml, '">')
table.insert(itemHtml, '[[')
table.insert(itemHtml, pageName)
table.insert(itemHtml, '|')
if args.class then
table.insert(itemHtml, '<span class="')
table.insert(itemHtml, args.class)
table.insert(itemHtml, '">')
end
table.insert(itemHtml, '<span style="display:inline-block; width:')
table.insert(itemHtml, containerWidth)
table.insert(itemHtml, 'px; height:')
table.insert(itemHtml, containerHeight)
table.insert(itemHtml, 'px; ')
table.insert(itemHtml, args.imgContainerStyle or '')
table.insert(itemHtml, '">')
if isValidImage then
-- 使用filepath解析器函数获取完整文件路径
local filepath = frame:callParserFunction{
name = 'filepath',
args = {imageFile}
}
-- 使用frame:callParserFunction调用#img
local imgCall = frame:callParserFunction{
name = '#img',
args = {
filepath,
'style=width:' .. imgWidth .. 'px; float:left;'
}
}
table.insert(itemHtml, tostring(imgCall))
end
table.insert(itemHtml, '</span>')
if args.class then
table.insert(itemHtml, '</span>')
end
table.insert(itemHtml, ']]<br />[[')
table.insert(itemHtml, pageName)
table.insert(itemHtml, '|')
table.insert(itemHtml, displayName)
table.insert(itemHtml, ']]</li>')
table.insert(addList, table.concat(itemHtml))
end
end
-- 输出雪碧图
if #orderList > 0 then
for _, html in ipairs(orderList) do
table.insert(output, html)
end
else
-- 如果没有顺序参数,按charas顺序输出
for _, html in ipairs(charaOrder) do
table.insert(output, html)
end
end
if #addList > 0 then
-- 最后输出add参数中的角色
for _, html in ipairs(addList) do
table.insert(output, html)
end
end
return table.concat(output)
end
function p.main(frame)
local args = getArgs(frame)
return p._main(frame, args)
end
return p