Skip to content

Commit

Permalink
fixes #90 - New feature : Add option to extract images from PDF
Browse files Browse the repository at this point in the history
  • Loading branch information
Swati4star committed Aug 12, 2018
1 parent e70d7e1 commit 9abd686
Show file tree
Hide file tree
Showing 7 changed files with 337 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import io.github.tonnyl.whatsnew.item.WhatsNewItem;
import swati4star.createpdf.R;
import swati4star.createpdf.fragment.AboutUsFragment;
import swati4star.createpdf.fragment.ExtractImagesFragment;
import swati4star.createpdf.fragment.HistoryFragment;
import swati4star.createpdf.fragment.ImageToPdfFragment;
import swati4star.createpdf.fragment.MergeFilesFragment;
Expand Down Expand Up @@ -238,6 +239,9 @@ public boolean onNavigationItemSelected(@NonNull MenuItem item) {
case R.id.nav_about:
fragment = new AboutUsFragment();
break;
case R.id.nav_extract_images:
fragment = new ExtractImagesFragment();
break;
}

if (fragment != null) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,240 @@
package swati4star.createpdf.fragment;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.support.annotation.NonNull;
import android.support.design.widget.BottomSheetBehavior;
import android.support.design.widget.Snackbar;
import android.support.v4.app.Fragment;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;

import com.dd.morphingbutton.MorphingButton;
import com.itextpdf.text.pdf.PRStream;
import com.itextpdf.text.pdf.PdfName;
import com.itextpdf.text.pdf.PdfObject;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.parser.PdfImageObject;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Objects;

import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import swati4star.createpdf.R;
import swati4star.createpdf.adapter.MergeFilesAdapter;
import swati4star.createpdf.util.DirectoryUtils;
import swati4star.createpdf.util.FileUtils;
import swati4star.createpdf.util.MorphButtonUtility;
import swati4star.createpdf.util.ViewFilesDividerItemDecoration;

import static android.app.Activity.RESULT_OK;

public class ExtractImagesFragment extends Fragment implements MergeFilesAdapter.OnClickListener {

private Activity mActivity;
private String mPath;
private MorphButtonUtility mMorphButtonUtility;
private FileUtils mFileUtils;
private DirectoryUtils mDirectoryUtils;
private static final int INTENT_REQUEST_PICKFILE_CODE = 10;

@BindView(R.id.selectFile)
Button selectFileButton;
@BindView(R.id.extractImages)
MorphingButton extractImagesButton;
BottomSheetBehavior sheetBehavior;
@BindView(R.id.bottom_sheet)
LinearLayout layoutBottomSheet;
@BindView(R.id.upArrow)
ImageView mUpArrow;
@BindView(R.id.downArrow)
ImageView mDownArrow;
@BindView(R.id.layout)
RelativeLayout mLayout;
@BindView(R.id.recyclerViewFiles)
RecyclerView mRecyclerViewFiles;

@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootview = inflater.inflate(R.layout.fragment_extract_images, container, false);
ButterKnife.bind(this, rootview);
sheetBehavior = BottomSheetBehavior.from(layoutBottomSheet);
sheetBehavior.setBottomSheetCallback(new ExtractImagesFragment.BottomSheetCallback());

ArrayList<String> mAllFilesPaths = mDirectoryUtils.getAllFilePaths();
if (mAllFilesPaths == null || mAllFilesPaths.size() == 0) {
mLayout.setVisibility(View.GONE);
}

// Init recycler view
MergeFilesAdapter mergeFilesAdapter = new MergeFilesAdapter(mActivity, mAllFilesPaths, this);
RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(mActivity);
mRecyclerViewFiles.setLayoutManager(mLayoutManager);
mRecyclerViewFiles.setAdapter(mergeFilesAdapter);
mRecyclerViewFiles.addItemDecoration(new ViewFilesDividerItemDecoration(mActivity));

return rootview;
}

@OnClick(R.id.viewFiles)
void onViewFilesClick(View view) {
if (sheetBehavior.getState() != BottomSheetBehavior.STATE_EXPANDED) {
sheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);
} else {
sheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
}
}

/**
* Displays file chooser intent
*/
@OnClick(R.id.selectFile)
public void showFileChooser() {
String folderPath = Environment.getExternalStorageDirectory() + "/";
Intent intent = new Intent();
intent.setAction(Intent.ACTION_GET_CONTENT);
Uri myUri = Uri.parse(folderPath);
intent.setDataAndType(myUri, getString(R.string.pdf_type));
Intent intentChooser = Intent.createChooser(intent, getString(R.string.merge_file_select));
startActivityForResult(intentChooser, INTENT_REQUEST_PICKFILE_CODE);
}

public void onActivityResult(int requestCode, int resultCode, Intent data) throws NullPointerException {
if (data == null || resultCode != RESULT_OK || data.getData() == null)
return;
if (requestCode == INTENT_REQUEST_PICKFILE_CODE) {
setTextAndActivateButtons(getFilePath(data.getData()));
}
}

//Returns the complete filepath of the PDF as a string
private String getFilePath(Uri uri) {
String uriString = uri.toString();
File file = new File(uri.toString());
String path = file.getPath();
String returnPath = Environment.getExternalStorageDirectory().getAbsolutePath();
Boolean success;
String name = null;
if (uriString.startsWith("content://") && uriString.contains("com.google.android.")) {
success = false;
} else {
success = true;
name = mFileUtils.getFileName(uri);
}
if (success) {
String folname = mDirectoryUtils.getParentFolder(path);
if (folname != null) {
String c = getString(R.string.path_seperator);
returnPath = returnPath + c + folname + c + name;
}
}
return returnPath;
}

@OnClick(R.id.extractImages)
public void parse() {
PdfReader reader = null;
int imagesCount = 0;
try {
reader = new PdfReader(mPath);
Log.v("path", mPath);
PdfObject obj;
for (int i = 1; i <= reader.getXrefSize(); i++) {
obj = reader.getPdfObject(i);
if (obj != null && obj.isStream()) {
PRStream stream = (PRStream) obj;
PdfObject type = stream.get(PdfName.SUBTYPE); //get the object type
if (type != null && type.toString().equals(PdfName.IMAGE.toString())) {
PdfImageObject pio = new PdfImageObject(stream);
byte[] image = pio.getImageAsBytes();
Bitmap bmp = BitmapFactory.decodeByteArray(image, 0,
image.length);
imagesCount++;
mFileUtils.saveImage(bmp);
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
if (imagesCount == 0) {
showSnackbar(getString(R.string.extract_images_failed));
} else {
showSnackbar(String.format(getString(R.string.extract_images_success),
imagesCount));
}
mPath = "";
selectFileButton.setText(R.string.merge_file_select);
selectFileButton.setBackgroundColor(getResources().getColor(R.color.colorGray));
mMorphButtonUtility.morphToGrey(extractImagesButton, mMorphButtonUtility.integer());
extractImagesButton.setEnabled(false);
}

@Override
public void onAttach(Context context) {
super.onAttach(context);
mActivity = (Activity) context;
mMorphButtonUtility = new MorphButtonUtility(mActivity);
mFileUtils = new FileUtils(mActivity);
mDirectoryUtils = new DirectoryUtils(mActivity);
}

@Override
public void onItemClick(String path) {
sheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
setTextAndActivateButtons(path);
}

private void setTextAndActivateButtons(String path) {
mPath = path;
selectFileButton.setText(mPath);
selectFileButton.setBackgroundColor(getResources().getColor(R.color.mb_green_dark));
extractImagesButton.setEnabled(true);
mMorphButtonUtility.morphToSquare(extractImagesButton, mMorphButtonUtility.integer());
}

private class BottomSheetCallback extends BottomSheetBehavior.BottomSheetCallback {

@Override
public void onStateChanged(@NonNull View bottomSheet, int newState) {
switch (newState) {
case BottomSheetBehavior.STATE_EXPANDED:
mUpArrow.setVisibility(View.GONE);
mDownArrow.setVisibility(View.VISIBLE);
break;
case BottomSheetBehavior.STATE_COLLAPSED:
mUpArrow.setVisibility(View.VISIBLE);
mDownArrow.setVisibility(View.GONE);
break;
}
}

@Override
public void onSlide(@NonNull View bottomSheet, float slideOffset) {
}
}

private void showSnackbar(String resID) {
Snackbar.make(Objects.requireNonNull(mActivity).findViewById(android.R.id.content),
resID, Snackbar.LENGTH_LONG).show();
}
}
24 changes: 24 additions & 0 deletions app/src/main/java/swati4star/createpdf/util/FileUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Bundle;
import android.os.CancellationSignal;
Expand All @@ -19,6 +20,7 @@
import android.provider.MediaStore;
import android.support.design.widget.Snackbar;
import android.support.v4.content.FileProvider;
import android.util.Log;

import java.io.File;
import java.io.FileInputStream;
Expand Down Expand Up @@ -288,4 +290,26 @@ else if (scheme.equals("content")) {
public String getFileName(String path) {
return path.substring(path.lastIndexOf(mContext.getString(R.string.path_seperator)) + 1);
}

/**
* Saves bitmap to external storage
* @param finalBitmap - bitmap to save
*/
public void saveImage(Bitmap finalBitmap) {
String root = Environment.getExternalStorageDirectory().toString();
File myDir = new File(root + mContext.getString(R.string.pdf_dir));
String fname = "image_" + System.currentTimeMillis() + ".jpg";

File file = new File(myDir, fname);
if (file.exists()) file.delete();
try {
FileOutputStream out = new FileOutputStream(file);
finalBitmap.compress(Bitmap.CompressFormat.JPEG, 100, out);
Log.v("saving", fname);
out.flush();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
9 changes: 9 additions & 0 deletions app/src/main/res/drawable/ic_broken_image_black_24dp.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M21,5v6.59l-3,-3.01 -4,4.01 -4,-4 -4,4 -3,-3.01L3,5c0,-1.1 0.9,-2 2,-2h14c1.1,0 2,0.9 2,2zM18,11.42l3,3.01L21,19c0,1.1 -0.9,2 -2,2L5,21c-1.1,0 -2,-0.9 -2,-2v-6.58l3,2.99 4,-4 4,4 4,-3.99z"/>
</vector>
51 changes: 51 additions & 0 deletions app/src/main/res/layout/fragment_extract_images.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/tableLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:stretchColumns="*"
android:orientation="vertical"
tools:context=".fragment.ExtractImagesFragment">

<Button
android:id="@+id/selectFile"
android:layout_width="match_parent"
android:layout_height="70dp"
android:layout_margin="24dp"
android:background="@color/colorGray"
android:maxWidth="30dp"
android:padding="3dip"
android:tag="fbt"
android:text="@string/merge_file_select"
android:textColor="@color/mb_white"
app:layout_constraintEnd_toStartOf="@+id/filetwobtn"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

<com.dd.morphingbutton.MorphingButton
android:id="@+id/extractImages"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="16dp"
android:layout_marginTop="112dp"
android:padding="10dp"
android:text="@string/extract_images"
android:textColor="@color/mb_white"
app:layout_constraintBottom_toTopOf="@id/recyclerView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/textView" />

</LinearLayout>

<include layout="@layout/bottom_sheet" />
</android.support.design.widget.CoordinatorLayout>
4 changes: 4 additions & 0 deletions app/src/main/res/menu/activity_main_drawer.xml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@
android:id="@+id/nav_history"
android:icon="@drawable/ic_history_black_24dp"
android:title="@string/history" />
<item
android:id="@+id/nav_extract_images"
android:icon="@drawable/ic_broken_image_black_24dp"
android:title="@string/extract_images" />

</group>

Expand Down
5 changes: 5 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,11 @@
<string name="view_history_here_message">View all your converted files history here!</string>
<string name="delete_history_message">Are you sure you want to delete history ?</string>

<!-- Extract images -->
<string name="extract_images">Extract Images</string>
<string name="extract_images_failed">We coouldn\'t find any images in the selected PDF.</string>
<string name="extract_images_success">We found %1$d image(s) in the selected PDF. They have been saved in the PDF Files folder in root directory.</string>

<string name="file_info">\n File Name : %1$s \n\n Path : %2$s \n\n Size : %3$s \n\n Date Modified %4$s</string>
<string name="default_font_family_text">Font Family (Default : %s)</string>
<string name="font_family_text">"Font Family : "</string>
Expand Down

0 comments on commit 9abd686

Please sign in to comment.