สำหรับเรื่องการสร้าง Crystal Report ที่มี Image บน Report นั้น ถ้าแบบ Static ก็คงจะไม่ยากอะไรเพียงแค่ add picture ตรงๆ จาก Report View แต่ถ้าหากสมมติเราต้องการให้ Image ของเราสามารถเปลี่ยนแปลงไปตาม database หรือชุดข้อมูลที่เราต้องการนั้น นับว่า โหดเอาการทีเดียวครับ แต่ทุกปัญหาย่อมมีทางออกครับ เมื่อตอนที่ผมทำงานเกี่ยวกับ Crystal Report ก็เจอปัญหานี้เช่นกัน(เมื่อนานมาแล้ว) ความรู้อาจจะมีหลงๆลืมๆบ้าง(ฮะฮ่าๆ อย่าว่ากันนะครับ) เพราะตอนนี้ผมไม่ได้เล่นตัว Crystal Report แล้วครับ แต่ทำ Report ด้วยวิธีอื่น ซึ่งผมคิดว่าง่ายและสะดวกกว่าการทำ Crystal ครับ(แล้วแต่ประเภทของงาน) ซึ่งสิ่งที่ว่านี้ก็คือ การใช้ Microsoft Charting ครับเป็นผลิตภัณฑ์(ที่ฟรี) ตัวใหม่ของ Microsoft ครับ คราวหน้าผมจะเขียนถึงการใช้มันในเบื้องต้น คิดว่าจะเป็นหัวข้อที่น่าสนใจแน่นอนครับ
OK นอกเรื่องมาพอสมควรแล้ว กลับมาสุดจุดเริ่มต้นของการ create dynamic image กันต่อนะครับ สิ่งแรกที่ผมแนะนำก่อนการใส่ Image แบบ Dynamic คือ สร้าง DataSet ก่อนครับ Okอาจจะงงๆแต่วิธีนี้ไม่ยากอย่างที่คิด ออ อย่าลืม import library 3 ตัวนี้ก่อน มาดูกันทีละขั้นเลยนะครับ
using System.Data;
using System.IO;
using CrystalDecisions.CrystalReports.Engine;
1. เพื่อความง่ายจะแบ่งเป็นMethod โดยสิ่งที่เราต้องการอันดับแรกคือ Xml Schema สำหรับ Binary ของ Image และ Path ของ Image ครับ ที่ต้องการก็เพราะว่าเราจะเอา Xml Schema ตัวนี้ไปใช้อ้างอิงจากตัว Crystal Report Viewer ครับใน step ต่อๆไป หลายคนอาจจะสงสัยว่า การอ้างอิง Field จาก Report Viewer ก็สามารถใช้ Strongly Type DataSet (.xsd) ของ Visual Studio ได้หนิ ทำไมเราต้องสร้าง Xml Schema ให้วุ่นวาย คำตอบ คือใน Crystal Report ตัวเก่าที่ผมและเพื่อนๆใช้กันอยู่นั้นมี Bug ... ใช่ครับมี bug ซึ่งทำให้การ Reference ไปยัง .xsd นั้นมีข้อผิดพลาดที่ร้ายแรงเกิดขึ้น ไปลองดูได้ครับว่าอะไร เพราะผมจำไม่ได้แล้ว (เรื่องมันนานนนนนมาแล้วหนะ) แต่สำหรับ Crystal Report ตัวใหม่ๆสุดๆนั้น ได้ทำการแก้ปัญหานี้แล้วครับ เรื่องรายละเอียดพวกนี้หาอ่านได้ครับ (ลอง google ดูนะ) ดังนั้นสรุปคือ เราต้องใช้ Xml Schema นั่่นเอง (โห.. พิมซะยืดดดยาวว)
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
PrepareXmlSchemaForImage();
}
}
private void PrepareXmlSchemaForImage()
{
DataSet dSet = new DataSet();
//create table in dSet for storing an image
dSet.Tables.Add("imgTable");
DataTable dTable = dSet.Tables["imgTable"];
DataColumn dCol1 = new DataColumn();
dCol1.DataType = System.Type.GetType("System.Byte[]"); //ตรงนี้สำคัญดูดีๆครับ
dCol1.ColumnName = "image"; //ชื่อนี้จะเป็นชื่อ field ใน crystal report viewer
dTable.Columns.Add(dCol1);
dCol1 = new DataColumn();
dCol1.DataType = System.Type.GetType("System.String"); //ตรงนี้สำคัญดูดีๆครับ
dCol1.ColumnName = "path"; //ชื่อนี้จะเป็นชื่อ field ใน crystal report viewer
dTable.Columns.Add(dCol1);
dSet.WriteXmlSchema("c:\\report_schema_for_img.xml"); //used for creating a xml schema of dataset
}
จากนั้น Run Application เลยครับ เราจะได้ report_schema_for_img.xml และนำมันมา include มาใส่ Project ของเราให้เรียบร้อย
พอเสร็จให้เรา mark comment(หรือลบทิ้ง) PrepareXmlSchemaForImage() ไปเลยครับ เราไม่ใช้แล้ว(ได้ schema แล้ว) ซึ่งไฟล์นี้จะนำไปใ้ช้ต่อไปครับ
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
//PrepareXmlSchemaForImage();
}
}
2.ต่อจากนั้นสร้าง Report เลยครับตามภาพ

สมมติชื่อ TestImgReport.rpt

เลือก standard

double click at Make New Connในหัวข้อ ADO.NET จะมีหน้าต่างขึ้นมาก็เลือก path ไปที่ๆ Xml schema ถูกสร้างมา(ในproject เราอะ) แล้วกด finish ซะ

จะได้ newdataset ออกมาเลือก imgTable แล้ว >> ไปฝั่งขวา ได้ผลลัพธ์ดังรูป

ถ้าสังเกต Field Explorer จะเห็นตามนี้ แปลว่ามาถูกทางแ้ล้ว แล้วเราก็ลาก image field ใน imgTable ลงมาวางที่ๆเราต้องการ ถ้ากดดู obj format ของ image จะเห็น format เป็น Blob object ซึ่งobjตัวนี้แหละที่จะเก็บ binary ของรูปที่เราต้องการ จากนั้นก็ตัดแต่ง Report ของเราได้ตามสบาย
3. กลับมาที่coding อีกหน่อย ก็คือเราต้องทำการระบุ Image ที่เราต้องการให้กับ Blob object ของ Report ที่เราเพิ่งจะสร้างมะกี้ครับ ผมเขียน comment เป็นอังกฤษนะครับ (ขี้เกียจเปลี่ยน) - -
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
//PrepareXmlSchemaForImage();
ConstructAndSaveReport(); //เพื่อความไม่งงผมจึงเขียนแบบนี้ครับ
}
}
private void ConstructAndSaveReport()
{
//convert img into binary by using FileStream
FileStream FilStr = new FileStream(Server.MapPath("Images/pic.jpg"), FileMode.Open); //path รูปที่ต้องการครับจะเห็นว่าเป็นแบบ dynamic
byte[] imageBytes = new byte[FilStr.Length];
FilStr.Read(imageBytes, 0, Convert.ToInt32(FilStr.Length));
//-----------this part is copied from previous PrepareXmlSchemaForImage() method---------
DataSet dSet = new DataSet();
//create table in dSet for storing an image
dSet.Tables.Add("imgTable");
DataTable dTable = dSet.Tables["imgTable"];
DataColumn dCol1 = new DataColumn();
dCol1.DataType = System.Type.GetType("System.Byte[]"); //ตรงนี้สำคัญดูดีๆครับ
dCol1.ColumnName = "image"; //ชื่อนี้จะเป็นชื่อ field ใน crystal report viewer
dTable.Columns.Add(dCol1);
dCol1 = new DataColumn();
dCol1.DataType = System.Type.GetType("System.String"); //ตรงนี้สำคัญดูดีๆครับ
dCol1.ColumnName = "path"; //ชื่อนี้จะเป็นชื่อ field ใน crystal report viewer
dTable.Columns.Add(dCol1);
//---------------------------------------------------------------------------------------
//Add new row and give'em the values (imageBytes and Path string)
dTable.Rows.Add(dTable.NewRow());
dTable.Rows[0]["image"] = imageBytes;//BinRed.ReadBytes((int)BinRed.BaseStream.Length);
dTable.Rows[0]["path"] = Server.MapPath("Images/pic.jpg");
FilStr.Close();
//finally, build the complete report and configure some properties.
ReportDocument tmpReportDoc = new ReportDocument();
string reportPath = Server.MapPath("TestImgReport.rpt");
tmpReportDoc.Load(reportPath);
tmpReportDoc.SetDataSource(dSet); //load source from our DataSet
UpdatePictureObjectProperties(tmpReportDoc); //OPTIONAL - configure some image properties อันนี้ไม่ต้องมีก็ได้ครับ
tmpReportDoc.ExportToDisk(CrystalDecisions.Shared.ExportFormatType.PortableDocFormat, Server.MapPath("example.pdf")); //defined type of PDF format
}
private void UpdatePictureObjectProperties(ReportDocument reportDocument)
{
ReportObject reportObject = reportDocument.ReportDefinition.ReportObjects["image1"]; //ขอให้เป็นชื่อใน object name ใน crystal report viewer นะครับ
if (reportObject != null)
{
ObjectFormat objectFormat = reportObject.ObjectFormat;
objectFormat.EnableCanGrow = false;
//objectFormat.EnableSuppress = true;
objectFormat.EnableCloseAtPageBreak = true;
objectFormat.EnableKeepTogether = true;
}
}
สำหรับ การปรับแต่ง ObjectFormat ก็สามารถดูได้ทีั่นี่ http://msdn.microsoft.com/en-us/library/ms225881%28VS.80%29.aspx เลยนะครับ

ผลลัพธ์ example.pdf ครับ จากตัวอย่างข้างต้นหวังว่าเพื่อนๆจะเข้าใจถึงการใช้ dynamic image ใน crystal report นะครับ ถ้ายังงงก็ leave comment ไว้หละ
af4d8a03-0d57-43f9-bce8-f93e630c855b|1|5.0