## グリッドに関する処理
# ABC075B_Minesweeper

## 考え方：pandasに入れて、df.ilocによる行×列のスライスでうまくやる

## for test
# 1
#height, width = 3, 5
#_s_list = ['.....','.#.#.','.....']

## for submit
import pandas as pd
height, width = map(int, input().split())
_s_list  = [input() for i in range(h)]
s_list = [list(ss) for ss in _s_list] # 列×行に1文字ずつ区切ってリストへ追加

df = pd.DataFrame(s_list)
#print(df.iloc[0:3, 0:3])  # debug 行×列のスライス # マイナスはNG, 要素数を超えるのは問題なし
# print(df.iloc[0:3, 1:4])  # debug 行×列のスライス 3*5 から、2行目3列目の周囲を取得する

ans_list = []
for _h in range(height):
    for _w in range(width):
        # 周囲1マスずつを取得
        if _h <= 1:
            h_s = 0
        else:
            h_s = _h-1
        h_e = _h + 2
        
        if _w <= 1:
            w_s = 0
        else:
            w_s = _w - 1
        w_e = _w + 2
        
        # print(df.iloc[h_s:h_e, w_s:w_e]) # debug
        # 周囲1マスずつから、#の数を数えるための前処理
        df_bool = (df.iloc[h_s:h_e, w_s:w_e] == '#')
        # PythonでTrueは1、Falseは0とみなされるため、bool値のオブジェクトに対してsum()メソッドを呼べば条件を満たす要素の数が得られる。
        # print(str(sum(df_bool.sum())))
        
        # チェック対象の中心が#なら#, それ以外はsumした結果の数値を文字列として保存
        if df.iloc[_h, _w] == '#':
            ans_list.append('#')
        else:
            ans_list.append(str(sum(df_bool.sum())))
        
# 結果を出力 width行を1区切りとして1行ずつ出力
ans_str = ''
for i in range(len(ans_list)):
    ans_str += ans_list[i]
    if (i+1) % width == 0:
        print(ans_str)
        ans_str = ''

### FIXED CODE ###

## グリッドに関する処理
# ABC075B_Minesweeper

## 考え方：
# A NG:pandasに入れて、df.ilocによる行×列のスライスでうまくやる -> pandasはimport不可
# B:np.arrayに入れて、うまいことやる  # PyPy3ではnumpyもimport不可。python3は、numpyはimport可。

## for test
# # 1
# height, width = 3, 5
# _s_list = ['.....', '.#.#.', '.....']

# # 2
# height, width = 3, 5
# _s_list = ['#####', '#####', '#####']

# 3
# height, width = 6, 6
# _s_list = ['#####.', '#.#.##', '####.#', '.#..#.', '#.##..', '#.#...']


## for submit
import numpy as np
height, width = map(int, input().split())
_s_list = [input() for i in range(height)]
s_list = [list(ss) for ss in _s_list]  # 列×行に1文字ずつ区切ってリストへ追加 -> 2次元配列化
s_arr  = np.array(s_list)
# print(s_list)  # debug
# print(s_arr)  # debug

ans_list = []
for _h in range(height):
    for _w in range(width):
        # 周囲1マスずつを取得
        if _h <= 1:
            h_s = 0
        else:
            h_s = _h-1
        # h_e = _h + 2  # 一応、範囲外アクセスしないように修正
        if _h == height-1:
            h_e = _h+1
        else:
            h_e = _h+2
        
        if _w <= 1:
            w_s = 0
        else:
            w_s = _w - 1
        # w_e = _w + 2  # 一応、範囲外アクセスしないように修正
        if _w == width-1:
            w_e = _w+1
        else:
            w_e = _w+2

        # print(s_arr[h_s:h_e, w_s:w_e])  # debug
        # # np.count_nonzero()を使うとTrueの数、すなわち、条件を満たす要素の個数が得られる。
        # print(np.count_nonzero(s_arr[h_s:h_e, w_s:w_e] == '#'))

#         # 周囲1マスずつから、#の数を数えるための前処理
#         df_bool = (df.iloc[h_s:h_e, w_s:w_e] == '#')
#         # PythonでTrueは1、Falseは0とみなされるため、bool値のオブジェクトに対してsum()メソッドを呼べば条件を満たす要素の数が得られる。
#         # print(str(sum(df_bool.sum())))
        
        # チェック対象の中心が#なら#, それ以外はcount_nonzeroした結果の数値を文字列として保存
        if s_arr[_h, _w] == '#':
            ans_list.append('#')
        else:
            ans_list.append(str(np.count_nonzero(s_arr[h_s:h_e, w_s:w_e] == '#')))
        
# 結果を出力 width行を1区切りとして1行ずつ出力
ans_str = ''
for i in range(len(ans_list)):
    ans_str += ans_list[i]
    if (i+1) % width == 0:
        print(ans_str)
        ans_str = ''