Movie Mood & Tone with Palette ลองใช้จานสีสร้างดูเล่นๆ

Minseo Chayabanjonglerd
Black Lens
Published in
5 min readApr 19, 2019

บล็อกก่อนมีคนถามว่าเรื่อง Palette โอเค งั้นเรามา re-write ของเดิมให้จบดีกว่า

Titanic (1997) dir. James Cameron , ref: https://twitter.com/CINEMAPALETTES/status/623518953973919744 ; ตอนแรกจะเลือกหนังที่ชอบ เลื่อนดูแล้ว เลือกหนังที่เคยดูจะง่ายกว่ากันเยอะ

เท่าที่เราดูภาพเล่นๆ น่าจะไม่เหมือนที่ Palette generate สีหรือเปล่านะ 555 แอปตัวอย่างในบล็อกนี้ คือ มีรูปจากหนัง แล้วให้มัน generate สีจาก Palette มาให้ ดูสิว่าจะตรง mood & tone หรือไม่

มาทำความรู้จักเจ้า Palette กันก๊อนนนน

palette เป็นหนึ่งใน library ของทางฝั่ง Android เอง โดยการเพิ่มเจ้านี่ลงไปใน dependency

implementation 'com.android.support:palette-v7:28.0.0'

ซึ่งไม่น่ามีใครเอ๊ะใจอะไร เนื่องจากตัวอย่างเราใช้เจ้า Android Support 28.0.0 ดังนั้นเทียบเท่ากับ AndroidX 1.0.0 นั่นเอง

implementation 'androidx.palette:palette:1.0.0'

ส่วน Document ที่เกี่ยวกับเจ้า Palette นั้น ก็น่าจะตัวนี้แหละ เพราะใน AndroidX ไม่ได้เขียนไว้

หลักการทำงานคร่าวๆ คือ เอารูปมารูปนึง ที่เป็น bitmap มาทำการ generate โดยเราสามารถดึง color profile ที่ Palette generate มาได้ ดังนี้

  • Vibrant : getVibrantColor()
  • Vibrant Dark : getDarkVibrantColor()
  • Vibrant Light : getLightVibrantColor()
  • Muted : getVibrantColor()
  • Muted Dark : getDarkVibrantColor()
  • Muted Light : getLightVibrantColor()

แต่จริงๆแล้วเจ้า Palette นาง Swatches สีทั้งหมดมาให้ 16 สี โดยเราสามารถนำไปใช้โดยการ getSwatches() ซึ่งหนุ่มๆไม่ต้องกังวลเวลาสาวขอแขนมา Swatches สีลิปสติก เอ้ยผิดๆๆๆๆๆ ><

การใช้งาน Palette

ก่อนอื่นมาสร้าง instance ของ Palette กันก่อน ซึ่งรองรับการทำงานทั้ง synchronous และ asynchronous

// Generate palette synchronously and return it
fun createPaletteSync(bitmap: Bitmap): Palette = Palette.from(bitmap).generate()

// Generate palette asynchronously and use it on a different
// thread using onGenerated()
fun createPaletteAsync(bitmap: Bitmap) {
Palette.from(bitmap).generate { palette ->
// Use generated instance
}
}

คำถามจากทางบ้านเมื่อคราวนั้น รวมไปถึงพี่เอกก็ทักตอนตรวจดราฟ ว่าทำไมไม่ใช้ palette generate สีให้เลยหล่ะ ตอนนี้เริ่มได้คำตอบนึงแล้วว่า มันรับ input เป็น bitmap มา generate สีให้เรา แล้วคำถามต่อไปว่า จะทำยังไงให้เป็น bitmap หล่ะ ในกรณีของ

  • ถ้าใส่เป็นสีหล่ะ ทำงานได้ไหม?

ก่อนอื่นต้องแปลงเป็น bitmap เสียก่อน แล้วจะแปลงยังไง google it แล้วพบอันนี้

แล้วใส่ไปแบบนี้

val bitmap = Bitmap.createBitmap(50, 50, Bitmap.Config.ARGB_8888)
val canvas = Canvas(bitmap)
canvas.drawColor(ContextCompat.getColor(this, R.color.colorBg))

จากนั้นเอาเข้าไปใน Palette ซึ่งเอาตัวอย่างจากใน Document มา

Palette.from(bitmap).generate { palette ->
textview.setTextColor(palette?.vibrantSwatch!!.titleTextColor)
}

ผลที่ได้คือ อื้มมม แบบนี้นี่เองง แต่ไม่ตรงทุกอันแหะ อันนี้ต้องไป work ต่อเอาเองว่าอันไหนจะได้สีตัวหนังสือที่เราต้องการจริงๆ แต่จริงๆสีตัวหนังสือมันไม่ออกขาวดำเลย มันเป็นสีๆไง

ซ้ายจาก Colourythm ที่ลองทำ ส่วนขวาคือจาก Palette

อธิบายเพิ่มเติม แต่ละ swatch นั้น สามารถดึง rgb, hsl, population รวมไปถึง title และ body text color ได้ด้วย มิน่าาา ทำไมถึงทักกันว่าทำไมไม่ใช่ Palette คือตอนแรกก็นึกว่าทำได้เฉพาะรูปอย่างเดียวซะอีก ฮ่าาาๆๆๆ

  • แล้ว drawable ที่เป็นรูปต้องแปลงเป็น bitmap ก่อน?

คราวนี้เราจะลองให้แสดงรูปต้นแบบด้านบน และสีที่ได้ด้านล่างเนอะ พร้อมชื่อของมันไปเลยจ้า การทำ layout ในตอนนี้ขอถึกนิดนึง คือสร้าง TextView มา 7 ตัว พร้อมใส่แต่ละ swatch จ้า

  • เจ้า drawable นั้น สามารถ get แบบปกติโดยใช้ ContextCompat และแปลงเป็น BitmapDrawable โดย get bitmap มาอีกที
(ContextCompat.getDrawable(this, R.drawable.sample) as BitmapDrawable).bitmap
  • แต่ละ swatch ที่ได้นั้น เช่น palette?.darkMutedSwatch output ที่ได้คือ Palette.Swatch ดังนั้นเราจะไปใช้ตรงๆในการ set color ต่างๆไม่ได้นะจ๊ะ
  • การนำสีแต่ละ swatch ไปใช้นั้น จะต้องห้อยด้วย .rgb เสมอ เช่น palette.darkMutedSwatch!!.rgb
  • แน่นอนว่าพวก text color จะมี 2 ตัวให้ใช้ คือ titleTextColor (palette?.darkMutedSwatch!!.titleTextColor) กับ bodyTextColor (palette?.darkMutedSwatch!!.bodyTextColor) ห้อยท้ายนั่นเอง

ดังนั้นผลที่ได้จะเป็นแบบนี้

ด้านซ้ายใช้ titleTextColor ส่วนด้านขวาใช้ bodyTextColor เท่าที่ดูเจ้า body สีจะคมชัดกว่านะ และน่าจะตรงกับที่คนทักจริงๆ ซึ่งมันเหมาะกับรูปแบบนี้นี่แหละ แต่ในอันนั้นต้องการสีขาวและสีดำเท่านั้น แต่สีตัวหนังสือที่ได้จาก Palette เป็นสีนอกจากสองสีนี้
  • แล้วถ้ารูปมาจาก url เราต้องให้ method ของ library นั้นๆทำให้เป็น bitmap

เราใช้ Library Fresco ในการดึงภาพจาก url ซึ่งจริงๆแล้วใช้ตั้งแต่ตัวอย่างที่แล้วแล้วแหละ 55555

ความเดิมตอนที่แล้ว

แต่ความยากเพิ่มขึ้นคือ ต้องทำให้เป็น Bitmap กับรูปตัวอย่างของเรา ซึ่งมันแอบไม่สอดคล้องกับความตั้งใจของเจ้า Fresco เท่าไหร่นัก 555

เท่าที่ดูมี 2 ways คือ ใช้ pipeline ใน Fresco กับ ดึงจาก connection ยัดเข้า InputStream แล้วได้ Bitmap มา ซึ่งซับซ้อนน้อยกว่าวิธีแรก งั้นลอง way ที่สองเนอะ

ข้อควรระวัง ใส่ async ด้วยไม่งั้นมันจะ crash นะเออ ซึ่งใส่ async ได้สองแบบ

แบบแรกแบบ สร้าง class AsyncTask

การเรียกใช้จะเป็นแบบนี้

AsyncGettingBitmapFromUrl().execute(url).get()

แบบที่สอง ใช้ Coroutines

ก่อนอื่นเข้าไปเพิ่มใน dependency

implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.0.1'

จากนั้นสร้าง function get bitmap จาก image url มา ซึ่งเหมือนข้างบน

private fun getBitmapFromUrl(src: String): Bitmap {
val url = URL(src)
val connection = url.openConnection() as HttpURLConnection
connection.doInput = true
connection.connect()

val input = connection.inputStream
return BitmapFactory.decodeStream(input)
}

วิธีการใช้งาน

GlobalScope.async {
createPaletteAsync(getBitmapFromUrl(url))
}

ซึ่งจะเขียนเรื่อง coroutine ทีหลังเนอะ :D

แต่เราก็หนี crash ไม่พ้น พอลอง debug เหมือนบางสีมันไม่มีให้ง่ะ ดังนั้นอย่าลืมดักด้วย

เพราะรูปตัวอย่างมันได้สีมาแค่นี้ใช่ไหม แต่ 16 สีมันดันมาครบไง

Mood & Tone ซีนในตำนานของ Girls don’t cry และเป็นซีนที่เป็น ref ในการเกรดสีหนัง ว่าให้เห็นหยดนํ้าตาน้องๆชัดๆ สุดท้ายเลยสีนี้มาที่เราเห็นนั่นแหละ //โดนซีนในตำนานของโอชิเล่นเฉยย

งั้นลองเอา Mood & Tone ที่เราเห็นๆตามเว็บมาลองดูสักหน่อย

ตรงก็แปลกแล้ว 5555555555

สุดท้ายกับการโชว์ swatch ทั้ง 16 สี ก็ดูจะค่อนข้างตรงบ้างเนอะ ในบางสี 555

ส่วนอันนี้สีเยอะเฉ้ยยย เท่าที่ดูเนี่ย สีแต่ละ swatch ก็อยู่ใน swatch ที่เป็น list อีกที

การประยุกต์ใช้ สามารถเอาสีใน Palette ไปใส่ตอน loading รูป เห็นหลายๆแอปชอบทำกัน เช่น Pinterest

ที่ทำไปก็ไม่แน่ใจว่า เขาหาสี Mood & Tone ของหนังแต่ละเรื่องยังไง เพราะของเขามีกัน 10 สี ของเราเนี่ยมีสีอะไรบ้าง 7 + 16 สีอ่ะ งั้นลองอ่านอันนี้ดู มีหลายองค์ประกอบเลยนะเนี่ย

ส่วนอันนี้ละเอียดจนล้องห้ายยย มันยาวมาก

Reference รูปเผื่ออยากเอาไปเล่นกัน :

https://www.pinterest.com/pin/701013498225632601/

วันดีคืนดีอาจจะมีคนแชร์โพสประมาณนี้ใน Facebook :)

โค้ดทั้งหมดอยู่ในนี้ มาส่องกันได้จ้า

ถ้ามีเวลาว่างๆจะตัดซีนหนังจากลิ้งด้านบนมาให้ swatch สีนะ น่าสนุกดี :D

สุดท้ายฝากร้านกันสักนิด ฝากเพจด้วยนะจ๊ะ

--

--

Minseo Chayabanjonglerd
Black Lens

Android Developer | Content Creator AKA. MikkiPastel | Web2 & Web3 Contributor