From d06b37007782e456f3a8d0c97c8681f79db30d23 Mon Sep 17 00:00:00 2001 From: Daniel <845765@qq.com> Date: Sat, 22 Nov 2025 10:55:08 +0800 Subject: [PATCH 1/4] :art: Image OCR supports more formats https://github.com/siyuan-note/siyuan/issues/16418 Signed-off-by: Daniel <845765@qq.com> --- kernel/util/ocr.go | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/kernel/util/ocr.go b/kernel/util/ocr.go index a9370071e..040468b54 100644 --- a/kernel/util/ocr.go +++ b/kernel/util/ocr.go @@ -182,9 +182,29 @@ func RemoveAssetText(asset string) { assetsTextsChanged.Store(true) } +var tesseractExts = []string{ + ".png", + ".jpg", + ".jpeg", + ".tif", + ".tiff", + ".bmp", + ".gif", + ".webp", + ".pbm", + ".pgm", + ".ppm", + ".pnm", +} + func IsTesseractExtractable(p string) bool { lowerName := strings.ToLower(p) - return strings.HasSuffix(lowerName, ".png") || strings.HasSuffix(lowerName, ".jpg") || strings.HasSuffix(lowerName, ".jpeg") + for _, ext := range tesseractExts { + if strings.HasSuffix(lowerName, ext) { + return true + } + } + return false } // tesseractOCRLock 用于 Tesseract OCR 加锁串行执行提升稳定性 https://github.com/siyuan-note/siyuan/issues/7265 @@ -300,7 +320,7 @@ func InitTesseract() { langs := getTesseractLangs() if 1 > len(langs) { - logging.LogWarnf("no tesseract langs found") + logging.LogWarnf("no tesseract langs found, disabling tesseract-ocr") TesseractEnabled = false tesseractInited.Store(true) return From aac7647ff55d6e1fbc2b0f0d66559bfb70384768 Mon Sep 17 00:00:00 2001 From: Daniel <845765@qq.com> Date: Sat, 22 Nov 2025 11:35:15 +0800 Subject: [PATCH 2/4] :bug: https://github.com/siyuan-note/siyuan/issues/16417 Signed-off-by: Daniel <845765@qq.com> --- kernel/model/transaction.go | 48 ++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 27 deletions(-) diff --git a/kernel/model/transaction.go b/kernel/model/transaction.go index 4a48bc4b9..0be647e05 100644 --- a/kernel/model/transaction.go +++ b/kernel/model/transaction.go @@ -343,6 +343,10 @@ func (tx *Transaction) processUndoInsertWithFoldedHeading() { // 删除折叠标题后撤销,需要调整 insert 顺序和 previousID // https://github.com/siyuan-note/siyuan/issues/16120 + if 1 > len(tx.DoOperations) { + return + } + // 所有操作均为 insert 才处理 for _, op := range tx.DoOperations { if "insert" != op.Action { @@ -350,6 +354,8 @@ func (tx *Transaction) processUndoInsertWithFoldedHeading() { } } + // 找到 ignoreProcess=true 的区间 [j, k] + var j, k int for i := 0; i < len(tx.DoOperations); i++ { op := tx.DoOperations[i] ignoreProcess := false @@ -361,38 +367,26 @@ func (tx *Transaction) processUndoInsertWithFoldedHeading() { return } } - if ignoreProcess { - // 找到从当前 i 到下个 ignoreProcess=false 的区间,整体反转 - j := i + 1 - if j >= len(tx.DoOperations) { - return - } - for ; j < len(tx.DoOperations); j++ { - nextOp := tx.DoOperations[j] - nextIgnoreProcess := false - if nil != nextOp.Context["ignoreProcess"] { - var convErr error - nextIgnoreProcess, convErr = strconv.ParseBool(nextOp.Context["ignoreProcess"].(string)) - if nil != convErr { - logging.LogErrorf("parse ignoreProcess failed: %s", convErr) - return - } - } - if !nextIgnoreProcess { - break - } + if !ignoreProcess { + if 0 != j && 0 != k { + break } - for _, nextOp := range tx.DoOperations[i:j] { - nextOp.PreviousID = tx.DoOperations[j].ID - } - slices.Reverse(tx.DoOperations[i : j+1]) - i = j + continue } - if i >= len(tx.DoOperations) { - return + + if 0 == j && 0 == k { + j = i } + k = i } + + // 调整 [j, k] 区间内的操作顺序和 previousID + for x := j; x <= k; x++ { + opx := tx.DoOperations[x] + opx.PreviousID = tx.DoOperations[k].PreviousID + } + slices.Reverse(tx.DoOperations[j : k+1]) } func (tx *Transaction) processLargeInsert() bool { From bebf8c8e9b3bbd0ee4e80649d62926e4b592e641 Mon Sep 17 00:00:00 2001 From: Daniel <845765@qq.com> Date: Sat, 22 Nov 2025 14:42:18 +0800 Subject: [PATCH 3/4] :art: Image OCR supports setting the timeout via the environment variable `SIYUAN_TESSERACT_TIMEOUT` https://github.com/siyuan-note/siyuan/issues/16419 Signed-off-by: Daniel <845765@qq.com> --- kernel/util/ocr.go | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/kernel/util/ocr.go b/kernel/util/ocr.go index 040468b54..c3935212a 100644 --- a/kernel/util/ocr.go +++ b/kernel/util/ocr.go @@ -234,7 +234,16 @@ func Tesseract(imgAbsPath string) (ret []map[string]interface{}) { defer logging.Recover() - ctx, cancel := context.WithTimeout(context.Background(), 7*time.Second) + timeout := 7000 + timeoutEnv := os.Getenv("SIYUAN_TESSERACT_TIMEOUT") + if "" != timeoutEnv { + if timeoutParsed, parseErr := strconv.Atoi(timeoutEnv); nil == parseErr { + timeout = timeoutParsed + } else { + logging.LogWarnf("parse tesseract timeout [%s] failed: %s", timeoutEnv, parseErr) + } + } + ctx, cancel := context.WithTimeout(context.Background(), time.Duration(timeout)*time.Millisecond) defer cancel() cmd := exec.CommandContext(ctx, TesseractBin, "-c", "debug_file=/dev/null", imgAbsPath, "stdout", "-l", strings.Join(TesseractLangs, "+"), "tsv") From a5a82795ada1df42ca33018b308df798ca3bf458 Mon Sep 17 00:00:00 2001 From: Daniel <845765@qq.com> Date: Sat, 22 Nov 2025 14:43:03 +0800 Subject: [PATCH 4/4] :art: Image OCR supports setting the timeout via the environment variable `SIYUAN_TESSERACT_TIMEOUT` https://github.com/siyuan-note/siyuan/issues/16419 Signed-off-by: Daniel <845765@qq.com> --- kernel/util/ocr.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/kernel/util/ocr.go b/kernel/util/ocr.go index c3935212a..b03824756 100644 --- a/kernel/util/ocr.go +++ b/kernel/util/ocr.go @@ -19,6 +19,7 @@ package util import ( "bytes" "context" + "errors" "fmt" "os" "os/exec" @@ -249,8 +250,8 @@ func Tesseract(imgAbsPath string) (ret []map[string]interface{}) { cmd := exec.CommandContext(ctx, TesseractBin, "-c", "debug_file=/dev/null", imgAbsPath, "stdout", "-l", strings.Join(TesseractLangs, "+"), "tsv") gulu.CmdAttr(cmd) output, err := cmd.CombinedOutput() - if ctx.Err() == context.DeadlineExceeded { - logging.LogWarnf("tesseract [path=%s, size=%d] timeout", imgAbsPath, info.Size()) + if errors.Is(ctx.Err(), context.DeadlineExceeded) { + logging.LogWarnf("tesseract [path=%s, size=%d] timeout [%dms]", imgAbsPath, info.Size(), timeout) return }