wp_posting_zon 0.0.3 → 0.0.9

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/wp_posting_zon.rb +314 -79
  3. metadata +3 -6
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 90696d79e57c50464e4d6ef3278261617a1fbb15990365b5c9da07f8dbeed5cd
4
- data.tar.gz: a6d5cc1cccac9fe3c5bdc8c064f7874d7b3c8e86c9733ce3828c10f81d1ffe87
3
+ metadata.gz: 5aeddc0ceb08cb7a26d1252f6b2e1c2b3cb3ee5c1404da3a2e97bf07c0ed0d0f
4
+ data.tar.gz: 3a33e130e13bc2ca04e57236c8620d03bfd29ed88b666882bb69e91746e1d056
5
5
  SHA512:
6
- metadata.gz: ec7085474ca62d8cb9d73ebc5eb4f5827e2a5d1d5eb7537a7f7f03080036a0f74191aa88146379e9f1bae7d1b6a294dc170decd2fcc886a84f90156bcaaff160
7
- data.tar.gz: cc08cb475aad2a23ed8a48e3c17e1ced3f155d953a6877cc05753c3d88415ab73f7621b7c0b5a54174fd41af813c7c68b38fee6c2fb44045f4718ed05b1afa86
6
+ metadata.gz: 959862a24098814c43dde5b88fe18ff2518c49d53c78e16c7f8d15ef8345d33fcada363599d7a06fd9e30d1ccf5fd4997f9be3f332677644dd3344e5958f17b4
7
+ data.tar.gz: 6ad3da66c7cc04822b594f32a64bb57051d05e7b61c7e9a5e7c3fe55712901c7142a5bf1f5245f1d2b78e8e77608f4ce3c36d23286202df4c83f461cc676e2b8
@@ -11,6 +11,7 @@ require 'open3'
11
11
  require 'zlib'
12
12
  require 'stringio'
13
13
  require 'timeout'
14
+ require 'httpclient'
14
15
 
15
16
  class Wordpress
16
17
  include Glimmer
@@ -337,23 +338,111 @@ class Wordpress
337
338
  return @data2
338
339
  end
339
340
 
340
- def auto_image
341
- begin
342
- page = rand(1..15)
343
- http = HTTP.get('https://unsplash.com/napi/photos?per_page=12&page='+page.to_s)
344
- json = JSON.parse(http.to_s)
345
- mm = Array.new
346
- json.each do |i|
347
- mm << i['urls']['full']
341
+ def crop_image_height_under_width(path, min_crop_ratio = 0.625)
342
+ img = Magick::Image.read(path).first
343
+ width = img.columns
344
+ height = img.rows
345
+
346
+
347
+
348
+ if height > width
349
+ min_height = (width * min_crop_ratio).to_i
350
+ new_height = rand(min_height..width)
351
+ crop_top = ((height - new_height) / 2.0).round
352
+
353
+ cropped = img.crop(0, crop_top, width, new_height, true)
354
+ cropped.write(path)
355
+
356
+
357
+ else
358
+
359
+ end
360
+ end
361
+
362
+ def auto_image(keyword = nil)
363
+ # auto_image 내부에서만 crop 호출
364
+ keyword ||= @keyword
365
+ puts "키워드: #{keyword}"
366
+
367
+ client = HTTPClient.new
368
+ client.default_header = {
369
+ 'User-Agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 '\
370
+ '(KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36',
371
+ 'Accept' => 'application/json, text/javascript, */*; q=0.01',
372
+ 'Accept-Language' => 'en-US,en;q=0.9',
373
+ 'Referer' => "https://unsplash.com/s/photos/#{URI.encode_www_form_component(keyword)}",
374
+ 'X-Requested-With' => 'XMLHttpRequest'
375
+ }
376
+
377
+ retry_count = 0
378
+ max_retries = 10
379
+ results = []
380
+
381
+ begin
382
+ page = rand(1..15)
383
+ url = "https://unsplash.com/napi/search/photos?query=#{URI.encode_www_form_component(keyword)}&page=#{page}&per_page=20"
384
+ puts "Request URL: #{url}"
385
+ res = client.get(url)
386
+
387
+ unless res.status == 200
388
+ puts "HTTP Error: #{res.status}"
389
+ raise "HTTP Error"
390
+ end
391
+
392
+ json = JSON.parse(res.body)
393
+ results = json['results']
394
+ mm = []
395
+
396
+ results.each do |photo|
397
+ full_url = photo.dig('urls', 'full').to_s
398
+ regular_url = photo.dig('urls', 'regular').to_s
399
+
400
+ if full_url.start_with?("https://images.unsplash.com/photo-") &&
401
+ regular_url.include?("1080")
402
+ mm << full_url
403
+ end
404
+ end
405
+
406
+ if mm.empty?
407
+ raise "No matching image"
408
+ end
409
+
410
+ selected_url = mm.sample
411
+ destination_path = "./image/memory.png"
412
+ Down.download(selected_url, destination: destination_path)
413
+ puts "이미지 다운로드 완료: #{selected_url}"
414
+
415
+ # 오직 auto_image에서만 자르기 호출
416
+ crop_image_height_under_width(destination_path)
417
+
418
+ rescue => e
419
+ retry_count += 1
420
+ puts "auto_image 에러: #{e.message} (재시도 #{retry_count}/#{max_retries})"
421
+ sleep(3)
422
+ if retry_count < max_retries
423
+ retry
424
+ else
425
+ puts "최대 재시도 초과. 조건 무시하고 랜덤 이미지 다운로드 시도..."
426
+
427
+ if results && !results.empty?
428
+ random_photo = results.sample
429
+ fallback_url = random_photo.dig('urls', 'full')
430
+ if fallback_url
431
+ Down.download(fallback_url, destination: "./image/memory.png")
432
+ puts "랜덤 이미지 다운로드 완료: #{fallback_url}"
433
+ crop_image_height_under_width("./image/memory.png")
434
+ else
435
+ puts "랜덤 이미지 URL을 찾을 수 없습니다. 단색 배경 이미지 생성합니다."
436
+ color_image
348
437
  end
349
- url = mm.sample
350
- Down.download(url, destination: "./image/memory.png")
351
- rescue
352
- puts 'image auto download error 5초후 재시도...'
353
- sleep(5)
354
- retry
438
+ else
439
+ puts "이미지 결과가 없어 다운로드할 수 없습니다. 단색 배경 이미지 생성합니다."
440
+ color_image
441
+ end
355
442
  end
356
443
  end
444
+ end
445
+
357
446
 
358
447
  def color_image
359
448
  color = File.open('./color.ini', 'r', :encoding => 'utf-8').read().split("\n")
@@ -363,80 +452,188 @@ class Wordpress
363
452
 
364
453
  def save_image
365
454
  if @data['이미지설정']['이미지'].length == 0
366
-
455
+ return
456
+ end
457
+
458
+ if @data['이미지설정']['순서사용'].checked?
459
+ image_path = @data['이미지설정']['이미지'][@image_counter][2]
460
+ @image_counter += 1
461
+ if @image_counter > @data['이미지설정']['이미지'].length - 1
462
+ @image_counter = 0
463
+ end
367
464
  else
368
- if @data['이미지설정']['순서사용'].checked?
369
- image_path = @data['이미지설정']['이미지'][@image_counter][2]
370
- @image_counter += 1
371
- if @image_counter > @data['이미지설정']['이미지'].length-1
372
- @image_counter = 0
373
- end
374
- else
375
- image_path = @data['이미지설정']['이미지'].sample[2]
465
+ # 초기화가 안됐거나 다 썼으면 새롭게 섞는다
466
+ @shuffled_images ||= []
467
+ if @shuffled_images.empty?
468
+ @shuffled_images = @data['이미지설정']['이미지'].shuffle
376
469
  end
377
- img = Magick::Image.read(image_path).first
378
- img.write('./image/memory.png')
470
+
471
+ image_path = @shuffled_images.shift[2]
379
472
  end
473
+
474
+ img = Magick::Image.read(image_path).first
475
+ img.write('./image/memory.png')
380
476
  end
381
477
 
382
478
  def change_image_size(w)
383
479
  img = Magick::Image.read('./image/memory.png').first
384
480
  width = img.columns
385
481
  height = img.rows
386
- begin
387
- if @data['image_type'][0].checked? or @data['image_type'][2].checked?
388
- img.resize!(w, w*(height.to_f/width.to_f))
389
- else
390
- img.resize!(w, w)
482
+
483
+ # '원본' 선택된 경우, 리사이징을 하지 않고 원본 이미지를 그대로 반환
484
+ if w == 'original'
485
+ return img # 원본 이미지 그대로 반환
486
+ else
487
+ begin
488
+ if @data['image_type'][0].checked? or @data['image_type'][2].checked?
489
+ # 비율을 맞추어 리사이징
490
+ img.resize!(w, w * (height.to_f / width.to_f))
491
+ else
492
+ # 정사각형으로 리사이징
493
+ img.resize!(w, w)
494
+ end
495
+ rescue
496
+ img.resize!(w, w) # 예외 처리 시에도 리사이징
391
497
  end
392
- rescue
393
- img.resize!(w, w)
394
498
  end
499
+
500
+ # 리사이징된 이미지 저장
395
501
  img.write('./image/memory.png')
396
502
  end
397
503
 
398
- def image_text(text1, text2)
399
- begin
400
- color = File.open('./color.ini', 'r', :encoding => 'utf-8').read().split("\n")
401
- font = Dir.entries('./fonts')
402
- img = Magick::Image.read('./image/memory.png').first
403
- text = Magick::Draw.new
404
- color2 = color.sample
405
- font2 = './fonts/'+font.sample
406
- message = text1.to_s+"\n"+text2.to_s
407
- begin
408
- size = rand(@data['이미지설정']['이미지글자1크기1'].text.to_i..@data['이미지설정']['이미지글자1크기2'].text.to_i)
409
- rescue
410
- size = 30
411
- end
412
- if @data['이미지설정']['글자그림자'].checked?
413
- img.annotate(text, 0,0, +3,+3, message) do
414
- text.gravity = Magick::CenterGravity
415
- text.pointsize = size
416
- text.fill = '#000000'
417
- text.font = font2
504
+ def wrap_text_to_fit(draw, text, max_width, max_height, font_path, initial_size)
505
+ size = initial_size
506
+ draw.font = font_path
507
+
508
+ loop do
509
+ draw.pointsize = size
510
+ words = text.chars # 글자 단위로 자름 (한국어 기준)
511
+ lines = []
512
+ line = ""
513
+
514
+ words.each do |char|
515
+ test_line = line + char
516
+ metrics = draw.get_type_metrics(test_line)
517
+ if metrics.width > max_width
518
+ lines << line
519
+ line = char
520
+ else
521
+ line = test_line
418
522
  end
419
523
  end
420
-
421
- img.annotate(text, 0,0,0,0, message) do
422
- text.gravity = Magick::CenterGravity
423
- text.pointsize = size
424
- if @data['이미지설정']['글자테두리'].checked?
425
- text.stroke_width = 2
426
- text.stroke = '#000000'
427
- end
428
- text.fill = color2
429
- text.font = font2
524
+ lines << line unless line.empty?
525
+
526
+ line_height = draw.get_type_metrics("가").height
527
+ total_height = line_height * lines.size
528
+
529
+ # 세로 초과 안 하면 성공
530
+ if total_height <= max_height || size <= 10
531
+ return [lines.join("\n"), size]
532
+ else
533
+ size -= 2
430
534
  end
431
-
432
- img.write('./image/memory.png')
535
+ end
536
+ end
537
+
538
+
539
+ def image_text(text1, text2)
540
+ begin
541
+ color = File.open('./color.ini', 'r', encoding: 'utf-8').read.split("\n").map(&:strip).reject(&:empty?)
542
+ font_files = Dir.entries('./fonts').select { |f| f.downcase.end_with?('.ttf') }
543
+ font2 = './fonts/' + font_files.sample
544
+
545
+ # 랜덤 글자색 선택
546
+ color2 = color.sample
547
+
548
+ # 헬퍼 함수: 색상 문자열 '#RRGGBB' -> [R,G,B] 배열로 변환
549
+ def hex_to_rgb(hex)
550
+ hex = hex.delete('#')
551
+ [hex[0..1], hex[2..3], hex[4..5]].map { |c| c.to_i(16) }
552
+ end
553
+
554
+ # 헬퍼 함수: 두 RGB 색상의 차이 계산 (간단한 유클리드 거리)
555
+ def color_distance(c1, c2)
556
+ Math.sqrt(
557
+ (c1[0] - c2[0])**2 +
558
+ (c1[1] - c2[1])**2 +
559
+ (c1[2] - c2[2])**2
560
+ )
561
+ end
562
+
563
+ # 대비가 충분히 되는 테두리 색상 선택
564
+ max_attempts = 10
565
+ stroke_color = nil
566
+ base_rgb = hex_to_rgb(color2)
567
+
568
+ max_attempts.times do
569
+ candidate = color.sample
570
+ candidate_rgb = hex_to_rgb(candidate)
571
+ dist = color_distance(base_rgb, candidate_rgb)
572
+
573
+ # 거리(차이) 임계값 100 (0~441 범위) — 필요시 조절 가능
574
+ if dist > 100
575
+ stroke_color = candidate
576
+ break
577
+ end
578
+ end
579
+ stroke_color ||= '#000000' # 만약 충분히 다른 색 없으면 검정색 기본값
580
+
581
+ img = Magick::Image.read('./image/memory.png').first
582
+ draw = Magick::Draw.new
583
+
584
+ raw_message = "#{text1}\n#{text2}".strip
585
+ max_width = img.columns * 0.85
586
+ max_height = img.rows * 0.6
587
+
588
+ begin
589
+ size = rand(@data['이미지설정']['이미지글자1크기1'].text.to_i..@data['이미지설정']['이미지글자1크기2'].text.to_i)
433
590
  rescue
434
- puts '이미지 폰트 불러오기 오류 재시도...'
435
- sleep(3)
436
- retry
591
+ size = 30
592
+ end
593
+
594
+ wrapped_message, adjusted_size = wrap_text_to_fit(draw, raw_message, max_width, max_height, font2, size)
595
+
596
+ if @data['이미지설정']['글자그림자'].checked?
597
+ img.annotate(draw, 0, 0, 2, 2, wrapped_message) do
598
+ draw.gravity = Magick::CenterGravity
599
+ draw.pointsize = adjusted_size
600
+ draw.fill = '#000000'
601
+ draw.font = font2
602
+ end
603
+ end
604
+
605
+ if @data['이미지설정']['글자테두리'].checked?
606
+ draw_stroke = Magick::Draw.new
607
+ img.annotate(draw_stroke, 0, 0, 0, 0, wrapped_message) do
608
+ draw_stroke.gravity = Magick::CenterGravity
609
+ draw_stroke.pointsize = adjusted_size
610
+ draw_stroke.fill = 'none'
611
+ draw_stroke.stroke = stroke_color
612
+ draw_stroke.stroke_width = rand(5..10)
613
+ draw_stroke.font = font2
614
+ end
615
+ end
616
+
617
+ draw2 = Magick::Draw.new
618
+ img.annotate(draw2, 0, 0, 0, 0, wrapped_message) do
619
+ draw2.gravity = Magick::CenterGravity
620
+ draw2.pointsize = adjusted_size
621
+ draw2.fill = color2
622
+ draw2.stroke = 'none'
623
+ draw2.font = font2
437
624
  end
625
+
626
+ img.write('./image/memory.png')
627
+
628
+ rescue => e
629
+ puts "이미지 폰트 불러오기 오류 재시도... (#{e.message})"
630
+ sleep(3)
631
+ retry
632
+ end
438
633
  end
439
634
 
635
+
636
+
440
637
  def border()
441
638
  color = File.open('./color.ini', 'r',:encoding => 'utf-8').read().split("\n")
442
639
  img = Magick::Image.read('./image/memory.png').first
@@ -462,48 +659,86 @@ class Wordpress
462
659
  else
463
660
  auto_image()
464
661
  end
465
-
466
- image_size = [480,740,650,550,480]
662
+
663
+ # '원본'을 포함한 이미지 크기 옵션 추가
664
+ image_size = [480, 740, 650, 550, 480, 'original']
467
665
  size = 0
468
- for n in 0..4
666
+
667
+ for n in 0..5 # 0부터 5까지 반복, '원본' 옵션까지 포함
469
668
  if @data['image_size'][n].checked?
470
- if n == 0
471
- size = image_size.sample
669
+ if n == 5 # '원본'이 선택되었을 경우
670
+ size = 'original'
671
+ elsif n == 0
672
+ size = image_size.sample # 랜덤 선택
472
673
  else
473
674
  size = image_size[n]
474
675
  end
475
676
  end
476
677
  end
678
+
679
+ # '원본'이 선택되지 않았다면 기본 값 설정
477
680
  if size == 0
478
681
  size = 480
479
682
  end
683
+
684
+ change_image_size(size) # 크기 변경 함수 호출
480
685
 
481
- change_image_size(size)
482
686
 
483
687
  if @data['이미지설정']['필터사용'].checked?
484
688
  image_filter()
485
689
  end
486
690
 
487
- insert_image_text1 = ''
488
- insert_image_text2 = ''
489
691
  if @data['이미지설정']['글자삽입1'].checked?
490
- insert_image_text1 = @data['이미지설정']['이미지글자1'].sample
692
+ if @data['이미지설정']['이미지글자1'].length == 0
693
+ image_text_path1 = ''
694
+ else
695
+ if @data['이미지설정']['글자랜덤'].checked?
696
+ image_text_path1 = @data['이미지설정']['이미지글자1'].sample
697
+ else
698
+ image_text_path1 = @data['이미지설정']['이미지글자1'][@image_text_soon1]
699
+ @image_text_soon1 += 1
700
+ if @image_text_soon1 > @data['이미지설정']['이미지글자1'].length - 1
701
+ @image_text_soon1 = 0
702
+ end
703
+ end
704
+ end
491
705
  end
492
706
 
493
707
  if @data['이미지설정']['글자삽입2'].checked?
494
- insert_image_text2 = @data['이미지설정']['이미지글자2'].sample
708
+ if @data['이미지설정']['이미지글자2'].length == 0
709
+ image_text_path2 = ''
710
+ else
711
+ if @data['이미지설정']['글자랜덤'].checked?
712
+ image_text_path2 = @data['이미지설정']['이미지글자2'].sample
713
+ else
714
+ image_text_path2 = @data['이미지설정']['이미지글자2'][@image_text_soon2]
715
+ @image_text_soon2 += 1
716
+ if @image_text_soon2 > @data['이미지설정']['이미지글자2'].length - 1
717
+ @image_text_soon2 = 0
718
+ end
719
+ end
720
+ end
495
721
  end
496
-
722
+
497
723
  if @data['이미지설정']['글자삽입1'].checked? or @data['이미지설정']['글자삽입2'].checked?
498
- image_text(insert_image_text1, insert_image_text2)
724
+ image_text(image_text_path1, image_text_path2)
499
725
  end
500
726
 
501
727
  if @data['이미지설정']['테두리사용'].checked?
502
728
  border()
503
729
  end
504
730
 
731
+ sleep(1)
505
732
  time = Time.now.to_s.split(' ')[0..1].join('').split(':').join('').split('-').join('')
506
733
  FileUtils.cp('./image/memory.png', './image/'+@keyword+time+'.png')
734
+ hi_dir = Dir.pwd
735
+ iconv = Iconv.new('UTF-8', 'CP949')
736
+ begin
737
+ hi_dir = iconv.iconv(hi_dir)
738
+ rescue
739
+
740
+ end
741
+ return hi_dir+'/image/'+@keyword+time+'.png'
507
742
  end
508
743
 
509
744
  def image_update22
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: wp_posting_zon
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - zon
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2025-01-09 00:00:00.000000000 Z
10
+ date: 2025-06-26 00:00:00.000000000 Z
12
11
  dependencies: []
13
12
  description: File to Clipboard gem
14
13
  email: mymin26@naver.com
@@ -21,7 +20,6 @@ homepage: ''
21
20
  licenses:
22
21
  - zon
23
22
  metadata: {}
24
- post_install_message:
25
23
  rdoc_options: []
26
24
  require_paths:
27
25
  - lib
@@ -36,8 +34,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
36
34
  - !ruby/object:Gem::Version
37
35
  version: '0'
38
36
  requirements: []
39
- rubygems_version: 3.3.7
40
- signing_key:
37
+ rubygems_version: 3.6.7
41
38
  specification_version: 4
42
39
  summary: file to clipboard
43
40
  test_files: []