@@ -52,11 +52,36 @@ function convertImgToPicture(
5252 additionalAttrs : string = "" ,
5353) : string {
5454 const safeAlt = alt || "" ;
55- const safeAttrs = additionalAttrs && additionalAttrs . trim ( ) ? " " + additionalAttrs . trim ( ) : "" ;
55+ let safeAttrs = additionalAttrs && additionalAttrs . trim ( ) ? " " + additionalAttrs . trim ( ) : "" ;
56+ let pictureStyle = "" ;
57+
58+ // width 속성 처리: 퍼센트나 단위가 있는 경우 picture의 스타일로 이동하여 중첩 계산 방지
59+ const widthMatch = / w i d t h = [ " ' ] ( [ ^ " ' ] + ) [ " ' ] / i. exec ( safeAttrs ) ;
60+ if ( widthMatch ) {
61+ const widthVal = widthMatch [ 1 ] ;
62+ if ( widthVal . includes ( "%" ) || widthVal . includes ( "px" ) ) {
63+ pictureStyle = `width: ${ widthVal } ; display: inline-block;` ;
64+ // img 태그에서는 원본 width 속성을 제거하고 내부적으로 100%를 가지도록 함
65+ safeAttrs = safeAttrs . replace ( / w i d t h = [ " ' ] [ ^ " ' ] * [ " ' ] / gi, "" ) . trim ( ) ;
66+
67+ if ( safeAttrs . includes ( "style=\"" ) ) {
68+ safeAttrs = safeAttrs . replace ( / s t y l e = [ " ' ] ( [ ^ " ' ] * ) [ " ' ] / i, ( m , s ) => {
69+ const baseStyle = s . trim ( ) ;
70+ const separator = baseStyle && ! baseStyle . endsWith ( ";" ) ? ";" : "" ;
71+ return `style="${ baseStyle } ${ separator } width: 100%;"` ;
72+ } ) ;
73+ } else {
74+ safeAttrs += " style=\"width: 100%;\"" ;
75+ }
76+ } else {
77+ // 숫자만 있는 경우(HTML5 표준) px 제거 로직 유지
78+ safeAttrs = safeAttrs . replace ( / w i d t h = " ( \d + ) ( p x ) ? " / gi, "width=\"$1\"" ) ;
79+ }
80+ }
5681
5782 // 외부 URL이거나 svg, gif는 picture 태그로 변환하지 않음
5883 if ( src . startsWith ( "http" ) || src . endsWith ( ".svg" ) || src . endsWith ( ".gif" ) ) {
59- return `<img src="${ src } " alt="${ safeAlt } "${ safeAttrs } loading="lazy" />` ;
84+ return `<img src="${ src } " alt="${ safeAlt } "${ safeAttrs ? " " + safeAttrs : "" } loading="lazy" />` ;
6085 }
6186
6287 // 이미지 포맷별 경로 생성
@@ -82,13 +107,14 @@ function convertImgToPicture(
82107
83108 // 변환된 이미지가 없으면 원본만 사용
84109 if ( sources . length === 0 ) {
85- return `<img src="${ src } " alt="${ safeAlt } "${ safeAttrs } loading="lazy" />` ;
110+ return `<img src="${ src } " alt="${ safeAlt } "${ safeAttrs ? " " + safeAttrs : "" } loading="lazy" />` ;
86111 }
87112
88113 // picture 태그 생성 (원본을 최종 fallback으로 사용)
89- return `<picture>
114+ const pictureAttr = pictureStyle ? ` style="${ pictureStyle } "` : "" ;
115+ return `<picture${ pictureAttr } >
90116 ${ sources . join ( "\n " ) }
91- <img src="${ src } " alt="${ safeAlt } "${ safeAttrs } loading="lazy" />
117+ <img src="${ src } " alt="${ safeAlt } "${ safeAttrs ? " " + safeAttrs : "" } loading="lazy" />
92118</picture>` ;
93119}
94120
@@ -117,6 +143,7 @@ function processHtmlImages(html: string, markdownPath: string): string {
117143 . replace ( / s r c = [ " ' ] [ ^ " ' ] * [ " ' ] / gi, "" )
118144 . replace ( / a l t = [ " ' ] [ ^ " ' ] * [ " ' ] / gi, "" )
119145 . replace ( / l o a d i n g = [ " ' ] [ ^ " ' ] * [ " ' ] / gi, "" ) // loading은 우리가 추가할 것이므로 제거
146+ . replace ( / \s + / g, " " ) // 중복 공백 제거
120147 . trim ( ) ;
121148
122149 // 속성이 비어있거나 공백만 있으면 빈 문자열로
@@ -142,16 +169,23 @@ export function markdownPicturePlugin(md: MarkdownIt) {
142169 md . renderer . rules . image = ( tokens , idx , options , env , self ) => {
143170 const token = tokens [ idx ] ;
144171 const srcIndex = token . attrIndex ( "src" ) ;
172+ const altIndex = token . attrIndex ( "alt" ) ;
145173
146174 if ( srcIndex < 0 ) {
147175 return defaultRender ( tokens , idx , options , env , self ) ;
148176 }
149177
150178 const src = token . attrs ! [ srcIndex ] [ 1 ] ;
151- const alt = token . content ;
179+ const alt = altIndex >= 0 ? token . attrs ! [ altIndex ] [ 1 ] : token . content || "" ;
152180 const markdownPath = env . path || "" ;
153181
154- return convertImgToPicture ( src , alt , markdownPath ) ;
182+ // src, alt를 제외한 나머지 속성들 추출 (width, height 등)
183+ const additionalAttrs = token . attrs !
184+ . filter ( ( [ name ] ) => name !== "src" && name !== "alt" )
185+ . map ( ( [ name , value ] ) => `${ name } ="${ value } "` )
186+ . join ( " " ) ;
187+
188+ return convertImgToPicture ( src , alt , markdownPath , additionalAttrs ) ;
155189 } ;
156190
157191 // 2. HTML inline 이미지 (<img>) 처리
0 commit comments