自動化縮圖與生成文章檔案

../../../arch_2013/files_2013/Coding/jpg2rst/800/800_Collage.jpg

在了解了縮圖對於照片的影響,以及Imagemagick的使用方法,我們現在將這些資訊實用化,應用在網路文章的寫作,我的目標有以下幾個:

  1. 將滑鼠點擊的次數降到最低。
  2. 跨平台的可能性。
  3. 未來應用的擴充性。
  4. 方便性。

這裡筆者以python程式進行上述目標的實作,請先去Imagemagick [1]網站下載convert套件並安裝好,確定他可以執行如下的縮圖指令

convert 原始圖檔.jpg -colorspace RGB -filter LanczosSharp -distort Resize 800x800 -unsharp 1x0.55+1.5+0.002 -colorspace sRGB -border 10 -quality 100 縮圖檔名.jpg

接著下載並安裝筆者的jpg2rst套件:

git clone https://github.com/sophAi/jpg2rst.git jpg2rst
cd jpg2rst
sudo easy_install *.egg

工作流程如下:

  1. 把想要縮圖的照片集中在一個目錄下。
  2. 執行jpg2rst.main()。
  3. 自動產生所有照片的縮圖到對應解析度的目錄下。
  4. 同時生成包含照片路徑的文件檔,這裡我們採用reStructuredText(ReST)格式。

這個檔案總共包含4個py檔,分別執行不同的工作,例如:

jpg2rst/file_tools.py

#!/usr/bin/env python
def search(keyword='.jpg',recursive='n'):
    ''' Search for the files (default=.jpg) in the current or the subdirectories and return a list of the full paths.
    return: file_list (str list)
    usage: search_file(str keyword,str recursive)
    example: search_file(keyword='*.jpg',recursive='y')
    recursive: 'y'   # turn on the recursive searching in the subdirectories'''
    import os
    from fnmatch import fnmatch
    file_list = list()
    if recursive == 'y':
        for root, dirs, files in os.walk('.'):
            for file_name in files:
                if fnmatch(os.path.join(root,
                    file_name).lower().lstrip('./'),keyword.lower()):
                    file_list.append(os.path.join(root,file_name).lstrip('./'))  #Using walk, the file name would start with './dir/file.dat'. Use lstrip('./') to remove the string.



    else:
        for file_name in os.listdir('.'):
            if fnmatch(file_name.lower().lstrip('./'),keyword.lower()):
                file_list.append(file_name)


    file_list.sort()
    return file_list

def clear(file_list):
    ''' Delete the files by the file_list. Use search() first to determine the file_list'''
    import os
    if type(file_list).__name__ == 'str':
        print('Delete '+file_list)
        os.remove(file_list)
    elif tpye(file_list).__name__ == 'list':
        for file_name in file_list:
            print('Delete '+file_name)
            os.remove(file_name)


def copy(file_list,destinate_list='.'):
    ''' Copy the files listed in the file_list to the destinate_list. Use search() first to
    determine the file_list.
    destinate_list may be a string(dir_path) or a list of full paths
    To copy the file to the current directory, specify '.' as the destinate_list'''
    import shutil, os, sys
    file_type = type(file_list).__name__
    file_len = len(file_list)
    destinate_type = type(destinate_list).__name__
    destinate_len = len(destinate_list)
    if file_list != destinate_list:
        if file_type == 'list' and destinate_type == 'list' and file_len == destinate_len:
            I0=0
            for file_name in file_list:
                print('Copy '+file_name+' to '+destinate_list[I0])
                shutil.copy(file_name,destinate_list[I0])
                I0=I0+1

        elif file_type == 'list' and destinate_type == 'str' and os.path.isdir(destinate_list):
# A list of files copied to a directory
           for file_name in file_list:
                print('Copy '+file_name+' to '+destinate_list)
                shutil.copy(file_name,destinate_list)

        elif file_type == 'str' and destinate_type == 'str':
# Copy one file
            shutil.copy(file_list,destinate_list)
        elif file_type == 'str' and destinate_type == 'list':
            multi_target_opt = raw_input("Copy one file to multiple targets. Are you sure? (y/n)\n")
            if multi_target_opt == 'y':
                for target_file_name in destinate_list:
                    print ('Copy '+ file_list+' to '+target_file_name)
                    shutil.copy(file_list,target_file_name)

        else:
            print ("Error occurs!Exit!")
            sys.exit(1)


def move(file_list,destinate_list='.'):
    ''' Move the files listed in the file_list to the destinate_list. Use searh() to determine
    the file_list'''
    print ('Copying files...')
    copy(file_list,destinate_list)
    remove_opt = raw_input('Delete the source files?(y/n)\n')
    if remove_opt == 'y':
        print('Deleting files...')
        clear(file_list)

    print('Moving files complete!')


def main():
     search()

if __name__ == "__main__":
    main()

其主要的任務是搜尋當前以及所有子目錄下的特定檔案,如同search()開頭所述,我們只要指定keyword,他就會將符合特徵的檔案列表傳回,我們將會利用這個列表來進行縮圖以及生成文字範例檔的工作,search()的用途當然不只是在縮圖,日後可以非常方便的用他來做大量處理檔案的工作。

jpg2rst/fig_tools.py

#!/usr/bin/env python
def resize(resolution,jpg_list):
    ''' Input the resolution referring to the maximal height and width of the resizing jpg files
    Return: resize_jpg_list (str list)
    Usage: resize_jpg(str/int/str_list resolution, str_list jpg_list)
    Example: resize_jpg(resolution=['640','800'],jpg_list=[])
    Resolution can be either integer, string, or a list of strings'''
    import subprocess, string, sys, os, shutil
    resize_jpg_list=list()
    if type(resolution).__name__ == 'int':
        resize_res_list=[str(resolution)]
    elif type(resolution).__name__ == 'str':
        resize_res_list=[resolution]
    elif type(resolution).__name__ == 'list':
        resize_res_list=resolution

    for resize_res in resize_res_list:
        if os.path.isdir(resize_res):
            print (resize_res+'/'+" directory exist! Cleaning it\n")
            shutil.rmtree(resize_res)

        print ("Making new directory: "+resize_res+'/ \n')
        os.mkdir(resize_res)
        for file_name in jpg_list:
            if file_name.find(resolution+'_') == -1:  #Detect existing resized jpg file
                resize_file_name=file_name.split('/')[0:-1]
                resize_file_name.append(resize_res+'/'+resize_res+'_'+file_name.split('/')[-1])
                resize_file_name = string.join(resize_file_name,'/')
                convert_command=['convert',file_name,'-colorspace','RGB','-filter','LanczosSharp','-distort','Resize',resize_res+'x'+resize_res,'-unsharp','1x0.55+1.5+0.002','-colorspace','sRGB','-border','10','-quality','95',resize_file_name]
                print(" ".join(convert_command)+"\n")
                cmd_status = subprocess.call(convert_command)
                if cmd_status != 0:
                    print('Subprocess.call failure! Exit now!\n')
                    sys.exit(1)

                resize_jpg_list.append(resize_file_name)


    resize_jpg_list.sort()
    return resize_jpg_list


def log(log_file,jpg_list):
    ''' Write a list of jpg file names to a log file
    Return: none
    Usage: fig_log(str log_file, str_list/str jpg_list)
    Example: fig_log(log_file='fig_list.log',jpg_list)'''
    import os
    log_file_obj = open(log_file,'w')
    if type(jpg_list).__name__ == 'str':
        file_list = [jpg_list]
    elif type(jpg_list).__name__ == 'list':
        file_list = jpg_list

    for file_name in file_list:
        log_file_obj.write(file_name+'\n')

    log_file_obj.close()
    print('Write log file to '+log_file+'\n')

def main():
    resize()

if __name__ == "__main__":
    main()

有了search()傳回的檔案列表,我們將其輸入至resize()這個函式裡,並指定圖形長與寬最大的解析度(例如800),他會偵測並將縮圖輸出到一個新的目錄(800/),同時也會自動略過已經縮圖過的圖檔,如果解析度的部份輸入none,則不會進行縮圖銳化的工作。

jpg2rst/rst_tools.py

#!/usr/bin/env python
def add_fig(fig_list):
    '''Form a template file in reST format and add the codes with the resized figures
    return rst_file (str), fig_num (int)
    usage: form_rst(str_list fig_list)
    example: form_rst(['fig1.jpg','fig2.jpg',...])'''
    import os
    import time
    from fnmatch import fnmatch
    time_label = time.strftime('%Y%m%d %H:%M:%S',time.localtime())
    try:
        rst_temp_file_obj = open('/'+os.getcwd().split('/')[1]+'/'+os.getcwd().split('/')[2]+'/.vim/template/temp_rst.txt','r')
        rst_slug = os.getcwd().split('/')[-1]
        rst_file = rst_slug+'.rst'
        jpg2rst_temp_file_obj = open(rst_file,'w')
        line_info = rst_temp_file_obj.readline()
        while line_info != '.\n':
            line_info = rst_temp_file_obj.readline()
            if fnmatch(line_info,'*slug:*'):
                jpg2rst_temp_file_obj.write('.. slug: '+rst_slug+'\n')
            elif fnmatch(line_info,'*data:*'):
                jpg2rst_temp_file_obj.write('.. data: '+time_label+'\n')
            elif fnmatch(line_info,'*description:*'):
                jpg2rst_temp_file_obj.write('.. description: Created at '+time_label+'\n')
            elif fnmatch(line_info,'*<body>*'):
                #Insert codes of resized figure here
                jpg2rst_temp_file_obj.write(line_info)
                fig_number = len(fig_list)
                for rst_figure in fig_list:
                    jpg2rst_temp_file_obj.write('\n.. figure:: '+rst_figure+'\n')
                    jpg2rst_temp_file_obj.write('   :target: '+rst_figure+'\n')
                    jpg2rst_temp_file_obj.write('   :align: center\n\n\n\n')
#                    jpg2rst_temp_file_obj.write('   :width: 640'+'\n\n')

            elif line_info == '.\n':
                print('\nMake '+rst_file+' complete\n')
            else:
                jpg2rst_temp_file_obj.write(line_info)


    finally:
        jpg2rst_temp_file_obj.close()
        rst_temp_file_obj.close()
        return rst_file


def main():
     add_fig()

if __name__ == "__main__":
    main()

resize()會輸出縮圖銳化後的檔案列表,我們可以進一步將其輸入到add_fig()函式裡,他會自動擷取vim的ReST範例檔,並且將所有縮圖的圖片連結加進去,例如

.. figure:: ../gallaries/640/640_01_P1370103_sharpen.jpg
   :target: ../gallaries/640/640_01_P1370103_sharpen.jpg
   :align: center

由於search()會自動依照檔案名稱排序,一個小技巧就是於檔名開頭加上01、02、03...等編號。

您可以將ReST範例檔儲存在~/.vim/template/temp_rst.txt檔案裡,有關vim的自動文件範例檔筆者會另外說明,簡單來說,他可以偵測您創造的文字檔是屬於哪種格式(C++, Python, Latex...等),然後利用對應的範例檔生成文件,是個非常強大且高效率的功能。

最後是jpg2rst.py這個程式,其實就是用來整合上面3個函式,讓我們的工作流程得以實現,裏面有些目錄的設定,可以依照需求修改;不難發現,任何一個函式都可以獨立運作,例如我們可以單獨使用resize()來測試縮圖銳化的參數,也可以用search()來蒐集任何檔案,或是用add_fig()來重整文章的圖片連結,除了幫我們省去不少縮圖銳化的功夫,更可以在其餘工作裡派上用場,等於是辛苦一次受用無窮的工具,當我們不斷進行例行性的操作時,一個良好的自動化工具可以大大提高工作效率,讓我們有更多時間陪陪家人,或是喝杯咖啡思考一下。

[1] http://www.imagemagick.org/script/binary-releases.php#iOS

Comments

Comments powered by Disqus
Creative Commons License © 2016 M43幸福之路/OASYS
Share