mirror of
https://github.com/commons-app/apps-android-commons.git
synced 2025-10-27 21:03:54 +01:00
* initial commit * initial commit * reading 3 exif directories * minor changes * fixed unit tests * reviwied requested changes * minor changes * minor changes
This commit is contained in:
parent
8cd87ad148
commit
3417d713d2
5 changed files with 89 additions and 9 deletions
60
app/src/main/java/fr/free/nrw/commons/upload/EXIFReader.java
Normal file
60
app/src/main/java/fr/free/nrw/commons/upload/EXIFReader.java
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
package fr.free.nrw.commons.upload;
|
||||
|
||||
import com.drew.imaging.ImageMetadataReader;
|
||||
import com.drew.imaging.ImageProcessingException;
|
||||
import com.drew.metadata.Directory;
|
||||
import com.drew.metadata.Metadata;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import fr.free.nrw.commons.utils.ImageUtils;
|
||||
import io.reactivex.Single;
|
||||
import timber.log.Timber;
|
||||
|
||||
/**
|
||||
* We try to avoid copyright violations in commons app.
|
||||
* For doing that we read EXIF data using the library metadata-reader
|
||||
* If an image doesn't have any EXIF Directoris in it's metadata then the image is an
|
||||
* internet download image(and not the one taken using phone's camera) */
|
||||
|
||||
@Singleton
|
||||
public class EXIFReader {
|
||||
@Inject
|
||||
public EXIFReader() {
|
||||
//Empty
|
||||
}
|
||||
/**
|
||||
* The method takes in path of the image and reads metadata using the library metadata-extractor
|
||||
* And the checks for the presence of EXIF Directories in metadata object
|
||||
* */
|
||||
|
||||
public Single<Integer> processMetadata(String path) {
|
||||
Metadata readMetadata = null;
|
||||
try {
|
||||
readMetadata = ImageMetadataReader.readMetadata(new File(path));
|
||||
} catch (ImageProcessingException e) {
|
||||
Timber.d(e.toString());
|
||||
} catch (IOException e) {
|
||||
Timber.d(e.toString());
|
||||
}
|
||||
if (readMetadata != null) {
|
||||
for (Directory directory : readMetadata.getDirectories()) {
|
||||
// In case of internet downloaded image these three fields are not present
|
||||
if (directory.getName().equals("Exif IFD0") //Contains information about the device capturing the photo
|
||||
|| directory.getName().equals("Exif SubIFD") //contains information like date, time and pixels of the image
|
||||
|| directory.getName().equals("Exif Thumbnail")) //contains information about image thumbnail like compression and reolution
|
||||
{
|
||||
Timber.d(directory.getName() + " Contains metadata");
|
||||
return Single.just(ImageUtils.IMAGE_OK);
|
||||
}
|
||||
}
|
||||
}
|
||||
return Single.just(ImageUtils.FILE_NO_EXIF);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -34,17 +34,19 @@ public class ImageProcessingService {
|
|||
private final ImageUtilsWrapper imageUtilsWrapper;
|
||||
private final MediaWikiApi mwApi;
|
||||
private final ReadFBMD readFBMD;
|
||||
private final EXIFReader EXIFReader;
|
||||
|
||||
@Inject
|
||||
public ImageProcessingService(FileUtilsWrapper fileUtilsWrapper,
|
||||
BitmapRegionDecoderWrapper bitmapRegionDecoderWrapper,
|
||||
ImageUtilsWrapper imageUtilsWrapper,
|
||||
MediaWikiApi mwApi, ReadFBMD readFBMD) {
|
||||
MediaWikiApi mwApi, ReadFBMD readFBMD, EXIFReader EXIFReader) {
|
||||
this.fileUtilsWrapper = fileUtilsWrapper;
|
||||
this.bitmapRegionDecoderWrapper = bitmapRegionDecoderWrapper;
|
||||
this.imageUtilsWrapper = imageUtilsWrapper;
|
||||
this.mwApi = mwApi;
|
||||
this.readFBMD = readFBMD;
|
||||
this.EXIFReader = EXIFReader;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -69,17 +71,16 @@ public class ImageProcessingService {
|
|||
Single<Integer> darkImage = checkDarkImage(filePath);
|
||||
Single<Integer> itemTitle = checkTitle ? validateItemTitle(uploadItem) : Single.just(ImageUtils.IMAGE_OK);
|
||||
Single<Integer> checkFBMD = checkFBMD(context,contentUri);
|
||||
|
||||
Single<Integer> checkEXIF = checkEXIF(filePath);
|
||||
Single<Integer> zipResult = Single.zip(duplicateImage, wrongGeoLocation, darkImage, itemTitle,
|
||||
(duplicate, wrongGeo, dark, title) -> {
|
||||
Timber.d("Result for duplicate: %d, geo: %d, dark: %d, title: %d", duplicate, wrongGeo, dark, title);
|
||||
return duplicate | wrongGeo | dark | title;
|
||||
});
|
||||
|
||||
return Single.zip(zipResult, checkFBMD, (zip, fbmd) -> {
|
||||
Timber.d("zip:" + zip + "fbmd:" + fbmd);
|
||||
return zip | fbmd;
|
||||
});
|
||||
return Single.zip(zipResult, checkFBMD , checkEXIF , (zip , fbmd , exif)->{
|
||||
Timber.d("zip:" + zip + "fbmd:" + fbmd + "exif:" + exif);
|
||||
return zip | fbmd | exif;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -100,6 +101,17 @@ public class ImageProcessingService {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* To avoid copyright we check for EXIF data in any image.
|
||||
* Images that are downloaded from internet generally don't have any EXIF data in them
|
||||
* while images taken via camera or screenshots in phone have EXIF data with them.
|
||||
* So we check if the image has no EXIF data then we display a warning to the user
|
||||
* * */
|
||||
|
||||
public Single<Integer> checkEXIF(String filepath){
|
||||
return EXIFReader.processMetadata(filepath);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Checks item title
|
||||
|
|
|
|||
|
|
@ -55,7 +55,11 @@ public class ImageUtils {
|
|||
* ie. 10000
|
||||
*/
|
||||
public static final int FILE_FBMD = 1 << 4;
|
||||
|
||||
/**
|
||||
* The parameter FILE_NO_EXIF is returned from the class EXIFReader if the uploaded image does not contains EXIF data else returns IMAGE_OK
|
||||
* ie. 100000
|
||||
*/
|
||||
public static final int FILE_NO_EXIF = 1 << 5;
|
||||
public static final int IMAGE_OK = 0;
|
||||
public static final int IMAGE_KEEP = -1;
|
||||
public static final int IMAGE_WAIT = -2;
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@
|
|||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/listView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
android:layout_height="match_parent"/>
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
|
|
|
|||
|
|
@ -30,6 +30,8 @@ class u {
|
|||
internal var mwApi: MediaWikiApi? = null
|
||||
@Mock
|
||||
internal var readFBMD: ReadFBMD?=null
|
||||
@Mock
|
||||
internal var readEXIF: EXIFReader?=null
|
||||
|
||||
@InjectMocks
|
||||
var imageProcessingService: ImageProcessingService? = null
|
||||
|
|
@ -84,6 +86,8 @@ class u {
|
|||
.thenReturn(false)
|
||||
`when`(readFBMD?.processMetadata(ArgumentMatchers.any(),ArgumentMatchers.any()))
|
||||
.thenReturn(Single.just(ImageUtils.IMAGE_OK))
|
||||
`when`(readEXIF?.processMetadata(ArgumentMatchers.anyString()))
|
||||
.thenReturn(Single.just(ImageUtils.IMAGE_OK))
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue