mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-03-07 12:21:52 +09:00
btex: img tag with src attrib
This commit is contained in:
@@ -162,18 +162,19 @@
|
||||
|
||||
<section>Figures</section>
|
||||
|
||||
<p>Figures, or external images can be inserted using the self-closing <code>img</code> tag.
|
||||
This tag inserts the image starting from the current line; if the size is taller than the
|
||||
remaining lines, the image will be printed onto the next page. Its syntax is as follows:</p>
|
||||
<p><index id="img (tag)"/>Figures, or external images can be inserted using the self-closing <code>img</code> tag.
|
||||
This tag inserts the image at the centre of the page, starting from the current line;
|
||||
if the size is taller than the remaining lines, the image will be printed onto the next page.
|
||||
Its syntax is as follows:</p>
|
||||
|
||||
<callout align="left" class="code"><!--
|
||||
--><img src="web URL" height="8"/><br/><!--
|
||||
--><img src="http(s) or file URL" height="8"/><br/><!--
|
||||
--><img fromgame="basegame:gui/small.png" height="4"/><br/><!--
|
||||
--><img gameitem="basegame:33" height="1"/>
|
||||
</callout>
|
||||
|
||||
<p>The <code>height</code> attribute specifies the height of the image <emph>in the number of lines</emph>,
|
||||
rather than pixels.</p>
|
||||
rather than pixels, the width is calculated automatically. Image width wider than the text width will cause an error.</p>
|
||||
|
||||
<p>Supported image formats: JPEG, PNG, BMP or TGA</p>
|
||||
|
||||
@@ -295,6 +296,22 @@
|
||||
|
||||
|
||||
|
||||
<part>Non-laymen Zone</part>
|
||||
|
||||
<chapter alt="The Waiting Process">Why Wait for the Books to be Printed? Why Can’t I just Print Them by Myself?</chapter>
|
||||
|
||||
<p>The <btex/> engine is not fast; it takes at least a few seconds to print a book. The “waiting”
|
||||
system is there because the book is being printed in the background on separate threads
|
||||
(yes, they are multi-threaded!) to not interfere with the normal gameplay, or else the players will
|
||||
encounter the freezing every time the book is being printed, and this would be a huge minus towards
|
||||
the gameplay experience. If the process exits without any error, the mailing system will be
|
||||
notified and will send the mail containing finished books to the player; if the process exits
|
||||
with errors, the mail containing details of the errors will be sent instead.</p>
|
||||
|
||||
<p>For this reason the “printing press” is not exposed to the player, they only get to interact with it
|
||||
indirectly through the “publisher” via mail.</p>
|
||||
|
||||
|
||||
|
||||
|
||||
<newpage/>
|
||||
|
||||
@@ -48,11 +48,11 @@
|
||||
<p><index id="btex 언어"/><btex/>(발음: [비ː텍])은 <latex/>과 유사하게 설계된 XML 기반의 마크업 언어이다.
|
||||
<btex/>은 세세한 스타일 정의문과 조판 설정을 추상화하여, 글을 쓰면서 <latex/> 매크로를 디버깅하는 등의 일 없이 글쓰기에 집중할 수 있도록 설계되었다. 다만 이러한 이유로 미리 정의된 스타일을 뜯어고치는 것은 어렵다.</p>
|
||||
<p><btex/> 문서는 다음의 다섯 부분으로 나뉘어진다: <!--
|
||||
--><a href="btexdoc">스타일 정의문</a>·<!--
|
||||
--><a href="표지 정의문">표지 정의문</a>·<!--
|
||||
--><a href="목차 정의문">목차 정의문</a>·<!--
|
||||
--><a href="원고">원고</a>·<!--
|
||||
--><a href="색인 페이지">색인 페이지</a>.
|
||||
--><a href="btexdoc">스타일 정의문</a>·<!--
|
||||
--><a href="표지 정의문">표지 정의문</a>·<!--
|
||||
--><a href="목차 정의문">목차 정의문</a>·<!--
|
||||
--><a href="원고">원고</a>·<!--
|
||||
--><a href="색인 페이지">색인 페이지</a>.
|
||||
이 중 스타일 정의문과 원고는 필수로 존재하여야 하는 부분이다.</p>
|
||||
|
||||
|
||||
@@ -61,9 +61,9 @@
|
||||
<p><index id="btexdoc"/>스타일 정의문은 <btex/> 문서의 가장 첫 부분이다. 스타일 정의문의 구조는 다음과 같다.</p>
|
||||
|
||||
<callout align="left" class="code"><index id="btexdoc (tag)"/><!--
|
||||
--><?xml version="1.0" encoding="UTF-8"?><br/><!--
|
||||
--><!DOCTYPE btexdoc SYSTEM "btexdoc.dtd"><br/><!--
|
||||
--><btexdoc cover="hardcover" inner="standard" papersize="standard">
|
||||
--><?xml version="1.0" encoding="UTF-8"?><br/><!--
|
||||
--><!DOCTYPE btexdoc SYSTEM "btexdoc.dtd"><br/><!--
|
||||
--><btexdoc cover="hardcover" inner="standard" papersize="standard">
|
||||
</callout>
|
||||
|
||||
<p><code>btexdoc</code> 태그는 다음의 속성을 지원한다.</p>
|
||||
@@ -77,10 +77,10 @@
|
||||
|
||||
<p><index id="표지 정의문"/><code>cover</code> 태그는 책의 표지를 지정한다. 표지가 없는 책이라면 이 부분은 생략 가능하다. 표지 정의문의 구조는 다음과 같다.</p>
|
||||
<callout align="left" class="code"><index id="cover (태그)"/><index id="title (태그)"/><index id="subtitle (태그)"/><index id="author (태그)"/><index id="edition (태그)"/><cover hue="358"><br/>
|
||||
<title>책 제목&zwsp;</title><br/>
|
||||
<subtitle>필요한 경우 부제목&zwsp;</subtitle><br/>
|
||||
<author>누가 이 책을 집필하였는가&zwsp;</author><br/>
|
||||
<edition>필요한 경우 판본 정보&zwsp;</edition><br/>
|
||||
<title>책 제목&zwsp;</title><br/>
|
||||
<subtitle>필요한 경우 부제목&zwsp;</subtitle><br/>
|
||||
<author>누가 이 책을 집필하였는가&zwsp;</author><br/>
|
||||
<edition>필요한 경우 판본 정보&zwsp;</edition><br/>
|
||||
</cover>
|
||||
</callout>
|
||||
<p>이 중 <code>title</code> 태그만이 필수 태그이다. 표지의 문구는 글자간 간격이 넓게 인쇄된다. 책 제목은 두배 큰 크기로 인쇄된다.</p>
|
||||
@@ -156,6 +156,21 @@
|
||||
</ul>
|
||||
|
||||
|
||||
<section>그림</section>
|
||||
|
||||
<p><index id="img (태그)"/>외부 이미지는 스스로 닫는 <code>img</code> 태그를 사용해 넣을 수 있다. 그림은 세로로는 현재 줄에서부터, 가로로는 페이지의 중앙에 인쇄된다. 페이지에 남아 있는 줄보다 이미지의 높이가 더 크다면, 이미지는 새로운 페이지에 인쇄된다. <code>img</code> 태그의 구조는 다음과 같다.</p>
|
||||
|
||||
<callout align="left" class="code"><!--
|
||||
--><img src="http(s)나 file URL" height="8"/><br/><!--
|
||||
--><img fromgame="basegame:gui/small.png" height="4"/><br/><!--
|
||||
--><img gameitem="basegame:33" height="1"/>
|
||||
</callout>
|
||||
|
||||
<p><code>height</code> 속성은 이미지의 높이를 <emph>픽셀 단위가 아닌 줄의 개수</emph>로 지정하어야 한다. 이미지의 너비는 자동으로 계산된다. 텍스트의 너비보다 넓다면 오류가 발생한다.</p>
|
||||
|
||||
<p>지원하는 이미지 포맷: JPEG·PNG·BMP·TGA</p>
|
||||
|
||||
|
||||
<chapter>색인 페이지</chapter>
|
||||
|
||||
<p><index id="색인 페이지"/>색인 페이지의 내용은 원고를 읽어 자동으로 채워진다.
|
||||
@@ -245,12 +260,12 @@
|
||||
<p>이 태그들은 다음과 같은 상황에 쓰일 수 있다. 아래와 같은 <btex/> 문서가 있다면,</p>
|
||||
|
||||
<callout align="left" class="code">[en] Send your <v fromgame="GAME_ITEM_HOLOTAPE"/> that contains the manuscript to the publisher via mail to have your books printed.<br/><!--
|
||||
-->[koKR] 원고가 담긴 <veul fromgame="GAME_ITEM_HOLOTAPE"/> 출판사로 우편을 통해 보내야 책이 인쇄됩니다.</callout>
|
||||
-->[koKR] 원고가 담긴 <veul fromgame="GAME_ITEM_HOLOTAPE"/> 출판사로 우편을 통해 보내야 책이 인쇄됩니다.</callout>
|
||||
|
||||
<p>변수는 현재 게임 언어에 따라 대입되고, 그 다음 조사처리가 진행된다. 조판이 완료된 문구는 다음과 같다. (파란색은 해당 단어가 태그에 의해 대입되었음을 뜻한다)</p>
|
||||
|
||||
<callout>[en] Send your <itemname>Holotape</itemname> that contains the manuscript to the publisher via mail to have your books printed.<br/><!--
|
||||
-->[koKR] 원고가 담긴 <itemname>홀로테이프를</itemname> 출판사로 우편을 통해 보내야 책이 인쇄됩니다.</callout>
|
||||
-->[koKR] 원고가 담긴 <itemname>홀로테이프를</itemname> 출판사로 우편을 통해 보내야 책이 인쇄됩니다.</callout>
|
||||
|
||||
|
||||
|
||||
|
||||
12
btexdoc.dtd
12
btexdoc.dtd
@@ -8,9 +8,8 @@
|
||||
<!ENTITY % OLStyle "CDATA">
|
||||
|
||||
<!ENTITY % counters "(i|I|1|a|A)">
|
||||
<!ENTITY % special.extra "img">
|
||||
<!ENTITY % special.basic "br | span | newpage">
|
||||
<!ENTITY % special "%special.basic; | %special.extra;">
|
||||
<!ENTITY % special "%special.basic;">
|
||||
<!ENTITY % fontstyle.extra "big | small | font | basefont">
|
||||
<!ENTITY % fontstyle.basic "tt | i | b | u | s | strike ">
|
||||
<!ENTITY % fontstyle "%fontstyle.basic; | %fontstyle.extra;">
|
||||
@@ -45,6 +44,11 @@
|
||||
<!ENTITY % key-value
|
||||
"key CDATA #REQUIRED
|
||||
value CDATA #REQUIRED">
|
||||
<!ENTITY % imgAttrs
|
||||
"src CDATA #IMPLIED
|
||||
fromgame CDATA #IMPLIED
|
||||
gameitem CDATA #IMPLIED
|
||||
height %Number; #REQUIRED">
|
||||
<!ENTITY % coreattrs
|
||||
"id CDATA #IMPLIED
|
||||
class CDATA #IMPLIED
|
||||
@@ -55,7 +59,7 @@
|
||||
<!ENTITY % heading "part | chapter | section | subsection">
|
||||
<!ENTITY % lists "ul | ol">
|
||||
<!ENTITY % blocktext "pre | anonbreak | callout | center | fullpagebox">
|
||||
<!ENTITY % block "p | %heading; | %lists; | %blocktext;">
|
||||
<!ENTITY % block "p | %heading; | %lists; | %blocktext; | img">
|
||||
<!ENTITY % Flow "(#PCDATA | %block; | %inline;)*">
|
||||
|
||||
<!ELEMENT btexdoc (macrodef?,cover?,tocpage?,manuscript,indexpage?)>
|
||||
@@ -111,6 +115,8 @@
|
||||
<!ATTLIST pair %key-value;>
|
||||
<!ELEMENT index EMPTY>
|
||||
<!ATTLIST index %id-only;>
|
||||
<!ELEMENT img EMPTY>
|
||||
<!ATTLIST img %imgAttrs;>
|
||||
|
||||
<!-- inherited from HTML -->
|
||||
<!ELEMENT p %Inline;>
|
||||
|
||||
@@ -63,6 +63,8 @@ class BTeXDocument : Disposable {
|
||||
|
||||
private fun String.escape() = this.replace("\"", "\\\"")
|
||||
|
||||
private fun newTempFile(name: String) = FileHandle.tempFile(name)
|
||||
|
||||
fun fromFile(fileHandle: FileHandle) = fromFile(fileHandle.file())
|
||||
|
||||
fun fromFile(file: File): BTeXDocument {
|
||||
@@ -97,7 +99,7 @@ class BTeXDocument : Disposable {
|
||||
Clustfile(DOM, "/${page}.png").also {
|
||||
if (!it.exists()) throw IllegalStateException("No file '${page}.png' on the archive")
|
||||
|
||||
val tempFile = Gdx.files.external("./.btex-import.png") // must create new file descriptor for every page, or else every page will share a single file descriptor which cause problems
|
||||
val tempFile = newTempFile("btex-import.png") // must create new file descriptor for every page, or else every page will share a single file descriptor which cause problems
|
||||
it.exportFileTo(tempFile.file())
|
||||
val texture = TextureRegion(Texture(tempFile))
|
||||
doc.pageTextures[page] = texture
|
||||
@@ -236,7 +238,7 @@ class BTeXDocument : Disposable {
|
||||
pagePixmaps.forEachIndexed { index, pixmap ->
|
||||
Clustfile(DOM, "$index.png").also { file ->
|
||||
file.createNewFile()
|
||||
val tempFile = Gdx.files.external("./.btex-export.png")
|
||||
val tempFile = newTempFile("btex-export.png")
|
||||
PixmapIO.writePNG(tempFile, pixmap, Deflater.BEST_COMPRESSION, false)
|
||||
val outstream = ClustfileOutputStream(file)
|
||||
outstream.write(tempFile.readBytes())
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
package net.torvald.btex
|
||||
|
||||
import com.badlogic.gdx.Gdx
|
||||
import com.badlogic.gdx.files.FileHandle
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.badlogic.gdx.graphics.Pixmap
|
||||
import com.badlogic.gdx.graphics.Texture
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import com.badlogic.gdx.utils.Disposable
|
||||
import com.badlogic.gdx.utils.GdxRuntimeException
|
||||
import com.jme3.math.FastMath.DEG_TO_RAD
|
||||
import net.torvald.colourutil.OKLch
|
||||
import net.torvald.colourutil.tosRGB
|
||||
@@ -27,15 +30,15 @@ import org.xml.sax.Attributes
|
||||
import org.xml.sax.InputSource
|
||||
import org.xml.sax.SAXParseException
|
||||
import org.xml.sax.helpers.DefaultHandler
|
||||
import java.io.File
|
||||
import java.io.FileInputStream
|
||||
import java.io.StringReader
|
||||
import java.io.*
|
||||
import java.net.URL
|
||||
import javax.xml.parsers.SAXParserFactory
|
||||
import kotlin.math.roundToInt
|
||||
import kotlin.reflect.KFunction
|
||||
import kotlin.reflect.full.declaredFunctions
|
||||
import kotlin.reflect.full.findAnnotation
|
||||
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2023-10-28.
|
||||
*/
|
||||
@@ -919,6 +922,74 @@ object BTeXParser {
|
||||
paragraphBuffer.append(value)
|
||||
}
|
||||
|
||||
@OpenTag // reflective access is impossible with 'private'
|
||||
fun processElemIMG(handler: BTeXHandler, doc: BTeXDocument, uri: String, attribs: HashMap<String, String>) {
|
||||
val heightInLines = attribs["height"]!!.toInt()
|
||||
val imgHeight = doc.lineHeightInPx * heightInLines - 6
|
||||
val btexObjName = "IMG@${makeRandomObjName()}"
|
||||
val img = attribs["src"]
|
||||
|
||||
// image overflowing?
|
||||
if (doc.pageLines - doc.linesPrintedOnPage.last() < heightInLines)
|
||||
doc.addNewPage()
|
||||
|
||||
if (img != null) {
|
||||
val tempFile = FileHandle.tempFile("btex_$btexObjName")
|
||||
try {
|
||||
|
||||
val inputPixmap = if (img.startsWith("file://")) {
|
||||
// printdbg("Using local file ${img.substring(7)}")
|
||||
Pixmap(Gdx.files.absolute(img.substring(7)))
|
||||
}
|
||||
else {
|
||||
// printdbg("Downloading image $img")
|
||||
BufferedInputStream(URL(img).openStream()).use { `in` ->
|
||||
FileOutputStream(tempFile.file()).use { fileOutputStream ->
|
||||
val dataBuffer = ByteArray(1024)
|
||||
var bytesRead: Int
|
||||
while ((`in`.read(dataBuffer, 0, 1024).also { bytesRead = it }) != -1) {
|
||||
fileOutputStream.write(dataBuffer, 0, bytesRead)
|
||||
}
|
||||
}
|
||||
}
|
||||
Pixmap(tempFile).also { App.disposables.add(it) }
|
||||
}
|
||||
|
||||
val imgWidth = (imgHeight.toFloat() / inputPixmap.height * inputPixmap.width).roundToInt()
|
||||
|
||||
if (imgWidth > doc.textWidth)
|
||||
throw RuntimeException("Image width ($imgWidth) is larger than the text width (${doc.textWidth})")
|
||||
|
||||
val drawCallObj = { parentText: BTeXDrawCall -> object : BTeXBatchDrawCall(imgWidth, (heightInLines - 1).coerceAtLeast(0), parentText) {
|
||||
private lateinit var inputTexture: Texture
|
||||
override fun draw(doc: BTeXDocument, batch: SpriteBatch, x: Float, y: Float, font: TerrarumSansBitmap?) {
|
||||
if (!::inputTexture.isInitialized) {
|
||||
inputTexture = Texture(inputPixmap).also { App.disposables.add(it) }
|
||||
}
|
||||
val destX = (x + (doc.pageDimensionWidth - imgWidth) / 2)
|
||||
val destY = y + 1
|
||||
batch.draw(inputTexture, destX, destY, imgWidth.toFloat(), imgHeight.toFloat())
|
||||
}
|
||||
override fun drawToPixmap(doc: BTeXDocument, pixmap: Pixmap, x: Int, y: Int, font: TerrarumSansBitmap?) {
|
||||
val destX = x
|
||||
val destY = y + 1
|
||||
pixmap.drawPixmap(inputPixmap, 0, 0, inputPixmap.width, inputPixmap.height, destX, destY, imgWidth, imgHeight)
|
||||
}
|
||||
} }
|
||||
|
||||
objDict[btexObjName] = { text: BTeXDrawCall -> drawCallObj(text) }
|
||||
objWidthDict[btexObjName] = imgWidth
|
||||
|
||||
typesetParagraphs(objectMarkerWithWidth(btexObjName, imgWidth), handler, align = "center")
|
||||
}
|
||||
catch (e: IOException) { }
|
||||
catch (e: GdxRuntimeException) { }
|
||||
finally {
|
||||
tempFile.delete()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1827,6 +1898,8 @@ object BTeXParser {
|
||||
else -> throw IllegalArgumentException("Non-object ID char: $c")
|
||||
}
|
||||
}
|
||||
|
||||
private fun makeRandomObjName() = (0 until 12).joinToString("") { "${hashStrMap.random()}" }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -26,9 +26,9 @@ import kotlin.system.measureTimeMillis
|
||||
*/
|
||||
class BTeXTest : ApplicationAdapter() {
|
||||
|
||||
val filePath = "btex.xml"
|
||||
// val filePath = "btex.xml"
|
||||
// val filePath = "btex_ko.xml"
|
||||
// val filePath = "test.xml"
|
||||
val filePath = "test.xml"
|
||||
// val filePath = "literature/en/daniel_defoe_robinson_crusoe.xml"
|
||||
// val filePath = "literature/ruRU/anton_chekhov_palata_no_6.xml"
|
||||
// val filePath = "literature/koKR/yisang_nalgae.btxbook"
|
||||
|
||||
Reference in New Issue
Block a user