cafe_basics_duo 0.1.51 → 0.1.53

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/cafe_basics_duo.rb +189 -110
  3. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3bce6014d5547f54cf0a19c0bec6f07359d2bdd76ed89ec46d6b99a65ad2d1b3
4
- data.tar.gz: 4337221b8ca009ec93d5ad70555cc22fb699fac7feed3ec2b15ee7d8b6381d87
3
+ metadata.gz: 6b868b13d28d76acb532714d33421cd445eb6b369b1a369a80c3711f26fb995a
4
+ data.tar.gz: b4b5777cb76884c022ed55c6ab9c16a34b84e9a61db13923a1fd94da9ed1e50e
5
5
  SHA512:
6
- metadata.gz: 2179f2e8fa67a6f30edd7e7291c7d2e1e6ea6f9ca7aa0df83db1e021c75d396488b589a739bb16e4bbf8a19d274ef92d8503f36f41d7af3a039bb47cf892c72a
7
- data.tar.gz: 335456160dcb7f18b5afebe98b002ad47b159c2880d9f21784591b49052f0032cffa42d725614c5ca1d8c2df7eb1b8ae9925b5b2619079a6ae3db5f630ac3900
6
+ metadata.gz: 4b60c2de99e80f65a1b9bb4b0fc231c9c7ee0fb3fb5d81d5fdb20524391a047e6003bb188924aec1614c76936e6aa8941b31d5e2609e60c7eaff1160df4b0812
7
+ data.tar.gz: 4caf5a67d2c104a676c40e5c41dedef98c3aabcd276d8f3f36fc9ecc10d9328516caebbe998725d5a3394541aca32877638c44bf73f44d443e5693e71d8d459d
@@ -2096,83 +2096,115 @@ class Wordpress
2096
2096
 
2097
2097
 
2098
2098
 
2099
- def auto_image(keyword = nil)
2100
- keyword ||= @keyword
2101
- puts "키워드: #{keyword}"
2102
-
2103
- client = HTTPClient.new
2104
- client.default_header = {
2105
- 'User-Agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 '\
2106
- '(KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36',
2107
- 'Accept' => 'application/json, text/javascript, */*; q=0.01',
2108
- 'Accept-Language' => 'en-US,en;q=0.9',
2109
- 'Referer' => "https://unsplash.com/s/photos/#{URI.encode_www_form_component(keyword)}",
2110
- 'X-Requested-With' => 'XMLHttpRequest'
2111
- }
2099
+ def crop_image_height_under_width(path, min_crop_ratio = 0.625)
2100
+ img = Magick::Image.read(path).first
2101
+ width = img.columns
2102
+ height = img.rows
2112
2103
 
2113
- retry_count = 0
2114
- max_retries = 10
2115
- results = []
2104
+ if height > width
2105
+ min_height = (width * min_crop_ratio).to_i
2106
+ new_height = rand(min_height..width)
2107
+ crop_top = ((height - new_height) / 2.0).round
2116
2108
 
2117
- begin
2118
- page = rand(1..15)
2119
- url = "https://unsplash.com/napi/search/photos?query=#{URI.encode_www_form_component(keyword)}&page=#{page}&per_page=20"
2120
- puts "Request URL: #{url}"
2121
- res = client.get(url)
2122
-
2123
- unless res.status == 200
2124
- puts "HTTP Error: #{res.status}"
2125
- raise "HTTP Error"
2109
+ cropped = img.crop(0, crop_top, width, new_height, true)
2110
+
2111
+ retries = 0
2112
+ begin
2113
+ cropped.write(path)
2114
+ rescue => e
2115
+ retries += 1
2116
+ puts "이미지 저장 오류 (#{e.message}), 재시도 #{retries}/5"
2117
+ sleep(1)
2118
+ retry if retries < 5
2119
+ raise "이미지 저장 실패: #{e.message}"
2126
2120
  end
2121
+ end
2122
+ end
2127
2123
 
2128
- json = JSON.parse(res.body)
2129
- results = json['results']
2130
- mm = []
2124
+ def auto_image(keyword = nil)
2125
+ # auto_image 내부에서만 crop 호출
2126
+ keyword ||= @keyword
2127
+ puts "키워드: #{keyword}"
2128
+
2129
+ client = HTTPClient.new
2130
+ client.default_header = {
2131
+ 'User-Agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 '\
2132
+ '(KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36',
2133
+ 'Accept' => 'application/json, text/javascript, */*; q=0.01',
2134
+ 'Accept-Language' => 'en-US,en;q=0.9',
2135
+ 'Referer' => "https://unsplash.com/s/photos/#{URI.encode_www_form_component(keyword)}",
2136
+ 'X-Requested-With' => 'XMLHttpRequest'
2137
+ }
2138
+
2139
+ retry_count = 0
2140
+ max_retries = 10
2141
+ results = []
2142
+
2143
+ begin
2144
+ page = rand(1..15)
2145
+ url = "https://unsplash.com/napi/search/photos?query=#{URI.encode_www_form_component(keyword)}&page=#{page}&per_page=20"
2146
+ puts "Request URL: #{url}"
2147
+ res = client.get(url)
2148
+
2149
+ unless res.status == 200
2150
+ puts "HTTP Error: #{res.status}"
2151
+ raise "HTTP Error"
2152
+ end
2131
2153
 
2132
- results.each do |photo|
2133
- full_url = photo.dig('urls', 'full').to_s
2134
- regular_url = photo.dig('urls', 'regular').to_s
2154
+ json = JSON.parse(res.body)
2155
+ results = json['results']
2156
+ mm = []
2135
2157
 
2136
- if full_url.start_with?("https://images.unsplash.com/photo-") &&
2137
- regular_url.include?("1080")
2138
- mm << full_url
2139
- end
2140
- end
2158
+ results.each do |photo|
2159
+ full_url = photo.dig('urls', 'full').to_s
2160
+ regular_url = photo.dig('urls', 'regular').to_s
2141
2161
 
2142
- if mm.empty?
2143
- raise "No matching image"
2144
- end
2162
+ if full_url.start_with?("https://images.unsplash.com/photo-") &&
2163
+ regular_url.include?("1080")
2164
+ mm << full_url
2165
+ end
2166
+ end
2167
+
2168
+ if mm.empty?
2169
+ raise "No matching image"
2170
+ end
2145
2171
 
2146
- selected_url = mm.sample
2147
- Down.download(selected_url, destination: "./image/memory.png")
2148
- puts "이미지 다운로드 완료: #{selected_url}"
2172
+ selected_url = mm.sample
2173
+ destination_path = "./image/memory.png"
2174
+ Down.download(selected_url, destination: destination_path)
2175
+ puts "이미지 다운로드 완료: #{selected_url}"
2149
2176
 
2150
- rescue => e
2151
- retry_count += 1
2152
- puts "auto_image 에러: #{e.message} (재시도 #{retry_count}/#{max_retries})"
2153
- sleep(3)
2154
- if retry_count < max_retries
2155
- retry
2156
- else
2157
- puts "최대 재시도 초과. 조건 무시하고 랜덤 이미지 다운로드 시도..."
2158
-
2159
- if results && !results.empty?
2160
- random_photo = results.sample
2161
- fallback_url = random_photo.dig('urls', 'full')
2162
- if fallback_url
2163
- Down.download(fallback_url, destination: "./image/memory.png")
2164
- puts "랜덤 이미지 다운로드 완료: #{fallback_url}"
2165
- else
2166
- puts "랜덤 이미지 URL을 찾을 수 없습니다. 단색 배경 이미지 생성합니다."
2167
- color_image
2168
- end
2177
+ # 오직 auto_image에서만 자르기 호출
2178
+ crop_image_height_under_width(destination_path)
2179
+
2180
+ rescue => e
2181
+ retry_count += 1
2182
+ puts "auto_image 에러: #{e.message} (재시도 #{retry_count}/#{max_retries})"
2183
+ sleep(3)
2184
+ if retry_count < max_retries
2185
+ retry
2186
+ else
2187
+ puts "최대 재시도 초과. 조건 무시하고 랜덤 이미지 다운로드 시도..."
2188
+
2189
+ if results && !results.empty?
2190
+ random_photo = results.sample
2191
+ fallback_url = random_photo.dig('urls', 'full')
2192
+ if fallback_url
2193
+ Down.download(fallback_url, destination: "./image/memory.png")
2194
+ puts "랜덤 이미지 다운로드 완료: #{fallback_url}"
2195
+ crop_image_height_under_width("./image/memory.png")
2169
2196
  else
2170
- puts "이미지 결과가 없어 다운로드할 수 없습니다. 단색 배경 이미지 생성합니다."
2171
- color_image
2172
- end
2197
+ puts "랜덤 이미지 URL을 찾을 수 없습니다. 단색 배경 이미지 생성합니다."
2198
+ color_image
2173
2199
  end
2200
+ else
2201
+ puts "이미지 결과가 없어 다운로드할 수 없습니다. 단색 배경 이미지 생성합니다."
2202
+ color_image
2203
+ end
2174
2204
  end
2175
2205
  end
2206
+ end
2207
+
2176
2208
 
2177
2209
  def color_image
2178
2210
  color = File.open('./color.ini', 'r', :encoding => 'utf-8').read().split("\n")
@@ -2266,57 +2298,104 @@ class Wordpress
2266
2298
  end
2267
2299
 
2268
2300
 
2269
- def image_text(text1, text2)
2301
+ def image_text(text1, text2)
2302
+ begin
2303
+ color = File.open('./color.ini', 'r', encoding: 'utf-8').read.split("\n").map(&:strip).reject(&:empty?)
2304
+ font_files = Dir.entries('./fonts').select { |f| f.downcase.end_with?('.ttf') }
2305
+ font2 = './fonts/' + font_files.sample
2306
+
2307
+ # 랜덤 글자색 선택
2308
+ color2 = color.sample
2309
+
2310
+ # 헬퍼 함수: 색상 문자열 '#RRGGBB' -> [R,G,B] 배열로 변환
2311
+ def hex_to_rgb(hex)
2312
+ hex = hex.delete('#')
2313
+ [hex[0..1], hex[2..3], hex[4..5]].map { |c| c.to_i(16) }
2314
+ end
2315
+
2316
+ # 헬퍼 함수: 두 RGB 색상의 차이 계산 (간단한 유클리드 거리)
2317
+ def color_distance(c1, c2)
2318
+ Math.sqrt(
2319
+ (c1[0] - c2[0])**2 +
2320
+ (c1[1] - c2[1])**2 +
2321
+ (c1[2] - c2[2])**2
2322
+ )
2323
+ end
2324
+
2325
+ # 대비가 충분히 되는 테두리 색상 선택
2326
+ max_attempts = 10
2327
+ stroke_color = nil
2328
+ base_rgb = hex_to_rgb(color2)
2329
+
2330
+ max_attempts.times do
2331
+ candidate = color.sample
2332
+ candidate_rgb = hex_to_rgb(candidate)
2333
+ dist = color_distance(base_rgb, candidate_rgb)
2334
+
2335
+ # 거리(차이) 임계값 100 (0~441 범위) — 필요시 조절 가능
2336
+ if dist > 100
2337
+ stroke_color = candidate
2338
+ break
2339
+ end
2340
+ end
2341
+ stroke_color ||= '#000000' # 만약 충분히 다른 색 없으면 검정색 기본값
2342
+
2343
+ img = Magick::Image.read('./image/memory.png').first
2344
+ draw = Magick::Draw.new
2345
+
2346
+ raw_message = "#{text1}\n#{text2}".strip
2347
+ max_width = img.columns * 0.85
2348
+ max_height = img.rows * 0.6
2349
+
2270
2350
  begin
2271
- color = File.open('./color.ini', 'r', :encoding => 'utf-8').read().split("\n")
2272
- font_files = Dir.entries('./fonts').select { |f| f.downcase.end_with?('.ttf') }
2273
- font2 = './fonts/' + font_files.sample
2274
- color2 = color.sample
2275
-
2276
- img = Magick::Image.read('./image/memory.png').first
2277
- draw = Magick::Draw.new
2278
-
2279
- raw_message = "#{text1}\n#{text2}".strip
2280
- max_width = img.columns * 0.85
2281
- max_height = img.rows * 0.6
2282
-
2283
- begin
2284
- size = rand(@data['이미지설정']['이미지글자1크기1'].text.to_i..@data['이미지설정']['이미지글자1크기2'].text.to_i)
2285
- rescue
2286
- size = 30
2287
- end
2288
-
2289
- wrapped_message, adjusted_size = wrap_text_to_fit(draw, raw_message, max_width, max_height, font2, size)
2290
-
2291
- if @data['이미지설정']['글자그림자'].checked?
2292
- img.annotate(draw, 0, 0, 2, 2, wrapped_message) do
2293
- draw.gravity = Magick::CenterGravity
2294
- draw.pointsize = adjusted_size
2295
- draw.fill = '#000000'
2296
- draw.font = font2
2297
- end
2298
- end
2299
-
2300
- draw2 = Magick::Draw.new
2301
- img.annotate(draw2, 0, 0, 0, 0, wrapped_message) do
2302
- draw2.gravity = Magick::CenterGravity
2303
- draw2.pointsize = adjusted_size
2304
- draw2.fill = color2
2305
- draw2.font = font2
2306
- if @data['이미지설정']['글자테두리'].checked?
2307
- draw2.stroke_width = 2
2308
- draw2.stroke = '#000000'
2309
- end
2310
- end
2311
-
2312
- img.write('./image/memory.png')
2351
+ size = rand(@data['이미지설정']['이미지글자1크기1'].text.to_i..@data['이미지설정']['이미지글자1크기2'].text.to_i)
2313
2352
  rescue
2314
- puts '이미지 폰트 불러오기 오류 재시도...'
2315
- sleep(3)
2316
- retry
2353
+ size = 30
2354
+ end
2355
+
2356
+ wrapped_message, adjusted_size = wrap_text_to_fit(draw, raw_message, max_width, max_height, font2, size)
2357
+
2358
+ if @data['이미지설정']['글자그림자'].checked?
2359
+ img.annotate(draw, 0, 0, 2, 2, wrapped_message) do
2360
+ draw.gravity = Magick::CenterGravity
2361
+ draw.pointsize = adjusted_size
2362
+ draw.fill = '#000000'
2363
+ draw.font = font2
2364
+ end
2365
+ end
2366
+
2367
+ if @data['이미지설정']['글자테두리'].checked?
2368
+ draw_stroke = Magick::Draw.new
2369
+ img.annotate(draw_stroke, 0, 0, 0, 0, wrapped_message) do
2370
+ draw_stroke.gravity = Magick::CenterGravity
2371
+ draw_stroke.pointsize = adjusted_size
2372
+ draw_stroke.fill = 'none'
2373
+ draw_stroke.stroke = stroke_color
2374
+ draw_stroke.stroke_width = rand(5..10)
2375
+ draw_stroke.font = font2
2376
+ end
2317
2377
  end
2378
+
2379
+ draw2 = Magick::Draw.new
2380
+ img.annotate(draw2, 0, 0, 0, 0, wrapped_message) do
2381
+ draw2.gravity = Magick::CenterGravity
2382
+ draw2.pointsize = adjusted_size
2383
+ draw2.fill = color2
2384
+ draw2.stroke = 'none'
2385
+ draw2.font = font2
2386
+ end
2387
+
2388
+ img.write('./image/memory.png')
2389
+
2390
+ rescue => e
2391
+ puts "이미지 폰트 불러오기 오류 재시도... (#{e.message})"
2392
+ sleep(3)
2393
+ retry
2394
+ end
2318
2395
  end
2319
2396
 
2397
+
2398
+
2320
2399
  def border()
2321
2400
  color = File.open('./color.ini', 'r',:encoding => 'utf-8').read().split("\n")
2322
2401
  img = Magick::Image.read('./image/memory.png').first
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cafe_basics_duo
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.51
4
+ version: 0.1.53
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