HSPポータル
サイトマップ お問い合わせ


HSPTV!掲示板


未解決 解決 停止 削除要請

2025
1210
usagiPSDのレイヤーを読み込むモジュールを作ってみました0解決


usagi

リンク

2025/12/10(Wed) 15:45:11|NO.104475

こんにちわ。
PSDのレイヤーを読み込むモジュールを作ってみました。(現状はArtlet2Dに依存)
私はPhotoshopを持っていない為、Gimpでエクスポートしたpsdで確認してます。
もっとこうする方が良い、これは良くないなどご意見頂けると嬉しいです。
改変、組み込みもご自由にどうぞ。
※レイヤー情報ってなにか使い道あったりするんですかね。。ツールとかデスクトップマスコットとか?

; ========================================================= ; PSD_簡易読み込みくん author: usagi ; ========================================================= #ifndef __PSD__ #define __PSD__ #include "a2d.hsp" #module PSD_FILE m_count, m_width, m_height, m_name, m_blend, m_type, m_left, m_top, m_right, m_bottom, m_opacity, m_flags #defcfunc local int16 int _i return _i<<16>>16 #defcfunc local wpeekB var _buf, int _ofs __v = wpeek(_buf, _ofs) return __v<<8 | __v>>8 & $FFFF #defcfunc local lpeekB var _buf, int _ofs __v = lpeek(_buf, _ofs) return __v<<24 | (__v<<8&$ff0000) | (__v>>8&$ff00) | (__v>>24&$ff) #defcfunc local padded int _num, int _bytes __mod = _bytes-_num\_bytes if __mod { __res = _num+__mod } else { __res = _num } return __res #defcfunc local pascalStr var _buf, int _ofs sdim __s, 256 : __n = peek(_buf, _ofs) : __i = _ofs+1 repeat __n : poke __s, cnt, peek(_buf, __i+cnt) : loop mref __st, 64 : __st = padded(__n, 4) return __s #defcfunc local pascalStrU16 var _buf, int _ofs sdim __s, 256 : __n = lpeekB(_buf, _ofs) : __i = _ofs+4 repeat __n : wpoke __s, cnt*2, wpeekB(_buf, __i+cnt*2) : loop __s = cnvwtos(__s) mref __st, 64 : __st = padded(__n, 4) return __s #defcfunc local keycode4 var _buf, int _ofs __s = " " : lpoke __s, 0, lpeek(_buf, _ofs) return __s #deffunc local unpackbits array _out, var _in, int _h, int _id __c = 16 - _id * 8 ; Writing color bit (AARRGGBB) __i = 2 * _h ; Skip (2byte * height) __j = 0 ; Start value for writing while __i < varsize(_in) ; RLE compression __n = peek(_in, __i) : __i++ ; Header byte if __n >= 128 { ; repeated byte __b = peek(_in, __i)<<__c : repeat 257-__n : _out.__j |= __b : __j++ : loop : __i++ } else { ; literal bytes repeat __n+1 : _out.__j |= (peek(_in, __i)<<__c) : __j++ : __i++ : loop } wend return ; ★Getter ------------------------------ #modcfunc psdWidth return m_width #modcfunc psdHeight return m_height #modcfunc psdCount return m_count #modcfunc psdName int _idx return m_name._idx #modcfunc psdBlend int _idx return m_blend._idx #modcfunc psdType int _idx return m_type._idx #modcfunc psdLeft int _idx return m_left._idx #modcfunc psdTop int _idx return m_top._idx #modcfunc psdRight int _idx return m_right._idx #modcfunc psdBottom int _idx return m_bottom._idx #modcfunc psdOpacity int _idx return m_opacity._idx #modcfunc psdFlags int _idx return m_flags._idx #modfunc psdSetFlags int _idx, int _flags m_flags._idx = _flags : return #modfunc psdSetFolder int _idx, int _flags if psdIsFolder(thismod, _idx) { if _flags { m_type._idx == -1 } else { m_type._idx == -2 } } : return #modcfunc psdIsLayer int _idx return m_type._idx >= 0 #modcfunc psdIsFolder int _idx return m_type._idx == -1 || m_type._idx == -2 #modcfunc psdIsFolderOpen int _idx return m_type._idx == -1 #modcfunc psdIsDivider int _idx return m_type._idx == -3 #modcfunc psdIsVisible int _idx return (m_flags._idx & 2) == 0 ; ★PSDファイル読み込み ファイル名, イメージid ;------------------------------------------------ #define global psdLoad(%1,%2,%3) newmod %1, PSD_FILE : _psdload %1, %2, %3 #modfunc _psdLoad str _file, int _img_id assert _img_id >= 0 exist _file : if strsize == -1 : return -1 sdim buf, strsize : bload _file, buf ; References: Adobe Photoshop File Formats Specification ; https://www.adobe.com/devnet-apps/photoshop/fileformatashtml/ ; File Header Section ;------------------------------------------------ if keycode4(buf, 0) != "8BPS" : return -1 ; Signature if wpeekB(buf, 4) != 1 : return -1 ; Version (1 only) if wpeekB(buf, 24) != 3 : return -1 ; Color mode (RGB only) if lpeekB(buf, 26) != 0 : return -1 ; Color Mode Data Section is Not Supported idx = 34 + lpeekB(buf, 30) ; Skip Image Resources Section m_height = lpeekB(buf, 14) ; Height m_width = lpeekB(buf, 18) ; Width ; Layer and Mask Information Section ;------------------------------------------------ idx+=4 ; Skip Section Length ; + Layer info ---------------------------------- idx+=4 ; Skip Section Length m_count = abs(int16(wpeekB(buf, idx))) : idx+=2 ; Layer Count sdim m_name, 255, m_count sdim m_blend, 4, m_count dim m_type, m_count dim m_left, m_count dim m_top, m_count dim m_right, m_count dim m_bottom, m_count dim m_opacity, m_count dim m_flags, m_count dim layer_chid, m_count, 4 dim layer_chlen, m_count, 4 dim layer_sct, m_count ; ++ Layer records ------------------------------ repeat m_count : i = cnt m_top.i = lpeekB(buf, idx) : idx+=4 ; Top m_left.i = lpeekB(buf, idx) : idx+=4 ; Left m_bottom.i = lpeekB(buf, idx) : idx+=4 ; Bottom m_right.i = lpeekB(buf, idx) : idx+=4 ; Right layer_ch.i = wpeekB(buf, idx) : idx+=2 ; Channel count repeat layer_ch.i ; Channel information layer_chid.i.cnt = int16(wpeekB(buf, idx)) : idx+=2 ; id layer_chlen.i.cnt = lpeekB(buf, idx) : idx+=4 ; length loop idx+=4 ; Skip Blend mode signature m_blend.i = keycode4(buf, idx) : idx+=4 ; Blend mode key m_opacity.i = peek(buf, idx) : idx+=1 ; Opacity idx+=1 ; Skip Clipping (0 = base, 1 = non-base) m_flags.i = peek(buf, idx) : idx+=1 ; Flags idx+=1 ; Skip Filler (0) edf_len = lpeekB(buf, idx) : idx+=4 ; Length of the extra data field next_idx = edf_len + idx ; +++ Layer mask / adjustment Layer data ---- idx+= lpeekB(buf, idx) +4 ; Skip ; +++ Layer blending ranges data ------------ idx+= lpeekB(buf, idx) +4 ; Skip ; +++ Layer name ---------------------------- m_name.i = pascalStr(buf, idx) : idx+=stat ; Name ; +++ Additional Layer info ----------------- repeat if keycode4(buf, idx) != "8BIM" { break } : idx+=4 ali_key = keycode4(buf,idx) : idx+=4 ali_len = lpeekB(buf,idx) : idx+=4 dupptr ali_data, varptr(buf)+idx, ali_len, 2 switch ali_key case "luni" ; Unicode layer name (Photoshop 5.0) m_name.i = pascalStrU16(ali_data, 0) : swbreak case "lsct" ; Section divider setting (Photoshop 6.0) m_type.i = -lpeekB(ali_data, 0) : swbreak default ; Not supported logmes strf("追加レイヤー情報をスキップしました。[Key: %s, Len: %d]", ali_key, ali_len) : swbreak swend idx+= ali_len loop idx = next_idx loop ; ++ Channel image data ------------------------- img_num = _img_id repeat m_count : i = cnt if m_type.i == 0 { ; Read image m_type.i = img_num : img_num++ alCreateImage m_type.i, m_right.i - m_left.i, m_bottom.i - m_top.i alGetBitmapVData ps, pv repeat layer_ch.i chimg_comp = wpeekB(buf, idx) dupptr chimg_data, varptr(buf)+idx+2, layer_chlen.i.cnt-2, 2 idx += layer_chlen.i.cnt if chimg_comp == 1 { ; RLE compressed the image data unpackbits pv, chimg_data, alGetHeight(), layer_chid.i.cnt } else { ; Not supported (0: Raw, 2 or 3: Zip) logmes "未サポートの圧縮です。" } loop } else { repeat layer_ch.i : idx += layer_chlen.i.cnt : loop } loop ; + Global layer mask info ---------------------- ; Image Data Section ;------------------------------------------------ sdim buf return img_num #global #endif ; ★ここからテスト★ #uselib "user32.dll" ; マウス位置取得用 #func ScreenToClient "ScreenToClient" int, var #define boxs(%1,%2,%3,%4) line (%3),(%2),(%1),(%2):line (%3),(%4):line (%1),(%4):line (%1),(%2) #define SCR_SIZE 512 #define FONT_SIZE 24 screen 0, SCR_SIZE, SCR_SIZE : font "", FONT_SIZE ; 背景の市松模様を作成 buffer 1, ginfo_sy, ginfo_sx : rgbcolor $dddddd : div = 16 repeat ginfo_sy/div : y = cnt : repeat ginfo_sx/div : x = cnt if (x+y)\2=0 { boxf x*div, y*div, x*div+div, y*div+div } loop : loop : gsel 0 ; ★PSD読み込み dialog "psd",16,"PSDファイル" : psdload psd, refstr, 0 : layer_ofs = 0,0 *MAIN ; 処理 ------------------------------------------ cursor = ginfo_mx, ginfo_my : ScreenToClient hwnd, cursor : stick pad, 512 ; ★左クリックで表示やフォルダ折り畳み切り替え if cur_layer>-1 && pad==256 { if cursor.0<FONT_SIZE { psdSetFlags psd, cur_layer, psdFlags(psd, cur_layer)^2 } else { psdSetFolder psd, cur_layer, psdIsFolderOpen(psd, cur_layer)^1 } } ; ★右クリックで画像移動 click_r = (click_r<<1 | pad==512) & 3 if click_r == 1 : old_cursor = cursor.0, cursor.1 if click_r == 3 : repeat 2 : layer_ofs.cnt -= old_cursor.cnt - cursor.cnt : loop : old_cursor = cursor.0, cursor.1 if click_r == 2 : layer_ofs = limit(layer_ofs.0, -psdWidth(psd), psdWidth(psd)), limit(layer_ofs.1, -psdHeight(psd), psdHeight(psd)) ; ★ホイールでレイヤー情報の表示位置移動 _mousew = mousew : tree_pos = limit(tree_pos+FONT_SIZE*((_mousew>0)-(_mousew<0)), -tree_cnt*FONT_SIZE+FONT_SIZE,0) ; 階層情報を求める level = 0 repeat psdCount(psd) : i = cnt if psdIsFolder(psd, i) : level-- ; フォルダなら階層を下げる if psdIsDivider(psd, i) : level++ ; セクション区切りなら階層を戻してスキップ psd_level.i = level loop ; 階層の表示状態を求める repeat psdCount(psd) : i = cnt psd_hidden.i = psdIsVisible(psd, i) if psdIsFolder(psd, i) == 0 : continue target_level = psd_level.i + 1 repeat i, 1 : j = i - cnt if psdIsDivider(psd, j) && (target_level == psd_level.j) : break if (target_level <= psd_level.j) : psd_hidden.j &= psdIsVisible(psd, i) loop loop ; フォルダの折り畳み状態を求める repeat psdCount(psd) : i = cnt psd_fold.i = 0 if psdIsFolder(psd, i) == 0 : continue if psdIsFolderOpen(psd, i) : continue target_level = psd_level.i + 1 repeat i, 1 : j = i - cnt if psdIsDivider(psd, j) && (target_level == psd_level.j) : break if (target_level <= psd_level.j) : psd_fold.j = 1 loop loop ; 描画 ------------------------------------------ redraw 0 : gmode 0, ginfo_sx, ginfo_sy : pos 0, 0 : gcopy 1 ; ★レイヤー画像表示:PSDのレイヤー情報は最背面から記憶されています。 repeat psdCount(psd) : i = cnt if psdIsLayer(psd, i) == 0 : continue if psd_hidden.i == 0 : continue alCopyModeAlpha 255.0/psdOpacity(psd, i) alCopyImageToScreen psdType(psd, i), 0, psdLeft(psd, i)+layer_ofs.0, psdTop(psd, i)+layer_ofs.1 loop ; ★レイヤー階層表示:最前面からの方が分かりやすい為、逆順で処理します。 pos 0, tree_pos cur_layer = -1 : target_level = -1 : tree_cnt = 0 repeat psdCount(psd), 1 : i = psdCount(psd) - cnt if psd_fold.i : continue if psdIsDivider(psd, i) : continue ; カーソル if (ginfo_cy<cursor.1) && (cursor.1<ginfo_cy+FONT_SIZE) && (0<cursor.0) && (cursor.0<ginfo_winx) { cur_layer = i } ; 情報表示 rgbcolor $111111 if psdIsVisible(psd, i) { mes "○", 1 : if psd_hidden.i == 0 { pos 0 : mes "/", 1 } } else { mes "−", 1 } pos ginfo_cx+psd_level.i*FONT_SIZE if psdIsLayer(psd, i) { ; サムネ w = psdRight(psd, i)-psdLeft(psd, i) : h = psdBottom(psd, i)-psdTop(psd, i) if w > h { s = 1.0, double(h)/w } else { s = double(w)/h, 1.0 } ofs = (1.0-s.0) * FONT_SIZE, (1.0-s.1) * FONT_SIZE, double(ginfo_cx), double(ginfo_cy) gzoom FONT_SIZE, FONT_SIZE, 1,,,FONT_SIZE*4, FONT_SIZE*4 alStretchImageToScreen psdType(psd, i), 0, 0,0,w,h, ofs.2+ofs.0, ofs.3+ofs.1, s.0*FONT_SIZE, s.1*FONT_SIZE boxs ofs.2, ofs.3, ofs.2+FONT_SIZE, ofs.3+FONT_SIZE pos ginfo_cx+FONT_SIZE } else { if psdIsFolderOpen(psd, i) { mes "∨", 1 } else { mes ">", 1 } } mes psdName(psd, i) pos 0 : tree_cnt++ loop redraw 1 : await 16 goto *MAIN



この記事に返信する


記事削除

記事NO.パスワード
(質問が解決したスレッドは他の利用者に活用してもらうため、削除しないようお願いします)

NO.104475への返信

マスコット

好きなマスコットを選んでください。

名前

e-mail
HOME
  1. 初めて利用する方は、HSP3掲示板の使い方をお読みください。
  2. 不要部分の多い長いスクリプトの投稿は ご遠慮ください。
  3. 書き込みは自動改行されません。適度に改行を入れてください。
  4. スクリプトは小文字の<pre>〜</pre>で囲むと見やすく表示できます。

削除用パスワード

エラー発生時、再送信すると二重送信になることがあります。
回答が得られたら、お礼書き込み時に[解決]チェックしてください。
SPAM防止のためURLから始まる文章は投稿できません。
SPAM防止のため英文字のみの本文を投稿することはできません。

ONION software Copyright 1997-2025(c) All rights reserved.