革博士程序V1仓库
Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.

562 wiersze
24 KiB

  1. using System;
  2. using System.Collections.Generic;
  3. using System.ComponentModel;
  4. using System.Drawing;
  5. using System.Drawing.Imaging;
  6. using System.IO;
  7. using System.Linq;
  8. using System.Reflection;
  9. using System.Runtime.InteropServices;
  10. using System.Text;
  11. using System.Threading;
  12. using System.Threading.Tasks;
  13. using System.Timers;
  14. using System.Windows.Forms;
  15. using IKapBoardClassLibrary;
  16. using LeatherApp.Interface;
  17. using Newtonsoft.Json.Linq;
  18. using OpenCvSharp;
  19. using OpenCvSharp.Dnn;
  20. using ErrorCode = IKapBoardClassLibrary.ErrorCode;
  21. namespace LeatherApp.Device
  22. {
  23. public class CamerCardDev2 : ABSCamerCardDev,IDisposable
  24. {
  25. [DllImport("user32.dll")]
  26. [return: MarshalAs(UnmanagedType.Bool)]
  27. private static extern bool IsWindow(IntPtr hWnd);
  28. [DllImport("kernel32.dll", EntryPoint = "RtlCopyMemory", SetLastError = false)]
  29. public static extern void CopyMemory(IntPtr dest, IntPtr src, uint count);
  30. [DllImport("User32.dll")]
  31. public extern static System.IntPtr GetDC(System.IntPtr hWnd);
  32. [DllImport("user32.dll")]
  33. private static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);
  34. //显示图像控件句柄
  35. private PictureBox previewHwnd = null;
  36. //
  37. // 采集卡设备句柄。
  38. public IntPtr m_hBoard = new IntPtr(-1);
  39. // 当前帧索引。
  40. public int m_nCurFrameIndex = 0;
  41. // 图像缓冲区申请的帧数。
  42. public int m_nTotalFrameCount = 1;
  43. // 保存图像的文件名。
  44. public string m_strFileName = "C:\\CSharpImage.bmp";
  45. //
  46. private int scanIndex = 0; //实际拍照从1开始命名,因先加的1
  47. private string bmpSavePath;
  48. /// <summary>
  49. /// 曝光 3.00-10000.00
  50. /// </summary>
  51. public float ExposureTime { get; private set; }
  52. /// <summary>
  53. /// 增益 0-23.981199
  54. /// </summary>
  55. public float Gain { get; private set; }
  56. /// <summary>
  57. /// 帧率 0-429496.718750
  58. /// </summary>
  59. public float ResultingFrameRate { get; private set; }
  60. /// <summary>
  61. /// 图片大小
  62. /// </summary>
  63. public System.Drawing.Size size { get; private set; }
  64. /// <summary>
  65. /// 是否打开设备成功
  66. /// </summary>
  67. public bool IsInit { get; private set; } = false;
  68. //public string ErrInfo { get; private set; }
  69. //private System.Timers.Timer timer = new System.Timers.Timer();
  70. private int _scannerCardIndex = 0;//采集卡索引
  71. private int _scannerIndex=0;//相机索引(一个采集卡上可插多个相机)
  72. public CamerCardDev2( )
  73. {
  74. }
  75. public override bool open(int cardIndex = 0,int scannerIndex = 0)
  76. {
  77. if (IsInit) return true;
  78. //m_stIFInfoList = _m_stIFInfoList;
  79. _scannerCardIndex = cardIndex;
  80. _scannerIndex = scannerIndex;
  81. System.GC.Collect();
  82. try
  83. {
  84. int ret = (int)ErrorCode.IK_RTN_OK;
  85. uint nPCIeDevCount = 0;
  86. StringBuilder resourceName;
  87. uint resourceNameSize = 0;
  88. IKapBoard.IKAPERRORINFO tIKei = new IKapBoard.IKAPERRORINFO();
  89. // 获取连接的采集卡数量。
  90. ret = IKapBoard.IKapGetBoardCount((int)BoardType.IKBoardPCIE, ref nPCIeDevCount);
  91. CheckIKapBoard(ret);
  92. // 当没有连接的采集卡时。
  93. if (nPCIeDevCount == 0 || nPCIeDevCount< cardIndex+1)
  94. {
  95. WarningEvent?.Invoke(WarningEnum.High, "Get board count 0");
  96. return false;
  97. }
  98. // 获取采集卡名称。
  99. for (uint i = 0; i < nPCIeDevCount; i++)
  100. {
  101. resourceNameSize = 0;
  102. resourceName = new StringBuilder(0);
  103. IKapBoard.IKapGetBoardName((uint)BoardType.IKBoardPCIE, i, resourceName, ref resourceNameSize);
  104. IKapBoard.IKapGetLastError(ref tIKei, true);
  105. if (tIKei.uErrorCode == (uint)ErrorCode.IKStatus_BufferTooSmall)
  106. {
  107. resourceName = new StringBuilder((int)resourceNameSize);
  108. IKapBoard.IKapGetBoardName((uint)BoardType.IKBoardPCIE, i, resourceName, ref resourceNameSize);
  109. }
  110. IKapBoard.IKapGetLastError(ref tIKei, true);
  111. if (tIKei.uErrorCode != (uint)ErrorCode.IKStatus_Success)
  112. {
  113. WarningEvent?.Invoke(WarningEnum.High, "Get Device Name Fail. Error Code:"+tIKei.uErrorCode);
  114. return false;
  115. }
  116. string sMesg = string.Concat("PCIE Device- ", i.ToString("d"), "\nName: ", resourceName);
  117. }
  118. // 打开采集卡。
  119. //
  120. // Open frame grabber.
  121. m_hBoard = IKapBoard.IKapOpen((int)BoardType.IKBoardPCIE, 0);//采集卡索引0-n
  122. if (m_hBoard.Equals(-1))
  123. {
  124. WarningEvent?.Invoke(WarningEnum.High, "Open device failure!");
  125. return false;
  126. }
  127. // 导入配置文件。
  128. string configFileName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + "\\DevCfg\\"+ Config.CarmerConfigFilePath;
  129. if (!File.Exists(configFileName))
  130. {
  131. WarningEvent?.Invoke(WarningEnum.High, "Fail to get configuration, using default setting!");
  132. return false;
  133. }
  134. ret = IKapBoard.IKapLoadConfigurationFromFile(m_hBoard, configFileName);
  135. CheckIKapBoard(ret);
  136. // 设置图像缓冲区帧数。
  137. //
  138. // Set frame count of buffer.
  139. ret = IKapBoard.IKapSetInfo(m_hBoard, (uint)INFO_ID.IKP_FRAME_COUNT, m_nTotalFrameCount);
  140. CheckIKapBoard(ret);
  141. // 设置超时时间。
  142. //
  143. // Set time out time.
  144. int timeout = -1;
  145. ret = IKapBoard.IKapSetInfo(m_hBoard, (uint)INFO_ID.IKP_TIME_OUT, timeout);
  146. CheckIKapBoard(ret);
  147. // 设置采集模式。
  148. //
  149. // Set grab mode.
  150. int grab_mode = (int)GrabMode.IKP_GRAB_NON_BLOCK;//非阻塞StartGrab
  151. ret = IKapBoard.IKapSetInfo(m_hBoard, (uint)INFO_ID.IKP_GRAB_MODE, grab_mode);
  152. CheckIKapBoard(ret);
  153. // 设置传输模式。
  154. //
  155. // Set transfer mode.
  156. int transfer_mode = (int)FrameTransferMode.IKP_FRAME_TRANSFER_SYNCHRONOUS_NEXT_EMPTY_WITH_PROTECT;
  157. ret = IKapBoard.IKapSetInfo(m_hBoard, (uint)INFO_ID.IKP_FRAME_TRANSFER_MODE, transfer_mode);
  158. CheckIKapBoard(ret);
  159. // 注册回调函数
  160. //
  161. // Register callback functions.
  162. OnGrabStartProc = new IKapCallBackProc(OnGrabStartFunc);
  163. ret = IKapBoard.IKapRegisterCallback(m_hBoard, (uint)CallBackEvents.IKEvent_GrabStart, Marshal.GetFunctionPointerForDelegate(OnGrabStartProc), m_hBoard);
  164. CheckIKapBoard(ret);
  165. OnFrameReadyProc = new IKapCallBackProc(OnFrameReadyFunc);
  166. ret = IKapBoard.IKapRegisterCallback(m_hBoard, (uint)CallBackEvents.IKEvent_FrameReady, Marshal.GetFunctionPointerForDelegate(OnFrameReadyProc), m_hBoard);
  167. CheckIKapBoard(ret);
  168. OnFrameLostProc = new IKapCallBackProc(OnFrameLostFunc);
  169. ret = IKapBoard.IKapRegisterCallback(m_hBoard, (uint)CallBackEvents.IKEvent_FrameLost, Marshal.GetFunctionPointerForDelegate(OnFrameLostProc), m_hBoard);
  170. CheckIKapBoard(ret);
  171. OnTimeoutProc = new IKapCallBackProc(OnTimeoutFunc);
  172. ret = IKapBoard.IKapRegisterCallback(m_hBoard, (uint)CallBackEvents.IKEvent_TimeOut, Marshal.GetFunctionPointerForDelegate(OnTimeoutProc), m_hBoard);
  173. CheckIKapBoard(ret);
  174. OnGrabStopProc = new IKapCallBackProc(OnGrabStopFunc);
  175. ret = IKapBoard.IKapRegisterCallback(m_hBoard, (uint)CallBackEvents.IKEvent_GrabStop, Marshal.GetFunctionPointerForDelegate(OnGrabStopProc), m_hBoard);
  176. CheckIKapBoard(ret);
  177. // 设置行触发参数。
  178. //SetLineTrigger();
  179. //
  180. getParam();
  181. IsInit = true;
  182. //timer.Elapsed += Timer_Elapsed;
  183. //timer.Interval = 100;
  184. //timer.Enabled = true;
  185. return true;
  186. }
  187. catch (Exception ex)
  188. {
  189. WarningEvent?.Invoke(WarningEnum.High, ex.Message);
  190. return false;
  191. }
  192. }
  193. public override void close()
  194. {
  195. if (!IsInit) return;
  196. try
  197. {
  198. IsInit = false;
  199. // 清除回调函数。
  200. UnRegisterCallback();
  201. // 关闭设备。
  202. CloseDevice();
  203. }
  204. catch { }
  205. }
  206. /// <summary>
  207. ///
  208. /// </summary>
  209. /// <param name="hwnd">显示图像控件句柄</param>
  210. /// <returns></returns>
  211. public override bool start(PictureBox preview_Hwnd,string bmp_save_path)
  212. {
  213. if (!IsInit) return false;
  214. this.previewHwnd= preview_Hwnd;
  215. this.bmpSavePath = bmp_save_path;
  216. //开始采集
  217. //第二个参数 nFrameCount 表示希望 IKapBoardClassLibrary 采集的帧数。
  218. //如果 nFrameCount = 1,IKapBoardClassLibrary 会从相机中采集一帧图像;
  219. //如果 nFrameCount = N 且 N> 1,则 IKapBoardClassLibrary 从相机中采集连续的 N 帧图 像;
  220. //如果 nFrameCount = 0,则 IKapBoardClassLibrary 开始连续采集图像。
  221. var ret = IKapBoard.IKapStartGrab(m_hBoard, 0);
  222. return ret == (int)ErrorCode.IK_RTN_OK;
  223. }
  224. /// <summary>
  225. /// 停止采集
  226. /// </summary>
  227. public override void stop()
  228. {
  229. if (!IsInit) return;
  230. try
  231. {
  232. // 停止图像采集。
  233. var ret = IKapBoard.IKapStopGrab(m_hBoard);
  234. CheckIKapBoard(ret);
  235. }
  236. catch
  237. {
  238. return;
  239. }
  240. }
  241. /// <summary>
  242. /// num 因拍了一张后回传的,当前已经是1了
  243. /// </summary>
  244. /// <param name="num"></param>
  245. public override void resetScanIndex()
  246. {
  247. scanIndex = 0;//
  248. }
  249. public override void getParam()
  250. {
  251. if (!IsInit) return;
  252. //CParam cDeviceParam = new CParam(m_cInterface);
  253. //MV_FG_FLOATVALUE stParam=new MV_FG_FLOATVALUE();
  254. //int nRet = cDeviceParam.GetFloatValue("ExposureTime", ref stParam);
  255. //if (nRet == CErrorCode.MV_FG_SUCCESS) ExposureTime = stParam.fCurValue;
  256. //nRet = cDeviceParam.GetFloatValue("Gain", ref stParam);
  257. //if (nRet == CErrorCode.MV_FG_SUCCESS) Gain = stParam.fCurValue;
  258. //nRet = cDeviceParam.GetFloatValue("ResultingFrameRate", ref stParam);
  259. //if (nRet == CErrorCode.MV_FG_SUCCESS) ResultingFrameRate = stParam.fCurValue;
  260. }
  261. /// <summary>
  262. ///
  263. /// </summary>
  264. /// <param name="exposureTime">曝光</param>
  265. /// <param name="gain">增益</param>
  266. /// <param name="resultingFrameRate">帧率</param>
  267. public override bool setParam(float exposureTime, float gain =-1, float resultingFrameRate =-1)
  268. {
  269. if (!IsInit) return false;
  270. bool change = false;
  271. //CParam cDeviceParam = new CParam(m_cInterface);
  272. //int nRet;
  273. //if (exposureTime != ExposureTime && exposureTime != -1)
  274. //{
  275. // nRet = cDeviceParam.SetEnumValue("ExposureAuto", (uint)0);
  276. // if (CErrorCode.MV_FG_SUCCESS != nRet)
  277. // WarningEvent?.Invoke(WarningEnum.Low, "ExposureTime SetEnumValue(\"ExposureAuto\") res=" + nRet);
  278. // nRet = cDeviceParam.SetFloatValue("ExposureTime", exposureTime);
  279. // if (CErrorCode.MV_FG_SUCCESS != nRet)
  280. // WarningEvent?.Invoke(WarningEnum.Low, "ExposureTime SetFloatValue(\"ExposureTime\") res=" + nRet);
  281. // change = true;
  282. //}
  283. //if (gain != Gain && gain != -1)
  284. //{
  285. // //device.MV_CC_SetEnumValue_NET("GainAuto", 0);
  286. // //nRet = device.MV_CC_SetFloatValue_NET("Gain", gain);
  287. // cDeviceParam.SetEnumValue("GainAuto", (uint)0);
  288. // cDeviceParam.SetFloatValue("Gain", gain);
  289. // change = true;
  290. //}
  291. //if (resultingFrameRate != ResultingFrameRate && resultingFrameRate != -1)
  292. //{
  293. // cDeviceParam.SetFloatValue("AcquisitionFrameRate", resultingFrameRate);
  294. // change = true;
  295. //}
  296. //
  297. if (change)
  298. getParam();
  299. return change;
  300. }
  301. public void Dispose()
  302. {
  303. stop();
  304. close();
  305. }
  306. //---------------
  307. /* @brief:设置行触发参数。
  308. *
  309. * @brief:Set line trigger parameters. */
  310. void SetLineTrigger()
  311. {
  312. int ret = (int)ErrorCode.IK_RTN_OK;
  313. // 设置CC1信号源。
  314. //
  315. // Set CC1 signal source.
  316. ret = IKapBoard.IKapSetInfo(m_hBoard, (uint)INFO_ID.IKP_CC1_SOURCE, (int)CCSource.IKP_CC_SOURCE_VAL_INTEGRATION_SIGNAL1);
  317. CheckIKapBoard(ret);
  318. // 设置积分控制方法触发信号源。
  319. //
  320. // Set integration control method trigger source.
  321. ret = IKapBoard.IKapSetInfo(m_hBoard, (uint)INFO_ID.IKP_INTEGRATION_TRIGGER_SOURCE, (int)IntegrationTriggerSource.IKP_INTEGRATION_TRIGGER_SOURCE_VAL_SHAFT_ENCODER1);
  322. CheckIKapBoard(ret);
  323. }
  324. /* @brief:清除回调函数。
  325. *
  326. * @brief:Unregister callback functions. */
  327. private void UnRegisterCallback()
  328. {
  329. int ret = (int)ErrorCode.IK_RTN_OK;
  330. ret = IKapBoard.IKapUnRegisterCallback(m_hBoard, (uint)CallBackEvents.IKEvent_GrabStart);
  331. ret = IKapBoard.IKapUnRegisterCallback(m_hBoard, (uint)CallBackEvents.IKEvent_FrameReady);
  332. ret = IKapBoard.IKapUnRegisterCallback(m_hBoard, (uint)CallBackEvents.IKEvent_FrameLost);
  333. ret = IKapBoard.IKapUnRegisterCallback(m_hBoard, (uint)CallBackEvents.IKEvent_TimeOut);
  334. ret = IKapBoard.IKapUnRegisterCallback(m_hBoard, (uint)CallBackEvents.IKEvent_GrabStop);
  335. }
  336. /* @brief:关闭设备。
  337. *
  338. * @brief:Close device. */
  339. private void CloseDevice()
  340. {
  341. // 关闭采集卡设备。
  342. //
  343. // Close frame grabber device.
  344. if (!m_hBoard.Equals(-1))
  345. {
  346. IKapBoard.IKapClose(m_hBoard);
  347. m_hBoard = (IntPtr)(-1);
  348. }
  349. }
  350. /* @brief:判断 IKapBoard 函数是否成功调用。
  351. * @param[in] ret:函数返回值。
  352. *
  353. * @brief:Determine whether the IKapBoard function is called successfully.
  354. * @param[in] ret:Function return value. */
  355. static void CheckIKapBoard(int ret)
  356. {
  357. if (ret != (int)ErrorCode.IK_RTN_OK)
  358. {
  359. string sErrMsg = "";
  360. IKapBoard.IKAPERRORINFO tIKei = new IKapBoardClassLibrary.IKapBoard.IKAPERRORINFO();
  361. // 获取错误码信息。
  362. IKapBoard.IKapGetLastError(ref tIKei, true);
  363. // 打印错误信息。
  364. sErrMsg = string.Concat("Error",
  365. sErrMsg,
  366. "Board Type\t = 0x", tIKei.uBoardType.ToString("X4"), "\n",
  367. "Board Index\t = 0x", tIKei.uBoardIndex.ToString("X4"), "\n",
  368. "Error Code\t = 0x", tIKei.uErrorCode.ToString("X4"), "\n"
  369. );
  370. throw new Exception(sErrMsg);
  371. }
  372. }
  373. #region Callback
  374. delegate void IKapCallBackProc(IntPtr pParam);
  375. /* @brief:本函数被注册为一个回调函数。当图像采集开始时,函数被调用。
  376. *
  377. * @brief:This function is registered as a callback function. When starting grabbing images, the function will be called. */
  378. private IKapCallBackProc OnGrabStartProc;
  379. /* @brief:本函数被注册为一个回调函数。当采集丢帧时,函数被调用。
  380. *
  381. * @brief:This function is registered as a callback function. When grabbing frame lost, the function will be called. */
  382. private IKapCallBackProc OnFrameLostProc;
  383. /* @brief:本函数被注册为一个回调函数。当图像采集超时时,函数被调用。
  384. *
  385. * @brief:This function is registered as a callback function. When grabbing images time out, the function will be called. */
  386. private IKapCallBackProc OnTimeoutProc;
  387. /* @brief:本函数被注册为一个回调函数。当一帧图像采集完成时,函数被调用。
  388. *
  389. * @brief:This function is registered as a callback function. When a frame of image grabbing ready, the function will be called. */
  390. private IKapCallBackProc OnFrameReadyProc;
  391. /* @brief:本函数被注册为一个回调函数。当图像采集停止时,函数被调用。
  392. *
  393. * @brief:This function is registered as a callback function. When stopping grabbing images, the function will be called. */
  394. private IKapCallBackProc OnGrabStopProc;
  395. #endregion
  396. #region Callback
  397. /* @brief:本函数被注册为一个回调函数。当图像采集开始时,函数被调用。
  398. * @param[in] pParam:输入参数。
  399. *
  400. * @brief:This function is registered as a callback function. When starting grabbing images, the function will be called.
  401. * @param[in] pParam:Input parameter. */
  402. public void OnGrabStartFunc(IntPtr pParam)
  403. {
  404. Console.WriteLine("Start grabbing image");
  405. }
  406. /* @brief:本函数被注册为一个回调函数。当采集丢帧时,函数被调用。
  407. * @param[in] pParam:输入参数。
  408. *
  409. * @brief:This function is registered as a callback function. When grabbing frame lost, the function will be called.
  410. * @param[in] pParam:Input parameter. */
  411. public void OnFrameLostFunc(IntPtr pParam)
  412. {
  413. Console.WriteLine("Image frame lost");
  414. }
  415. /* @brief:本函数被注册为一个回调函数。当图像采集超时时,函数被调用。
  416. * @param[in] pParam:输入参数。
  417. *
  418. * @brief:This function is registered as a callback function. When grabbing images time out, the function will be called.
  419. * @param[in] pParam:Input parameter. */
  420. public void OnTimeoutFunc(IntPtr pParam)
  421. {
  422. Console.WriteLine("Grab image timeout");
  423. }
  424. /* @brief:本函数被注册为一个回调函数。当一帧图像采集完成时,函数被调用。
  425. * @param[in] pParam:输入参数。
  426. *
  427. * @brief:This function is registered as a callback function. When a frame of image grabbing ready, the function will be called.
  428. * @param[in] pParam:Input parameter. */
  429. public void OnFrameReadyFunc(IntPtr pParam)
  430. {
  431. Console.WriteLine("Grab frame ready");
  432. IntPtr hDev = (IntPtr)pParam;
  433. IntPtr pUserBuffer = IntPtr.Zero;
  434. int nFrameSize = 0;
  435. int nFrameCount = 0;
  436. IKapBoard.IKAPBUFFERSTATUS status = new IKapBoard.IKAPBUFFERSTATUS();
  437. IKapBoard.IKapGetInfo(hDev, (uint)INFO_ID.IKP_FRAME_COUNT, ref nFrameCount);
  438. IKapBoard.IKapGetBufferStatus(hDev, m_nCurFrameIndex, ref status);
  439. // 当图像缓冲区满时。
  440. //
  441. // When the buffer is full.
  442. if (status.uFull == 1)
  443. {
  444. // 获取一帧图像的大小。
  445. //
  446. // Get the size of a frame of image.
  447. IKapBoard.IKapGetInfo(hDev, (uint)INFO_ID.IKP_FRAME_SIZE, ref nFrameSize);
  448. // 获取缓冲区地址。
  449. //
  450. // Get the buffer address.
  451. IKapBoard.IKapGetBufferAddress(hDev, m_nCurFrameIndex, ref pUserBuffer);
  452. // === 保存图像。
  453. //存文件
  454. //IKapBoard.IKapSaveBuffer(hDev, m_nCurFrameIndex, m_strFileName, (int)ImageCompressionFalg.IKP_DEFAULT_COMPRESSION);
  455. // 存到byte[]
  456. byte[] imageBuff = new byte[nFrameSize]; // 创建字节数组
  457. Marshal.Copy(pUserBuffer, imageBuff, 0, imageBuff.Length); // 将目标内存空间中的数据复制到结果字节数组
  458. //存到地址
  459. //IntPtr m_pDataBuf = Marshal.AllocHGlobal(nFrameSize); //分配空间
  460. //CopyMemory(m_pDataBuf, pUserBuffer, (uint)nFrameSize);
  461. //pictureBox1显示
  462. if (this.previewHwnd != null && IsWindow(this.previewHwnd.Handle))
  463. {
  464. this.previewHwnd.Image = bytes2bmp(imageBuff);
  465. }
  466. }
  467. m_nCurFrameIndex++;
  468. m_nCurFrameIndex = m_nCurFrameIndex % m_nTotalFrameCount;
  469. }
  470. /* @brief:本函数被注册为一个回调函数。当图像采集停止时,函数被调用。
  471. * @param[in] pParam:输入参数。
  472. *
  473. * @brief:This function is registered as a callback function. When stopping grabbing images, the function will be called.
  474. * @param[in] pParam:Input parameter. */
  475. public void OnGrabStopFunc(IntPtr pParam)
  476. {
  477. Console.WriteLine("Stop grabbing image");
  478. }
  479. #endregion
  480. private byte[] bmp2bytes(Bitmap bmp)
  481. {
  482. MemoryStream ms = new MemoryStream();
  483. bmp.Save(ms, System.Drawing.Imaging.ImageFormat.Bmp);
  484. byte[] bytes = ms.GetBuffer(); //byte[] bytes= ms.ToArray(); 这两句都可以,至于区别么,下面有解释
  485. ms.Close();
  486. bmp.Dispose();
  487. return bytes;
  488. }
  489. private Bitmap bytes2bmp(byte[] bytes)
  490. {
  491. MemoryStream ms1 = new MemoryStream(bytes);
  492. Bitmap bm = (Bitmap)Image.FromStream(ms1);
  493. ms1.Close();
  494. return bm;
  495. }
  496. }
  497. }