Lấy các Ảnh nhỏ từ một Ảnh lớn theo tọa độ.

Liên hệ QC

VMH0307

Thành viên tiêu biểu
Tham gia
5/8/11
Bài viết
765
Được thích
602
KÍnh gửi: mọi người!
Hiện tại em đang có nhu cầu chia file ảnh ra làm nhiều ảnh con. Trước đó em đã nhận được sự giúp đỡ nhiệt tình của bác Siwtom thông qua bài viết ấn tượng với file Bitmap
http://www.giaiphapexcel.com/forum/showthread.php?70434-Game-Ghép-ảnh&p=433414#post433414
Hiện em vẫn trong quá trình "tiêu hóa" các code này. Nay em có 1 hình ảnh đuôi PNG (sở dĩ vậy vì nó cho phép nền trong suốt) và file xml về các tọa độ của từng ảnh con trên ảnh theo đính kèm. Em muốn mọi người hướng dẫn em cách thức để:
1. Có thể lấy bất kỳ ảnh con nào theo tọa độ của chúng, tức cắt ảnh nhỏ từ ảnh to mà không ảnh hưởng đến chất lượng hình ảnh, cũng như khả năng trong suốt của nền.
2. Em muốn sử dụng ảnh con sau khi đã "cắt" ra từ ảnh to chèn vào form hoặc image trong Form (mà vẫn giữ nguyên chất lượng ảnh và nền trong suốt).
Em cám ơn.
 

File đính kèm

  • Texture_PNG.rar
    1 MB · Đọc: 103
Mọi người cho em hỏi thêm liên quan đến giải quyết vấn đề trên:
1. Mọi người có thể gợi ý giúp em có DrectX nào cho phép việc lấy ảnh Png này trong vba không ạ?

2. Có cách nào để 1 ảnh Bitmap chèn vào trong Image trong Form mà nền của Ảnh Bitmap này được trong suốt không ạ?

Em cám ơn!
 
Upvote 0
Mọi người cho em hỏi thêm liên quan đến giải quyết vấn đề trên: 1. Mọi người có thể gợi ý giúp em có DrectX nào cho phép việc lấy ảnh Png này trong vba không ạ? 2. Có cách nào để 1 ảnh Bitmap chèn vào trong Image trong Form mà nền của Ảnh Bitmap này được trong suốt không ạ? Em cám ơn!
Nếu đi hướng này không không được thì bạn thử đi hướng khác xem. 1. Tại sao phải PNG? Có thể là JPG không? 2. Cụ thể bạn định làm gì mà cần tới cái bạn gọi là Transparent? 3. Bạn nên làm 1 UserForm và đặt cái bạn dự tính. Bạn nạp PNG vào rồi gửi tập tin lên cho mọi người xem. Biết đâu ai đó nhìn vào, và đọc mô tả sẽ có sáng kiến thì sao.
 
Upvote 0
Nếu đi hướng này không không được thì bạn thử đi hướng khác xem. 1. Tại sao phải PNG? Có thể là JPG không? 2. Cụ thể bạn định làm gì mà cần tới cái bạn gọi là Transparent? 3. Bạn nên làm 1 UserForm và đặt cái bạn dự tính. Bạn nạp PNG vào rồi gửi tập tin lên cho mọi người xem. Biết đâu ai đó nhìn vào, và đọc mô tả sẽ có sáng kiến thì sao.
Cháu cám ơn chú Siwtom.
Cháu xin gửi chú và mọi người file đính kèm tham khảo trong đó có sử dụng Code chia file bmp (jpg) của chú trong đó. Mong chú hiểu được phần nào nhu cầu cháu, cháu không quan trọng là ảnh PNG, nhưng phải đạt yêu cầu điểm ảnh tốt, đẹp và nền trong suốt sau khi đã chèn và form hoặc control.
Với nhu cầu đã trình bày ở trên, theo suy nghĩ của cháu sẽ giúp ích được một số việc:
1. Có thể tạo giao diện đẹp thân thiện, hơn nữa có thể tạo được các Template khác nhau trong form và dùng được cho nhiều lần, thay đổi các Theme dễ dàng hơn thông qua thay đổi ảnh nguồn và texture của nó.
2. Có thể tạo các Button với các sự kiện thay đổi hình ảnh, chuyển động thông qua các Class.
3. Có thể tạo các Motion phù hợp cho Game, cho mở đầu, chào của 1 chương trình.
Hiện tại với file ví dụ đính kèm có nhược điểm:
- Ảnh chèn vào Image vẫn còn nền, do vậy tính thẩm mỹ rất xấu => cần sử lý để transparent nền này?
- Từ 1 file ảnh chia ra nhiều file nhỏ (tức file nhỏ vẫn hiện hữu trên ổ đĩa) -> nhu cầu khả năng có thể lấy từng điểm ảnh của file Bmp sau đó "paste" trực tiếp lên thuộc tính picture của Control, form?
Vậy kính mong chú và mọi người giúp đỡ!
Cháu cám ơn!
 

File đính kèm

  • Load anh.zip
    150.9 KB · Đọc: 51
Upvote 0
C
3. Có thể tạo các Motion phù hợp cho Game, cho mở đầu, chào của 1 chương trình.

Tôi có 1 thắc mắc ngoài lề chút:
- Bạn tham gia GPE dường như là để VIẾT GAME là chủ yếu
- Vậy sao bạn không dùng ngôn ngữ lập trình khác (như VB6 chẳng hạn) mà viết? Cớ gì cứ phải viết trên Excel cho cực thân?
 
Upvote 0
Tôi có 1 thắc mắc ngoài lề chút:
- Bạn tham gia GPE dường như là để VIẾT GAME là chủ yếu
- Vậy sao bạn không dùng ngôn ngữ lập trình khác (như VB6 chẳng hạn) mà viết? Cớ gì cứ phải viết trên Excel cho cực thân?
Nhận định của bác có đúng, có sai:
Đúng: em rất thích viết Game
Sai: Đó không phải là mục đích chủ yếu. Mỗi người có một cách thức, phương pháp để tiếp cận vấn đề khác nhau, và có những hứng thú riêng của bản thân. Đối với bản thân công việc hiện tại của em, có lẽ: công thức, Pivot, ADO, Solve đã đủ để đáp ứng công việc. Việc sử dụng Game để học hỏi cũng là một phương pháp, đòi hỏi nhìn nhận toàn diện, phân tích vấn đề, chia nhỏ công việc, cách thức diễn đạt và trình bày dần dần tiến tới tư duy tốt hơn cho việc tạo lập Project, bao gồm nhiều thứ phức tạp, liên kết ràng buộc như 1 dự án thực thụ. Thêm vào đó Game cho ra thành quả trực quan, không chỉ hiểu, phân tích thuật toán, mà còn có giao diện, có tương tác, tạo được cảm xúc cho người dùng.
Việc "cực thân" trên Excel mới thật sự thú vị. Nhớ lần đầu tiên cảm thấy ngạc nhiên khi 1 phần mềm văn phòng phổ biến có thể làm được nhiều thứ ngoài sức tưởng tưởng của ta mới thú vị làm sao. Các ngôn ngữ, phần mềm lập trình chuyên biệt sao cho ta được hứng thú khi có thể tạo lập Game, ứng dụng như vậy chứ. Nếu có chăng sử dụng ngôn ngữ lập trình khác thì có khi nên dùng Java, Script, Php, dễ dàng tương tác với Web, tiếp cận với các ứng dụng Android thì sẽ "hợp thời" hơn ngôn ngữ vb6 "già nua" và giới hạn trong mã nguồn đóng này chứ. Có lẽ em hơi dài dòng, nhưng dù sao đó là sở thích cá nhân, sở thích excel, gpe là 1 trong nhiều nơi cung cấp lượng kiến thức tốt, chú Siwtom tự gọi mình là "khách qua đường", em có lẽ là "người đi khất thực kiến thức".
Em cám ơn ^^
 
Upvote 0
Cháu cám ơn chú Siwtom.
Cháu xin gửi chú và mọi người file đính kèm tham khảo trong đó có sử dụng Code chia file bmp (jpg) của chú trong đó. Mong chú hiểu được phần nào nhu cầu cháu, cháu không quan trọng là ảnh PNG, nhưng phải đạt yêu cầu điểm ảnh tốt, đẹp và nền trong suốt sau khi đã chèn và form hoặc control.
Với nhu cầu đã trình bày ở trên, theo suy nghĩ của cháu sẽ giúp ích được một số việc:
1. Có thể tạo giao diện đẹp thân thiện, hơn nữa có thể tạo được các Template khác nhau trong form và dùng được cho nhiều lần, thay đổi các Theme dễ dàng hơn thông qua thay đổi ảnh nguồn và texture của nó.
2. Có thể tạo các Button với các sự kiện thay đổi hình ảnh, chuyển động thông qua các Class.
3. Có thể tạo các Motion phù hợp cho Game, cho mở đầu, chào của 1 chương trình.
Hiện tại với file ví dụ đính kèm có nhược điểm:
- Ảnh chèn vào Image vẫn còn nền, do vậy tính thẩm mỹ rất xấu => cần sử lý để transparent nền này?
- Từ 1 file ảnh chia ra nhiều file nhỏ (tức file nhỏ vẫn hiện hữu trên ổ đĩa) -> nhu cầu khả năng có thể lấy từng điểm ảnh của file Bmp sau đó "paste" trực tiếp lên thuộc tính picture của Control, form?
Vậy kính mong chú và mọi người giúp đỡ!
Cháu cám ơn!

Đọc bài #1 tôi tưởng bạn chỉ nhờ cắt ảnh còn load "trong suốt" vào Image bạn đã làm bằng cách nào rồi. Bây giờ bạn nói là bạn chưa làm được trong suốt.

Cái này thì chịu thôi. Nói là chịu thì không hẳn đúng vì có thể (ít ra là tôi nghĩ thế, chưa thử) viết lại hàm cửa sổ để tóm thông điệp vd. WM_PAINT để vẽ ảnh trong suốt lên Form. Còn vẽ lên Image thì tôi chịu vì không biết bằng cách nào lấy được device context của cái gọi là Image.

Bạn làm những việc chả liên quan gì tới Excel mà lại chọn Excel? Excel được thiết kế làm việc khác nên để làm việc của bạn thì rất khó.

Nếu bạn dùng vd. Delphi thì việc lại dễ ợt. Những kiểu vẽ trong suốt đó tôi "ăn" hàng ngày trong bữa sáng.
 
Upvote 0
Đọc bài #1 tôi tưởng bạn chỉ nhờ cắt ảnh còn load "trong suốt" vào Image bạn đã làm bằng cách nào rồi. Bây giờ bạn nói là bạn chưa làm được trong suốt.

Cái này thì chịu thôi. Nói là chịu thì không hẳn đúng vì có thể (ít ra là tôi nghĩ thế, chưa thử) viết lại hàm cửa sổ để tóm thông điệp vd. WM_PAINT để vẽ ảnh trong suốt lên Form. Còn vẽ lên Image thì tôi chịu vì không biết bằng cách nào lấy được device context của cái gọi là Image.

Bạn làm những việc chả liên quan gì tới Excel mà lại chọn Excel? Excel được thiết kế làm việc khác nên để làm việc của bạn thì rất khó.

Nếu bạn dùng vd. Delphi thì việc lại dễ ợt. Những kiểu vẽ trong suốt đó tôi "ăn" hàng ngày trong bữa sáng.
Vâng, cám ơn chú, quan trọng là giải quyết được việc chèn được ảnh trong suốt vào form hoặc control cắt ra từ 1 ảnh và có nền trong suốt. Lúc nào rảnh chú có thể hướng dẫn giúp cháu phần suy nghĩ bên trên của chú về vẽ ảnh trong suốt trên Form chú nhé.
Về phần nền trong suốt, ý tưởng cháu nghĩ không biết ta có thể làm được trong VBA không?
Đó là tạo ra 1 Transparentkey cho ảnh Bitmap chèn vào (với Transparentkey là màu quy định trong suốt được đặt tại mảng byte màu (0,0), giống như kiểu dạng Icon). Rồi từ đó duyệt đồng thời mảng màu của file bitmap và mảng màu của background của control/ Form (cái này cháu vẫn chưa biết bản chất của background của control/ Form như thế nào, lấy điểm ảnh, tọa độ ra sao) sau đó lấy từng byte màu, nếu mầu trùng Transparentkey thì lấy màu của Background không thì lấy màu từ file bitmap. Tiếp đó xếp cấu trúc tạo file Bitmap.
Việc sử lý được nhu cầu này, cháu nghĩ không phải chỉ để chơi, nếu như ta nghĩ rằng có thể tạo được control với hình dạng tùy biến khác nhau thì nó cũng có ích vô cùng đó chứ. Rồi tham vọng hơn nữa nếu có thể tạo được Backstyle cho Form giống như Control Image thì Form cũng có thể có được những hình dạng khác nhau chứ không chỉ đơn thuần là 1 hình chữ nhật.
 
Upvote 0
Việc sử lý được nhu cầu này, cháu nghĩ không phải chỉ để chơi, nếu như ta nghĩ rằng có thể tạo được control với hình dạng tùy biến khác nhau thì nó cũng có ích vô cùng đó chứ. Rồi tham vọng hơn nữa nếu có thể tạo được Backstyle cho Form giống như Control Image thì Form cũng có thể có được những hình dạng khác nhau chứ không chỉ đơn thuần là 1 hình chữ nhật.

ĐÚng là rất hay,

Nhưng lại là dở khi lấy VBA để thực hiện việc đó, hãy dùng các phần mềm lập trình chuyên lun, như Delphi bác Siwtom nói trên, hay VB, hay visual C++ , hay ngôn ngữ khác nữa... để thực hiện thì tốt hơn
 
Upvote 0
Vâng, cám ơn chú, quan trọng là giải quyết được việc chèn được ảnh trong suốt vào form hoặc control cắt ra từ 1 ảnh và có nền trong suốt. Lúc nào rảnh chú có thể hướng dẫn giúp cháu phần suy nghĩ bên trên của chú về vẽ ảnh trong suốt trên Form chú nhé.
Về phần nền trong suốt, ý tưởng cháu nghĩ không biết ta có thể làm được trong VBA không?
Đó là tạo ra 1 Transparentkey cho ảnh Bitmap chèn vào (với Transparentkey là màu quy định trong suốt được đặt tại mảng byte màu (0,0), giống như kiểu dạng Icon). Rồi từ đó duyệt đồng thời mảng màu của file bitmap và mảng màu của background của control/ Form (cái này cháu vẫn chưa biết bản chất của background của control/ Form như thế nào, lấy điểm ảnh, tọa độ ra sao) sau đó lấy từng byte màu, nếu mầu trùng Transparentkey thì lấy màu của Background không thì lấy màu từ file bitmap. Tiếp đó xếp cấu trúc tạo file Bitmap.
Việc sử lý được nhu cầu này, cháu nghĩ không phải chỉ để chơi, nếu như ta nghĩ rằng có thể tạo được control với hình dạng tùy biến khác nhau thì nó cũng có ích vô cùng đó chứ. Rồi tham vọng hơn nữa nếu có thể tạo được Backstyle cho Form giống như Control Image thì Form cũng có thể có được những hình dạng khác nhau chứ không chỉ đơn thuần là 1 hình chữ nhật.

Bạn đợi 1, 2 ngày tôi có thời gian nhé
 
Upvote 0
Tôi có chút việc của mình nên bây giờ mới trả lời bạn. Vì viết code mất khá nhiều thời gian. Nếu tôi viết trong Delphi thì chỉ viết code thôi vì Delphi có unit Windows mà trong đó có khai báo mọi hàm, mọi cấu trúc, kiểu dữ liệu. Viết trong VBA tôi phải tự khai báo tất cả.
Ngoài ra nếu tôi viết một code ví dụ để biểu diễn thì sẽ nhanh hơn. Nhưng để viết thành những sub, function hoàn chỉnh để sau này bạn có thể dùng chúng trong các code của mình thì sẽ lâu hơn.

Vâng, cám ơn chú, quan trọng là giải quyết được việc chèn được ảnh trong suốt vào form hoặc control cắt ra từ 1 ảnh và có nền trong suốt. Lúc nào rảnh chú có thể hướng dẫn giúp cháu phần suy nghĩ bên trên của chú về vẽ ảnh trong suốt trên Form chú nhé.
Về phần nền trong suốt, ý tưởng cháu nghĩ không biết ta có thể làm được trong VBA không?
Đó là tạo ra 1 Transparentkey cho ảnh Bitmap chèn vào (với Transparentkey là màu quy định trong suốt được đặt tại mảng byte màu (0,0), giống như kiểu dạng Icon). Rồi từ đó duyệt đồng thời mảng màu của file bitmap và mảng màu của background của control/ Form (cái này cháu vẫn chưa biết bản chất của background của control/ Form như thế nào, lấy điểm ảnh, tọa độ ra sao) sau đó lấy từng byte màu, nếu mầu trùng Transparentkey thì lấy màu của Background không thì lấy màu từ file bitmap. Tiếp đó xếp cấu trúc tạo file Bitmap.
Việc sử lý được nhu cầu này, cháu nghĩ không phải chỉ để chơi, nếu như ta nghĩ rằng có thể tạo được control với hình dạng tùy biến khác nhau thì nó cũng có ích vô cùng đó chứ. Rồi tham vọng hơn nữa nếu có thể tạo được Backstyle cho Form giống như Control Image thì Form cũng có thể có được những hình dạng khác nhau chứ không chỉ đơn thuần là 1 hình chữ nhật.

Để làm cửa sổ có hình bất kỳ (đỏ đỏ) không có gì là khó. Chỉ cần có window handle. Tất nhiên trong VBA khó vì tôi nghĩ VBA tự mình vẽ các control, chúng không hẳn là các window của Windows.

Ví dụ code trong VB6

http://www.giaiphapexcel.com/forum/...h-tròn-lục-lăng-di-chuyển&p=515654#post515654

Trong VBA tôi làm cho bạn 3 ví dụ
1. Form có hình dạng bất kỳ. Để đóng cửa sổ thì chuột phải lên thanh tiêu đề (chỉ còn đoạn nhỏ) và chọn Close

2. Image trong suốt. Tôi tạo từ ảnh nguồn một ảnh tạm thời mà trong đó những chỗ có có mầu trong suốt sẽ được thay bằng mầu BackColor của Form. Ảnh tạm thời sẽ được nhập vào Image. Trong module modPicProcedure tôi viết thêm hàm RegionFromBitmap mà trong đó tham số TransColor là Optional. Bạn có thể nhập giá trị của "mầu trong suốt". Nếu bạn không nhập thì "mầu trong suốt" sẽ được lấy từ pixel (0, 0) - góc trái bên trên.
Trong module modPicProcedure cũng có tủ tục SetImageFromFile dùng để nhập ảnh "trong suốt" vào Image - phải truyền đường dẫn tập tin ảnh trên đĩa, color của nền (backcolor của Form hoặc Frame nếu Image nằm trên Frame), và đối tượng Image. Cũng có hàm SetImageFromHandle - thay cho truyền đường dẫn tập tin ảnh trên đĩa thì truyền handle của bitmap nếu đã có từ các thao tác nào đó.

3. Static. Ở ví dụ này tôi tạo cửa sổ của Windows có class là "Static" với "tư cách" là "con" của UserForm. "Static" của Windows có thể dùng để hiển thị chuỗi (Label) hoặc ảnh (Image). Tôi load ảnh vào của sổ Static nhưng cho nó có hình dạng của ảnh trong suốt y như tôi đã làm Form biến dạng ở ví dụ 1. Vì đối với Windows thì UserForm hay Static đều là window - cửa sổ.
Trong module1 tôi viết cho bạn hàm CreateStaticFromBitmapFile. Các đối số là đường dẫn tập tin ảnh trên đĩa, handle của UserForm, tọa độ left, top của Static trong cửa sổ của UserForm. Cũng có hàm CreateStaticFromBitmapHandle - thay cho đường dẫn tập tin ảnh trên đĩa thì truyền handle của bitmap.
 

File đính kèm

  • FormRgn.rar
    82.9 KB · Đọc: 64
Upvote 0
Tôi có chút việc của mình nên bây giờ mới trả lời bạn. Vì viết code mất khá nhiều thời gian. Nếu tôi viết trong Delphi thì chỉ viết code thôi vì Delphi có unit Windows mà trong đó có khai báo mọi hàm, mọi cấu trúc, kiểu dữ liệu. Viết trong VBA tôi phải tự khai báo tất cả.
Ngoài ra nếu tôi viết một code ví dụ để biểu diễn thì sẽ nhanh hơn. Nhưng để viết thành những sub, function hoàn chỉnh để sau này bạn có thể dùng chúng trong các code của mình thì sẽ lâu hơn.



Để làm cửa sổ có hình bất kỳ (đỏ đỏ) không có gì là khó. Chỉ cần có window handle. Tất nhiên trong VBA khó vì tôi nghĩ VBA tự mình vẽ các control, chúng không hẳn là các window của Windows.

Ví dụ code trong VB6

http://www.giaiphapexcel.com/forum/...h-tròn-lục-lăng-di-chuyển&p=515654#post515654

Trong VBA tôi làm cho bạn 3 ví dụ
1. Form có hình dạng bất kỳ. Để đóng cửa sổ thì chuột phải lên thanh tiêu đề (chỉ còn đoạn nhỏ) và chọn Close

2. Image trong suốt. Tôi tạo từ ảnh nguồn một ảnh tạm thời mà trong đó những chỗ có có mầu trong suốt sẽ được thay bằng mầu BackColor của Form. Ảnh tạm thời sẽ được nhập vào Image. Trong module modPicProcedure tôi viết thêm hàm RegionFromBitmap mà trong đó tham số TransColor là Optional. Bạn có thể nhập giá trị của "mầu trong suốt". Nếu bạn không nhập thì "mầu trong suốt" sẽ được lấy từ pixel (0, 0) - góc trái bên trên.
Trong module modPicProcedure cũng có tủ tục SetImageFromFile dùng để nhập ảnh "trong suốt" vào Image - phải truyền đường dẫn tập tin ảnh trên đĩa, color của nền (backcolor của Form hoặc Frame nếu Image nằm trên Frame), và đối tượng Image. Cũng có hàm SetImageFromHandle - thay cho truyền đường dẫn tập tin ảnh trên đĩa thì truyền handle của bitmap nếu đã có từ các thao tác nào đó.

3. Static. Ở ví dụ này tôi tạo cửa sổ của Windows có class là "Static" với "tư cách" là "con" của UserForm. "Static" của Windows có thể dùng để hiển thị chuỗi (Label) hoặc ảnh (Image). Tôi load ảnh vào của sổ Static nhưng cho nó có hình dạng của ảnh trong suốt y như tôi đã làm Form biến dạng ở ví dụ 1. Vì đối với Windows thì UserForm hay Static đều là window - cửa sổ.
Trong module1 tôi viết cho bạn hàm CreateStaticFromBitmapFile. Các đối số là đường dẫn tập tin ảnh trên đĩa, handle của UserForm, tọa độ left, top của Static trong cửa sổ của UserForm. Cũng có hàm CreateStaticFromBitmapHandle - thay cho đường dẫn tập tin ảnh trên đĩa thì truyền handle của bitmap.
Cháu cám ơn chú!
Code chú rất hay, súc tích. Cháu có thêm ý kiến, muốn thêm phần Tolerance (tỷ lệ phần trăm) của TransColor, cho các pixel có màu gần giống trong khoảng Tolerance thì vẫn cho trong suốt được không chú.
Cháu xin phép được sử code như sau, nhưng vẫn không thành công.
[GPECODE=vb]Function RegionFromBitmap(b As Long, Optional TransColor As Long = -1, Optional Tolerance As Long = 0) As LongDim w As Long, h As Long, drawing As Boolean, rgn As Long, temprgn As Long
Dim cl As Long, X As Long, DC As Long, old As Long, bm As BITMAP, pixel As RGBTRIPLE
Dim ArrBits() As Byte, Arr() As RGBTRIPLE
GetObject b, Len(bm), bm
ArrBits = MyGetDIBits(b, bm.bmWidth, bm.bmHeight)

If TransColor = -1 Then
Arr = ScanLineFromColors(ArrBits, bm.bmWidth, bm.bmHeight, 0)
pixel = Arr(0)
TransColor = RGB(pixel.rgbtRed, pixel.rgbtGreen, pixel.rgbtBlue)
End If

rgn = CreateRectRgn(0, 0, 0, 0)
For h = 0 To bm.bmHeight - 1
Arr = ScanLineFromColors(ArrBits, bm.bmWidth, bm.bmHeight, h)
drawing = False
For w = 0 To bm.bmWidth - 1
pixel = Arr(w)
cl = RGB(pixel.rgbtRed, pixel.rgbtGreen, pixel.rgbtBlue)
If (Not drawing And cl >= TransColor And cl <= TransColor * (1 + Tolerance / 100)) Or _
(drawing And (cl < TransColor Or cl > TransColor * (1 + Tolerance / 100)) And (w < bm.bmWidth - 1)) Then
Else
If Not drawing Then
X = w
Else
temprgn = CreateRectRgn(X, h, w - 1, h + 1)
CombineRgn rgn, rgn, temprgn, RGN_OR
DeleteObject temprgn
End If
drawing = Not drawing
End If
Next w
Next h

RegionFromBitmap = rgn
End Function[/GPECODE]
Ví dụ cháu muốn sử dụng hình sau (theo đính kèm) để làm trong suốt nền nhưng vẫn không triệt để.
 

File đính kèm

  • Key.rar
    35.2 KB · Đọc: 25
Upvote 0
Cháu cám ơn chú!
Code chú rất hay, súc tích. Cháu có thêm ý kiến, muốn thêm phần Tolerance (tỷ lệ phần trăm) của TransColor, cho các pixel có màu gần giống trong khoảng Tolerance thì vẫn cho trong suốt được không chú.
Cháu xin phép được sử code như sau, nhưng vẫn không thành công.
[GPECODE=vb]Function RegionFromBitmap(b As Long, Optional TransColor As Long = -1, Optional Tolerance As Long = 0) As LongDim w As Long, h As Long, drawing As Boolean, rgn As Long, temprgn As Long
Dim cl As Long, X As Long, DC As Long, old As Long, bm As BITMAP, pixel As RGBTRIPLE
Dim ArrBits() As Byte, Arr() As RGBTRIPLE
GetObject b, Len(bm), bm
ArrBits = MyGetDIBits(b, bm.bmWidth, bm.bmHeight)

If TransColor = -1 Then
Arr = ScanLineFromColors(ArrBits, bm.bmWidth, bm.bmHeight, 0)
pixel = Arr(0)
TransColor = RGB(pixel.rgbtRed, pixel.rgbtGreen, pixel.rgbtBlue)
End If

rgn = CreateRectRgn(0, 0, 0, 0)
For h = 0 To bm.bmHeight - 1
Arr = ScanLineFromColors(ArrBits, bm.bmWidth, bm.bmHeight, h)
drawing = False
For w = 0 To bm.bmWidth - 1
pixel = Arr(w)
cl = RGB(pixel.rgbtRed, pixel.rgbtGreen, pixel.rgbtBlue)
If (Not drawing And cl >= TransColor And cl <= TransColor * (1 + Tolerance / 100)) Or _
(drawing And (cl < TransColor Or cl > TransColor * (1 + Tolerance / 100)) And (w < bm.bmWidth - 1)) Then
Else
If Not drawing Then
X = w
Else
temprgn = CreateRectRgn(X, h, w - 1, h + 1)
CombineRgn rgn, rgn, temprgn, RGN_OR
DeleteObject temprgn
End If
drawing = Not drawing
End If
Next w
Next h

RegionFromBitmap = rgn
End Function[/GPECODE]
Ví dụ cháu muốn sử dụng hình sau (theo đính kèm) để làm trong suốt nền nhưng vẫn không triệt để.

Giả dụ, để cho đơn giản, ta xét sai số tuyệt đối là 1. Theo cách hiểu của bạn thì mầu có giá trị cl và mầu TransColor là "lơ lớ" như nhau nếu có |cl - TransColor| <= 1. Theo tôi hiểu như thế là sai. Tôi cho vd.
Trong UserForm_Initialize bạn nhập code:
Mã:
Me.BackColor = 255 ' = RGB(255, 0, 0)

Bạn sẽ có mầu đỏ do Red = 255, Green = 0, Blue = 0
Trong UserForm_Initialize bạn nhập code:
Mã:
Me.BackColor = 256 ' = RGB(0, 1, 0)

Bạn sẽ có mầu "gần đen" do Red = 0, Green = 1, Blue = 0
Theo cách hiểu của bạn thì chúng khác nhau 1 đơn vị nhưng 2 mầu không "lơ lớ" như nhau.
------------------
Theo tôi 2 mầu "lơ lớ" như nhau khi và chỉ khi |R1 - R2| ≤ a AND |G1 - G2| ≤ a AND |B1 - B2| ≤ a
với a là sai số và R1, R2, G1, G2, B1, B2 là các thành phần Red, Green và Blue của mỗi mầu.
R1, G1, B1 chính là pixel.rgbtRed, pixel.rgbtGreen, pixel.rgbtBlue. R2, G2, B2 thì đọc từ TransColor hoặc nếu TransColor = -1 thì chúng chính là Arr(0).rgbtRed, Arr(0).rgbtGreen, Arr(0).rgbtBlue
---------------
Thực ra cũng có thể làm đơn giản hơn, không dùng toàn bộ code đã có:
1. LoadImage ảnh để có bitmap handle bmp
2. Tạo device context DC
3. "lấy" bitmap vào device context: oldbitmap = SelectObject(DC, bmp)
4. Đi từng dòng và trong mỗi dòng đi từng cột và dùng GetPixel để đọc giá trị của mầu --> "tách" ra 3 thành phần R1, G1, B1. Kiểm tra đk và nếu thỏa thì dùng SetPixel để thiết lập mầu cho pixel hiện hành thành mầu backcolor.
5. SelectObject DC, oldbitmap
6. Hủy device context DC

Trong bmp bây giờ có ảnh mà các pixel có mầu "lơ lớ" với TransColor đã bị thay bằng mầu backcolor.

Cách dùng GetPixel và SetPixel tôi đã trình bầy trong các bài viết trên GPE. Tất nhiên 2 hàm này rất chậm nên khi cần copy trong suốt không ai dùng chúng cả.

Trong ví dụ tôi chỉ trình bầy 1 cách copy trong suốt. Đó là copy bình thường nhưng dùng SelectClipRgn để giới hạn vùng mà việc copy có tác dụng

Trong những animate thì người ta thường dùng cách tạo 2 bitmap hỗ trợ, ta gọi là mask và sprite. mask là bitmap trắng - đen. Ở vị trí pixel có mầu TransColor ở ảnh nguồn thì ở mask có mầu trắng, các pixel còn lại có mầu đen. Ở vị trí pixel có mầu TransColor ở ảnh nguồn thì ở sprite có mầu đen, các pixel còn lại có mầu của ảnh nguồn. Người ta sẽ dùng BitBlt 2 lần để copy mask và sprite vào cùng chỗ ở đích. Kết quả sẽ có copy trong suốt.
---------------

Thôi tôi xin rút lui. Viết nhiều ngại quá. Vấn đề của bạn thuộc loại mà nếu muốn giúp thì tôi phải tự làm từ A tới Z. Mà phải viết rất nhiều. Ngại quá. Bạn chỉ nhấn nút "Cám ơn" nên bạn không cảm thấy ngại. Thậm chí bạn chả phải nhọc công viết lời cám ơn. Nút "Cám ơn" làm thay bạn tất cả.
 
Upvote 0
Xin mạo muội có một vài ý kiến trong topic này:

bạn tttmuah... đã có 1 tinh thần học hỏi nghiên cứu, quyết tâm muốn làm từ VBA của Excel chứ không dùng ngôn ngữ lập trình khác, đó là rất tốt.
Bạn muốn học, và túm được một ông thầy giỏi để học, lại là một việc quá rất rất tốt.

Tuy nhiên, khi tôi đọc bài liền kề bên trên của anh siwtom thì tôi có cảm giác như sau:

1. Việc so sánh chỉ số màu của 1 màu và các màu "na ná" (lơ lớ) là thuộc kiến thức cơ bản, mà vẫn phải để cho "ông thầy" giải thích. Nghĩa là bạn sẽ phải nhờ ông thầy ấy viết rất nhiều để bạn làm được 1 dự án lớn, lần này và cả những lần sau.

2. Đặt địa vị của mình vào người trả lời, tôi cũng có cảm giác như anh siwtom. Chẳng thà tôi viết 1 hẳn chuyên đề, có thể tôi viết 1 lần từ A đến Z, có thể tôi chia ra các level khác nhau và viết từng phần. Tôi sẽ không "ngại". Một ngày bận rộn thì tôi viết 15 phút, rảnh thì viết 1 vài giờ, viết xong 1 phần thì post lên. Viết những chuyên đề như thế có ý nghĩa như những bài giảng và dành cho nhiều người quan tâm, ai muốn tìm hiểu đến đâu thì đọc đến đó. Chứ viết trong topic này là viết chỉ cho 1 người, và phải viết chuyên sâu từ A đến Z, đồng thời vẫn phải giải thích cả các điều cơ bản.

3. Hướng đi:
Thí dụ tôi có hình scan chữ ký chẳng hạn, tôi muốn insert vào văn bản word và loại bỏ nền xám xám. Hình scan tốt thì trong word chỉ cần click chuột 1 cái là màu nền trở thành transparent, hình scan kém thì nền gồm nhiều màu na ná và chức năng của word không loại bỏ hết. Thế là tôi đưa vào photoshop, thực hiện 1 vài thao tác, thế là đạt. Có thể tttmuah thích lập trình cho việc này, nhưng lại không làm được, phải hỏi, mà không nghĩ rằng muốn trả lời sẽ tốn bao nhiêu công sức. Còn tôi, nếu thấy hướng đi này phức tạp và làm phiền người khác, tôi sẽ suy nghĩ khác đi, bỏ cái muốn của tôi đi.

Vậy: Nếu là tôi, tôi đã học được 1 chiêu quá tuyệt ở bài #11, tôi muốn áp dụng và sử dụng 1 ảnh bất kỳ mà vẫn đạt hiệu ứng transparent tốt, thì tôi sẽ xử lý cái ảnh đó bằng phần mềm xử lý ảnh, loại bỏ những màu nền "na ná", rồi mới sử dụng.

Ngoài ra, một khi ảnh đã xử lý trước, khi đưa vào game, (tức là 1 hình phải đưa vào nhiều lần, rất nhiều lần), sẽ không phải xử lý bằng code nhiều lần, và bị chậm.

Tôi còn định viết nhiều hơn, nhưng lại "ngại" rồi.
 
Lần chỉnh sửa cuối:
Upvote 0
Cám ơn các Chú rất nhiều!
Cháu cũng đang trong quá trình tìm tòi, học hỏi các kiến thức API. Các bải viết của chú Siwtom rất bổ ích. Cảm phiền chú Siwtom đừng giận, vì để ngẫm được những code của chú thật sự cháu cũng phải mất khá nhiều thời gian. Từ lần cháu hỏi riêng chú về cấu trúc Bitmap đến giờ, cháu đã cảm nhận được câu nói hồi trước của chú " đã "mệt" vì tìm hiểu cấu trúc của tập tin Bitmap" như thế nào. Thông qua topic này, với những code chú đưa ra, nay cháu được thêm một "chương" kiến thức mới về các tạo Rectangle, combine chúng rồi tạo các Object, xử lý các Handle divice context. Thật sự rất thú vị, một lần nữa cám ơn chú rất nhiều.
Cám ơn chú Ptm0412 đã góp ý. Cháu sẽ cố gắng học hỏi thêm nhiều để có kiến thức VBA, API được bằng như các chú.
Cháu cám ơn ^^
 
Upvote 0
Từ sự hướng dẫn của chú Siwtom:
Em có được Hàm TransparentPic như sau:
Lấy ảnh Bitmap từ 1 file ngoài, trích 1 phần ảnh của Bitmap này theo tọa độ xSrc và ySrc, kích thước SrcWidth và SrcHeight. Sau đó "Paste" vào vùng có handle of device context (ví dụ như Form, Static, Button... hay 1 Window tự tạo) tại tọa độ PosX và PosY, có thể co giãn về kích thước Width, Height đồng thời tất cả các màu trùng với màu rColorTransparent đều trong suốt.
[GPECODE=vb]
'Declare Const
Private Const SRCCOPY = &HCC0020 ' (DWORD) dest = source
Private Const SRCPAINT = &HEE0086 ' (DWORD) dest = source OR dest
Private Const SRCAND = &H8800C6 ' (DWORD) dest = source AND dest
Private Const NOTSRCCOPY = &H330008 ' (DWORD) dest = (NOT source)
Private Const IMAGE_BITMAP As Long = 0
Private Const LR_LOADFROMFILE As Long = &H10
'Declare Func
Private Declare Function CreateCompatibleDC Lib "gdi32" (ByVal hdc As Long) As Long
Private Declare Function CreateCompatibleBitmap Lib "gdi32" (ByVal hdc As Long, ByVal nWidth As Long, ByVal nHeight As Long) As Long
Private Declare Function SelectObject Lib "gdi32" (ByVal hdc As Long, ByVal hObject As Long) As Long
Private Declare Function DeleteDC Lib "gdi32" (ByVal hdc As Long) As Long
Private Declare Function DeleteObject Lib "gdi32" (ByVal hObject As Long) As Long
Private Declare Function SetBkColor Lib "gdi32" (ByVal hdc As Long, ByVal crColor As Long) As Long
Private Declare Function BitBlt Lib "gdi32" (ByVal hDestDC As Long, ByVal x As Long, ByVal y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal hSrcDC As Long, ByVal xSrc As Long, ByVal ySrc As Long, ByVal dwRop As Long) As Long
Private Declare Function StretchBlt Lib "gdi32" (ByVal hdc As Long, ByVal x As Long, ByVal y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal hSrcDC As Long, ByVal xSrc As Long, ByVal ySrc As Long, ByVal nSrcWidth As Long, ByVal nSrcHeight As Long, ByVal dwRop As Long) As Long
Private Declare Function CreateBitmap Lib "gdi32" (ByVal nWidth As Long, ByVal nHeight As Long, ByVal nPlanes As Long, ByVal nBitCount As Long, lpBits As Any) As Long
Private Declare Function LoadImage Lib "user32" Alias "LoadImageA" (ByVal hInst As Long, ByVal lpsz As String, ByVal un1 As Long, ByVal n1 As Long, ByVal n2 As Long, ByVal un2 As Long) As Long
'----------------------------------
Private Function TransparentPic(Fullfilename As String, hdc As Long, PosX As Long, _
PosY As Long, Width As Long, Height As Long, xSrc As Long, ySrc As Long, _
SrcWidth As Long, SrcHeight As Long, rColorTransparent As Long) As Long
Dim hBitmap As Long
Dim hdc As Long
Dim tmpDC As Long
Dim oldtmpDC As Long
Dim SrcDC As Long
Dim oldSrcDC As Long
Dim tmpBitmap As Long
Dim oldDC As Long
Dim dcMask As Long
Dim olddcMask As Long
Dim hBitmapMask As Long
'Lay anh tu file nguon neu tai Fullfilename
hBitmap = LoadImage(0, Fullfilename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE)
'Tao SrcDC de tao nguon anh de copy vao hdc
SrcDC = CreateCompatibleDC(hdc)
oldSrcDC = SelectObject(SrcDC, hBitmap)
'Tao tmpDC tuong thich voi hdc de lam trung gian luu tru anh
tmpDC = CreateCompatibleDC(hdc)
tmpBitmap = CreateCompatibleBitmap(hdc, Width, Height)
oldtmpDC = SelectObject(tmpDC, tmpBitmap)
'Tao Mask: MonoChrome or Black and White Bitmap
hBitmapMask = CreateBitmap(Width, Height, 1, 1, ByVal 0&)
dcMask = CreateCompatibleDC(hdc)
olddcMask = SelectObject(dcMask, hBitmapMask)
'Buoc 1: Cai dat mau Transprent lam mau Background
oldcolor = SetBkColor(SrcDC, rColorTransparent) 'Su dung rColorTransparent=RGB(...,...,...)
'Buoc 2: Tao 1 Mask voi BackGround= Black; ForeGround=White
StretchBlt dcMask, PosX, PosY, Width, Height, SrcDC, xSrc, ySrc, SrcWidth, SrcHeight, NOTSRCCOPY
'Buoc 3: Tra lai BackGround ban dau cho anh nguon
SetBkColor SrcDC, oldcolor
'Buoc 4: Tao anh Back trong suot, fore mau trang
BitBlt hdc, PosX, PosY, Width, Height, dcMask, 0, 0, SRCPAINT
'Buoc 5: Chen anh vao tmpdc
StretchBlt tmpDC, PosX, PosY, Width, Height, SrcDC, xSrc, ySrc, SrcWidth, SrcHeight, SRCCOPY
'Buoc 6: Dao (Invert) mau cho dcMask
BitBlt dcMask, PosX, PosY, Width, Height, dcMask, 0, 0, NOTSRCCOPY
'Buoc 7: Them Mask vao tmdc sao cho Back mau trang, Fore la hinh anh
BitBlt tmpDC, PosX, PosY, Width, Height, dcMask, 0, 0, SRCPAINT
'Buoc 8: Chen anh vao hdc lam trong suot phan mau trang cua tmpdc
BitBlt hdc, PosX, PosY, Width, Height, tmpDC, 0, 0, SRCAND
'Giai phong bo nho
SelectObject tmpDC, oldtmpDC
DeleteDC tmpDC
SelectObject dcMask, olddcMask
DeleteDC dcMask
SelectObject SrcDC, oldSrcDC
DeleteDC SrcDC
DeleteObject tmpBitmap
DeleteObject hBitmapMask
End Function
[/GPECODE]
Cám ơn mọi người!
 
Lần chỉnh sửa cuối:
Upvote 0
Web KT
Back
Top Bottom