posting_duo 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.
Files changed (3) hide show
  1. checksums.yaml +4 -4
  2. data/lib/posting_duo.rb +292 -128
  3. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b94314eb4bae25ac63d0d1c0463a6d81ff25780b0b447926d7352df561857bc6
4
- data.tar.gz: 65bf34b8204f135fd2cf5d4e298142ae648dcae8269c218b3ce74b4a84f2f385
3
+ metadata.gz: a7059a2e61381d05735169ead0ee105eab4e3b457414fca4afbea96c2d76f1f6
4
+ data.tar.gz: 2640dcaa0dd2336a40877213eb3f3dd6b3953dc6f32d7770ed36abf31caedb7e
5
5
  SHA512:
6
- metadata.gz: d56759319ca4d4af03dbb1a764ed2728a65b0ab0a213ad361904d6a584a872e713aa9be2b7fddf1267bd93005a32328c2e028f95a8c1f741dc921f152fff5ed6
7
- data.tar.gz: fdf80b9d1c45627139848740c937c2fa3dd52f7565ab14d02f97b5d6177b226526212950a5d926f43f7b653c277bfafaf4354887c4b02d3f5ef87b14eabaae88
6
+ metadata.gz: b41153ffd4e39f2d2f8d2f9928c8cf8eb0af6497c8b9186b4ceb36bc4a6fff3633521f1f131d9a072d29246e0be4a8ed4ceca90a5427089228d8046ed3751f81
7
+ data.tar.gz: c2c833d13f58e5379c33160e43c0064ea3b25c7d1d87538111ac823ad0455752544b80726474af6cb291d7f76dc39d53657f8aedcc6e11cf50b0cb8568516cb6
data/lib/posting_duo.rb CHANGED
@@ -13087,82 +13087,109 @@ class Wordpress
13087
13087
 
13088
13088
 
13089
13089
 
13090
+ def crop_image_height_under_width(path, min_crop_ratio = 0.625)
13091
+ img = Magick::Image.read(path).first
13092
+ width = img.columns
13093
+ height = img.rows
13094
+
13095
+
13096
+
13097
+ if height > width
13098
+ min_height = (width * min_crop_ratio).to_i
13099
+ new_height = rand(min_height..width)
13100
+ crop_top = ((height - new_height) / 2.0).round
13101
+
13102
+ cropped = img.crop(0, crop_top, width, new_height, true)
13103
+ cropped.write(path)
13104
+
13105
+
13106
+ else
13107
+
13108
+ end
13109
+ end
13110
+
13090
13111
  def auto_image(keyword = nil)
13091
- keyword ||= @keyword
13092
- puts "키워드: #{keyword}"
13093
-
13094
- client = HTTPClient.new
13095
- client.default_header = {
13096
- 'User-Agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 '\
13097
- '(KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36',
13098
- 'Accept' => 'application/json, text/javascript, */*; q=0.01',
13099
- 'Accept-Language' => 'en-US,en;q=0.9',
13100
- 'Referer' => "https://unsplash.com/s/photos/#{URI.encode_www_form_component(keyword)}",
13101
- 'X-Requested-With' => 'XMLHttpRequest'
13102
- }
13112
+ # auto_image 내부에서만 crop 호출
13113
+ keyword ||= @keyword
13114
+ puts "키워드: #{keyword}"
13115
+
13116
+ client = HTTPClient.new
13117
+ client.default_header = {
13118
+ 'User-Agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 '\
13119
+ '(KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36',
13120
+ 'Accept' => 'application/json, text/javascript, */*; q=0.01',
13121
+ 'Accept-Language' => 'en-US,en;q=0.9',
13122
+ 'Referer' => "https://unsplash.com/s/photos/#{URI.encode_www_form_component(keyword)}",
13123
+ 'X-Requested-With' => 'XMLHttpRequest'
13124
+ }
13103
13125
 
13104
- retry_count = 0
13105
- max_retries = 10
13106
- results = []
13126
+ retry_count = 0
13127
+ max_retries = 10
13128
+ results = []
13107
13129
 
13108
- begin
13109
- page = rand(1..15)
13110
- url = "https://unsplash.com/napi/search/photos?query=#{URI.encode_www_form_component(keyword)}&page=#{page}&per_page=20"
13111
- puts "Request URL: #{url}"
13112
- res = client.get(url)
13113
-
13114
- unless res.status == 200
13115
- puts "HTTP Error: #{res.status}"
13116
- raise "HTTP Error"
13117
- end
13130
+ begin
13131
+ page = rand(1..15)
13132
+ url = "https://unsplash.com/napi/search/photos?query=#{URI.encode_www_form_component(keyword)}&page=#{page}&per_page=20"
13133
+ puts "Request URL: #{url}"
13134
+ res = client.get(url)
13135
+
13136
+ unless res.status == 200
13137
+ puts "HTTP Error: #{res.status}"
13138
+ raise "HTTP Error"
13139
+ end
13118
13140
 
13119
- json = JSON.parse(res.body)
13120
- results = json['results']
13121
- mm = []
13141
+ json = JSON.parse(res.body)
13142
+ results = json['results']
13143
+ mm = []
13122
13144
 
13123
- results.each do |photo|
13124
- full_url = photo.dig('urls', 'full').to_s
13125
- regular_url = photo.dig('urls', 'regular').to_s
13145
+ results.each do |photo|
13146
+ full_url = photo.dig('urls', 'full').to_s
13147
+ regular_url = photo.dig('urls', 'regular').to_s
13126
13148
 
13127
- if full_url.start_with?("https://images.unsplash.com/photo-") &&
13128
- regular_url.include?("1080")
13129
- mm << full_url
13130
- end
13131
- end
13149
+ if full_url.start_with?("https://images.unsplash.com/photo-") &&
13150
+ regular_url.include?("1080")
13151
+ mm << full_url
13152
+ end
13153
+ end
13132
13154
 
13133
- if mm.empty?
13134
- raise "No matching image"
13135
- end
13155
+ if mm.empty?
13156
+ raise "No matching image"
13157
+ end
13136
13158
 
13137
- selected_url = mm.sample
13138
- Down.download(selected_url, destination: "./image/memory.png")
13139
- puts "이미지 다운로드 완료: #{selected_url}"
13159
+ selected_url = mm.sample
13160
+ destination_path = "./image/memory.png"
13161
+ Down.download(selected_url, destination: destination_path)
13162
+ puts "이미지 다운로드 완료: #{selected_url}"
13140
13163
 
13141
- rescue => e
13142
- retry_count += 1
13143
- puts "auto_image 에러: #{e.message} (재시도 #{retry_count}/#{max_retries})"
13144
- sleep(3)
13145
- if retry_count < max_retries
13146
- retry
13147
- else
13148
- puts "최대 재시도 초과. 조건 무시하고 랜덤 이미지 다운로드 시도..."
13149
-
13150
- if results && !results.empty?
13151
- random_photo = results.sample
13152
- fallback_url = random_photo.dig('urls', 'full')
13153
- if fallback_url
13154
- Down.download(fallback_url, destination: "./image/memory.png")
13155
- puts "랜덤 이미지 다운로드 완료: #{fallback_url}"
13156
- else
13157
- puts "랜덤 이미지 URL을 찾을 수 없습니다. 단색 배경 이미지 생성합니다."
13158
- color_image
13159
- end
13164
+ # 오직 auto_image에서만 자르기 호출
13165
+ crop_image_height_under_width(destination_path)
13166
+
13167
+ rescue => e
13168
+ retry_count += 1
13169
+ puts "auto_image 에러: #{e.message} (재시도 #{retry_count}/#{max_retries})"
13170
+ sleep(3)
13171
+ if retry_count < max_retries
13172
+ retry
13173
+ else
13174
+ puts "최대 재시도 초과. 조건 무시하고 랜덤 이미지 다운로드 시도..."
13175
+
13176
+ if results && !results.empty?
13177
+ random_photo = results.sample
13178
+ fallback_url = random_photo.dig('urls', 'full')
13179
+ if fallback_url
13180
+ Down.download(fallback_url, destination: "./image/memory.png")
13181
+ puts "랜덤 이미지 다운로드 완료: #{fallback_url}"
13182
+ crop_image_height_under_width("./image/memory.png")
13160
13183
  else
13161
- puts "이미지 결과가 없어 다운로드할 수 없습니다. 단색 배경 이미지 생성합니다."
13162
- color_image
13163
- end
13184
+ puts "랜덤 이미지 URL을 찾을 수 없습니다. 단색 배경 이미지 생성합니다."
13185
+ color_image
13164
13186
  end
13187
+ else
13188
+ puts "이미지 결과가 없어 다운로드할 수 없습니다. 단색 배경 이미지 생성합니다."
13189
+ color_image
13165
13190
  end
13191
+ end
13192
+ end
13166
13193
  end
13167
13194
 
13168
13195
 
@@ -13174,79 +13201,187 @@ class Wordpress
13174
13201
 
13175
13202
  def save_image
13176
13203
  if @data['이미지설정']['이미지'].length == 0
13177
-
13204
+ return
13205
+ end
13206
+
13207
+ if @data['이미지설정']['순서사용'].checked?
13208
+ image_path = @data['이미지설정']['이미지'][@image_counter][2]
13209
+ @image_counter += 1
13210
+ if @image_counter > @data['이미지설정']['이미지'].length - 1
13211
+ @image_counter = 0
13212
+ end
13178
13213
  else
13179
- if @data['이미지설정']['순서사용'].checked?
13180
- image_path = @data['이미지설정']['이미지'][@image_counter][2]
13181
- @image_counter += 1
13182
- if @image_counter > @data['이미지설정']['이미지'].length-1
13183
- @image_counter = 0
13184
- end
13185
- else
13186
- image_path = @data['이미지설정']['이미지'].sample[2]
13214
+ # 초기화가 안됐거나 다 썼으면 새롭게 섞는다
13215
+ @shuffled_images ||= []
13216
+ if @shuffled_images.empty?
13217
+ @shuffled_images = @data['이미지설정']['이미지'].shuffle
13187
13218
  end
13188
- img = Magick::Image.read(image_path).first
13189
- img.write('./image/memory.png')
13219
+
13220
+ image_path = @shuffled_images.shift[2]
13190
13221
  end
13222
+
13223
+ img = Magick::Image.read(image_path).first
13224
+ img.write('./image/memory.png')
13191
13225
  end
13192
13226
 
13193
13227
  def change_image_size(w)
13194
13228
  img = Magick::Image.read('./image/memory.png').first
13195
13229
  width = img.columns
13196
13230
  height = img.rows
13197
- begin
13198
- if @data['image_type'][0].checked? or @data['image_type'][2].checked?
13199
- img.resize!(w, w*(height.to_f/width.to_f))
13200
- else
13201
- img.resize!(w, w)
13231
+
13232
+ # '원본' 선택된 경우, 리사이징을 하지 않고 원본 이미지를 그대로 반환
13233
+ if w == 'original'
13234
+ return img # 원본 이미지 그대로 반환
13235
+ else
13236
+ begin
13237
+ if @data['image_type'][0].checked? or @data['image_type'][2].checked?
13238
+ # 비율을 맞추어 리사이징
13239
+ img.resize!(w, w * (height.to_f / width.to_f))
13240
+ else
13241
+ # 정사각형으로 리사이징
13242
+ img.resize!(w, w)
13243
+ end
13244
+ rescue
13245
+ img.resize!(w, w) # 예외 처리 시에도 리사이징
13202
13246
  end
13203
- rescue
13204
- img.resize!(w, w)
13205
13247
  end
13248
+
13249
+ # 리사이징된 이미지 저장
13206
13250
  img.write('./image/memory.png')
13207
13251
  end
13208
13252
 
13209
- def image_text(text1, text2)
13210
- begin
13211
- color = File.open('./color.ini', 'r', :encoding => 'utf-8').read().split("\n")
13212
- font = Dir.entries('./fonts')
13213
- img = Magick::Image.read('./image/memory.png').first
13214
- text = Magick::Draw.new
13215
- color2 = color.sample
13216
- font2 = './fonts/'+font.sample
13217
- message = text1.to_s+"\n"+text2.to_s
13218
- begin
13219
- size = rand(@data['이미지설정']['이미지글자1크기1'].text.to_i..@data['이미지설정']['이미지글자1크기2'].text.to_i)
13220
- rescue
13221
- size = 30
13222
- end
13223
- if @data['이미지설정']['글자그림자'].checked?
13224
- img.annotate(text, 0,0, +3,+3, message) do
13225
- text.gravity = Magick::CenterGravity
13226
- text.pointsize = size
13227
- text.fill = '#000000'
13228
- text.font = font2
13253
+ def wrap_text_to_fit(draw, text, max_width, max_height, font_path, initial_size)
13254
+ size = initial_size
13255
+ draw.font = font_path
13256
+
13257
+ loop do
13258
+ draw.pointsize = size
13259
+ words = text.chars # 글자 단위로 자름 (한국어 기준)
13260
+ lines = []
13261
+ line = ""
13262
+
13263
+ words.each do |char|
13264
+ test_line = line + char
13265
+ metrics = draw.get_type_metrics(test_line)
13266
+ if metrics.width > max_width
13267
+ lines << line
13268
+ line = char
13269
+ else
13270
+ line = test_line
13229
13271
  end
13230
13272
  end
13231
-
13232
- img.annotate(text, 0,0,0,0, message) do
13233
- text.gravity = Magick::CenterGravity
13234
- text.pointsize = size
13235
- if @data['이미지설정']['글자테두리'].checked?
13236
- text.stroke_width = 2
13237
- text.stroke = '#000000'
13238
- end
13239
- text.fill = color2
13240
- text.font = font2
13273
+ lines << line unless line.empty?
13274
+
13275
+ line_height = draw.get_type_metrics("가").height
13276
+ total_height = line_height * lines.size
13277
+
13278
+ # 세로 초과 안 하면 성공
13279
+ if total_height <= max_height || size <= 10
13280
+ return [lines.join("\n"), size]
13281
+ else
13282
+ size -= 2
13241
13283
  end
13284
+ end
13285
+ end
13286
+
13287
+
13288
+ def image_text(text1, text2)
13289
+ begin
13290
+ color = File.open('./color.ini', 'r', encoding: 'utf-8').read.split("\n").map(&:strip).reject(&:empty?)
13291
+ font_files = Dir.entries('./fonts').select { |f| f.downcase.end_with?('.ttf') }
13292
+ font2 = './fonts/' + font_files.sample
13242
13293
 
13243
- img.write('./image/memory.png')
13294
+ # 랜덤 글자색 선택
13295
+ color2 = color.sample
13296
+
13297
+ # 헬퍼 함수: 색상 문자열 '#RRGGBB' -> [R,G,B] 배열로 변환
13298
+ def hex_to_rgb(hex)
13299
+ hex = hex.delete('#')
13300
+ [hex[0..1], hex[2..3], hex[4..5]].map { |c| c.to_i(16) }
13301
+ end
13302
+
13303
+ # 헬퍼 함수: 두 RGB 색상의 차이 계산 (간단한 유클리드 거리)
13304
+ def color_distance(c1, c2)
13305
+ Math.sqrt(
13306
+ (c1[0] - c2[0])**2 +
13307
+ (c1[1] - c2[1])**2 +
13308
+ (c1[2] - c2[2])**2
13309
+ )
13310
+ end
13311
+
13312
+ # 대비가 충분히 되는 테두리 색상 선택
13313
+ max_attempts = 10
13314
+ stroke_color = nil
13315
+ base_rgb = hex_to_rgb(color2)
13316
+
13317
+ max_attempts.times do
13318
+ candidate = color.sample
13319
+ candidate_rgb = hex_to_rgb(candidate)
13320
+ dist = color_distance(base_rgb, candidate_rgb)
13321
+
13322
+ # 거리(차이) 임계값 100 (0~441 범위) — 필요시 조절 가능
13323
+ if dist > 100
13324
+ stroke_color = candidate
13325
+ break
13326
+ end
13327
+ end
13328
+ stroke_color ||= '#000000' # 만약 충분히 다른 색 없으면 검정색 기본값
13329
+
13330
+ img = Magick::Image.read('./image/memory.png').first
13331
+ draw = Magick::Draw.new
13332
+
13333
+ raw_message = "#{text1}\n#{text2}".strip
13334
+ max_width = img.columns * 0.85
13335
+ max_height = img.rows * 0.6
13336
+
13337
+ begin
13338
+ size = rand(@data['이미지설정']['이미지글자1크기1'].text.to_i..@data['이미지설정']['이미지글자1크기2'].text.to_i)
13244
13339
  rescue
13245
- puts '이미지 폰트 불러오기 오류 재시도...'
13246
- sleep(3)
13247
- retry
13340
+ size = 30
13341
+ end
13342
+
13343
+ wrapped_message, adjusted_size = wrap_text_to_fit(draw, raw_message, max_width, max_height, font2, size)
13344
+
13345
+ if @data['이미지설정']['글자그림자'].checked?
13346
+ img.annotate(draw, 0, 0, 2, 2, wrapped_message) do
13347
+ draw.gravity = Magick::CenterGravity
13348
+ draw.pointsize = adjusted_size
13349
+ draw.fill = '#000000'
13350
+ draw.font = font2
13351
+ end
13248
13352
  end
13353
+
13354
+ if @data['이미지설정']['글자테두리'].checked?
13355
+ draw_stroke = Magick::Draw.new
13356
+ img.annotate(draw_stroke, 0, 0, 0, 0, wrapped_message) do
13357
+ draw_stroke.gravity = Magick::CenterGravity
13358
+ draw_stroke.pointsize = adjusted_size
13359
+ draw_stroke.fill = 'none'
13360
+ draw_stroke.stroke = stroke_color
13361
+ draw_stroke.stroke_width = rand(5..10)
13362
+ draw_stroke.font = font2
13363
+ end
13364
+ end
13365
+
13366
+ draw2 = Magick::Draw.new
13367
+ img.annotate(draw2, 0, 0, 0, 0, wrapped_message) do
13368
+ draw2.gravity = Magick::CenterGravity
13369
+ draw2.pointsize = adjusted_size
13370
+ draw2.fill = color2
13371
+ draw2.stroke = 'none'
13372
+ draw2.font = font2
13373
+ end
13374
+
13375
+ img.write('./image/memory.png')
13376
+
13377
+ rescue => e
13378
+ puts "이미지 폰트 불러오기 오류 재시도... (#{e.message})"
13379
+ sleep(3)
13380
+ retry
13249
13381
  end
13382
+ end
13383
+
13384
+
13250
13385
 
13251
13386
  def border()
13252
13387
  color = File.open('./color.ini', 'r',:encoding => 'utf-8').read().split("\n")
@@ -13273,40 +13408,69 @@ class Wordpress
13273
13408
  else
13274
13409
  auto_image()
13275
13410
  end
13276
-
13277
- image_size = [480,740,650,550,480]
13411
+
13412
+ # '원본'을 포함한 이미지 크기 옵션 추가
13413
+ image_size = [480, 740, 650, 550, 480, 'original']
13278
13414
  size = 0
13279
- for n in 0..4
13415
+
13416
+ for n in 0..5 # 0부터 5까지 반복, '원본' 옵션까지 포함
13280
13417
  if @data['image_size'][n].checked?
13281
- if n == 0
13282
- size = image_size.sample
13418
+ if n == 5 # '원본'이 선택되었을 경우
13419
+ size = 'original'
13420
+ elsif n == 0
13421
+ size = image_size.sample # 랜덤 선택
13283
13422
  else
13284
13423
  size = image_size[n]
13285
13424
  end
13286
13425
  end
13287
13426
  end
13427
+
13428
+ # '원본'이 선택되지 않았다면 기본 값 설정
13288
13429
  if size == 0
13289
13430
  size = 480
13290
13431
  end
13432
+
13433
+ change_image_size(size) # 크기 변경 함수 호출
13291
13434
 
13292
- change_image_size(size)
13293
13435
 
13294
13436
  if @data['이미지설정']['필터사용'].checked?
13295
13437
  image_filter()
13296
13438
  end
13297
13439
 
13298
- insert_image_text1 = ''
13299
- insert_image_text2 = ''
13300
13440
  if @data['이미지설정']['글자삽입1'].checked?
13301
- insert_image_text1 = @data['이미지설정']['이미지글자1'].sample
13441
+ if @data['이미지설정']['이미지글자1'].length == 0
13442
+ image_text_path1 = ''
13443
+ else
13444
+ if @data['이미지설정']['글자랜덤'].checked?
13445
+ image_text_path1 = @data['이미지설정']['이미지글자1'].sample
13446
+ else
13447
+ image_text_path1 = @data['이미지설정']['이미지글자1'][@image_text_soon1]
13448
+ @image_text_soon1 += 1
13449
+ if @image_text_soon1 > @data['이미지설정']['이미지글자1'].length - 1
13450
+ @image_text_soon1 = 0
13451
+ end
13452
+ end
13453
+ end
13302
13454
  end
13303
13455
 
13304
13456
  if @data['이미지설정']['글자삽입2'].checked?
13305
- insert_image_text2 = @data['이미지설정']['이미지글자2'].sample
13457
+ if @data['이미지설정']['이미지글자2'].length == 0
13458
+ image_text_path2 = ''
13459
+ else
13460
+ if @data['이미지설정']['글자랜덤'].checked?
13461
+ image_text_path2 = @data['이미지설정']['이미지글자2'].sample
13462
+ else
13463
+ image_text_path2 = @data['이미지설정']['이미지글자2'][@image_text_soon2]
13464
+ @image_text_soon2 += 1
13465
+ if @image_text_soon2 > @data['이미지설정']['이미지글자2'].length - 1
13466
+ @image_text_soon2 = 0
13467
+ end
13468
+ end
13469
+ end
13306
13470
  end
13307
-
13471
+
13308
13472
  if @data['이미지설정']['글자삽입1'].checked? or @data['이미지설정']['글자삽입2'].checked?
13309
- image_text(insert_image_text1, insert_image_text2)
13473
+ image_text(image_text_path1, image_text_path2)
13310
13474
  end
13311
13475
 
13312
13476
  if @data['이미지설정']['테두리사용'].checked?
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: posting_duo
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.111.003
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-25 00:00:00.000000000 Z
10
+ date: 2025-06-26 00:00:00.000000000 Z
11
11
  dependencies: []
12
12
  description: File to Clipboard gem
13
13
  email: mymin26@naver.com