---
# System prepended metadata

title: 圖片轉Ascii Art小工具
tags: [' python', ' small_tool', blog]

---

---
layout: post
title: 圖片轉Ascii Art小工具
date: 2019-9-26 21:00:00 +0800
categories: [用Python搞點事]
tags: blog, python, small_tool
---

#### 本文概述
需具備能力: 了解python基礎語法
能學到甚麼: 使用PIL套件處理圖片、檔案讀寫
使用軟體: python3、PIL、Notepad++
{% endnote %}

## 介紹
這次要帶大家用Python寫一個將圖片轉換成Ascii Art的小工具。
### 先來個Demo
**這是原圖**
![](https://i.imgur.com/bBpb2at.jpg)

**經過我們的工具轉換後**
![](https://i.imgur.com/uVceeF1.png)

嗯? 你說你不知道我在幹嘛嗎? 我們把它放大點來看。
![](https://i.imgur.com/wy77UDr.png)

這個是柴柴拳頭的部分XD

我們這次就是要用Python做一個可以把圖片轉換成這樣，由一個一個文字符號組成的"Ascii Art"。

## 什麼是Ascii Art
所謂的Ascii Art，意旨使用Ascii的符號所創作的圖片，也就是用一個個小小的文字，拼湊成一張圖片的一種創作手法。這邊放幾張好看的Ascii Art來給各位欣賞。
![](https://s3.amazonaws.com/media-p.slid.es/uploads/922060/images/6046202/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/922060/images/6046204/pasted-from-clipboard.png)
![]()
但是一個字一個字去敲，敲成一張圖片，這樣實在很麻煩。假設你想要一張100 x 100大小的圖片就要敲10000個字，而且還要考慮每個字放在哪裡才能組合成特定形狀，真的會打到眼花撩亂。
因此，我們可以自製工具，透過讀取圖片中一個個像素的方式，將像素傳換為文字，藉此達到我們要的效果。

## 何謂套件
套件是別人寫好的工具，我們可以用這些工具提供給我們的api(application programming interface)來完成我們想做的事情。

## PIL套件介紹
PIL(Python Image Library)是一套處理圖片的套件，他可以調整圖片的大小、亮度、對比、色調、裁切圖片、旋轉圖片、加濾鏡、附加文字......等等，雖然沒有專業的圖像編輯軟體來的強大，但可以批次處理圖片，而且彈性較大。

## 圖片檔概念
圖像檔案保存的方式是這樣的，假設有一張200x100的圖片檔，顏色編碼為RGB，這是什麼意思呢?
200x100指的是像素，這張圖片的寬有200個像素、高有100，也就是說這張圖片總共有20000個像素
那每個像素究竟存了什麼值? 這邊看到RGB，代表每個像素存取的是RGB三個顏色的值，每個顏色一個Byte(8bit)

## 設計想法
* 目標: 製作一個圖片轉成文字檔的小工具
* 核心流程: 將圖片轉為黑白，讀取每個像素，是黑的就填上@符號，是白的就填上_符號

## 實作
:::info
完整程式碼: 
在開始之前先確定電腦有裝好python3、pip、Notepad++
notepad++載點: https://notepad-plus-plus.org/download/v7.6.6.htmlNotepad++ 
選這個zip package 32-bit x86
:::
1. 安裝並引入PIL套件
    使用pip(python的套件管理系統)進行安裝，這邊注意要用pillow作為名稱
    ```bash=
    C:\Users\Sam> pip install pillow
    ```
    在python檔案開頭使用這行程式碼可將PIL當中的Image模組引入
    ```python=
    from PIL import Image
    ```
2. 開啟圖片
    ```python=
    img = Image.open(imgName)
    ```
3. 顯示圖片資訊，如果色彩模式不是RGB則轉換為RGB
    ```python=
    print("圖片資訊: 大小為{}x{}, 格式為{}, 色彩模式為{}".format(img.size[0], img.size[1], img.format, img.mode))

    if img.mode != 'RGB':
        print("圖片顏色編碼不是RGB，進行轉換")    
        img = img.convert('RGB')
        print("轉換完成")
    ```
    * img.size是一個紀錄圖片大小的tuple，img.size[0]是寬、img.size[1]是高
    * img.mode是一個字串，紀錄圖片的編碼，常見的有這些
        * RGB: 三色，R紅、G綠、B藍(3x8bits)
        * RGBA: 跟RGB一樣，只是多了Alpha值，也就是透明度(4x8bits)
        * CMYK: 四色，C青、M洋紅、Y黃、K黑色(4x8bits)
        * 1: 黑白(1bit)
        * L: 256色灰階(8bits)
        * P: 256色彩色(8bits)
        > 參考: https://pillow.readthedocs.io/en/3.1.x/handbook/concepts.html#modes
4. 調整圖片大小
```python=
zoom = 0 # 縮小比率
if width >= maxSize:
    zoom = width / maxSize
    width = int(width / zoom) 
    height = int(height / zoom) 
    height = int(height / 2) # 除2讓比例看起來比較正確
    img = img.resize((width, height))
    print("圖片寬於{}，已縮小為{}x{}".format(maxSize, img.size[0], img.size[1]))
```
5. 將圖片轉為黑白
```python=
img = img.convert('1')
```
6. 開啟文字文件
```python=
txt = open(namestr, 'w')
```
7. 從上至下、從左至右讀取每個pixel的值
轉換成黑白顏色編碼後，每個pixel的值，不是1就是0，我們從上而下、由左而右讀取每個pixel，如果是1則在文字檔中寫入@代表黑色部分，如果是0則寫入_代表白色部分。
```python=
for y in range(height):
    for x in range(width):
        pixel = img.getpixel((x, y))
        # print('x= ', x, 'y= ', y, 'pixel= ', pixel)
        if pixel != 0:
            txt.write('_')
        else:
            txt.write('@')
    txt.write('\n')
```
8. 關閉文字文件
```python=
txt.close()
```

> 參考資料: [Python趣味实用小工具](http://www.demodashi.com/demo/12918.html)