PhotoShop也可以轻松些
2015 年 02 月 11 日
other

    昨日, 一老友突然发个信息问在没, 有事, 当时一紧张, 想到底应该说在还是不在呢?接着又来了几句说会不会PS, 还好这位朋友没有问我会不会修电脑, 心理顿时欣慰了。 就勉强问要P啥(心理完全没底, 几年没安装过PS了, 就大学学了几个皮毛), 沟通后, 知道是要修改图片上的文字, 感觉还好, 瞎搞瞎搞就能弄出来了。

  • 图片样例大概这样:

  • 一张图大概7, 8个地方需要修改, 修改下来已经累觉不爱了, 特别是字体大小, 位置, 颜色等, 太费时间了。 被告知会有50, 60个需要修改的, 顿时感觉压力山大了, 心理想PhotoShop会不会有什么机制能支持这种重复 繁杂的工作呢?了解到PhotoShop是支持脚本的, 感觉看到一些希望了。

  • PhotoShop支持三种脚本语言


  • PhotoShop DOM结构

  • PhotoShop DOM结构很类似于HTML的DOM结构, 理解起来也比较容易
  • 脚本编写(JavaScript)

  • 现在把主要的工作分成: 擦除需要修改的区域和填写对应的文本到擦除区域, 于是写了这两个这样的函数
  • // 当前选中的文档
    var doc = app.activeDocument;
    
    // 白色
    var white = new SolidColor();
    white.rgb.red = 255;
    white.rgb.green = 255;
    white.rgb.blue = 255;
    
    // 文本颜色
    var textColor = new SolidColor();
    textColor.rgb.red = 47;
    textColor.rgb.green = 48;
    textColor.rgb.blue = 48;
    
    // 擦除某个区域
    var erase = function(pos){
        doc.selection.select(pos);  //选择文档的某个区, 分别为左上, 右上, 右下, 左下四个点的(x, y)坐标
        doc.selection.fill(white);  //填充为白色
        doc.selection.deselect();   //取消选择
    }
    
    // 填充文本
    var text = function(pos, font, color, size, contents){
        var eraseLayer = doc.artLayers.add();   // 添加图层
        eraseLayer.kind = LayerKind.TEXT;       // 设置图层为文本类型
        var textItem = eraseLayer.textItem;
        textItem.font = font;                   // 字体, 如 "SimSun"(宋体)
        textItem.color = color;
        textItem.size = size;                   // 字体大小(points)
        textItem.contents = contents;           // 文本内容
        textItem.position = pos;                // 文本位置
        doc.mergeVisibleLayers();               // 合并文档所有可见的图层
    }
    
    // 假如我们要修改某个区域, 则可以定义一个函数
    var patchPayDate = function(){
        erase(Array(Array(930, 125), Array(1400, 125), Array(1400, 175), Array(930, 175)));
        text(Array(940, 170), "SimSun", textColor, 11, payDate);
    }
    patchPayDate();
            

    1. 中文支持: 必须设置字体, 否则中文乱码textItem.font="SimSum"
    2. 执行下次操作前合并图层doc.mergeVisibleLayers(), 否则不能继续进行。
    3. PS中的矩阵区域表示为: Array(Array(930, 125), Array(1400, 125), Array(1400, 175), Array(930, 175))
    4. 文本区域和擦除区域不太吻合: 按理擦除区域即为之后的填充区域, 但实际会有像素偏差, 需要调整。

  • 处理Excel为JSON

  • # 主要代码
    
    import sys
    import xlrd, json
    import math, random
    from xlrd import xldate_as_tuple
    
    def openExcel(file="file.xls"):
        try:
            return xlrd.open_workbook(file)
        except Exception, e:
            print str(e)
    
        """
        read a sheet of xls to json
        """
        def read2json(file="file.xls", sheetIndex=0, headerIndex=0, startRow=1):
            excel = openExcel(file);
            sheet = excel.sheets()[sheetIndex];
            nrows = sheet.nrows
            colnames = sheet.row_values(headerIndex);
            facets = []
            for rownum in range(startRow, nrows):
                row = sheet.row_values(rownum)
                if row:
                facet = {}
                for i in range(len(colnames)):
                    facet[colnames[i]] = row[i]
                facets.append(facet)
            return json.dumps(facets, ensure_ascii=False, indent=2)
        

    1. 日期处理: 读取excel时, 读取日期类型后为浮点数, 需要引入xldate_as_tuple进行处理

    # 第二个参数表示起始时间: 0: 1900; 1: 1904
    # 返回(年, 月, 日, 时, 分, 秒)
    dateTuple = xldate_as_tuple(date, 0);
    year = dateTuple[0]
    month = dateTuple[1]
        

    2. 默认Python使用Ascii进行IO解码, 需要运行时设置

    reload(sys)
    sys.setdefaultencoding('utf-8')
        

    3. json dump时, 会将中文编码为Ascii, 也需要设置参数json.dumps(facets, ensure_ascii=False, indent=2)

  • 完善JavaScript脚本

  • // excel数据
    var bills = [{
        "payNo": "14009052048",
        "businessCategory": "...",
        "clerkNo": "00023",
        "payerBank": "...",
        "payDate": "2014年09月09日",
        "tradeCode": "52110",
        "payNote": "...",
        "printDate": "2014年02月05日",
        "payAmount1": "壹万壹仟伍佰贰拾元",
        "payAmount2": "11,520.00元",
        "printCode": "4N1HTDSPVX2",
        "payerNo": "...",
        "payerName": "..."
    },
    ...];
    
    var doc = app.activeDocument;
    
    // 修复类
    var Patch = function(){
        var that = {};
    
        var white = new SolidColor();
        white.rgb.red = 255;
        white.rgb.green = 255;
        white.rgb.blue = 255;
    
        var textColor = new SolidColor();
        textColor.rgb.red = 47;
        textColor.rgb.green = 48;
        textColor.rgb.blue = 48;
    
        var erase = function(pos){
            doc.selection.select(pos);
            doc.selection.fill(white);
            doc.selection.deselect();
        }
    
        var text = function(pos, font, color, size, contents){
            var eraseLayer = doc.artLayers.add();
            eraseLayer.kind = LayerKind.TEXT;
            var textItem = eraseLayer.textItem;
            textItem.font = font;
            textItem.color = color;
            textItem.size = size;
            textItem.contents = contents;
            textItem.position = pos;
            doc.mergeVisibleLayers();
        }
    
        // 修复日期
        var patchPayDate = function(payDate){
            erase(Array(Array(930, 125), Array(1400, 125), Array(1400, 175), Array(930, 175)));
            text(Array(940, 170), "SimSun", textColor, 11, payDate);
        }
    
        // ...其他修复功能
    
        var patch = function(b){
            if (!b) return;
    
            if (b.payDate) patchPayDate(b.payDate);
    
            // ...其他修复操作
        }
        that.patch = patch;
    
        return that;
    
    }();
    
    // 图片保存
    var Saver = function(){
        var that = {};
    
        // 图片质量
        var jpegOptions = new JPEGSaveOptions();
        jpegOptions.quality = 8;
    
        var saveAs = function(path){
            doc.saveAs(new File(path), jpegOptions);
        }
        that.saveAs = saveAs;
    
        return that;
    
    }();
    
    // go
    for (var i = 0; i<bills.length; i++){
        Patch.patch(bills[i]);
        Saver.saveAs("~/temp/" + bills[i].payerName + ".jpg");
    }
        
  • 脚本执行

  • 打开PhotoShop及其对应的图片文档, 选择执行的脚本即可
  • 这样基本不需要操作就能完成PS了, 具体可参考 文档

好人,一生平安。