LoginSignup
0
1

More than 1 year has passed since last update.

Photoshop 形式のファイルから RichText を取り出して HTML と CSS に変換する - 前編

Last updated at Posted at 2021-10-26

本稿の目的

どうも、フロントエンドエンジニアです。
(たまにバックもやります)

さて、HTML コーダーなどをやっていると
「テキストでコーディングしてください!」という依頼を受けることがたまにあります。

以下のような RichText ですが、普通は画像化したほうが早いです。
sample.png
sample_ja.psd

とはいえ、お客様のご要望であればテキスト化します。
これを HTML と CSS で表現すると、以下のようなコードになります。

<p class="text1"><span>100本<small></small>解説動画</span><span>6つ<small></small>豪華特典</span><br>
さらに講師が<span>あなた<small></small><strong>徹底</strong>サポート!</span></p>

<style>
@import url('https://fonts.googleapis.com/css2?family=Noto+Sans+JP:wght@700&display=swap');

.text1 {
    color: #242424;
    font-family: 'Noto Sans JP';
    font-size: 40px;
    line-height: 60px;
}

.text1 span {
    color: #d92367;
    font-size: 50px;
}

.text1 small {
    font-size: 40px;
}

.text1 strong {
    color: #ff9900;
    font-weight: bold;
    text-decoration: underline;
}
</style>

(自分なら)軽く2-3分はかかる作業です。

スニペット化したら幾分、高速化できそうですが
それでも時間はかかりますし、数が少ないならまだしも
ランディングページともなると、RichText が至る所に存在します。

これを一瞬で作ることができたなら・・・という記事です。
(実際のスクリプトは後編へ)

試してみたこと

1) Photoshop Script - TextExportToCSV

テキストレイヤーからテキストと、最初の文字のスタイルを CSV に書き出してくれます。
ただ、後続の RichText に対しては何もしてくれません。
全部は試してませんが、Photoshop Script だとこれが限界かも?

2) Node.js - psd

PSD ファイルを食わせると中身をパースしてくれる優れものです。
が、今回の記事では残念ながら不採用となりました。

一応、以下の手順を Windows で試してみました。
(ちなみに 2021/10/26 現在、最新版の psd.js@3.3.0 はバグのため fromFile ないよと言われて続行不可。3.2.0 へダウングレードしてます)

  • Node.js をインストール
  • mkdir %USERPROFILE%¥Desktop¥sample
  • cd %USERPROFILE%¥Desktop¥sample
  • npm install psd@3.2.0
  • 以下の index.js を sample フォルダに保存
index.js
let psd = require('psd').fromFile('sample.psd');
psd.parse();
let data = psd.tree().export();
console.dir(data, {depth: null});
  • PSD ファイルを sample フォルダに突っ込む
  • node index.js
{
  children: [
    {
      type: 'layer',
      visible: true,
      opacity: 1,
      blendingMode: 'normal',
      name: 'text1',
      left: 20,
      right: 779,
      top: 25,
      bottom: 164,
      height: 139,
      width: 759,
      mask: {},
      text: {
        value: '100本の解説動画と6つの豪華特典、\rさらに講師があなたを徹底サポート!',
        font: {
          name: 'KozGoPr6N-Heavy',
          sizes: [
            50, 50, 40, 50, 40, 50,
            40, 50, 40, 50, 40, 50,
            50
          ],
          colors: [
            [ 217, 35, 103, 255 ],
            [ 217, 35, 103, 255 ],
            [ 217, 35, 103, 255 ],
            [ 217, 35, 103, 255 ],
            [ 36, 36, 36, 255 ],
            [ 217, 35, 103, 255 ],
            [ 217, 35, 103, 255 ],
            [ 217, 35, 103, 255 ],
            [ 36, 36, 36, 255 ],
            [ 217, 35, 103, 255 ],
            [ 217, 35, 103, 255 ],
            [ 255, 153, 0, 255 ],
            [ 217, 35, 103, 255 ]
          ],
          alignment: [ 'center', 'center' ]
        },
        left: 0,
        top: 0,
        right: 0,
        bottom: 0,
        transform: { xx: 1, xy: 0, yx: 0, yy: 1, tx: 407, ty: 65.36346435546875 }
      },
      image: {}
    },
  ],
  document: {
    width: 800,
    height: 180,
    resources: { layerComps: [], guides: [], slices: [] }
  }
}

上記が psd.js で得られた結果ですが、
テキスト本文及び、スタイル毎のサイズと色は判るものの、どこからどこまでがこのサイズとこの色で〜という情報は一切取得できてません。いや、欲しい情報はポジションなので非常に惜しい!

3) Python - psd-tools

Python のパッケージで、こちらも PSD ファイルをパースしてくれますが
psd.js よりもさらにディープに取得してくれます。
今回の記事ではこちらを採用しました。

こちらも手順を Windows で試してみました。
途中、pip コマンド実行中に Microsoft Visual C++ 14.0 is required. と何故か怒られてしまったので
「Microsoft Visual C++ 14.0 or greater is required.」が出た場合の対処方法
を参考に対処したところ無事、解決しました。

  • Python3 をインストール
  • pip install psd-tools
  • mkdir %USERPROFILE%¥Desktop¥sample
  • cd %USERPROFILE%¥Desktop¥sample
  • 以下の index.py を sample フォルダに保存
index.py
from psd_tools import PSDImage

psd = PSDImage.open('sample.psd')
for layer in list(psd.descendants()):
    if layer.kind == 'type':
        print(layer.engine_dict)
  • PSD ファイルを sample フォルダに突っ込む
  • python index.py
{
  'Editor': {
    'Text': '100本の解説動画と6つの豪華特典、\rさらに講師があなたを徹底サポート!\r'
  },
  'ParagraphRun': {
    'DefaultRunData': {
      'ParagraphSheet': {
        'DefaultStyleSheet': 0,
        'Properties': {}
      },
      'Adjustments': {
        'Axis': [1.0, 0.0, 1.0],
        'XY': [0.0, 0.0]
      }
    },
    'RunArray': [{
      'ParagraphSheet': {
        'DefaultStyleSheet': 0,
        'Properties': {
          'Justification': 2,
          'FirstLineIndent': 0.0,
          'StartIndent': 0.0,
          'EndIndent': 0.0,
          'SpaceBefore': 0.0,
          'SpaceAfter': 0.0,
          'AutoHyphenate': False,
          'HyphenatedWordSize': 6,
          'PreHyphen': 2,
          'PostHyphen': 2,
          'ConsecutiveHyphens': 8,
          'Zone': 36.0,
          'WordSpacing': [0.8, 1.0, 1.33],
          'LetterSpacing': [0.0, 0.0, 0.0],
          'GlyphSpacing': [1.0, 1.0, 1.0],
          'AutoLeading': 1.75,
          'LeadingType': 1,
          'Hanging': False,
          'Burasagari': False,
          'KinsokuOrder': 0,
          'EveryLineComposer': False
        }
      },
      'Adjustments': {
        'Axis': [1.0, 0.0, 1.0],
        'XY': [0.0, 0.0]
      }
    }, {
      'ParagraphSheet': {
        'DefaultStyleSheet': 0,
        'Properties': {
          'Justification': 2,
          'FirstLineIndent': 0.0,
          'StartIndent': 0.0,
          'EndIndent': 0.0,
          'SpaceBefore': 0.0,
          'SpaceAfter': 0.0,
          'AutoHyphenate': False,
          'HyphenatedWordSize': 6,
          'PreHyphen': 2,
          'PostHyphen': 2,
          'ConsecutiveHyphens': 8,
          'Zone': 36.0,
          'WordSpacing': [0.8, 1.0, 1.33],
          'LetterSpacing': [0.0, 0.0, 0.0],
          'GlyphSpacing': [1.0, 1.0, 1.0],
          'AutoLeading': 1.75,
          'LeadingType': 1,
          'Hanging': False,
          'Burasagari': False,
          'KinsokuOrder': 0,
          'EveryLineComposer': False
        }
      },
      'Adjustments': {
        'Axis': [1.0, 0.0, 1.0],
        'XY': [0.0, 0.0]
      }
    }],
    'RunLengthArray': [19, 18],
    'IsJoinable': 1
  },
  'StyleRun': {
    'DefaultRunData': {
      'StyleSheet': {
        'StyleSheetData': {}
      }
    },
    'RunArray': [{
      'StyleSheet': {
        'StyleSheetData': {
          'Font': 1,
          'FontSize': 50.0,
          'FauxBold': False,
          'FauxItalic': False,
          'AutoLeading': False,
          'Leading': 80.0,
          'HorizontalScale': 1.0,
          'VerticalScale': 1.0,
          'Tracking': 0,
          'AutoKerning': False,
          'Kerning': 0,
          'BaselineShift': -4.11664,
          'FontCaps': 0,
          'FontBaseline': 0,
          'Underline': False,
          'Strikethrough': False,
          'Ligatures': True,
          'DLigatures': False,
          'BaselineDirection': 2,
          'Tsume': 0.0,
          'StyleRunAlignment': 2,
          'Language': 0,
          'NoBreak': False,
          'FillColor': {
            'Type': 1,
            'Values': [1.0, 0.85098, 0.13727, 0.40393]
          },
          'StrokeColor': {
            'Type': 1,
            'Values': [1.0, 0.93329, 0.93329, 0.93329]
          },
          'YUnderline': 1,
          'HindiNumbers': False,
          'Kashida': 1
        }
      }
    }, {

' 中略 '

    }],
    'RunLengthArray': [1, 3, 1, 4, 1, 2, 1, 4, 8, 3, 1, 2, 6],
    'IsJoinable': 2
  },
  'GridInfo': {
    'GridIsOn': False,
    'ShowGrid': False,
    'GridSize': 18.0,
    'GridLeading': 22.0,
    'GridColor': {
      'Type': 1,
      'Values': [0.0, 0.0, 0.0, 1.0]
    },
    'GridLeadingFillColor': {
      'Type': 1,
      'Values': [0.0, 0.0, 0.0, 1.0]
    },
    'AlignLineHeightToGridFlags': False
  },
  'AntiAlias': 4,
  'UseFractionalGlyphWidths': True,
  'Rendered': {
    'Version': 1,
    'Shapes': {
      'WritingDirection': 0,
      'Children': [{
        'ShapeType': 0,
        'Procession': 0,
        'Lines': {
          'WritingDirection': 0,
          'Children': []
        },
        'Cookie': {
          'Photoshop': {
            'ShapeType': 0,
            'PointBase': [0.0, 0.0],
            'Base': {
              'ShapeType': 0,
              'TransformPoint0': [1.0, 0.0],
              'TransformPoint1': [0.0, 1.0],
              'TransformPoint2': [0.0, 0.0]
            }
          }
        }
      }]
    }
  }
}

実際の出力には改行が一切なかったので、下記オンラインツールで整形しました。 https://lab.syncer.jp/Tool/JavaScript-PrettyPrint/

上記が psd-tools で得られた結果です。
目的のデータ RunLengthArray が入ってます。これならいけそう!

後編に続く。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1