misohena / el-easydraw

Embedded drawing tool for Emacs
https://misohena.jp/blog/2021-09-21-emacs-easy-draw.html
GNU General Public License v3.0
769 stars 21 forks source link

Drawing works but no image shown after finished #5

Closed nxtruong closed 3 years ago

nxtruong commented 3 years ago

Thanks for the great work. This is very exciting. I installed easydraw on Mac OS (Big Sur) with emacs-plus 28.0.50, native compile. The drawing worked perfectly (everything). However, when I finished editing (C-c C-c or selected "Finish edit" from the main menu), the final image is not shown but only a very small empty / white box. When I clicked on the box (or C-c C-o on it), the editor was opened again, the correct image was shown, and I could edit it as usual, so the image was not lost. It just was not shown properly when not being edited. Exporting to HTML worked: the SVG image was shown properly in HTML. Any idea how to fix or debug this problem?

misohena commented 3 years ago

nxtruongさんこんにちは。 ご報告ありがとうございます。

小さな白い箱が表示されるということはオーバーレイの作成はうまくいっていて、しかしオーバーレイのdisplayプロパティに問題がある可能性が高いです。

edraw-org-link-image-create がdisplayプロパティ(画像)を構築している関数です。この関数の中において、create-imageの引数(file-or-data変数)に問題があるとたいてい小さな白い箱が表示されます。

file-or-dataの値はedraw-org-link-props-image-data-or-file関数で作成します。 データはgzipされた後base64エンコードされたSVGです。なのでこの関数はbase64-decode-stringを呼び出して……この関数がgzipを展開していないのは私の環境ではそのままで表示できたからです。gzipされたSVGはsvgzと呼ばれています。ひょっとしたらこのsvgzが表示できないのでしょうか?

だとすれば次の変更で表示できるようになるかもしれません。

- (ignore-errors (cons (base64-decode-string data) t))
+ (ignore-errors (cons (edraw-decode-svg data t) t))

edraw-decode-svgはedraw.elに含まれています。edraw-org.elは編集開始までedraw.elの読み込みを先送りしているので、上の変更は読み込み前はエラーになる可能性があります。読み込み時間を気にしないなら最初から(require 'edraw)すれば回避できます。

また、速度は変更前の方が速いと思うので恒久的にこの変更をするかは迷います。

Google Translate: Hello nxtruong. Thank you for your report.

If you see a small white box, the overlay was created successfully, but it is likely that there is a problem with the overlay's display property.

edraw-org-link-image-create is the function that builds the display property (image). Inside this function, if there is a problem with the create-image argument (file-or-data variable), you will usually see a small white box.

The value of file-or-data is created by the edraw-org-link-props-image-data-or-file function. The data is gzipped and then base64 encoded SVG. So this function calls base64-decode-string ... This function doesn't ungzip because it could be displayed as is in my environment. The gzipped SVG is called svgz. Maybe this svgz can't be displayed?

If so, it may be possible to display it with the next change. I'm sorry. see next comment.

- (ignore-errors (cons (base64-decode-string data) t))
+ (ignore-errors (cons (edraw-decode-svg data t) t))

edraw-decode-svg is included in edraw.el. Since edraw-org.el postpones loading edraw.el until the start of editing, the above changes may result in an error before loading. If you don't care about loading time, you can avoid it by (require 'edraw) from the beginning.

Also, I think the speed is faster before the change, so I'm wondering whether to make this change permanently.

misohena commented 3 years ago

すみません、上の変更はダメです。xmlをパースしてしまうので。 次のような関数を作って試してみてください。

I'm sorry, the above change is useless. Because it parses xml. Create a function like the following and try it out.

(defun edraw-decode-svg-string (data base64-p)
  (with-temp-buffer
    (insert data)
    (when base64-p
      (base64-decode-region (point-min) (point-max))
      (unless (edraw-buffer-gzip-p)
        (decode-coding-region (point-min) (point-max) 'utf-8)))
    (when (edraw-buffer-gzip-p)
      (edraw-gunzip-buffer))
    (buffer-string)))
- (ignore-errors (cons (base64-decode-string data) t))
+ (ignore-errors (cons (edraw-decode-svg-string data t) t))
nxtruong commented 3 years ago

The fix worked perfectly. Thanks. Perhaps you can incorporate this change into the code.

misohena commented 3 years ago

確認して頂いてありがとうございます。動いたようで良かったです。

今旅行に出ているので帰ったら組み込んでみようと思います。 デフォルトでgunzipして、オプションでgunzipしないようにするのが安全かもしれません。

Thank you for checking. I'm glad it worked.

I'm on a trip now, so I'll try to incorporate it when I get home. It may be safe to gunzip by default and optionally not gunzip.

nxtruong commented 3 years ago

I reopened this issue because the same problem reappeared when [[edraw:]] was used with a file name instead of embedded data (i.e., [[edraw:file=filename.svg]]). I tracked the problem to the file edraw-org.el, function edraw-org-link-props-image-data-or-file, line (if (file-exists-p file) (cons file nil))))). The file name is used with create-image, however, the docs of create-image states that:

Image file names that are not absolute are searched for in the "images" sub-directory of ‘data-directory’ and ‘x-bitmap-file-path’ (in that order).

It turns out that the relative file name used is not an absolute path, therefore it's not found by create-image. I fixed this problem by converting the relative path to an absolute path so that create-image can find the file. I changed the above line to: (if (file-exists-p file) (cons (expand-file-name file) nil))))) where expand-file-name does the conversion. It now works properly for both embedded SVG data ([[edraw:data=...]]) and file name ([[edraw:file=...]]).

misohena commented 3 years ago

create-image を何度も使用してきましたが、そのことを知りませんでした。動いていたのは x-bitmap-file-path が (".")だからだったのですね! 教えて頂きありがとうございます。

Pull Requestもありがとうございます。マージしました。

Google Translate: I've used create-image many times, but didn't know that. It worked because x-bitmap-file-path was (".")! Thank you for telling me.

Thank you for Pull Request. Merged.