Tải bản đầy đủ (.docx) (19 trang)

(TIỂU LUẬN) đề tài xây dựng ứng dụng chỉnh sửa ảnh

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (590.01 KB, 19 trang )

Báo cáo đồ án tin học:
Xây dựng phần mềm

Đề tài: Xây dựng ứng dụng
chỉnh sửa ảnh

Thực hiện bởi:
Trần Minh Hải - 20161327 (trưởng nhóm)

Bế Trần Văn - 20164603

1


Mục lục
Lời mở đầu…………………………………………………………3
I.
Giới thiệu về nhóm……………………………………………3-5
1. Giới thiệu chung……………………………………………...4
2. Mục tiêu, khó khăn và cách tiếp cận…………………………4
3. Cách thức hoạt động………………………………………….4-5
a) Cách lam việc của cả nhóm………………………………….4
b) Cách làm việc của mỗi thành viên…………………………..4-5
c) Phân chia công việc cụ thể…………………………………..5
d) Báo cáo tiến độ công việc theo tuần………………………....5
4. Những gì học được sau dự án………………………………...5
5. Kết quả làm việc và đánh giá…………………………………5 II.
Hướng dẫn sử dụng……………………………………………6-16
1. Đối với người sử dụng………………………………………..6-8
2. Đối với người phát triển………………………………………8-16
a) Thiết kế hệ thống……………………………………………..9


b) Thiết kế giao diện……………………………………………9-11
i. Phác thảo logo bằng công cụ vẽ trên máy tính…………9-10
ii. Thiết kế giao diện trong android studio………………..10-11
iii. Sử dụng resources……………………………………...11
c) Lập trình cho hệ thống………………………………………..12-15
i.
Các class có trong hệ thống………………………………..1214
ii.
Các bẫy lỗi đã sử dụng…………………………………...15
d) Đánh giá…………………………………………………….15
e)
Định hướng phát triển………………………………………..1516 III. Thảo luận………………………………………………………1617 IV. Kết luận………………………………………………………...17

2


Lời mở đầu
Chụp ảnh là nhu cầu cần thiết trong cuộc sống hiện nay. Để có một
bức ảnh đẹp, ghi lại những khoảnh khắc đáng nhớ, không thể thiếu ứng
dụng chỉnh sửa ảnh.
Chính vì điều này, nhóm V_CH group đã quyết định làm một ứng
dụng chỉnh sửa ảnh có tính cạnh tranh. Ứng dụng này cần đảm bảo yếu
tố: đủ một số công cụ cơ bản như chỉnh sửa màu sắc, tốc độ nhanh và
dung lượng thấp. Từ đó, ứng dụng có thể được sự tin tưởng của người
dùng.
Sau hơn 3 tháng triển khai, nhóm V_CH group đã 1 phần hoàn thành
được những chỉ tiêu trên.
Chúng em xin phép được cảm ơn thầy Vũ Hải, người hướng dẫn
chính trong khi chúng em thực hiện dự án này.
Trưởng nhóm V_CH group,

Trần Minh Hải

I. Giới thiệu về nhóm
1.Giới thiệu chung

3


Nhóm có tên VCH_Group, với VCH lấy theo ba chữ cái đầu tronng
tên của ba thành viên ban đầu của nhóm gồm Văn , Hải và Cường. Nhóm
được thành lập nhằm phát triển một ứng dụng chỉnh sửa ảnh có đầy đủ
các công cụ cơ bản hoạt động trên nền tảng android 4.0 trở nên. Hiện tại
vì nhiều nguyên nhân khách quan VCH_Group có hai thành viên hoạt
động thường xuyên gồm:
- Trần Minh Hải (trưởng nhóm)
- Bế Trần Văn
Ngồi ra, không thể không kể đến sự hỗ trợ đắc lực, cùng với
những lời nhận xét thẳng thắn và khách quan đến từ thầy Vũ Hải cùng
với tập thể các bạn trong lớp CLC_THCN K61.
2.Mục tiêu, khó khăn và cách tiếp cận
 Mục tiêu khi bắt đầu dự án:

Ra được ứng dụng chỉnh sửa ảnh trên điện
thoại với các công cụ cơ bản.

Các thành viên cùng thực hiện dự án, hiểu
về dự án và có khả năng thuyết trình về cơng việc
của mình khi dự án kết thúc.

Ứng dụng có tốc độ nhanh và dung lượng nhẹ.

 Khó khăn:
Chun mơn của từng thành viên chưa đồng đều,
chưa sử dụng phần mềm android studio thành thục.
Kỹ năng làm việc nhóm cịn kém.
Chưa có kinh nghiệm thiết kế app trên nền tảng di
động.
Thời gian làm việc hạn chế.
 Cách tiếp cận:
Mơ hình thác nước.
Chun mơn hóa từng thành viên.
3.Cách thức hoạt động
a. Cách làm việc của cả nhóm
Phân chia cơng việc ngay sau khi báo cáo vào
buổi chiều thứ 6 hàng tuần.
Họp online qua facebook cùng nhau giải quyết những
khó khăn.
b. Cách àm việc của mỗi thành viên
Nhận công việc phù hợp với khả năng cá nhân.
Có trách nhiệm với cơng việc của bản thân, giúp đỡ các
thành viên khác nếu có thể.
Mỗi thành viên là một người giám sát với các thành
viên khác trong nhóm.
c. Phân chia cơng việc cụ thể

4


Trần Minh Hải: Hồn thành các cơng cụ cơ bản cho app
chỉnh sửa ảnh, là thư kí của nhóm.
Bế Trần Văn: Thiết kế và tạo thành giao diện cho app.

Tạo và quản lí blog để phân chia cơng việc cho mỗi cá
nhân theo từng tuần.
d.Báo cáo tiến độ theo tuần.

4.Những gì học được sau dự án
Làm việc:
- Cách làm việc nhóm: Phân chia cơng việc.
- Vai trị của làm việc có chiến lược(thác nước).
- Tạo và quản lí blogger.
Thuyết trình và viết báo cáo đồ
án. Kĩ thuật:
- Làm việc trên android studio: biết cách thiết kế
user interface và lập trình java cho một ứng dụng.
- Xây dựng một ứng dụng dễ đọc cho người phát
triển sau(resources).
5.Kết quả làm được và đánh giá.
Nhóm đã phát triển thành cơng ứng dụng chỉnh sửa ảnh trên nền tảng
android phù hợp với tiêu chí ứng dụng nhanh và gọn. Mặc dù ứng dụng
chỉ mới có cơng cụ filter color ảnh do hạn chế về mặt thời gian cũng như
có sự biến động trong số lượng thành viên nhóm, nhưng đây cũng là
thành cơng bước đầu và là nền tảng vững chắc để nhóm tiếp tục phát triển
ứng dụng này , cũng như các ứng dụng khác trên nền tảng android trong
tương lai.
Định hướng phát triển ứng dụng:
- Thêm công cụ crop, add text, emoji…
- Hoàn thiện chức năng load ảnh.
- Hoàn thiện chức năng cài đặt.

II.


Hướng dẫn sử dụng

1.

Đối với người sử dụng
Để sử dụng ứng dụng chỉnh sửa ảnh này, người sử dụng cần cung
cấp cho chúng tôi quyền truy cập vào bộ nhớ của thiết bị.
5


Ứng dụng chỉnh sửa ảnh gồm 3 hoạt động chính:
 Phần mở đầu ứng dụng:

Trong hoạt động này, người sử dụng có 2 lựa chọn như sau:
 Nhấn vào hình ảnh đại diện lớn của nhóm ở giữa màn
hình để đi tới hoạt động tải bức ảnh lên chính sửa
 Nhấn vào dòng chữ:”For more information about us”, 1
hộp tin nhắn sẽ hiện lên như sau:”If you keep this action, the
editor application will be paused”. Tới đây, người dùng sẽ có
2 lựa chọn. Nếu ấn cancel, thì người dùng sẽ trở lại màn hình
mở đầu của ứng dụng. Nếu ấn OK, người dùng sẽ di chuyển
tới blogger của nhóm.
 Màn hình tải bức ảnh để chỉnh sửa:

6


Trong hoạt động này, người dùng sẽ nhìn thấy một bức ảnh lớn ở
chính giữa với dịng chữ:”Chọn ảnh đi”. Người dùng ấn vào bức ảnh
này, sẽ có một hộp tin nhắn hiện lên, yêu cầu người dùng sử dụng

thực hiện thao tác chọn gallery. Cuối cùng người dùng chọn 1 bức
ảnh.
 Màn hình chỉnh sửa ảnh:

7


Trong hoạt động chỉnh sửa ảnh, chúng tơi có cung cấp 17 các mẫu lọc
màu cho bức ảnh: Normal, Struck, Clarendon, OldMan, Mars, Rise,
April, Amazon, Starlit, Whisper, Lime, Haan, BlueMess, Adele, Cruz,
Metropolis, Audrey. Sau khi chọn 1 trong các lọc màu sắc trên, người
dùng có thể lưu trữ lại bức ảnh bằng cách ấn vào nút SAVE bên góc
phải trên cùng (Người dùng cần chú ý, bức ảnh sẽ được lưu trữ vào
chính bức ảnh ban đầu). Nếu bức ảnh có thể save được, sẽ có 1 dịng
chữ hiện lên ở phía cuối màn hình:”Image saved to gallery”. Bên cạnh
dịng chữ này, có 1 chữ OPEN màu đỏ. Nhấn vào nút này để đi tới
gallery, nơi bức ảnh vừa sửa được lưu trữ. Nếu bức ảnh không thể lưu
trữ, sẽ có một dịng chữ hiện lên ở phía cuối màn hình là:”Unable to
save image!”.
Sau đó, người dùng có thể tiếp tục hoạt động chỉnh sửa ảnh bằng cách
ấn vào bức ảnh to ở chính giữa màn hình để load 1 bức ảnh khác.
2. Đối với người phát triển
Ứng dụng chỉnh sửa ảnh do V_CH group xây dựng và phát triển
trên nền tảng phần mềm Android Studio. Ngôn ngữ sử dụng là
JAVA. Chính vì vậy người phát triển cần cài đặt phần mềm Android
Studio trên máy tính của mình. Link tải phần mềm này được đính
kèm sau đây: Sau đó, cần
tải và cài đặt JDK trên máy tính từ trang web sau:

/>h

tml. Về phần thiết bị để chạy ứng dụng, người dùng có 2 lựa chọn.

Lựa chọn 1 là sử dụng Virtual device. Để cài đặt Virtual device,
người phát triền có thể tham khảo cách cài đặt sau đây:
Lựa chọn 2
là sử dụng thiết bị di động của chính người phát triển. Người phát
triển lựa chọn cách này thì có thể tham khảo link dưới đây:
/>
Mỗi ứng dụng android đều gồm 2 phần chính: user interface hay
UI (được hiển thị bằng file.xml) và code cho từng user interface.
Trong ứng dụng chỉnh sửa ảnh này, chúng tôi sử dụng ngôn ngữ
JAVA. Chính vì vậy, để có thể hiểu được phần lập trình cho ứng
dụng này, người đọc cần có những hiểu biết cơ bản về ngơn ngữ lập
trình JAVA và ngôn ngữ xml.
Về ngôn ngữ xml cho thiết kế giao diện, chúng tôi tham khảo
nhiều
trên
trang
web:
/>Về ngôn ngữ JAVA, người phát triển có thể đọc qua sách:
Beginning Android® Programming with Android Studio 4th Edition
(J.F.DiMarzio)
Để lập trình và thiết kế cho hệ thống này, cần thêm vào
dependencies thuộc build.gradle (Module app):
8


implementation 'com.android.support:recyclerview-v7:28.0.0'
implementation 'com.android.support:design:28.0.0'
implementation 'com.karumi:dexter:4.1.0' implementation

'info.androidhive:imagefilters:1.0.7'

Imagefilter, được chỉnh sửa từ thư viện AndroidHive, trong ứng
dụng này, được sử dụng để sử dụng các công cụ color filters
Dexter dùng để request runtime permission và tải ảnh, lưu ảnh
dễ dàng hơn
a) Thiết kế hệ thống

b)Thiết kế giao diện
i. Phác thảo logo bằng công cụ vẽ trên
máy tính Logo của app và nhóm:

9


ii.

Thiết kế giao diện trong android studio
 Các view được sử dụng trong app:
- TextView: nhiệm vụ chính của TextView là hiển thị
dịng văn bản trên màn hình dung nhằm cung cấp
thơng tin cho người dùng. Người lập trình cũng có
thể thay đổi nội dung dịng văn bản này bằng cách sử
dụng câu lệnh android:text= “information”.
- ImageView: là view dùng để hiện thị hình ảnh lên
màn hình sử dụng. Các hình ảnh này có thể là tài
ngun lưu trữ trong app hay các hình ảnh tải xuống
từ bộ nhớ máy hay internet.
- Button: button tiếp nhận hành động click của người
dùng và thực hiện một thao tác đã được lập trình từ

trước đó.
- Các View Group: Recyclerview, Toolbar,
LinearLayout, ConstraintLayout, RelativeLayout,
CoordinatorLayout.
 Layout: Các layout chính là các View (cụ thể nó kế
thừa thừa ViewGroup) được thiết kế với mục đích chứa
các View con và điều khiển, sắp xếp vị trí các View con
đó trên màn hình, mỗi layout có cơ chế điều khiển vị trí
View con riêng của mình. Các layout đã được thiết kế
trong app:
Activity_starting.xml: là một ConstraintLayout cho
phép điều chỉnh vị trí và ứng sử của các view bằng
10


cách dàng buộc đơn giản vào mỗi view con. Trong
activity_starting.xml chúng tôi thiết kế 2 view con là
textview và imageview. Textview này dùng để hiển
thị dòng văn bản: “for more information about us”.
Imageview này dùng để hiển thị logo của app.
- Activity_loading.xml: là một CoordinatorLayout
nó được thiết kế nhằm mục đích có sự tương tác của
các view con trong nó. Trong activity_loading.xml
có chứa 2 layout con là appbarlayout và
layout_content. Trong appbarlayout sử dụng toolbar
có chứa 2 button và một textview, một button với
chức năng điều hướng button còn lại thực hiện chức
năng save ảnh, textview hiển thị dòng văn bản
VCH_Filter.
- Layout_content.xml: là một RelativeLayout cho

phép sắp xếp các view con ở bất cứ vị trí nào mà
người thiết kế muốn. Như đã nói ở trên lay_content
là layout con của activity_loading.xml trong đó nó
có chứa 3 view con là imageview,
NonSwipeableViewPager và tablayout.
- Fragment_filter_list.xml: là một FrameLayout nó
cung cấp một vùng màn hình và hiển thị một view
con duy nhất là Recyclerview. Recyclerview này
hiển thị một tập các item gồm các màu sắc khác
nhau khi lọc ảnh. Nó cho phép thao tác scroll màn
hình theo chiều ngang.
Thumbnail_item.xml: là một LinearLayout cho phép
các view con sắp xếp nối tiếp nhau theo cột. Nó gồm
2 view con là textview dùng để hiển thị dòng text:
“filter name” và một imageview.
iii. Sử dụng values trong resources
Việc sử dụng Values trong thiết kế giao diện của ứng dụng là
tất yếu. Việc sử dụng Resources làm cho việc thiết kế trở nên rõ
ràng hơn cho người phát triển. Chính vì vậy, để có một phần thiết
kế hồn chỉnh, người thiết kế cần sử dụng cả 3 mục: colors,
strings, styles. Các màu sắc, dòng chữ và các styles dùng trong
thiết kế cần lưu trữ trong các mục cùng tên. Chẳng hạn, trong dự
án này có dịng chữ:”For more information about us”, cần lưu trữ
vào trong mục Strings, để người phát triển sau có thể nắm rõ được
các dịng chữ hiển thị trên giao diện của người dùng.
c)Lập trình cho hệ thống
i. Các class có trong hệ thống
Hệ thống được xây dựng bởi 2 lớp chính:

11




Starting Activity: Trong lớp này xử lý 2 nút là
startingButton và informationButton. Núi startingButton
sử dụng Intent để dẫn sang LoadingActivity. Nút
informationButton, cũng sử dụng Intent, chuyển người
dùng đến blogger của nhóm. Bên cạnh đó, sau khi người
dùng nhấn vào nút informationButton này, sẽ có 1 dịng
gạch chân dưới dịng chữ “For more information about
us”. Để thực hiện điều này, chúng tôi sử dụng 1 phương
thúc của TextView là setPaintFlags. Thêm nữa, cũng trong
informationButton, AlertDialog.Builder được thêm vào,
nhằm mục đích mở ra 1 tin nhắn cho người dùng: nếu tiếp
tục sẽ dừng lại ứng dụng. Khi đoạn nhắn hiện lên, để có 2
sự lựa chọn là “OK” hoặc “Cancel” cho người sử dụng,
cần dùng lần lượt đến setPositiveButton và
setNegativeButton của AlertDialog.Builder. Cuối cùng, tạo
AlertDialog và dùng hàm show() của AlertDialog để hiện
thị hộp thoại

Loading Activity: đây là nơi chúng tôi đã xử lý
phần tải bức ảnh để chỉnh sửa, chỉnh sửa bức ảnh và lưu
trữ lại bức ảnh sau khi chỉnh sửa.
- Tải bức ảnh lên để chỉnh sửa: Chúng tôi không sử dụng
cách thông thường là dùng button để tải bức ảnh lên, thay
vào đó, chúng tơi sử dụng “ImageView”. Để truyền bức
ảnh với dòng chữ: “Chọn ảnh đi” (loading_image) vào
ImageView, chúng tôi viết hàm loadImage(). Trong hàm
này, tôi sử dụng 3 thuộc tính kiểu trả về Bitmap:

originalBitmap, filterBitmap, finalBitmap. Thuộc tính giá
trị của originalBitmap (để tránh trường hợp bức
loading_image khơng bị crash trong q trình tải lên,
chúng tơi có viết lớp BitmapUtils với phương thức
getBitmapFromAssets và Asset là nơi chứa bức
loading_image. Phương thức này cho phép lấy bức ảnh, rồi
crop nó theo độ dài và độ rộng cho trước) sẽ được truyền
vào thuộc tính img_preview, được sử dụng như 1 nút để tải
bức ảnh. 2 thuộc tính kiểu trả về Bitmap còn lại được dùng
trong trường hợp người dùng lưu trữ chính loading_image.
Khi đó, sẽ khơng có lỗi xảy ra.
Sau khi truyền được bức ảnh loading_image vào
img_preview, chúng tôi tiến tới truyền khả năng tải ảnh vào
img_preview. Các hàm cần viết thêm BitmapUtils (sử dụng
phương thức getBitmapFromGallery). Trong lớp
LoadingActivity, có 1 phương thức là loadImage. Đây là
phương thức xử lí “onClick” của image_preview trong
layout_content.xml. Để load được ảnh, cần phương thức
openImageFromGallery trong hàm cùng tên. Hàm này xử
12


dụng thư viện Dexter để dễ dàng tải ảnh lên. Để có thể tải
ảnh lên, cần quyền truy cập vào bộ nhớ của thiết bị:
READ_EXTERNAL_STORAGE

WRITE_EXTERNAL_STORAGE. Nếu người dùng không
cấp quyền truy cập, 1 dòng text, nội dung là Permission,
được hiện lên nhờ sử dụng Toast.makeText. Ngược lại,
Intent sẽ giúp chúng ta tải bức ảnh lên và chúng ta sử dụng

startActivityForResult. Sau đó, tại phương thức
onActivityResult, các originalBitmap, filterBitmap,
finalBitmap, sẽ cập nhật bitmap của bức ảnh vừa được tải
và cuối cùng, img_preview nhận bức ảnh này:
img_preview.setImageBitmap(originalBitmap) trước khi
các bức ảnh con ở filter màu sắc dưới cũng đồng loạt
update lại bức ảnh này.
- Chỉnh sửa bức ảnh: phục vụ cho chỉnh sửa ảnh, chúng tôi
đã viết interface: FilterListFragmentListener và các lớp:
ThumbnailAdapter,
ViewPageAdapter

FilterListFragment. ViewPageAdapter chúng tôi đã giới
thiệu ở mục b) thiết kế giao diện cho hệ thống. Tại lớp
FilterListFragment, phương thức setListener sử dụng
phương thức trong interface FilterListFragmentListener để
tạo default cho filter màu sắc, ngay sau khi người dùng vào
hoạt động chỉnh sửa ảnh. Bên cạnh đó, phương thức
onCreateView được tạo. Khi biến kiểu trả về
FilterListFragment
được tạo
ở LoadingActivity
(setupViewPager), onCreateView được chạy, truyền các
filter màu sắc của thư viện AndroidHive với sự hỗ trợ của
phương thức DisplayThumbnail trong cùng lớp và của lớp
ThumbnailAdapter. Sau đó, bức ảnh vừa được tải lên sẽ
được truyền vào các ảnh con của các filter này. Nếu như
bức ảnh được tải lên có giá trị Bitmap là null thì
loading_image sẽ được thay thế.
Trong

lớp
LoadingActivity,
tại
phương
thức
onFilterSelected, khi 1 filter màu sắc được chọn, thuộc tính
filterBitmap sẽ thay đổi màu sắc: filterBitmap=
originalBitmap.copy(Bitmap.Config.ARGB_8888, true) và
img_preview và finalBitmap sẽ cập nhật sự thay đổi này.
- Lưu trữ bức ảnh: Chúng tôi thực hiện việc lưu trữ bức
ảnh nhờ vào thư viện Dexter. Trước đó, chúng tơi cũng có
u cầu người dùng cho các quyền đọc và viết vào bộ nhớ
của thiết bị:
Dexter.withActivity(this)
.withPermissions(Manifest.permission.READ_E
XTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE).
13


Nếu người dùng khơng cấp quyền truy cập, 1 dịng text, nội
dung là Permission, được hiện lên nhờ sử dụng
Toast.makeText
Bắt đầu tại lớp LoadingActivity, ở phương thức
onOptionsItemSelected, sau khi người dùng ấn vào nút
save, phương thức saveImage() được gọi. Sau khi các
quyền truy cập vào bộ nhwos thiết bị được đáp ứng, với sự
trợ giúp của phương thức insertImage tại hàm BitmapUtils
chúng tôi đã đề cập bên trên, bức ảnh được lưu lại:
final String path =

BitmapUtils.insertImage(getContentResolver(),
finalBitmap, System.currentTimeMillis() + "_profile.jpg",
null);
Tuy nhiên, ở đây có 2 trường hợp xảy ra: bức ảnh có thể
lưu lại và khơng thể lưu lại bức ảnh.
Trường hợp không thể lưu lại bức ảnh xảy ra khi bộ nhớ
của thiết bị đã đầy. Chính vì vậy, cần có 1 báo hiệu cho
người dùng:
Snackbar snackbar = Snackbar.make(coordinatorLayout,
"Unable to save image!", Snackbar.LENGTH_LONG);
Trường hợp còn lại, khi bức ảnh đã được lưu lại, sẽ có một
dịng text thể hiện bức ảnh đã được lưu lại:
Snackbar snackbar = Snackbar.make(coordinatorLayout,
"Image
saved
to
gallery!",
Snackbar.LENGTH_LONG).setAction("OPEN",
new
View.OnClickListener(){
@Override
public void onClick(View v) {
openImage(path);
}
});
Bên cạnh dịng chữ này, để có 1 link dẫn đến bức ảnh vừa
lưu, chúng tôi đã viết thêm phương thức openImage. Tại
phương thức này, chúng tôi sử dụng intent để đến nơi lưu
trữ bức ảnh.
ii. Các bẫy lỗi đã sử dụng

Trong quá trình xây dựng ứng dụng này, nhóm V_CH group
chủ yếu đặt các bẫy lỗi khi truyền bức ảnh loading_image vào
image_preview, tải bức ảnh lên hoặc khi lưu trữ bức ảnh sau khi
chỉnh sửa.
Bẫy lỗi khi truyền bức ảnh loading_image vào
image_preview. Dạng bẫy lỗi sử dụng: IOException. Bẫy lỗi đặt ở
đây phòng trường hợp người phát triển quên không đưa
loading_image vào assets file. Khi ấy, hệ thống sẽ in ra chỗ bị sai
e.printStackTrace();
14


Bẫy lỗi khi tải bức ảnh chỉnh sửa. Lỗi xảy ra khi người dùng
không cung cấp quyền truy cập vào bộ nhớ thiết bị. Ở đây, chúng
tôi sử dụng bẫy lỗi dưới dạng mệnh đề if else. Khi lỗi xảy ra, hệ
thống in ra báo hiệu:
Toast.makeText(LoadingActivity.this,
"Permission",
Toast.LENGTH_SHORT).show();
Bẫy lỗi khi lưu trữ bức ảnh sau chỉnh sửa. Tương tự khi tải
bức ảnh lên, nếu người dùng không cung cấp quyền truy cập thì
hệ thống in ra cảnh báo tương tự. Bên cạnh đó, cịn có lỗi khi nào
bộ nhớ của thiết bị đã đầy, khơng cịn chỗ trống để lưu trữ bức ảnh
mới được chỉnh sửa
d)Đánh giá
Như đã đề cập tại phần mục tiêu, khó khăn và cách tiếp cận, ban
đầu, chúng tôi đã đề ra 3 mục tiêu cần phải thực hiện:
 Ra được 1 ứng dụng chỉnh sửa ảnh trên điện thoại với các cơng
cụ cơ bản.
 Ứng dụng có tốc độ nhanh và dung lượng nhẹ.

 Các thành viên cùng thực hiện dự án, hiểu được dự án và có khả
năng trình bày về cơng việc của mình khi dự án kết thúc.
Hiện nay, chúng tơi đã hồn thành được mục tiêu 1 và 3, tương
ứng với 66% mục tiêu đã đề ra. Nhóm đã hồn thành được 1 công cụ
chỉnh sửa ảnh trên điện thoại và demo được trong buổi trình bày cuối
cùng. Cũng trong buổi này, cả 2 thành viên hiện tại còn hoạt động đều
hiểu được và trình bày được rõ ràng về những phần cơng việc mà
mình đã nhận và hồn thành.
Mục tiêu thứ 2 là xây dựng ứng dụng có tốc độ nhanh và dung
lượng nhẹ, nhóm sẽ tiếp tục hồn thiện trong thời gian sắp tới.
e)Định hướng phát triển
Trong thời gian tới, mục tiêu của nhóm là tối ưu hóa tốc độ của
phần mềm và cải thiện tốc độ.
Bên cạnh đó, trong quá trình 3 tháng vừa rồi, nhóm cũng nghiên
cứu những cơng cụ cơ bản trong chỉnh sửa ảnh như crop, rotate và
phần setting cho ứng dụng. Chính vì vậy, việc tích hợp 3 công cụ này
cũng sẽ nằm trong phần phát triển trong thời gian tới.
Tách hoạt động chỉnh sửa ảnh ra khỏi hoạt động tải bức ảnh lên là
1 trăn trở của những người xây dựng công cụ này. Đây sẽ là 1 mục
tiêu rất quan trọng trong thời gina sắp tới. Không chỉ giúp ứng dụng
trở nên chuyên nghiệp hơn, việc tách 2 hoạt động này cũng làm tăng
sự hiểu biết về lớp Bitmap, 1 công cụ đắc lực trong Android Studio.
Hồn thành những cơng việc chun mơn đã đề ra trong phần này
đòi hỏi cải thiện cách làm việc của từng thành viên. Trong đó, cần
phân chia những công việc phù hợp hơn với khả năng của từng người.
Thêm nữa, các thành viên cũng cần có trách nhiệm hơn với phần việc
mà mình đã nhận, hồn thành đúng hạn. Tuy vậy, cần tránh trường
15



hợp làm việc qua loa, đối phó để hồn thành đúng hạn. Nếu khơng thể
hồn thành đúng hạn, cần báo cáo lại với nhóm trước 1 ngày định
trước để cả nhóm có thể sớm giải quyết trục trặc này.
Cuối cùng, cần đẩy mạnh hơn trong cập nhật tiến độ làm việc và
mục tiêu trên blogger của nhóm. Bởi lẽ, sẽ có những cơng việc mà
nhóm khơng thể làm được. Khi ấy, để giải quyết thắc mắc, giáo viên
hướng dẫn cần biết tiến độ, chỗ vướng mắc, mà ở đây, blogger là
công cụ hiệu quả để cập nhật cho 1 người ngồi khơng nằm trong
nhóm.

III. Thảo luận

1) Cách làm việc nhóm
- Trong q trình làm việc, chúng tơi thấy, nếu sắp xếp được thời
gian để gặp gỡ và trao đổi với các thành viên trong nhóm ngay trước
và sau buổi báo cáo định kì sẽ thúc đẩy tính gắn kết giữa các thành
viên. Thêm nữa, các buổi họp này cũng làm cho các thành viên
trong nhóm hiểu hơn về chính dự án, tiến độ công vệc, các khúc
mắc của từng thành viên đang có với cơng việc hiện tại của mình.
Đây là tiền đề cho các cách giải quyết đến với từng vấn đề va chạm
phải trong quá trình làm việc.
- Làm việc qua mạng là 1 trong những giải pháp để giải quyết vấn
đề sắp xếp thời gian, khi các thành viên khơng thể đến được buổi
họp.
- Khi có mâu thuẫn xảy ra giữa các thành viên, cần trao đổi trực tiếp
với nhau, tránh tình trạng giữ sự bực bội trong người mà làm ảnh
hưởng đến kết quả của công việc. Chẳng hạn, việc so bì khối lượng
cơng việc người này với người khác là mẫu thuẫn thường xảy ra
trong khi làm việc nhóm. Khi ấy, cần trao đổi trực tiếp ngay để các
thành viên đều cảm thấy công bằng và hài lịng với phần việc mình

nhận.
2) Phát triển hệ thống
Để phục vụ cho mục tiêu ban đầu là tốc độ và dung lượng của
ứng dụng, cần thiết thiết kế một thư viện riêng, chỉ bao gồm những
công cụ sử dụng trong ứng dụng. Trong ứng dụng chúng tôi đã hoàn
thiện, thư viện androidHive đã được đưa vào. Bên cạnh những công
cụ chỉnh sửa ảnh rất hữu hiệu của thư viện được đưa vào dự án, cũng
có những cơng cụ khơng được sử dụng như crop, add image,… Chính
điều này đã làm tăng dung lượng của ứng dụng. Hay việc để quá
nhiều phương thức trong 1 lớp như lớp loadingActivity chúng tôi đã
làm cũng làm giảm tốc độ khi activity này được chạy. Để giải quyết
việc này, nhất thiết cần tách hoạt động chỉnh sửa ảnh và hoạt động tải
bức ảnh cần chỉnh sửa.

IV. Kết Luận
16


Sau 3 tháng hoạt động, ứng dụng đã được xây dựng và phát triển gần
như kì vọng. Tuy vậy, chúng tơi cũng cần nỗ lực nhiều hơn nữa để hồn
thiện ứng dụng chỉnh sửa ảnh này, phục vụ tốt hơn cho người dùng.
Cuối cùng, xin một lần nữa cảm ơn các thành viên trong nhóm đã
cống hiến hết mình trong suốt thời gian quá. Xin phép được cảm ơn thầy
giáo Vũ Hải đã giúp đỡ chúng em trong quá trình xây dựng ứng dụng này.
Main:

package com.example.v_chproject;
import
import
import

import
import

android.Manifest;
android.content.Intent;
android.graphics.Bitmap;
android.net.Uri;
android.support.annotation.Nullable;

import
import
import
import
import
import
import
import
import
import
import

android.support.v4.view.ViewPager;
android.support.v7.app.AppCompatActivity;
android.os.Bundle;
android.support.v7.widget.Toolbar;
android.text.TextUtils;
android.view.Menu;
android.view.MenuItem;
android.view.View;
android.widget.Button;

android.widget.ImageView;
android.widget.Toast;

import android.support.design.widget.CoordinatorLayout;
import android.support.design.widget.Snackbar; import
android.support.design.widget.TabLayout;

import com.example.v_chproject.Adapter.ViewPageAdapter;
import com.example.v_chproject.Interface.FilterListFragmentListener;
import com.example.v_chproject.Utils.BitmapUtils; import
com.karumi.dexter.Dexter;
import com.karumi.dexter.MultiplePermissionsReport;
import com.karumi.dexter.PermissionToken;
import com.karumi.dexter.listener.PermissionRequest;
import com.karumi.dexter.listener.multi.MultiplePermissionsListener;
import com.zomato.photofilters.imageprocessors.Filter;
import com.zomato.photofilters.imageprocessors.subfilters.BrightnessSubFilter;
import com.zomato.photofilters.imageprocessors.subfilters.ContrastSubFilter;
import com.zomato.photofilters.imageprocessors.subfilters.SaturationSubfilter;
import java.io.IOException;
import java.util.List;
public class LoadingActivity extends AppCompatActivity implements FilterListFragmentListener{
public static final String pictureName = "loading_image.png";
public static final int PERMISSION_PICK_IMAGE = 1000;

ImageView img_preview;
TabLayout tabLayout;
ViewPager viewPager;
CoordinatorLayout coordinatorLayout;
Bitmap originalBitmap, filterBitmap, finalBitmap;

FilterListFragment filterListFragment;
/*
load native image filters library
*/
static {
System.loadLibrary("NativeImageProcessor");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_loading);
Toolbar toolbar = findViewById(R.id.toolBar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setTitle("V_CH Filter");
img_preview = (ImageView) findViewById(R.id.image_preview);

17


tabLayout = (TabLayout) findViewById(R.id.tabs); viewPager =
(ViewPager) findViewById(R.id.viewPager); coordinatorLayout =
(CoordinatorLayout) findViewById(R.id.coordinator);
loadImage();
setupViewPager(viewPager);
tabLayout.setupWithViewPager(viewPager);
}
private void loadImage() {
originalBitmap = BitmapUtils.getBitmapFromAssets(this, pictureName, 300,
300); filterBitmap = originalBitmap.copy(Bitmap.Config.ARGB_8888, true);

finalBitmap = originalBitmap.copy(Bitmap.Config.ARGB_8888, true);
img_preview.setImageBitmap(originalBitmap);
}
private void setupViewPager(ViewPager viewPager) {
ViewPageAdapter adapter = new ViewPageAdapter(getSupportFragmentManager());
filterListFragment = new FilterListFragment();
filterListFragment.setListener(this);
adapter.addFragment(filterListFragment, "Filters");
}

viewPager.setAdapter(adapter);

@Override
public void onFilterSelected(Filter filter) {

filterBitmap= originalBitmap.copy(Bitmap.Config.ARGB_8888, true);
img_preview.setImageBitmap(filter.processFilter(filterBitmap));
finalBitmap = filterBitmap.copy(Bitmap.Config.ARGB_8888, true);

}
@Override
public boolean onCreateOptionsMenu(Menu menu)
{ getMenuInflater().inflate(R.menu.menu_main,
menu); return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_save) {
saveImage();

return true;
}
return super.onOptionsItemSelected(item);
}
private void saveImage() {
Dexter.withActivity(this)
.withPermissions(Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE)
.withListener(new MultiplePermissionsListener() {
@Override
public void onPermissionsChecked(MultiplePermissionsReport report) {
if (report.areAllPermissionsGranted()) {
try {
final String path = BitmapUtils.insertImage(getContentResolver(),
finalBitmap, System.currentTimeMillis() + "_profile.jpg", null);
if (!TextUtils.isEmpty(path)) {
Snackbar snackbar = Snackbar.make(coordinatorLayout, "Image
saved to gallery!", Snackbar.LENGTH_LONG).setAction("OPEN", new View.OnClickListener() {
@Override
public void onClick(View v) {
openImage(path);
}
});
snackbar.show();
} else {
Snackbar snackbar = Snackbar.make(coordinatorLayout,
"Unable to save image!", Snackbar.LENGTH_LONG);
snackbar.show();
}
} catch (IOException e) {

e.printStackTrace();
}
} else {
Toast.makeText(LoadingActivity.this, "Permission",
Toast.LENGTH_SHORT).show();
}
}

18


@Override

public void onPermissionRationaleShouldBeShown(List<PermissionRequest>
permissions, PermissionToken token) {

token.continuePermissionRequest();
}
}).check();
}
private void openImage(String path) {
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.parse(path), "image/*");
startActivity(intent);
}
private void openImageFromGallery() {
Dexter.withActivity(this)
.withPermissions(Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE)

.withListener(new MultiplePermissionsListener() {
@Override
public void onPermissionsChecked(MultiplePermissionsReport report) {
if (report.areAllPermissionsGranted()) {
Intent intent = new Intent(Intent.ACTION_PICK);
intent.setType("image/*");
startActivityForResult(intent, PERMISSION_PICK_IMAGE);
} else {
Toast.makeText(LoadingActivity.this, "Permission",
Toast.LENGTH_SHORT).show();
}
}
@Override

public void onPermissionRationaleShouldBeShown(List<PermissionRequest>
permissions, PermissionToken token) {

token.continuePermissionRequest();
}
}).check();
}
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data)
{ if (resultCode == RESULT_OK && requestCode == PERMISSION_PICK_IMAGE) {
Bitmap bitmap = BitmapUtils.getBitmapFromGallery(this, data.getData(), 800, 800);

originalBitmap.recycle();
finalBitmap.recycle();
filterBitmap.recycle();
originalBitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true);

finalBitmap = originalBitmap.copy(Bitmap.Config.ARGB_8888, true);
filterBitmap = originalBitmap.copy(Bitmap.Config.ARGB_8888,
true); img_preview.setImageBitmap(originalBitmap);
bitmap.recycle();
filterListFragment.displayThumbnail(originalBitmap);
}
}
public void loadingImage(View view) {
openImageFromGallery();
}
}

19



×