【Mac】プレビューで画像をコピペして保存すると白黒(グレー)になる件 🎨

便利な macOS プレビューアプリですが、

絵を描いて保存した瞬間になぜか白黒になるものがある。

このように丸を描いて保存すると、

こうなってしまいます。

上に画像をコピペで貼り付けした場合もグレーになってしまいます。

エクスポートしても同じ。

画像の形式の話だろうけど、どうしたらいいのか。

👉 プレビューからコピーした画像が白黒にな… - Apple コミュニティ hatena-bookmark

👉 saving Preview annotations color - Apple Community hatena-bookmark

 

🎨 画像形式を確認する

元画像は w.png。

プレビューの [ツール] - [インスペクター] で。

「Gray」と表示されてるのが気になります。

コマンドラインでも見てみます。


❯ file w.png
w.png: PNG image data, 300 x 300, 1-bit grayscale, non-interlaced

❯ identify w.png
w.png PNG 300x300 300x300+0+0 8-bit Grayscale Gray 2c 346B 0.000u 0:00.024

❯ pngcheck w.png
OK: w.png (300x300, 1-bit grayscale, non-interlaced, 97.0%).

「grayscale (グレースケール)」とどれも表示されています。

👉 pngcheck - verifies the integrity of PNG, JNG and MNG files

 

🎨 ImageMagick でPNG形式を変換する

以下で変換できるようです。

You need to supply PNG24, PNG8 or PNG32 prefix if planning to use this canvas to layer colour images over. Without it, it creates a Grey colour space. I used 32, as I need "varying degrees of transparency for each pixel"

このキャンバスを使用してカラー画像を重ねる場合は、PNG24、PNG8、または PNG32 プレフィックスを指定する必要があります。これがないとグレーの色空間が作成されます。 私の場合は、各ピクセルの透明度を変える必要があるので 32 を使用しました。


convert w.png png32:w.png

👉 Create blank image in Imagemagick - Stack Overflow hatena-bookmark

上記コマンドを実行して変換後、確認してみます。


❯ file w.png
w.png: PNG image data, 300 x 300, 8-bit/color RGBA, non-interlaced

❯ identify w.png
w.png PNG 300x300 300x300+0+0 8-bit sRGB 1294B 0.000u 0:00.000

❯ pngcheck w.png
OK: w.png (300x300, 32-bit RGB+alpha, non-interlaced, 99.6%).

「graayscale」という文字は消えています。

再度、赤い丸を描いて保存するといけました!

 

🎨 まとめ

最初に開くファイルの形式が保存時に影響する。

ちなみに、ImageMagick が対応してるのは以下。


❯ identify -list format | grep PNG
      JNG* PNG       rw-   JPEG Network Graphics
      MNG* PNG       rw+   Multiple-image Network Graphics (libpng 1.6.39)
      PNG* PNG       rw-   Portable Network Graphics (libpng 1.6.39)
             See http://www.libpng.org/ for details about the PNG format.
    PNG00* PNG       rw-   PNG inheriting bit-depth, color-type from original, if possible
    PNG24* PNG       rw-   opaque or binary transparent 24-bit RGB
    PNG32* PNG       rw-   opaque or transparent 32-bit RGBA
    PNG48* PNG       rw-   opaque or binary transparent 48-bit RGB
    PNG64* PNG       rw-   opaque or transparent 64-bit RGBA
     PNG8* PNG       rw-   8-bit indexed with optional binary transparency

しかし、プレビューアプリだけで完結できないものか。

以下の記事がわかりやすく解説されていました。

👉 ImageMagick で PNG の形式を変換 - awm-Tech hatena-bookmark



【Mac】OS標準 プレビュー アプリで画像を新規作成する方法 🎨

いいアプリ見つけた。

Mac標準ソフト「プレビュー」には、図形や線、テキストなどを挿入できるマークアップ機能が搭載されています。しかし、同機能は既存の画像のみに適用できるほか、同ソフトでは新規ファイルも作成できません。それでも簡単な図を作成するために別のペイントツールをダウンロードしたくないという人には、このソフトがオススメです。コンテクストメニューから起動して新規画像のサイズや色を指定すると、画像を作成して自動的に「プレビュー」を開き、マークアップ機能を使えるようになります。

👉 「プレビュー」用の新規ファイル作成|MacFan hatena-bookmark

と思ったら、なぜか動かないので。

 

🎨 ImageMagick で

定番コマンドラインツールをインストールしておきます。


brew install imagemagick


👉 ImageMagick – Convert, Edit, or Compose Digital Images hatena-bookmark

以下のようなコマンドを使います。


convert -size 200x200 xc:white canvas.png

👉 macos - Create PNG/JPG file with commandline on Mac - Stack Overflow hatena-bookmark

これで真っ白な画像ファイルが生成できます。

 

🎨 ショートカットで開く

画像サイズを選択するようにして、先ほどのコマンドをショートカットに仕込みます。


cd ~/Desktop
convert -size {Chosen Item} xc:white {Chosen Item}.png
open -a Preview {Chosen Item}.png

これで、[サイズ選択] → [画像作成] → [プレビューを開く] の流れが実行できます。

サイズや作成先ディレクトリや拡張子はお好みで。

あと、日本語でOS設定している人は open -a するアプリ名が「プレビュー」なのかも。

 

🎨 保存すると白黒になってしまう

ショートカット内コマンドで作成する白キャンバス画像の形式が影響してカラーのまま保存できない。

PNG32:というように作成するファイル名の前にプレフィックスをつけるといい。

ショートカット内コマンドで作成する白キャンバス画像の形式が影響してカラーのまま保存できない。

これでカラーのまま保存できるようになります。

👉 【Mac】プレビューで画像をコピペして保存すると白黒(グレー)になる件 🎨 hatena-bookmark

 

🎨 まとめ

なぜ、Preview は新規キャンバス作成ができないのか。

「プレビュー」ではなくなるからかな。


【Kotlin】kotlinx.serialization で JSON を自在に変換する 🤔

 

🤔 Kotlin Serialization Guide を眺めてみる

JSON 処理なら、ここらですよね。

どんな扱いになっているのか見てみましょうか。


👉 kotlinx.serialization/serialization-guide.md at master · Kotlin/kotlinx.serialization · GitHub hatena-bookmark

基本的な使い方「Chapter 1.Basic Serialization」として、以下のようなデータクラスを例に以下のサンプルコード。


@Serializable
class Project(val name: String, val language: String)


val data = Project("kotlinx.serialization", "Kotlin")
println(Json.encodeToString(data))

// {"name":"kotlinx.serialization","language":"Kotlin"}


val data = Json.decodeFromString<Project>("""
  {"name":"kotlinx.serialization","language":"Kotlin"}
""")
println(data)

// Project(name=kotlinx.serialization, language=Kotlin)

以下のようなイメージのことを書いてる。


                +-----------------------------------+                 
                |                                   |                 
                | Project(                          |                 
                |   name = "kotlinx.serialization", |                 
                |   language = "Kotlin"             |                 
                | )                                 |                 
                |                                   |                 
                +-----------------------------------+                 
                              |      ^                                
                              |      |                                
                              |      |                                
Json.encodeToString(Project)  |      |  Json.decodeFromString(String) 
                              |      |                                
                              |      |                                
                              v      |                                
               +------------------------------------+                 
               |                                    |                 
               | {                                  |                 
               |   "name":"kotlinx.serialization",  |                 
               |   "language":"Kotlin"              |                 
               | }                                  |                 
               |                                    |                 
               +------------------------------------+

汎用的にしてこうですか。


            +-----------------------------------+                          
            |                 T                 |                          
            +-----------------------------------+                          
                            |  ^                                           
                            |  |                                           
                            |  |                                           
Json.encodeToString(T)      |  |     Json.decodeFromString<T>(String)      
                            |  |                                           
                            |  |                                           
                            v  |                                           
           +------------------------------------+                          
           |               String               |                          
           +------------------------------------+

メソッド名的には、


シリアル化  → encode
逆シリアル化 → decode

となってます。

 

🤔 JsonElement

というのがあります。

👉 JsonElement hatena-bookmark

少し試してみます。変換しながら型を見ていきます。


// T
val t = Project(name = "kotlinx.serialization", language = "Kotlin")
println("$t ${t::class.simpleName}")
// Project(name=kotlinx.serialization, language=Kotlin) Project


// T -> JsonElement
val e = Json.encodeToJsonElement(t)
println("$e ${e::class.simpleName}")
// {"name":"kotlinx.serialization","language":"Kotlin"} JsonObject


// JsonElement -> String
val s = Json.encodeToString(e)
println("$s ${s::class.simpleName}")
// {"name":"kotlinx.serialization","language":"Kotlin"} String


// String -> JsonElement
val e2 = Json.parseToJsonElement(s)
println("$e2 ${e2::class.simpleName}")
// {"name":"kotlinx.serialization","language":"Kotlin"} JsonObject


// JsonElement -> T
val t2 = Json.decodeFromJsonElement<Project>(e2)
println("$t2 ${t2::class.simpleName}")
// Project(name=kotlinx.serialization, language=Kotlin) Project

JsonElement の型は JsonObject です。

図にします。


                  +-----------------------------------+                             
                  |                 T                 |                             
                  +-----------------------------------+                             
                                  |  ^                                              
                                  |  |                                              
                                  |  |                                              
  Json.encodeToJsonElement(T)     |  |  Json.decodeFromJsonElement<T>(JsonElement)  
                                  |  |                                              
                                  |  |                                              
                                  v  |                                              
                 +------------------------------------+                             
                 |            JsonObject              |                             
                 +------------------------------------+                             
                                  |  ^                                              
                                  |  |                                              
                                  |  |                                              
Json.encodeToString(JsonElement)  |  |  Json.parseToJsonElement(String)      
                                  |  |                                              
                                  |  |                                              
                                  v  |                                              
                 +------------------------------------+                             
                 |               String               |                             
                 +------------------------------------+

しかし、考えてみると、JsonObject って最近ではあまり見かけなくなった気がします。

 

🤔 まとめ

以上を図にしておきます。


👉 Json.md GitHub Gist hatena-bookmark

String 方向が encode(エンコード)serialize(シリアル化)

T 方向が decode(デコード)deserialize(逆シリアル化)