posting_zon 3.111.003 → 3.111.005
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/posting_zon.rb +292 -128
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4cc0c303b04c477f8b1c6571e2c8d3c8c7d308b0ce981280e10cbcefb7cae0fb
|
4
|
+
data.tar.gz: 40f8a0b7550bceac056fcf9ed4ddc89dec4ce4cdffb072a718c737d5a5ef0407
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 971f7b80bcd49c588b1c40bacf0d1612f4ec6ce861bce0cc93ec75d9a539e71610da2ad58fa5013258db6f96598ed8f76ef5f2a0ee5af2361f866038279052cf
|
7
|
+
data.tar.gz: b693cc1459a8415fffed9f2397251627b188060a43dd9d9c68ff9f20f5262fa1dcc559a1687261f8d81bf61daf50479b90b001e3f3bdf68152ae65f607f07263
|
data/lib/posting_zon.rb
CHANGED
@@ -12984,82 +12984,109 @@ class Wordpress
|
|
12984
12984
|
|
12985
12985
|
|
12986
12986
|
|
12987
|
+
def crop_image_height_under_width(path, min_crop_ratio = 0.625)
|
12988
|
+
img = Magick::Image.read(path).first
|
12989
|
+
width = img.columns
|
12990
|
+
height = img.rows
|
12991
|
+
|
12992
|
+
|
12993
|
+
|
12994
|
+
if height > width
|
12995
|
+
min_height = (width * min_crop_ratio).to_i
|
12996
|
+
new_height = rand(min_height..width)
|
12997
|
+
crop_top = ((height - new_height) / 2.0).round
|
12998
|
+
|
12999
|
+
cropped = img.crop(0, crop_top, width, new_height, true)
|
13000
|
+
cropped.write(path)
|
13001
|
+
|
13002
|
+
|
13003
|
+
else
|
13004
|
+
|
13005
|
+
end
|
13006
|
+
end
|
13007
|
+
|
12987
13008
|
def auto_image(keyword = nil)
|
12988
|
-
|
12989
|
-
|
12990
|
-
|
12991
|
-
|
12992
|
-
|
12993
|
-
|
12994
|
-
|
12995
|
-
|
12996
|
-
|
12997
|
-
|
12998
|
-
|
12999
|
-
|
13009
|
+
# auto_image 내부에서만 crop 호출
|
13010
|
+
keyword ||= @keyword
|
13011
|
+
puts "키워드: #{keyword}"
|
13012
|
+
|
13013
|
+
client = HTTPClient.new
|
13014
|
+
client.default_header = {
|
13015
|
+
'User-Agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 '\
|
13016
|
+
'(KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36',
|
13017
|
+
'Accept' => 'application/json, text/javascript, */*; q=0.01',
|
13018
|
+
'Accept-Language' => 'en-US,en;q=0.9',
|
13019
|
+
'Referer' => "https://unsplash.com/s/photos/#{URI.encode_www_form_component(keyword)}",
|
13020
|
+
'X-Requested-With' => 'XMLHttpRequest'
|
13021
|
+
}
|
13000
13022
|
|
13001
|
-
|
13002
|
-
|
13003
|
-
|
13023
|
+
retry_count = 0
|
13024
|
+
max_retries = 10
|
13025
|
+
results = []
|
13004
13026
|
|
13005
|
-
|
13006
|
-
|
13007
|
-
|
13008
|
-
|
13009
|
-
|
13010
|
-
|
13011
|
-
|
13012
|
-
|
13013
|
-
|
13014
|
-
|
13027
|
+
begin
|
13028
|
+
page = rand(1..15)
|
13029
|
+
url = "https://unsplash.com/napi/search/photos?query=#{URI.encode_www_form_component(keyword)}&page=#{page}&per_page=20"
|
13030
|
+
puts "Request URL: #{url}"
|
13031
|
+
res = client.get(url)
|
13032
|
+
|
13033
|
+
unless res.status == 200
|
13034
|
+
puts "HTTP Error: #{res.status}"
|
13035
|
+
raise "HTTP Error"
|
13036
|
+
end
|
13015
13037
|
|
13016
|
-
|
13017
|
-
|
13018
|
-
|
13038
|
+
json = JSON.parse(res.body)
|
13039
|
+
results = json['results']
|
13040
|
+
mm = []
|
13019
13041
|
|
13020
|
-
|
13021
|
-
|
13022
|
-
|
13042
|
+
results.each do |photo|
|
13043
|
+
full_url = photo.dig('urls', 'full').to_s
|
13044
|
+
regular_url = photo.dig('urls', 'regular').to_s
|
13023
13045
|
|
13024
|
-
|
13025
|
-
|
13026
|
-
|
13027
|
-
|
13028
|
-
|
13046
|
+
if full_url.start_with?("https://images.unsplash.com/photo-") &&
|
13047
|
+
regular_url.include?("1080")
|
13048
|
+
mm << full_url
|
13049
|
+
end
|
13050
|
+
end
|
13029
13051
|
|
13030
|
-
|
13031
|
-
|
13032
|
-
|
13052
|
+
if mm.empty?
|
13053
|
+
raise "No matching image"
|
13054
|
+
end
|
13033
13055
|
|
13034
|
-
|
13035
|
-
|
13036
|
-
|
13056
|
+
selected_url = mm.sample
|
13057
|
+
destination_path = "./image/memory.png"
|
13058
|
+
Down.download(selected_url, destination: destination_path)
|
13059
|
+
puts "이미지 다운로드 완료: #{selected_url}"
|
13037
13060
|
|
13038
|
-
|
13039
|
-
|
13040
|
-
|
13041
|
-
|
13042
|
-
|
13043
|
-
|
13044
|
-
|
13045
|
-
|
13046
|
-
|
13047
|
-
|
13048
|
-
|
13049
|
-
|
13050
|
-
|
13051
|
-
|
13052
|
-
|
13053
|
-
|
13054
|
-
|
13055
|
-
|
13056
|
-
|
13061
|
+
# 오직 auto_image에서만 자르기 호출
|
13062
|
+
crop_image_height_under_width(destination_path)
|
13063
|
+
|
13064
|
+
rescue => e
|
13065
|
+
retry_count += 1
|
13066
|
+
puts "auto_image 에러: #{e.message} (재시도 #{retry_count}/#{max_retries})"
|
13067
|
+
sleep(3)
|
13068
|
+
if retry_count < max_retries
|
13069
|
+
retry
|
13070
|
+
else
|
13071
|
+
puts "최대 재시도 초과. 조건 무시하고 랜덤 이미지 다운로드 시도..."
|
13072
|
+
|
13073
|
+
if results && !results.empty?
|
13074
|
+
random_photo = results.sample
|
13075
|
+
fallback_url = random_photo.dig('urls', 'full')
|
13076
|
+
if fallback_url
|
13077
|
+
Down.download(fallback_url, destination: "./image/memory.png")
|
13078
|
+
puts "랜덤 이미지 다운로드 완료: #{fallback_url}"
|
13079
|
+
crop_image_height_under_width("./image/memory.png")
|
13057
13080
|
else
|
13058
|
-
|
13059
|
-
|
13060
|
-
end
|
13081
|
+
puts "랜덤 이미지 URL을 찾을 수 없습니다. 단색 배경 이미지 생성합니다."
|
13082
|
+
color_image
|
13061
13083
|
end
|
13084
|
+
else
|
13085
|
+
puts "이미지 결과가 없어 다운로드할 수 없습니다. 단색 배경 이미지 생성합니다."
|
13086
|
+
color_image
|
13062
13087
|
end
|
13088
|
+
end
|
13089
|
+
end
|
13063
13090
|
end
|
13064
13091
|
|
13065
13092
|
|
@@ -13071,79 +13098,187 @@ class Wordpress
|
|
13071
13098
|
|
13072
13099
|
def save_image
|
13073
13100
|
if @data['이미지설정']['이미지'].length == 0
|
13074
|
-
|
13101
|
+
return
|
13102
|
+
end
|
13103
|
+
|
13104
|
+
if @data['이미지설정']['순서사용'].checked?
|
13105
|
+
image_path = @data['이미지설정']['이미지'][@image_counter][2]
|
13106
|
+
@image_counter += 1
|
13107
|
+
if @image_counter > @data['이미지설정']['이미지'].length - 1
|
13108
|
+
@image_counter = 0
|
13109
|
+
end
|
13075
13110
|
else
|
13076
|
-
|
13077
|
-
|
13078
|
-
|
13079
|
-
|
13080
|
-
@image_counter = 0
|
13081
|
-
end
|
13082
|
-
else
|
13083
|
-
image_path = @data['이미지설정']['이미지'].sample[2]
|
13111
|
+
# 초기화가 안됐거나 다 썼으면 새롭게 섞는다
|
13112
|
+
@shuffled_images ||= []
|
13113
|
+
if @shuffled_images.empty?
|
13114
|
+
@shuffled_images = @data['이미지설정']['이미지'].shuffle
|
13084
13115
|
end
|
13085
|
-
|
13086
|
-
|
13116
|
+
|
13117
|
+
image_path = @shuffled_images.shift[2]
|
13087
13118
|
end
|
13119
|
+
|
13120
|
+
img = Magick::Image.read(image_path).first
|
13121
|
+
img.write('./image/memory.png')
|
13088
13122
|
end
|
13089
13123
|
|
13090
13124
|
def change_image_size(w)
|
13091
13125
|
img = Magick::Image.read('./image/memory.png').first
|
13092
13126
|
width = img.columns
|
13093
13127
|
height = img.rows
|
13094
|
-
|
13095
|
-
|
13096
|
-
|
13097
|
-
|
13098
|
-
|
13128
|
+
|
13129
|
+
# '원본'이 선택된 경우, 리사이징을 하지 않고 원본 이미지를 그대로 반환
|
13130
|
+
if w == 'original'
|
13131
|
+
return img # 원본 이미지 그대로 반환
|
13132
|
+
else
|
13133
|
+
begin
|
13134
|
+
if @data['image_type'][0].checked? or @data['image_type'][2].checked?
|
13135
|
+
# 비율을 맞추어 리사이징
|
13136
|
+
img.resize!(w, w * (height.to_f / width.to_f))
|
13137
|
+
else
|
13138
|
+
# 정사각형으로 리사이징
|
13139
|
+
img.resize!(w, w)
|
13140
|
+
end
|
13141
|
+
rescue
|
13142
|
+
img.resize!(w, w) # 예외 처리 시에도 리사이징
|
13099
13143
|
end
|
13100
|
-
rescue
|
13101
|
-
img.resize!(w, w)
|
13102
13144
|
end
|
13145
|
+
|
13146
|
+
# 리사이징된 이미지 저장
|
13103
13147
|
img.write('./image/memory.png')
|
13104
13148
|
end
|
13105
13149
|
|
13106
|
-
def
|
13107
|
-
|
13108
|
-
|
13109
|
-
|
13110
|
-
|
13111
|
-
|
13112
|
-
|
13113
|
-
|
13114
|
-
|
13115
|
-
|
13116
|
-
|
13117
|
-
|
13118
|
-
|
13119
|
-
|
13120
|
-
|
13121
|
-
|
13122
|
-
|
13123
|
-
|
13124
|
-
text.fill = '#000000'
|
13125
|
-
text.font = font2
|
13150
|
+
def wrap_text_to_fit(draw, text, max_width, max_height, font_path, initial_size)
|
13151
|
+
size = initial_size
|
13152
|
+
draw.font = font_path
|
13153
|
+
|
13154
|
+
loop do
|
13155
|
+
draw.pointsize = size
|
13156
|
+
words = text.chars # 글자 단위로 자름 (한국어 기준)
|
13157
|
+
lines = []
|
13158
|
+
line = ""
|
13159
|
+
|
13160
|
+
words.each do |char|
|
13161
|
+
test_line = line + char
|
13162
|
+
metrics = draw.get_type_metrics(test_line)
|
13163
|
+
if metrics.width > max_width
|
13164
|
+
lines << line
|
13165
|
+
line = char
|
13166
|
+
else
|
13167
|
+
line = test_line
|
13126
13168
|
end
|
13127
13169
|
end
|
13128
|
-
|
13129
|
-
|
13130
|
-
|
13131
|
-
|
13132
|
-
|
13133
|
-
|
13134
|
-
|
13135
|
-
|
13136
|
-
|
13137
|
-
|
13170
|
+
lines << line unless line.empty?
|
13171
|
+
|
13172
|
+
line_height = draw.get_type_metrics("가").height
|
13173
|
+
total_height = line_height * lines.size
|
13174
|
+
|
13175
|
+
# 세로 초과 안 하면 성공
|
13176
|
+
if total_height <= max_height || size <= 10
|
13177
|
+
return [lines.join("\n"), size]
|
13178
|
+
else
|
13179
|
+
size -= 2
|
13138
13180
|
end
|
13181
|
+
end
|
13182
|
+
end
|
13183
|
+
|
13184
|
+
|
13185
|
+
def image_text(text1, text2)
|
13186
|
+
begin
|
13187
|
+
color = File.open('./color.ini', 'r', encoding: 'utf-8').read.split("\n").map(&:strip).reject(&:empty?)
|
13188
|
+
font_files = Dir.entries('./fonts').select { |f| f.downcase.end_with?('.ttf') }
|
13189
|
+
font2 = './fonts/' + font_files.sample
|
13139
13190
|
|
13140
|
-
|
13191
|
+
# 랜덤 글자색 선택
|
13192
|
+
color2 = color.sample
|
13193
|
+
|
13194
|
+
# 헬퍼 함수: 색상 문자열 '#RRGGBB' -> [R,G,B] 배열로 변환
|
13195
|
+
def hex_to_rgb(hex)
|
13196
|
+
hex = hex.delete('#')
|
13197
|
+
[hex[0..1], hex[2..3], hex[4..5]].map { |c| c.to_i(16) }
|
13198
|
+
end
|
13199
|
+
|
13200
|
+
# 헬퍼 함수: 두 RGB 색상의 차이 계산 (간단한 유클리드 거리)
|
13201
|
+
def color_distance(c1, c2)
|
13202
|
+
Math.sqrt(
|
13203
|
+
(c1[0] - c2[0])**2 +
|
13204
|
+
(c1[1] - c2[1])**2 +
|
13205
|
+
(c1[2] - c2[2])**2
|
13206
|
+
)
|
13207
|
+
end
|
13208
|
+
|
13209
|
+
# 대비가 충분히 되는 테두리 색상 선택
|
13210
|
+
max_attempts = 10
|
13211
|
+
stroke_color = nil
|
13212
|
+
base_rgb = hex_to_rgb(color2)
|
13213
|
+
|
13214
|
+
max_attempts.times do
|
13215
|
+
candidate = color.sample
|
13216
|
+
candidate_rgb = hex_to_rgb(candidate)
|
13217
|
+
dist = color_distance(base_rgb, candidate_rgb)
|
13218
|
+
|
13219
|
+
# 거리(차이) 임계값 100 (0~441 범위) — 필요시 조절 가능
|
13220
|
+
if dist > 100
|
13221
|
+
stroke_color = candidate
|
13222
|
+
break
|
13223
|
+
end
|
13224
|
+
end
|
13225
|
+
stroke_color ||= '#000000' # 만약 충분히 다른 색 없으면 검정색 기본값
|
13226
|
+
|
13227
|
+
img = Magick::Image.read('./image/memory.png').first
|
13228
|
+
draw = Magick::Draw.new
|
13229
|
+
|
13230
|
+
raw_message = "#{text1}\n#{text2}".strip
|
13231
|
+
max_width = img.columns * 0.85
|
13232
|
+
max_height = img.rows * 0.6
|
13233
|
+
|
13234
|
+
begin
|
13235
|
+
size = rand(@data['이미지설정']['이미지글자1크기1'].text.to_i..@data['이미지설정']['이미지글자1크기2'].text.to_i)
|
13141
13236
|
rescue
|
13142
|
-
|
13143
|
-
|
13144
|
-
|
13237
|
+
size = 30
|
13238
|
+
end
|
13239
|
+
|
13240
|
+
wrapped_message, adjusted_size = wrap_text_to_fit(draw, raw_message, max_width, max_height, font2, size)
|
13241
|
+
|
13242
|
+
if @data['이미지설정']['글자그림자'].checked?
|
13243
|
+
img.annotate(draw, 0, 0, 2, 2, wrapped_message) do
|
13244
|
+
draw.gravity = Magick::CenterGravity
|
13245
|
+
draw.pointsize = adjusted_size
|
13246
|
+
draw.fill = '#000000'
|
13247
|
+
draw.font = font2
|
13248
|
+
end
|
13145
13249
|
end
|
13250
|
+
|
13251
|
+
if @data['이미지설정']['글자테두리'].checked?
|
13252
|
+
draw_stroke = Magick::Draw.new
|
13253
|
+
img.annotate(draw_stroke, 0, 0, 0, 0, wrapped_message) do
|
13254
|
+
draw_stroke.gravity = Magick::CenterGravity
|
13255
|
+
draw_stroke.pointsize = adjusted_size
|
13256
|
+
draw_stroke.fill = 'none'
|
13257
|
+
draw_stroke.stroke = stroke_color
|
13258
|
+
draw_stroke.stroke_width = rand(5..10)
|
13259
|
+
draw_stroke.font = font2
|
13260
|
+
end
|
13261
|
+
end
|
13262
|
+
|
13263
|
+
draw2 = Magick::Draw.new
|
13264
|
+
img.annotate(draw2, 0, 0, 0, 0, wrapped_message) do
|
13265
|
+
draw2.gravity = Magick::CenterGravity
|
13266
|
+
draw2.pointsize = adjusted_size
|
13267
|
+
draw2.fill = color2
|
13268
|
+
draw2.stroke = 'none'
|
13269
|
+
draw2.font = font2
|
13270
|
+
end
|
13271
|
+
|
13272
|
+
img.write('./image/memory.png')
|
13273
|
+
|
13274
|
+
rescue => e
|
13275
|
+
puts "이미지 폰트 불러오기 오류 재시도... (#{e.message})"
|
13276
|
+
sleep(3)
|
13277
|
+
retry
|
13146
13278
|
end
|
13279
|
+
end
|
13280
|
+
|
13281
|
+
|
13147
13282
|
|
13148
13283
|
def border()
|
13149
13284
|
color = File.open('./color.ini', 'r',:encoding => 'utf-8').read().split("\n")
|
@@ -13170,40 +13305,69 @@ class Wordpress
|
|
13170
13305
|
else
|
13171
13306
|
auto_image()
|
13172
13307
|
end
|
13173
|
-
|
13174
|
-
|
13308
|
+
|
13309
|
+
# '원본'을 포함한 이미지 크기 옵션 추가
|
13310
|
+
image_size = [480, 740, 650, 550, 480, 'original']
|
13175
13311
|
size = 0
|
13176
|
-
|
13312
|
+
|
13313
|
+
for n in 0..5 # 0부터 5까지 반복, '원본' 옵션까지 포함
|
13177
13314
|
if @data['image_size'][n].checked?
|
13178
|
-
if n ==
|
13179
|
-
size =
|
13315
|
+
if n == 5 # '원본'이 선택되었을 경우
|
13316
|
+
size = 'original'
|
13317
|
+
elsif n == 0
|
13318
|
+
size = image_size.sample # 랜덤 선택
|
13180
13319
|
else
|
13181
13320
|
size = image_size[n]
|
13182
13321
|
end
|
13183
13322
|
end
|
13184
13323
|
end
|
13324
|
+
|
13325
|
+
# '원본'이 선택되지 않았다면 기본 값 설정
|
13185
13326
|
if size == 0
|
13186
13327
|
size = 480
|
13187
13328
|
end
|
13329
|
+
|
13330
|
+
change_image_size(size) # 크기 변경 함수 호출
|
13188
13331
|
|
13189
|
-
change_image_size(size)
|
13190
13332
|
|
13191
13333
|
if @data['이미지설정']['필터사용'].checked?
|
13192
13334
|
image_filter()
|
13193
13335
|
end
|
13194
13336
|
|
13195
|
-
insert_image_text1 = ''
|
13196
|
-
insert_image_text2 = ''
|
13197
13337
|
if @data['이미지설정']['글자삽입1'].checked?
|
13198
|
-
|
13338
|
+
if @data['이미지설정']['이미지글자1'].length == 0
|
13339
|
+
image_text_path1 = ''
|
13340
|
+
else
|
13341
|
+
if @data['이미지설정']['글자랜덤'].checked?
|
13342
|
+
image_text_path1 = @data['이미지설정']['이미지글자1'].sample
|
13343
|
+
else
|
13344
|
+
image_text_path1 = @data['이미지설정']['이미지글자1'][@image_text_soon1]
|
13345
|
+
@image_text_soon1 += 1
|
13346
|
+
if @image_text_soon1 > @data['이미지설정']['이미지글자1'].length - 1
|
13347
|
+
@image_text_soon1 = 0
|
13348
|
+
end
|
13349
|
+
end
|
13350
|
+
end
|
13199
13351
|
end
|
13200
13352
|
|
13201
13353
|
if @data['이미지설정']['글자삽입2'].checked?
|
13202
|
-
|
13354
|
+
if @data['이미지설정']['이미지글자2'].length == 0
|
13355
|
+
image_text_path2 = ''
|
13356
|
+
else
|
13357
|
+
if @data['이미지설정']['글자랜덤'].checked?
|
13358
|
+
image_text_path2 = @data['이미지설정']['이미지글자2'].sample
|
13359
|
+
else
|
13360
|
+
image_text_path2 = @data['이미지설정']['이미지글자2'][@image_text_soon2]
|
13361
|
+
@image_text_soon2 += 1
|
13362
|
+
if @image_text_soon2 > @data['이미지설정']['이미지글자2'].length - 1
|
13363
|
+
@image_text_soon2 = 0
|
13364
|
+
end
|
13365
|
+
end
|
13366
|
+
end
|
13203
13367
|
end
|
13204
|
-
|
13368
|
+
|
13205
13369
|
if @data['이미지설정']['글자삽입1'].checked? or @data['이미지설정']['글자삽입2'].checked?
|
13206
|
-
image_text(
|
13370
|
+
image_text(image_text_path1, image_text_path2)
|
13207
13371
|
end
|
13208
13372
|
|
13209
13373
|
if @data['이미지설정']['테두리사용'].checked?
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: posting_zon
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.111.
|
4
|
+
version: 3.111.005
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- zon
|
8
8
|
bindir: bin
|
9
9
|
cert_chain: []
|
10
|
-
date: 2025-06-
|
10
|
+
date: 2025-06-26 00:00:00.000000000 Z
|
11
11
|
dependencies: []
|
12
12
|
description: posting app
|
13
13
|
email: mymin26@naver.com
|