Ý tưởng này cũng hay, có điều là trong Excel 2003 trở về trước, số ký tự lưu trong 1 cell là 256 ký tự, Excel 2007 trở lại đây là 32,768 ký tự. Nếu với định dạng Excel2007 mà lưu mỗi cell một byte thì có thể lưu 17,179,869,184 byte (16,384 MB). Không biết anh sẽ tổ chức việc lưu trên sheet như thế nào? Dung lượng file nhị phân có lẽ cũng giới hạn?
Tôi ghi mảng bai với "tư cách" là mảng bai định nghĩa mầu của các pixels trong tập tin BMP 24bit. Tức tạo BMP có mảng bai cho trước là mảng bai mầu. BMP sau đó được nạp vào Image trên sheet. Cũng có thể không cần tạo BMP trên đĩa nhưng có thể có người cần, và BMP luôn có thể xóa nếu không thích.
-------------
Tải về tại:
http://www.mediafire.com/?numsilmpvkx72l3
Tôi vừa viết xong code. Chú thích đầy đủ. Nếu ai muốn hiểu chút về code và "thuật toán" thì tôi sẽ giải thích ngắn gọn. Trước tiên ta nói về cấu trúc tập tin BMP.
Ở đầu mỗi BMP là 1 cấu trúc BITMAPFILEHEADER (tổng cộng 14 bai) có chứa những thông tin về tập tin, trong đó có trường bfOffBits (Long). Tiếp theo là cấu trúc BITMAPINFOHEADER (40 bai) chứa các thông tin về bitmap: width, height, bao nhiêu bit v...v. Trong trường hợp bitmap 1bit, 4bit, 8bit thì tiếp theo là palette (bảng mầu) được ghi. Phần này có độ lớn thay đổi. Vd. nếu là bitmap 8bit thì nó có bảng mầu 2^8 = 256 mầu, mà mỗi mầu được xác định bằng 3 bai (3 thành phần Red, Green, Blue) - vậy palette chiếm 768 bai.
Tôi chọn bitmap 24bit vì nó đơn giản. Với bitmap 24bit thì sau cấu trúc BITMAPINFOHEADER không có bảng mầu (do bitmap không dùng bảng mầu). Trường bfOffBits trong cấu trúc BITMAPFILEHEADER chứa offset (tính từ đầu tập tin) tới một mảng bai, tôi tạm gọi là mảng M. Mảng M có ý nghĩa khác nhau tùy bitmap là 1, 4, 8, 16, 24 hay 32bit.
Ví dụ với bitmap 8bit thì mảng M này chứa những bai là chỉ số tới bảng mầu (palette). Chẳng hạn với pixel ở dòng y cột x ta có bai tương ứng trong mảng M có giá trị 5 thì có nghĩa là nhẩy tới mầu thứ 5 (tính từ 0 do bai = 0..255) trong palette ta sẽ đọc được 3 thành phần R, G, B của mầu pixel ở dòng y cột x.
Bitmap 24bit không có palette, và mảng M chính là mảng bai định nghĩa 3 thành phần R, G, B của mỗi pixel.
Ở trên tôi viết: "pixel ở dòng y cột x ta có bai tương ứng trong mảng M". Tương ứng ở đây là gì?
Là các dòng pixels được ghi nối tiếp nhau từ dòng "cuối" tới dòng "đầu" (hoặc từ dòng đầu tới dòng cuối).
Với bitmap 24bit mỗi dòng pixels được ghi trong mảng M như sau: 3 bai B, G, R (theo thứ tự đó) của pixel thứ nhất, 3 bai B, G, R của pixel thứ 2, ..., 3 bai B, G, R của pixel cuối cùng trong dòng. Tổng cộng mỗi dòng dùng hết 3*width bai. Nếu 3*width không là bội của 4 thì trong tập tin BMP mỗi dòng được ghi thêm từ 1 tới 3 bai 0 để số bai trong dòng là bội của 4. Tổng cộng có height dòng như thế được ghi nối tiếp nhau. Biết pixel ở dòng cột nào thì cũng tính được vị trí 3 bai trong mảng M mà xác định B, G, R của pixel đó.
Từ miêu tả trên thì nảy ra ý tưởng ghi mảng bai tùy ý. Tức là ta tạo một BMP nào đó mà nó có một đoạn bai liên tục "trùng" với mảng bai cần ghi. Để về sau dễ đọc ra thì ta tạo BMP mà mảng M của nó ở đoạn đầu có chứa mảng bai cần ghi. Hơn thế nữa do mảng cần ghi và mảng M có thể có độ lớn khác nhau (mảng cần ghi có thể có độ lớn không là bội của 4 còn mảng M phải có độ lớn là bội của 4) nên để về sau có được mảng M thì biết đọc ra bao nhiêu bai cho mảng đã ghi thì ta làm như sau: Ta cần ghi mảng Arr có x bai. Ta tạo mảng tmp có độ lớn (x + 4) bai. Trong 4 bai đầu của tmp ta ghi độ lớn của Arr, tức giá trị x (Long), tiếp theo ta ghi toàn bộ các bai của mảng Arr. Và ta tạo BMP sao cho mảng M của nó có đoạn đầu "trùng" với mảng tmp. Khi cần đọc lại mảng đã ghi thì chỉ cần có mảng M rồi ta đọc 4 bai đầu để biết cần đọc ra bao nhiêu bai rồi tiếp theo đọc bấy nhiêu bai ra.
Từ miêu tả cấu trúc bitmap 24bit thì ta thấy là việc đọc mảng M không có gì khó khăn. Offset của nó được ghi trong trường bfOffBits trong cấu trúc BITMAPFILEHEADER. Nhưng trong code tôi dùng hàm của system để đọc ra mảng M - hàm GetDIBits.
------------
Trong tập tin đính kèm có 2 ví dụ.
1. Nhấn nút "Test 1": tạo mảng Arr chứa 100 giá trị từ 1 tới 100 --> tạo BMP có mảng M chứa mảng Arr --> BMP được ghi trong thư mục của tập tin XLS --> đồng thời cũng tạo Image trên sheet rồi nap BMP vào Image. Sau đó từ tập tin BMP trên đĩa đọc ra mảng đã ghi Arr1, và từ Image trên sheet đọc ra mảng đã ghi Arr2, và nhập chúng vào cột A và B. Ta thấy rằng Arr1, Arr2 và mảng ban đầu là y hệt nhau.
2. Trong ví dụ 2 tôi đã nhập sẵn nội dung của video clip. Nhấn nút "Play video clip" thì mảng bai sẽ được lấy ra từ Image trên sheet rồi ghi mảng bai đó trong thư mục của tập tin XLS với tên "CafeSuaNong.wmv". Đồng thời BMP từ Image trên sheet được ghi ra đĩa trong thư mục của tập tin XLS với tên "CafeSuaNong.bmp". Tiếp theo video clip "CafeSuaNong.wmv" được chiếu. Tôi dùng hàm đơn giản tự tạo trong module đính kèm - mciSendString - để chiếu. Nhấn nút "Close video" sẽ dừng và đóng device.
--------------
Tôi có câu hỏi các bạn: Tại sao tập tin XLS lại phình to lên tới 12,5 MB? Các tập tin tôi tách ra và ghi trên đĩa thì BMP có 4,17 MB (4.381.434 bai), WMV có 4,17 MB (4.379.842 bai).
Tất nhiên tôi biết nó có cái gì mà to thế. Tôi ghi lại ở dạng XLSM rồi dùng WinRar bung ra thì thấy trong thư mục xl\media có tập tin image1.emf - có 97 x 97 pixels mà độ lớn 8,35 MB. Thư mục xl\activeX có activeX1.bin với 4,17 MB. Đúng là khó hiểu thật.
-------------
Code có ghi chú đầy đủ. Nếu không xem được thì trong VBE: Tools --> Options --> thẻ Editor Format, mục Font --> chọn Times New Roman (vietnamese)