Month: January 2023

  • Photoshop ปรับภาพเอียงให้ตรง

    การปรับภาพเอียงให้ตรงแบบง่ายๆใน Photoshop 

    เปิดโปรแกรม Photoshop แล้วเลือกภาพที่ต้องการแก้ไข ในภาพจะเห็นว่าเส้นขอบฟ้าจะมีความเอียงอยู่ สังเกตจากเส้นสีแดงที่เทียบไว้

    อย่าลืมปลดล๊อคเดี๋ยวจะแก้ไขไม่ได้

    ไปที่ Tool เลือก Ruler Tool

    ลากเส้นให้ขนานกับเส้นขอบฟ้า

    กดปุ่ม Straighten Layer ภาพจะถูกปรับให้ตรงแล้ว แต่จะมีเนื้อภาพบริเวณมุมทั้ง 4 ด้านหายไป

    เลือก Lasso Tool

    ทำการ Selection ทั้ง 4 มุม ที่เนื้อภาพหายไป (ตอนทำการ Selection เพิ่มในมุมที่ 2 มุมที่3 มุมที่4 ให้กดปุ่ม shift ค้างไว้)

    ไปที่ Edit เลือก Content-Aware Fill

    กดปุ่ม OK

    ในโปรแกรมจะเห็นภาพเฉพาะทางด้านขวาที่แก้ไขเรียบร้อยแล้วครับ

  • Photoshop เปลี่ยนท้องฟ้าในรูปภาพแบบง่ายๆ

    การเปลี่ยนท้องฟ้าในรูปภาพแบบง่ายๆใน Photoshop สำหรับ Feature นี้จะมีใน Photoshop 2021 ขึ้นไปถ้าจำไม่ผิดนะ แหะๆ

    มาเริ่มกันเลยดีกว่า เปิดโปรแกรม Photoshop แล้วเลือกภาพที่ต้องการแก้ไข ในภาพจะเห็นว่าขาดรายละเอียดของท้องฟ้าไป

    ไปที่เมนู Edit => Sky Replacement

    จะได้หน้าต่างดังภาพ ในกรอบที่ 1 เป็นการเลือกภาพท้องฟ้าที่จะมาแทนที่

    ในกรอบที่ 2 เป็นการปรับเพื่อให้เข้ากับภาพต้นฉบับ Shift Edge Fade Edge เป็นการกินระยะขอบและการปรับความเนียนของภาพ

    Brightness และ Temperature เป็นการปรับความสว่างและอุณหภูมิสี Scale เป็นการย่อขยายภาพท้องฟ้า

    ท้องฟ้าที่อยู่ในรูปสามารถ click mouse ซ้ายค้างไว้ (Drag mouse นั่นล่ะ) เพื่อเลื่อนให้ได้มุม ได้ view ที่เราต้องการได้

    ในตอนที่ทำจริงๆแล้วก็จะลองเลื่อนๆปรับไปปรับมาดูให้กลมกลืนที่สุดนั่นละ ^^ เมื่อได้ภาพที่ต้องการแล้วกดปุ่ม OK ได้เลย

    ในโปรแกรมจะเห็นภาพเฉพาะทางด้านขวาที่แก้ไขเรียบร้อยแล้ว

    *** ในกรณีที่ไม่มีรูปท้องฟ้าที่เราต้องการ เราสามารถหาภาพท้องฟ้าที่เราถูกตา ถูกใจ แล้วทำการเพิ่มเก็บเอาไว้ได้ โดย Click ที่รูปเฟือง

    เลือกที่ Get More Skies => Import Images

    เลือกภาพท้องฟ้าที่เราเตรียมไว้

    ภาพท้องฟ้าก็จะอยู่ในโกดังท้องฟ้าของเรา ไว้ใช้ในโอกาสหน้าได้อีกด้วย

    ปัจจุบันการเปลี่ยนท้องฟ้ามีหลายๆ APP ที่สามารถทำได้แล้วทั้งในมือถือ หรือบน PC ในPhotoshop ก็เป็นอีกทางเลือกนึงเช่นกันครับ

  • เรียนรู้เบื้องต้นกับการใส่ลายน้ำ(Watermark)ให้กับเอกสาร PDF ของเราด้วย iTextSharp

                   ในบทความนี้เราก็ยังคงอยู่กับเรื่องการทำภาพลายน้ำอย่างต่อเนื่องจาก EP. ที่แล้วที่พูดถึงการทำข้อความลายน้ำบนภาพที่เราทำการอัพโหลด ถ้าใครยังไม่ได้อ่านสามารถตามไปอ่านกันได้ ที่นี่ นะคะแต่สำหรับ EP. นี้เราจะขอเปลี่ยนบรรยากาศไปทำ ลายน้ำบนไฟล์ PDF โดยใช้เครื่องมือ iTextSharp กันบ้าง เผื่อว่าผู้อ่านบางท่านที่อาจจะกำลังใช้งาน iTextSharp ในการจัดทำไฟล์ PDF อยู่พอดี และอยากจะลองใส่ลายน้ำให้กับงานเอกสารของท่านดูบ้าง จะได้สามารถนำวิธีการนี้ไปประยุกต์ใช้กับงานของตนได้ไม่ทางใดก็ทางหนึ่งนะคะ โดยตัวอย่างที่จะนำมาแนะนำกันจะมีทั้งแบบลายน้ำที่เป็นข้อความ และลายน้ำที่เป็นภาพค่ะ นอกจากนี้ก็ยังมีทั้งแบบที่เป็นการทำภาพลายน้ำทับไฟล์เดิมที่มีอยู่ และแบบที่ทำภาพลายน้ำและบันทึกเป็นไฟล์ใหม่ค่ะ ผู้อ่านจะได้ลองในหลายๆวิธี และสามารถเลือกไปปรับใช้ให้เหมาะกับงานของแต่ละท่านได้เพื่อไม่ให้เป็นการเสียเวลา งั้นเรามาเริ่มทำภาพลายน้ำบนงานเอกสาร PDF ของเรากันเลยดีกว่าค่ะ

    แบบที่ 1 : การสร้างลายน้ำแบบข้อความ ซึ่งวิธีการนี้ จะมีการทำ Template ต้นฉบับของลายน้ำแบบข้อความไว้ก่อน และเมื่อต้องการทำไฟล์ลายน้ำ จะต้องทำการอ่านไฟล์ลายน้ำจากต้นแบบมาจัดทำลายน้ำบนไฟล์ที่ต้องการได้ ดังนี้ค่ะ

    1.1 ระบุ Library เพิ่มเติม

    using iTextSharp.text;
    using iTextSharp.text.pdf;
    using System.IO;

    1.2 สร้างเมธอดในการสร้าง Template ลายน้ำต้นฉบับ เพื่อใช้ในการทำลายน้ำให้กับไฟล์ PDF ที่ต้องการ

            ////กรณียังไม่เคยสร้างหรือมี Template มาก่อน ให้เรียกใช้งาน CreateTemplate("ข้อความที่ต้องการให้แสดงในเทมเพลต",พาธที่จะสร้างไฟล์เทมเพลตดังกล่าว) 
            public void CreateTemplate(string watermarkText, string targetFileName)
            {
                var document = new Document();
    
                ////ระบุพาธที่ต้องการสร้างไฟล์เทมเพลต
                var pdfWriter = PdfWriter.GetInstance(document, new FileStream(targetFileName, FileMode.Create));
                ///ระบุค่าต่างๆเกี่ยวกับตัวอักษรที่จะแสดงผลในเทมเพลตลายน้ำที่สร้างขึ้น
                var font = new Font(Font.FontFamily.HELVETICA, 60, Font.NORMAL, BaseColor.LIGHT_GRAY);
                document.Open();
    
                ////ระบุค่าข้อความ และค่าต่างๆให้กับลายน้ำที่ต้องการ
                ColumnText.ShowTextAligned(pdfWriter.DirectContent, Element.ALIGN_CENTER, new Phrase(watermarkText, font), 300, 400, 45);
                document.Close();
            }

    ตัวอย่าง ไฟล์ PDF ของ Template ลายน้ำที่ได้จากการเรียกใช้งานเมธอด CreateTemplate ข้างต้น

    1.3 สร้างเมธอดในการจัดทำลายน้ำข้อความให้กับไฟล์ PDF จาก template ลายน้ำต้นฉบับ

    public void AddTextWatermark(string sourceFilePath, string watermarkTemplatePath, string targetFilePath)
            {
                ///ระบุพาธไฟล์ต้นทางที่ต้องการทำข้อความลายน้ำ
                var pdfReaderSource = new PdfReader(sourceFilePath);
                ///ระบุพาธไฟล์ปลายทางที่ต้องการบันทึกไฟล์แบบมีลายน้ำ
                var pdfStamper = new PdfStamper(pdfReaderSource, new FileStream(targetFilePath, FileMode.Create));
    
                ///ระบุพาธของไฟล์ต้นแบบลายน้ำที่จัดทำไว้
                var pdfReaderTemplate = new PdfReader(watermarkTemplatePath);
                var page = pdfStamper.GetImportedPage(pdfReaderTemplate, 1);
    
                ///ทำการวนลูปเพื่อทำลายน้ำให้กับไฟล์ PDF ทีละหน้า
                for (var i = 0; i < pdfReaderSource.NumberOfPages; i++)
                {
                    ///ระบุตำแหน่งในการแสดงผลลายน้ำกับเนื้อหาในไฟล์ PDF กรณีนี้คือวางไว้ใต้เนื้อหา แต่หากต้องการให้อยู่บนเนื้อหาให้เปลี่ยนเป็น GetOverContent แทน 
                    var content = pdfStamper.GetUnderContent(i + 1);
                    content.AddTemplate(page, 0, 0);
                }
    
                pdfStamper.Close();
                pdfReaderTemplate.Close();
            }

    1.4 เรียกใช้งานเมธอดเพื่อทำลายน้ำให้กับไฟล์ PDF ที่ต้องการ(กรณีนี้สมมุติให้เป็นการกดปุ่มเพื่อเรียกใช้งานเมธอดดังกล่าว)

     protected void btnGenWatermark_Click(object sender, EventArgs e)
            {
                 ////กำหนด Path ของไฟล์ PDF ต้นทางที่ต้องการทำลายน้ำ กรณีที่ gen จาก iTextSharp สามารถนำมาประยุกต์ใช้โดยเอาพาธดังกล่าวมาใช้เป็น strSourcePath ได้เลย
                string strSourcePath = HttpContext.Current.Server.MapPath("~/PDF/File/PDFDocument.pdf");
    
                 ////สร้างตัวแปรชื่อไฟล์ PDF ที่จะบันทึกใหม่ในชื่อตัวแปร genName
                string genName = Guid.NewGuid().ToString() + ".pdf";
    
                 ////กรณียังไม่เคยสร้างหรือมี Template มาก่อนให้เรียกใช้งาน CreateTemplate("ข้อความที่ต้องการให้แสดงในเทมเพลต",templatePath)  ทั้งชื่อไฟล์เทมเพลตใหม่ที่จะบันทึก
                string templatePath = HttpContext.Current.Server.MapPath("~/PDF/TemplateWatermarkPDF/" + genName);
    
                 ////ระบุพาธปลายทางที่ต้องการบันทึกไฟล์แบบมีลายน้ำพร้อมทั้งชื่อไฟล์ใหม่ที่จะบันทึก
                string targetPath = HttpContext.Current.Server.MapPath("~/PDF/WatermarkPDF/" + genName);
    
                 ////ตรวจสอบว่ามีไฟล์ดังกล่าวอยู่จริงตามที่อยู่ที่ระบุไว้หรือไม่
                if( File.Exists(strSourcePath))
                { 
                     ////กรณียังไม่เคยสร้างหรือมี Template มาก่อน ให้เรียกใช้งาน CreateTemplate("ข้อความที่ต้องการให้แสดงในเทมเพลต",พาธที่จะสร้างไฟล์เทมเพลตดังกล่าว) 
                    CreateTemplate("Copyrights (c) 2023", templatePath);
    
                     ////เรียกใช้งานเมธอดในการสร้างข้อความลายน้ำตามเทมเพลตที่มี(ตามพาธที่ระบุ) โดยส่งค่าที่อยู่ของไฟล์ต้นทาง พาธเทมเพลตที่ต้องการทำลายน้ำ และพาธปลายทางที่ต้องการบันทึกไฟล์แบบมีลายน้ำ
                    AddTextWatermark(strSourcePath, templatePath, targetPath);
                }
            }

    ตัวอย่างผลลัพธ์

    หมายเหตุ : 

    1. บางครั้งอาจพบว่าการใช้ GetUnderContent อาจทำให้ข้อความลายน้ำโดนเนื้อหาบดบังได้ในบางกรณี จนอาจจะต้องใช้ GetOverContent แทนดังเช่นตัวอย่างต่อไปนี้ 

    แต่สำหรับเนื้อหาในไฟล์ PDF โดยทั่วไปแล้ว สามารถใช้งาน GetUnderContent ได้ตามปกติ เพื่อไม่ให้ข้อความลายน้ำบดบังเนื้อหาในเอกสาร

    แบบที่ 2 การสร้างลายน้ำแบบรูปภาพให้กับเอกสาร PDF โดยจะขอยกตัวอย่างให้ดู 2 แบบนะคะ คือแบบที่สร้างลายน้ำบนไฟล์ PDF ใหม่ และแบบที่สร้างลายน้ำบนไฟล์ต้นทางเดิมค่ะ 

    2.1 แบบสร้างลายน้ำบนไฟล์ใหม่ โดยการสร้างเมธอด AddImageWatermark

        public void AddImageWatermark(string sourceFilePath, string watermarkImagePath, string targetFilePath)
            {
                ///ระบุพาธไฟล์ต้นทางที่ต้องการทำภาพลายน้ำ
                var pdfReader = new PdfReader(sourceFilePath);
    
                ///ระบุพาธไฟล์ปลายทางที่ต้องการบันทึกไฟล์แบบมีภาพลายน้ำ
                var pdfStamper = new PdfStamper(pdfReader, new FileStream(targetFilePath, FileMode.Create));
    
                ///ระบุพาธของไฟล์ภาพที่ต้องการนำมาทำภาพลายน้ำ
                var image = iTextSharp.text.Image.GetInstance(watermarkImagePath);
                image.SetAbsolutePosition(200, 400);
    
                ///ทำการวนลูปเพื่อทำภาพลายน้ำให้กับไฟล์ PDF ทีละหน้า
                for (var i = 0; i < pdfReader.NumberOfPages; i++)
                {
                    var content = pdfStamper.GetUnderContent(i + 1);
                    content.AddImage(image);
                }
    
                pdfStamper.Close();
            }

    วิธีเรียกใช้งาน (กรณีนี้สมมุติให้เป็นการกดปุ่มเพื่อเรียกใช้งานเมธอดดังกล่าว)

            protected void btnGenWatermark_Click(object sender, EventArgs e)
            {
                ////กำหนด Path ของไฟล์ภาพที่ต้องการทำลายน้ำ
                string strWaterMark = HttpContext.Current.Server.MapPath("~/images/clientpreview.png");
                
    ////ระบุ Path ของไฟล์ PDF ต้นทางที่ต้องการทำลายน้ำ string strSourcePath = HttpContext.Current.Server.MapPath("~/PDF/File/job_apply_form.pdf");
    ////สร้างตัวแปรชื่อไฟล์ PDF ที่จะบันทึกใหม่ในชื่อตัวแปร genName string genName = Guid.NewGuid().ToString() + ".pdf";
    ////ระบุพาธปลายทางที่ต้องการบันทึกไฟล์แบบมีลายน้ำพร้อมทั้งชื่อไฟล์ใหม่ที่จะบันทึก string targetPath = HttpContext.Current.Server.MapPath("~/PDF/WatermarkPDF/" + genName);
    ////ตรวจสอบว่ามีไฟล์ภาพลายน้ำ และไฟล์ PDF ต้นทางดังกล่าวอยู่จริงตามที่อยู่ที่ระบุไว้หรือไม่ if (File.Exists(strWaterMark) && File.Exists(strSourcePath)) { AddImageWatermark(strSourcePath, strWaterMark, targetPath); } }

    2.2 แบบสร้างลายน้ำบนไฟล์เดิม โดยการสร้างเมธอด AddImageWatermarkInExistingFile

     private void AddImageWatermarkInExistingFile(string sourceFilePath,string watermarkImagePath )
            {
                 ///อ่านค่าจากพาธไฟล์ต้นทางที่ต้องการทำภาพลายน้ำ
                byte[] bytes = File.ReadAllBytes(sourceFilePath);
    
                 ///ระบุพาธของไฟล์ภาพที่ต้องการนำมาทำภาพลายน้ำ
                var img = iTextSharp.text.Image.GetInstance(watermarkImagePath);
    
                img.SetAbsolutePosition(200, 400);
                PdfContentByte waterMark;
    
                using (MemoryStream stream = new MemoryStream())
                {
                     ///ทำภาพลายน้ำในไฟล์ต้นทางที่ต้องการทำภาพลายน้ำ
                    PdfReader reader = new PdfReader(bytes);
                    using (PdfStamper stamper = new PdfStamper(reader, stream))
                    {
                        ///ทำการวนลูปเพื่อทำภาพลายน้ำให้กับไฟล์ PDF ทีละหน้า
                        int pages = reader.NumberOfPages;
                        for (int i = 1; i <= pages; i++)
                        {
                            waterMark = stamper.GetUnderContent(i);
                            waterMark.AddImage(img);
                        }
                    }
                    bytes = stream.ToArray();
                }
                File.WriteAllBytes(sourceFilePath, bytes);
            }

    วิธีเรียกใช้งาน (กรณีนี้สมมุติให้เป็นการกดปุ่มเพื่อเรียกใช้งานเมธอดดังกล่าว)

            protected void btnGenWatermark_Click(object sender, EventArgs e)
            {
                ////กำหนด Path ของไฟล์ภาพที่ต้องการทำลายน้ำ
                string strWaterMark = HttpContext.Current.Server.MapPath("~/images/clientpreview.png");
    
                ////ระบุ Path ของไฟล์ PDF ต้นทางที่ต้องการทำลายน้ำ
                string strSourcePath = HttpContext.Current.Server.MapPath("~/PDF/File/job_apply_form.pdf");
    
                ////สร้างตัวแปรชื่อไฟล์ PDF ที่จะบันทึกใหม่ในชื่อตัวแปร genName
                string genName = Guid.NewGuid().ToString() + ".pdf";
    
                 ////ตรวจสอบว่ามีไฟล์ภาพลายน้ำ และไฟล์ PDF ต้นทางดังกล่าวอยู่จริงตามที่อยู่ที่ระบุไว้หรือไม่
                if (File.Exists(strWaterMark) && File.Exists(strSourcePath))
                {
                    AddImageWatermarkInExistingFile(strSourcePath,strWaterMark);
                 }
            }
    

    ตัวอย่างผลลัพธ์

    หมายเหตุ :
    1. ทั้งสองวิธีข้างต้นจะให้ผลลัพธ์ของภาพลายน้ำแบบเดียวกัน แต่ต่างกันตรงที่ไฟล์ที่บันทึกภาพลายน้ำ โดยแบบแรกจะสร้างเป็นไฟล์ใหม่ แต่แบบที่สองจะบันทึกลงบนไฟล์เดิม

    2. ในการใช้ภาพทำภาพลายน้ำ อาจจะต้องระวังเกี่ยวกับขนาดภาพที่นำมาใช้ในการแสดงผล และอาจต้องทดสอบการจัดวางตำแหน่งของภาพ เพื่อให้ภาพลายน้ำดังกล่าวออกมาสวยงาม และตรงกับความต้องการในการใช้งาน เพราะหากใช้ภาพที่ใหญ่หรือเล็กเกินไป อาจทำให้ไม่เหมาะกับการนำมาใช้งานได้

               ซึ่งทั้งหมดนี้ก็เป็นเพียงวิธีเบื้องต้นในการสร้างภาพลายน้ำด้วย iTextSharp เท่านั้น เราอาจจะต้องลองผิดลองถูก ประยุกต์วิธีการนำไปใช้ไปด้วยกัน และหวังว่าบทความนี้จะเป็นประโยชน์กับผู้อ่านเพื่อให้แต่ละท่านสามารถนำวิธีดังกล่าวไปประยุกต์ใช้เพิ่มเติมกับงานพัฒนาที่ท่านกำลังทำอยู่ หรือหากผู้อ่านท่านใดมีข้อเสนอแนะสามารถให้คำแนะนำมาได้นะคะ ทางเรายินดีรับฟังทุกข้อเสนอแนะ เพื่อเป็นการต่อยอดความรู้ร่วมกันนะคะ แล้วพบกันใหม่ในบทความหน้า และขอบคุณที่ติดตามกันนะคะ ^^

    แหล่งอ้างอิง

  • มาลองใส่ข้อความ/ภาพลายน้ำ(Watermark) บนรูปภาพที่เราอัพโหลดด้วย C# กันเถอะ

              ในการทำงานของนักพัฒนาโปรแกรม อาจจะมีบางงานที่มีความเกี่ยวข้องกับการบันทึกข้อมูลรูปภาพต่างๆลงบนเซิร์ฟเวอร์ และอาจมีความต้องการที่จะใส่ลายน้ำให้กับรูปภาพเหล่านั้น ซึ่งจริงๆแล้วการทำลายน้ำนั้น ถือเป็นกระบวนการหนึ่งในการคุ้มครองลิขสิทธิ์ ป้องกัน หรือปกป้องลิขสิทธิ์ของเจ้าของภาพผู้อัพโหลดข้อมูลหรือเป็นการแจ้งที่มาของภาพนั้นๆ เพื่อไม่ให้ผู้อื่นนำไปใช้ในทางมิชอบ และทำให้มั่นใจได้ว่าจะไม่สามารถนำกลับมาใช้ซ้ำหรือเปลี่ยนแปลงได้โดยไม่ได้รับอนุญาต นอกจากนี้ยังอาจใช้เป็นกลยุทธ์ในการสร้างแบรนด์ให้กับงานของคุณได้ หรืออาจทำหน้าที่เป็นตราประทับเพื่อระบุสถานะของเอกสารโดยมีคำเช่น “สำเนา” “ฉบับร่าง” หรือ “ตัวอย่าง” ซึ่งช่วยให้มั่นใจได้ว่าจะไม่มีการจัดการเอกสารสำคัญอย่างไม่ถูกต้อง อีกทั้งยังช่วยให้คุณสามารถจัดระเบียบงานของคุณได้ในขณะที่คุณทำเอกสารฉบับร่างให้เป็นเอกสารฉบับจริง

              และสำหรับในบทความนี้ทางผู้เขียนจึงถือโอกาสมาแนะนำวิธีการทำภาพลายน้ำให้กับรูปภาพที่เราบันทึกข้อมูลจากการอัพโหลดไฟล์โดยระบบที่พัฒนาขึ้นกันค่ะ โดยวิธีการเพิ่มลายน้ำสามารถทำได้หลายทาง อาจจะเป็นการนำรูปภาพทั้งหมดที่มีการอัพโหลดมาตกแต่งด้วยโปรแกรมตกแต่งภาพ แต่ในกรณีนี้ ผู้เขียนจะขอแนะนำวิธีเบื้องต้นในการพัฒนาโปรแกรมในการใส่ลายน้ำให้กับภาพตอนอัพโหลดไฟล์ด้วย C#  เพื่อเป็นแนวทางให้กับผู้อ่านได้นำไปต่อยอดงานพัฒนาของตนเองได้ ซึ่งในบทความนี้จะแบ่งวิธีที่มาแนะนำการใส่ลายน้ำให้กับรูปภาพที่อัพโหลดออกเป็น 2 แบบดังนี้ค่ะ

    1.การใส่ลายน้ำแบบข้อความ โดยการทำลายน้ำด้วยวิธีนี้ เราจะต้องมีการระบุข้อความที่เราต้องการให้แสดงลายน้ำในภาพที่ทำการอัพโหลด ซึ่งขั้นตอนการทำลายน้ำ มีดังนี้

    1.1 เพิ่ม Library ที่เกี่ยวข้องเพิ่มเติมเข้ามา

    using System.IO;
    using System.Drawing;

    1.2 สร้างหน้าจอที่มี File upload และปุ่มเพื่อทำการอัพโหลดไฟล์

    .aspx page

       <html >
            <head runat="server">
            <title></title>
            </head>
            <body>
                    <form id="form1" runat="server">
                            <div><asp:FileUpload ID="FileUpload" runat="server" />
                            <asp:Button runat="server" Text="Upload" ID="btnSave" OnClick="btnSave_Click" />
                            </div>
                    </form>
            </body>
        </html>

    1.3 สร้างเมธอดที่ใช้ในการสร้างภาพลายน้ำ ที่ชื่อว่า AddTextWatermark() โดยมีพารามิเตอร์เป็นข้อความที่ต้องการให้แสดงเป็นลายน้ำ ดังนี้

    Code C#

    เมธอด AddTextWatermark

     protected void AddTextWatermark(string watermarkText)
            {
                ////รับพารามิเตอร์เป็นข้อความที่ต้องการแสดงผล ในชื่อตัวแปร watermarkText 
                ////สร้างตัวแปรรูปภาพที่ได้จากการอัพโหลดไฟล์โดยผู้ใช้งาน ในชื่อตัวแปร image
                System.Drawing.Image image = System.Drawing.Image.FromStream(FileUpload.PostedFile.InputStream);
    
                ////หาค่าความกว้างและความสูงของภาพที่อัพโหลดใส่ตัวแปร w และ h
                int w = image.Width;
                int h = image.Height;
    
                ////สร้างตัวแปรชื่อรูปภาพที่จะบันทึกใหม่จากการรอัพโหลดไฟล์โดยผู้ใช้งาน ในชื่อตัวแปร genName
                string genName = Guid.NewGuid().ToString() + Path.GetExtension(FileUpload.PostedFile.FileName);
    
                ////สร้างตัวแปร Bitmap ในชื่อ bmp และระบุค่าความสูงและความกว้างตามภาพที่ได้ทำการอัพโหลด 
                System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(w, h);
    
                ////กำหนดค่าต่างๆให้กับ Graphics ในตัวแปรที่ชื่อว่า g จากตัวแปร Bitmap ที่สร้างไว้
                System.Drawing.Graphics g = System.Drawing.Graphics.FromImage((System.Drawing.Image)bmp);
                g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.High;
                g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
                g.Clear(System.Drawing.Color.Transparent);
                g.DrawImage(image, 0, 0, w, h);
    
                ////กำหนดขนาดของตัวอักษร และค่าต่างๆในการแสดงผลของตัวอักษรของข้อความ
                System.Drawing.Font drawFont = new System.Drawing.Font("Arial", 30, FontStyle.Bold, GraphicsUnit.Pixel);
    
                ////หาขนาดของข้อความ ตามค่าตัวอักษร(font)ที่ระบุข้างต้น
                SizeF textSize = new SizeF();
                textSize = g.MeasureString(watermarkText, drawFont);
    
                /////กำหนดสีของข้อความที่ต้องการทำลายน้ำและการกำหนดสีแบบ transparency
                System.Drawing.SolidBrush drawBrush = new System.Drawing.SolidBrush(Color.FromArgb(200, 211, 211, 211));
    
                /////กำหนดจุดหมุนจากจุดกึ่งกลางภาพ และหมุนให้ข้อความเอียง 45 องศา
                g.TranslateTransform(bmp.Width / 2, bmp.Height / 2);
                g.RotateTransform(45);
    
                ////ระบุข้อความ ลักษณะตัวอักษร สีและตำแหน่งในการวางข้อความลงบนรูปภาพที่กำหนด โดยจะกำหนดให้อยู่กึ่งกลางภาพแบบทะแยงมุม 45 องศา
                g.DrawString(watermarkText, drawFont, drawBrush, -(textSize.Width / 2), -(textSize.Height / 2));
                System.Drawing.Image newImage = (System.Drawing.Image)bmp;
    
                ////บันทึกภาพไปยังที่อยู่ไฟล์ที่ระบุ
                newImage.Save(Server.MapPath("~/Uploads/" + genName));
                g.Dispose();
            }

    เรียกใช้เมธอดเมื่อกดปุ่ม Upload โดยส่งพารามิเตอร์เป็นข้อความที่ต้องการให้แสดงลายน้ำบนภาพไป

    protected void btnSave_Click(object sender, EventArgs e) {       AddTextWatermark("Copyrights (c) 2023"); }

    ผลลัพธ์ตัวอย่าง

    เพิ่มเติม

    1. หากต้องการเปลี่ยนตำแหน่งของภาพลายน้ำ สามารถทำได้หลายแบบ โดยผู้เขียนจะขอยกตัวอย่างกรณีที่ต้องการให้ภาพลายน้ำอยู่ตำแหน่งขวาล่าง ซึ่งปรับแก้เพิ่มเติม ดังนี้
      เปลี่ยนจาก
      /////กำหนดจุดหมุนจากจุดกึ่งกลางภาพ และหมุนให้ข้อความเอียง 45 องศา
      g.TranslateTransform(bmp.Width / 2, bmp.Height / 2);
      g.RotateTransform(45);

      ////ระบุข้อความ ลักษณะตัวอักษร สีและตำแหน่งในการวางข้อความลงบนรูปภาพที่กำหนด โดยจะกำหนดให้อยู่กึ่งกลางภาพแบบทะแยงมุม 45 องศา
      g.DrawString(watermarkText, drawFont, drawBrush, -(textSize.Width / 2), -(textSize.Height / 2));
      System.Drawing.Image newImage = (System.Drawing.Image)bmp;
      เป็น 
      Point position = new Point((bmp.Width – ((int)textSize.Width + 10)), (bmp.Height – ((int)textSize.Height + 10)));

      ////ระบุข้อความ ลักษณะตัวอักษร สีและตำแหน่งในการวางข้อความลงบนรูปภาพที่กำหนด โดยจะกำหนดให้อยู่ขวาล่างแทน
      g.DrawString(watermarkText, drawFont, drawBrush, position);
      แทน
    2. ในการนำไปใช้งานจริง ในส่วนของตำแหน่ง สีและขนาดตัวอักษร ท่านสามารถระบุได้ตามความเหมาะสมเพื่อให้รองรับกับการใช้งานจริง ในตัวอย่างเป็นเพียงกรณีศึกษาเท่านั้นค่ะ

    ตัวอย่างผลลัพธ์หลังมีการปรับตำแหน่งการแสดงผลลายน้ำ

    2.การใส่ลายน้ำด้วยรูปภาพ หลังจากที่เราได้ลองทำลายน้ำบนภาพด้วยข้อความกันไปแล้ว คราวนี้เราจะลองแบบกรณีที่ต้องการให้นำภาพมาเป็นลายน้ำบนรูปภาพที่ทำการอัพโหลดกันบ้างค่ะ โดยมีวิธี ดังนี้นะคะ

    Code C#

    เมธอด AddImageWatermark

       protected void AddImageWatermark(string watermarkImagePath)
            {
                try {
                    ////สร้างตัวแปรชื่อรูปภาพที่จะบันทึกใหม่จากการรอัพโหลดไฟล์โดยผู้ใช้งาน ในชื่อตัวแปร genName
                    string genName = Guid.NewGuid().ToString() + Path.GetExtension(FileUpload.PostedFile.FileName);
    
                    ////ประกาศตัวแปรของไฟล์รูปภาพที่ทำการอัพโหลด
                    using (Bitmap image = (Bitmap)System.Drawing.Image.FromStream(FileUpload.PostedFile.InputStream))
    
                    ////ประกาศตัวแปรไฟล์ภาพที่ต้องการนำมาทำเป็นภาพลายน้ำ
                    using (System.Drawing.Image watermarkImage = System.Drawing.Image.FromFile(watermarkImagePath))
    
                    using (Graphics imageGraphics = Graphics.FromImage(image))
                    using (TextureBrush watermarkBrush = new TextureBrush(watermarkImage))
                    {
                        ////หาจุดตำแหน่งกึ่งกลางภาพที่ต้องการวางภาพลายน้ำ
                        int x = (image.Width / 2 - watermarkImage.Width / 2);
                        int y = (image.Height / 2 - watermarkImage.Height / 2);
                        watermarkBrush.TranslateTransform(x, y);
                        imageGraphics.FillRectangle(watermarkBrush, new Rectangle(new Point(x, y), new Size(watermarkImage.Width + 1, watermarkImage.Height)));
    
                        ////บันทึกรูปภาพตามที่อยู่(Path)ที่ระบุ
                        image.Save(Server.MapPath("~/Uploads/" + genName));
                    }
                }
                catch (Exception ex)
                {
                    ////แสดงข้อความแจ้งเตือนกรณีที่พบข้อผิดพลาดระหว่างดำเนินการ
                    Page.ClientScript.RegisterClientScriptBlock(Page.GetType(), "alert", "alert('ไม่สามารถอัพโหลดไฟล์และทำลายน้ำภาพดังกล่าวได้" + ex.Message + "')", true);
                }
               
            }

    เรียกใช้เมธอดเมื่อกดปุ่ม Upload โดยส่งพารามิเตอร์เป็นที่อยู่ของภาพที่ต้องการให้แสดงลายน้ำบนภาพไป

    protected void btnSave_Click(object sender, EventArgs e) { string strWaterMark = HttpContext.Current.Server.MapPath("~/images/preview.png");       AddImageWatermark(strWaterMark); }

    ผลลัพธ์ตัวอย่าง

    หมายเหตุ : หน้า aspx ที่ใช้จะเป็นแบบเดียวกับวิธีที่ 1 (การทำลายน้ำแบบข้อความ) แต่จะแตกต่างกันเฉพาะในส่วนของการทำงานใน btnSave_Click ที่มีการเรียกใช้เมธอดและส่งค่าพารามิเตอร์ต่างกันค่ะ

                    และทั้งหมดนี้ ก็เป็นวิธีการใส่ลายน้ำในเบื้องต้น ที่ผู้อ่านสามารถนำไปประยุกต์ใช้ให้เข้ากับงานของท่านได้ตามความสะดวกและความถนัดของแต่ละคน เพื่อให้รูปภาพ.o’kของเรามีลายน้ำได้โดยง่าย โดยที่ไม่ต้องเสียเวลามานั่งปรับแต่งรูปเองในภายหลังให้วุ่นวายกันค่ะ แต่ในการใช้งานจริง ผู้ใช้อาจจะต้องปรับค่าต่างๆให้เหมาะสมกับงานที่ใช้ เช่น ขนาดหรือสีตัวอักษร หรือขนาด/สีของรูปภาพที่ใช้เป็นลายน้ำ เพื่อให้ผลลัพธ์ของภาพลายน้ำออกมาสวยงาม และเหมาะสมไม่บดบังตัวภาพจริงจนเกินไปนะคะ ผู้เขียนหวังว่าเนื้อหาบทความนี้จะเป็นประโยชน์ให้กับนักพัฒนาที่กำลังตามหาวิธีการนี้กันอยู่นะคะหากมีคำแนะนำเพิ่มเติม สามารถชี้แนะเพื่อเป็นประโยชน์ร่วมกันได้ค่ะ ขอบคุณค่ะ

    แหล่งอ้างอิง

  • [บันทึกันลืม] Shell script เพื่อทำงาน parallel ด้วย screen

    Parellel processing

    เมื่อเราเขียน shell script เพื่อทำหลาย ๆ งานพร้อมกัน เช่น มีข้อมูล 1,000,000 รายการ ถ้าวิธีแบบ Sequential ก็เริ่มจาก 1, 2, 3, …, 1,000,000 ซึ่งก็จะเสียเวลามาก เพราะต้องรอให้ งานที่ 1 เสร็จก่อน แล้วถึงไปทำงานที่ 2, 3 ถ้าแต่ละงานให้เวลา 1 วินาที ก็ต้องใช้เวลา 1,000,000 วินาที กว่าจะเสร็จ

    แต่ถ้าเราแบ่ง เป็น 100 process ย่อย ๆ แต่ละ process จัดการ 10,000 รายการ ก็จะใช้เวลาลดลง (เมื่อ resources เหลือเฟือ) ทั้งนี้ก็ขึ้นกับประสิทธิภาพเครื่องคอมพิวเตอร์ด้วย

    เช่น เรามี process.py หน้าตาประมาณนี้

    import time
    import sys
    def processing(start_position, steps):
        # something blah
        for i in range(start_position, start_position+steps):
            print(f'processing {i}')
            time.sleep(1)
    
    def main():
        start_position=sys.argv[1]
        steps=sys.argv[2]
        processing(start_position, steps)
    
    if __name__ == "__main__":
        main()
    

    เดิมเราก็จะใช้เครื่องหมาย & เพื่อทำให้ไปอยู่ background

    !/bin/bash
    for i in $(seq 1 100); do
        python3 process.py $i 10000 &amp;
    done
    

    ปัญหาคือ เราจะไม่สามารถดูได้ว่า ตอนนี้ แต่ละ process ไปถึงไหนแล้ว

    screen

    screen เป็น Utility ที่ทำให้เราสามารถส่งคำสั่งไปทำงาน แล้วค่อยสลับเข้าไปดูได้ เทคนิคการใช้งานคำสั่ง screen บน Linux

    เราก็เปลี่ยนจากการใช้ & ต่อท้าย เป็น screen แทนดังนี้

    !/bin/bash
    for i in $(seq 1 100); do
        screen -S p$i -dm python3 process.py $i 10000
    done
    
    

    วิธีนี้ ทำให้สามารถใช้คำสั่ง

    screen -ls
    

    และ

    screen -r p1
    

    เพื่อเข้าไปดูว่า ตอนนี้ process p1 ทำงานถึงไหนแล้ว

    หวังว่าจะเป็นประโยชน์ครับ

  • Create a feedback form with NotionForms

    สวัสดีท่านผู้อ่านทุกๆ ท่าน มาค่ะ เรามาต่อกันใน Blog ที่ 4 ของรอบ TOR นี้
    ซึ่งผู้เขียนขอพาไปรู้จักกับ NotionForms

    ถ้าพร้อมแล้ว ไปค่ะ ไปเรียนรู้ไปพร้อมๆ กัน 😜


    NotionForms 💬
    NotionForms was created to help Notion users to achieve more with their favourite tool.
    Need a contact form? Doing a survey? Create a form in 3 minutes
    and receive responses directly in Notion.


    เอาจริงๆ หลายๆ ท่านก็คงจะรู้จักวิธีการสร้างฟอร์ม สร้างแบบสอบถาม ด้วยเครื่องมืออื่นๆ มาบ้างแล้ว เช่น google form, microsoft form หรือ อื่นๆ NotionForms ก็คล้ายๆ กับเครื่องมือเหล่านั้น อาจจะมีแตกต่างกันบ้างในเรื่องของลูกเล่น หรือฟังก์ชัน ให้เราได้ลองใช้งานกันค่ะ

    เมื่อพร้อมแล้ว เรามาทดลองสร้าง Form ด้วย NotionForms ตัวนี้กันเลย

    💡 หมายเหตุ : แบบฟอร์มที่เราสร้างขึ้นด้วย NotionForms ข้อมูลการตอบกลับจะถูกเก็บไว้ใน Notion

    Step 1

    ก่อนอื่นเราต้องสร้างฐานข้อมูลหรือตารางสำหรับจัดเก็บข้อมูลแบบฟอร์มของเราขึ้นมาก่อน ตัวอย่างใน Blog นี้ผู้เขียนขอสร้างตารางชื่อ Admission Feedback เก็บข้อมูล 4 column
    – name (type = text)
    – feedback (type = text)
    – the system is easy to use (type = select)
    – How do you feel after using the system (type = select)

    โดย column ที่อยู่ในรูปแบบ select เราก็จะเพิ่ม option เข้าไป เช่น column “How do you feel after using the system” ก็จะมี 2 option
    1. 👍 ฉันถูกใจสิ่งนี้
    2. 👎 ฉันไม่ถูกใจ

    📌 วิธีการสร้าง Table เก็บข้อมูลใน notion สามารถตามไปอ่านได้ใน Blog ก่อนหน้า จัดการข้อมูลง่ายๆ ด้วย Database Notion

    Step 2

    ไปยัง NotionForms

    คลิก Create Form จากนั้น Register ข้อมูล โดยใช้ Email เดียวกับตอนสมัครเว็บไซต์ Notion

    Step 3

    คลิก Create a new form

    Step 4

    ให้เลือก Notion Database Name สำหรับขั้นตอนนี้ให้เราระบุชื่อ Database ที่เราสร้างไว้ใน Notion (ตามในขั้นตอนที่ 1) จากตัวอย่างเราจะเลือก Database ที่ชื่อ Admission Feedback


    Step 5

    NotionForms จะดึงข้อมูล Column ทั้งหมดที่เราสร้างไว้ใน Admission Feedback จาก Notion ขึ้นมาแสดง เราสามารถปรับแต่งการแสดงผลของ Forms ได้ตามต้องการ (setting ได้ภายใต้ฟังก์ชันที่ใช้ฟรีอะนะทุกคน 😜)

    Step 6

    แนะนำให้เพื่อนๆ เลื่อนลงมาในส่วนของการ Custom Block เราสามารถกำหนดการแสดงผลข้อมูล Column ของเราได้ เช่น ปิด/เปิด การแสดงผลหัวข้อใน form ได้ และยังสามารถ setting ค่าอื่นๆ เพิ่มเติมได้

    Step 7

    ตัวอย่างแบบฟอร์มนี้ผู้เขียนต้องการให้ Column ที่เป็น Type select ทั้ง 2 รายการ แสดงข้อมูล Option ภายในที่เรากำหนดเอาไว้ทันที โดยไม่ต้องคลิกเลือกจาก Dropdownlist ในฟอร์ม

    วิธีการ คือ ในส่วนของ Custom Block ให้ผู้ใช้ทดลองคลิก ⚙️ หลัง column จากนั้นเลื่อนหาส่วน select Option ให้ ✅ หน้าช่อง Always show all select options.

    Step 8

    ตัวอย่างผลลัพธ์การแสดงผลของ Form ที่ได้จากการตั้งค่าของเรา ก็จะแสดง Option ภายในที่เรากำหนดไว้ หากเราพอใจแล้ว ต้องการนำ Form ดังกล่าวไปใช้ต่อ ให้เพื่อนๆ คลิก “Create Form” ได้เลย

    Step 9

    NotionForms ก็จะ Generate URL ขึ้นมาให้เราซึ่งสามารถ copy และนำไปใช้ต่อได้เลย

    ตัวอย่างการนำมา embed ไว้ใน Notion Page ของเรา เพียงเท่านี้เราก็จะได้หน้าสำหรับเก็บ Feedback จากลูกค้าแบบน่ารัก น่าใช้ สวยงาม ด้วยเวลาอันรวดเร็ว

    👍👍👍


    เป็นยังไงกันบ้างค่ะ ผู้เขียนก็ยังคงหวังเป็นอย่างยิ่งว่า Blog นี้จะมีประโยชน์กับใครหลายๆคน ให้สามารถนำไปปรับใช้ หรืออย่างน้อยได้มาทำความรู้จัก เห็นหน้าค่าตากับเจ้าตัวที่ชื่อว่า NotionForms กันไม่มากก็น้อย

    💜💙💚 ตามคติ รู้ไว้ใช่ว่า ใส่บ่าแบกหามมม นะทุกคน 💚💙💜

    📍 พบกันใหม่ใน Blog หน้า ส่วนจะเป็นเรื่องอะไรนั้น ตอนนี้ผู้เขียนก็ยังนึกไม่ออกแหละ 555+ เอาเป็นว่าเจอกันใหม่โอกาสหน้าน๊า ….. 🙂

  • จัดการข้อมูลง่ายๆ ด้วย Database ใน Notion

    สวัสดีท่านผู้อ่านทุกๆ ท่าน สำหรับ Blog ที่ 3 ในรอบ TOR นี้ ผู้เขียนขอแนะนำการสร้าง Database เก็บข้อมูลบน Notion กันค่ะ

    📍 Blog นี้จะไม่ลงลึกในส่วนการสมัครใช้งาน notion แต่จะเน้นในส่วนของการสร้าง Table เพื่อเก็บข้อมูล

    Notion 💬
    Notion is a workspace with lots of tools to help you stay organized and productive.
    You can use notes, tasks, wikis and databases to manage projects, tasks, ideas and more.

    📲 More than a doc. Or a table. Customize Notion to work the way you do.


    📢 หากผู้อ่านอยากรู้ว่า Notion คืออะไร สามารถไปอ่านได้ที่ More than noting “Notion” ซึ่งมีสมาชิกผู้ร่วมอุดมการณ์เขียนแบบย่อๆ เอาไว้เรียบร้อยแล้ว

    มาค่ะ เรามาเริ่มขั้นตอนการสร้าง Database Notion กัน —>> สมัครใช้งาน Notion คลิกที่นี่ 📌

    ตัวอย่าง Blog นี้จะแนะนำการสร้าง Table สำหรับเก็บข้อมูลบันทึกการแจ้งปัญหาการใช้งานจากลูกค้า


    📝 Step 1 — เมื่อเราสมัครใช้งานให้เรียบร้อยแล้ว ให้เราเลือก Add a page ขึ้นมาจาก Sidebar ด้านซ้ายมือ

    📝 Step 2 — ตั้งชื่อ Page ตามต้องการ ตัวอย่างนี้ขอตั้งชื่อ “Report Problem” และเลือก Database รูปแบบ “Table”

    📝 Step 3 — เลือก New database เพื่อเริ่มต้นกำหนดและสร้าง Table เพื่อเก็บข้อมูลในรูปแบบที่เราต้องการ

    📝 Step 4 — กำหนด column ที่เราต้องการลงใน Table ตัวอย่างจะเก็บข้อมูล 5 column (ผู้อ่านสามารถทดลองกำหนดในรูปแบบตามที่ตนเองต้องการได้เลย)

    • รายละเอียดของปัญหา (Type = Text)
    • Category (Type = Multi-select)
    • ชื่อผู้แจ้ง (Type = Text)
    • หมายเลขติดต่อกลับ (Type = Phone)
    • วันที่แจ้ง (Type = Date)

    📝 Step 5 — เรามาทดสอบเพิ่มข้อมูลลง Table กัน ให้เอาเมาส์ไปชี้บน record ว่าง ใน column แรก เลือก OPEN ก็จะปรากฏหน้าจอให้เราเพิ่มรายละเอียดข้อมูลตามรายการ Column ที่เราสร้างไว้

    💡 แนะนำให้ทดลองเพิ่มเข้าไปหลายๆ รายการนะ

    📝 Step 6 — เมื่อสร้างรายการเรียบร้อยแล้ว เรามาลองนำข้อมูลรายการดังกล่าวที่อยู่ในมุมมอง Table ไปแสดงในมุมมองอื่นๆ –>> ให้เราคลิกสัญลักษณ์ +

    📝 Step 7 — เราสามารถเลือก View ได้หลายมุมมอง เช่น Calendar, Board, Timeline, List หรือ Gallery ตัวอย่างนี้ขอทดลองแสดงในรูปแบบ Calendar ละกันนะ

    💡 เราสามารถ Customize การแสดงผลข้อมูลในหน้าดังกล่าวเพิ่มเติมได้นะ ให้คลิกตรงจุด 3 จุดหน้าปุ่ม New ตามในรูป จากนั้น หน้าต่าง notion ก็จะ View Option ขึ้นมาให้เราสามารถกำหนด หรือปรับเปลี่ยนได้ตามต้องการ

    📌 สะดวก ใช้งานง่าย มี Template มากมาย รวมทุกฟังก์ชันไว้ในที่เดียว แนะนำ Notion นะทุกคน ! 📌


    📢 สุดท้าย ท้ายสุด ผู้เขียนหวังเป็นอย่างยิ่งว่า Blog นี้จะเป็นประโยชน์ต่อผู้อ่านไม่มากก็น้อยค่ะ แล้วพบกันใหม่
    Blog หน้า จะมาแนะนำการสร้าง Notion Form เพื่อสร้างแบบสำรวจ หรือแบบฟอร์มเก็บข้อมูล Feedback จากลูกค้ากันค่ะ

  • [บันทึกกันลืม] วิธีติดตั้ง mariadb package สำหรับ python บน Ubuntu

    เรามักเข้าใจว่าแค่ใข้คำสั่ง

    pip install mariadb

    แล้วจะก็จะเรียกใช้งานได้ แต่จริง ๆ แล้ว ไม่ใช่ เพราะจะต้องติดตั้ง package บน OS (ในที่นี้จะเป็น Ubuntu 20.04 – focal)

    sudo apt install libmariadb3 libmariadb-dev

    แต่จะติดตั้ง package นี้ได้ จะต้องติดตั้ง MariaDB Connector/C Community Server package repository (CS)

    ซึ่งขั้นตอนต้นฉบับของ mariadb นั้น ก็ช่าง …. ซับซ้อน ลิงค์ไปมา

    https://mariadb.com/docs/server/connect/programming-languages/python/install/#Prerequisites_for_Source_Distributions

    https://mariadb.com/docs/server/connect/programming-languages/c/install/

    ซึ่งจุดใหญ่ใจความคือ การติดตั้ง repository ให้ได้ แล้วก็จะติดตั้ง package ได้

    เลยบันทึกกันลืมไว้ที่นี่ copy วางได้เลย

    sudo apt install wget -y
    wget https://downloads.mariadb.com/MariaDB/mariadb_repo_setup
    echo "367a80b01083c34899958cdd62525104a3de6069161d309039e84048d89ee98b  mariadb_repo_setup" \
        | sha256sum -c -
    chmod +x mariadb_repo_setup
    sudo ./mariadb_repo_setup \
       --os-type='ubuntu' \
       --os-version='focal' \
       --mariadb-server-version="mariadb-10.6"
    sudo apt update -y
    sudo apt install libmariadb3 libmariadb-dev -y
    pip3 install mariadb
    

    เท่านี้แหล่ะ

    Update สำหรับ Ubuntu 22.04

    ไม่รู้ว่าเกี่ยวกับการเป็น Ubuntu pro หรือไม่ แต่ libssl1.1 ไม่สามารถลงตรง ๆ ได้ ต้องทำดังนี้

    wget http://archive.ubuntu.com/ubuntu/pool/main/o/openssl/libssl1.1_1.1.1f-1ubuntu2_amd64.deb
    sudo dpkg -i libssl1.1_1.1.1f-1ubuntu2_amd64.deb
    sudo apt install libmariadbclient-dev