Skip to content
Commits on Source (30)
*.iml
.gradle
/local.properties
/.idea/caches
/.idea/libraries
/.idea/modules.xml
/.idea/workspace.xml
/.idea/navEditor.xml
/.idea/assetWizardSettings.xml
.DS_Store
/build
/captures
.externalNativeBuild
.cxx
local.properties
# Default ignored files
/shelf/
/workspace.xml
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<bytecodeTargetLevel target="11" />
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="testRunner" value="GRADLE" />
<option name="distributionType" value="DEFAULT_WRAPPED" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/app" />
</set>
</option>
</GradleProjectSettings>
</option>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="Android Studio default JDK" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">
<option name="id" value="Android" />
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>
\ No newline at end of file
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
/**
* AcceptFile class that reads a text file and identifies whether it is in the
* following format:
* 1) First two lines must contain exactly one integer (representing width & length)
* 2) There must be width * height more lines after
* 3) Each of these lines must have exactly 3 integers with values within 0 to 100 inclusive
* @param String fileName
* @return error messages if criterias are not met
*/
public class AcceptFile {
public static void main(String[] args) {
String fileName = "wrongInput.txt"; // Replace with the name of text file to check
// BufferedReader is used to parse through text file line by line
try (BufferedReader br = new BufferedReader(new FileReader(fileName))) {
// Read and check the first two lines to get the width and height
String line = br.readLine();
int width = Integer.parseInt(line.trim());
line = br.readLine();
int height = Integer.parseInt(line.trim());
if (width <= 0 || height <= 0) {
System.out.println("Error: width and height must be positive integers.");
return;
}
// Check that there are width * height more lines in the file
int expectedNumLines = width * height;
int currentNumLines = 0; // Counter to keep track number of lines
while ((line = br.readLine()) != null) {
currentNumLines++;
}
if (expectedNumLines != currentNumLines) {
System.out.println("Error: Expected " + expectedNumLines + " lines, but found " + currentNumLines + " lines.");
return;
}
// Check that each of the following lines has exactly 3 integers between 0 and 100
for (int i = 0; i < 2 + expectedNumLines; i++) { // We skip the first two lines
br.readLine();
}
while ((line = br.readLine()) != null) {
String[] tokens = line.split("\\s+");
if (tokens.length != 3) {
System.out.println("Error: Line \"" + line + "\" does not contain exactly 3 integers.");
return;
}
for (String token : tokens) {
int value = Integer.parseInt(token);
if (value < 0 || value > 100) {
System.out.println("Error: Value " + value + " is not between 0 and 100.");
return;
}
}
}
br.close();
// When text file meets all the requirements
System.out.println("The file \"" + fileName + "\" meets all the requirements.");
} catch (IOException e) {
System.out.println("Error reading file \"" + fileName + "\": " + e.getMessage());
} catch (NumberFormatException e) {
System.out.println("Error parsing integer \"" + "\": " + e.getMessage());
}
}
}
# Default ignored files
/shelf/
/workspace.xml
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/ImageFiltererProject.iml" filepath="$PROJECT_DIR$/.idea/ImageFiltererProject.iml" />
</modules>
</component>
</project>
\ No newline at end of file
# Group6Project # Group6DEMO
Instructions:
1) Go to Foswiki and click on link. This will lead you to ‘Group6demo’ project.
2) Clone master branch and open it in android studio
- Allow build.gradle to complete and configure the device to be Pixel 2A API 30 (Create Device > Pixel 2 > R)
Files to take note of:
- badImage.txt = sample of wrong input to test the Toast feature
- goodImage.txt = sample of correct input
- blur.jpg = sample image to test for blur
3) To include the previous mentioned files into the emulator:
Select “upload text”
4) Drag the desired image (in .txt format) onto the emulator
5) Go to “Download” and click on the file to display it on screen
...@@ -15,14 +29,14 @@ Already a pro? Just edit this README.md and make it your own. Want to make it ea ...@@ -15,14 +29,14 @@ Already a pro? Just edit this README.md and make it your own. Want to make it ea
``` ```
cd existing_repo cd existing_repo
git remote add origin https://agile.bu.edu/gitlab/ec327_projects/group6project.git git remote add origin https://agile.bu.edu/gitlab/eburhan/group6demo.git
git branch -M master git branch -M master
git push -uf origin master git push -uf origin master
``` ```
## Integrate with your tools ## Integrate with your tools
- [ ] [Set up project integrations](https://agile.bu.edu/gitlab/ec327_projects/group6project/-/settings/integrations) - [ ] [Set up project integrations](https://agile.bu.edu/gitlab/eburhan/group6demo/-/settings/integrations)
## Collaborate with your team ## Collaborate with your team
......
/build
\ No newline at end of file
plugins {
id 'com.android.application'
}
android {
namespace 'com.example.imagefilterer'
compileSdk 33
defaultConfig {
applicationId "com.example.imagefilterer"
minSdk 24
targetSdk 33
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
dependencies {
implementation 'androidx.appcompat:appcompat:1.4.1'
implementation 'com.google.android.material:material:1.5.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
implementation 'com.squareup.retrofit2:retrofit:2.3.0'
implementation 'com.squareup.retrofit2:converter-gson:2.1.0'
}
\ No newline at end of file
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
\ No newline at end of file
package com.example.imagefilterer;
import android.content.Context;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.*;
/**
* Instrumented test, which will execute on an Android device.
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
@Test
public void useAppContext() {
// Context of the app under test.
Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
assertEquals("com.example.imagefilterer", appContext.getPackageName());
}
}
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/Theme.ImageFilterer"
tools:targetApi="31">
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
package com.example.imagefilterer;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Context;
import android.graphics.Bitmap;
import android.provider.MediaStore;
import android.view.ViewGroup;
import android.widget.Button;
import android.os.Bundle;
import android.view.View;
import android.content.Intent;
import android.net.Uri;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Scanner;
import android.app.Activity;
import android.graphics.Color;
import android.util.Log;
import android.widget.ImageView;
import android.widget.Toast;
import java.io.IOException;
import java.util.Scanner;
import android.widget.EditText;
import android.widget.TextView;
// Addition by Ian Lee
import android.graphics.drawable.BitmapDrawable;
import android.graphics.Color;
public class MainActivity extends AppCompatActivity{
// When declaring the components we want to specify the type
// from xml file and the corresponding string.
//Component Tree:
//BUTTONS
private Button uploadimage;
private Button uploadtext;
private Button zeroGB;
private Button resize;
private Button rotate;
private Button blur;
private Button grayscale;
//IMAGE VIEW
private Button histogram;
private ImageView dispimage;
//TEXT VIEW
private TextView angle;
private TextView edit_height;
private TextView edit_width;
private static final int PICK_FILE_REQUEST_CODE = 1;
private static final int READ_REQUEST_CODE = 42;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
uploadimage = (Button) findViewById(R.id.uploadimage);
uploadtext = (Button) findViewById(R.id.uploadtext);
resize = (Button) findViewById(R.id.resize);
rotate = (Button) findViewById(R.id.rotate);
dispimage = (ImageView) findViewById(R.id.dispimage);
blur = (Button) findViewById(R.id.imageblur);
zeroGB = (Button) findViewById(R.id.zeroGB);
angle = (EditText) findViewById(R.id.angle);
grayscale = (Button) findViewById(R.id.grayscale);
edit_height = (EditText) findViewById(R.id.edit_height);
edit_width = (EditText) findViewById(R.id.edit_width);
histogram = (Button) findViewById(R.id.histogram);
//histogramView = (ImageView) findViewById(R.id.histogramView);
uploadimage.setOnClickListener(new View.OnClickListener() {
// Logic that enables the user to click the Upload Image button to access the device storage
@Override
public void onClick(View v) {
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("*/*"); //set MIME type to filter files
startActivityForResult(Intent.createChooser(intent, "Select File"), PICK_FILE_REQUEST_CODE);
}
});
resize.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//openDialog();
int newWidth = Integer.parseInt(edit_width.getText().toString());
int newHeight = Integer.parseInt(edit_height.getText().toString());
// Get the current dimensions of the image
int currentWidth = dispimage.getWidth();
int currentHeight = dispimage.getHeight();
// Create a new bitmap with the desired dimensions
Bitmap bitmap = ((BitmapDrawable) dispimage.getDrawable()).getBitmap();
Bitmap resizedBitmap = Bitmap.createScaledBitmap(bitmap, newWidth, newHeight, true);
// Update the ImageView with the resized bitmap
dispimage.setImageBitmap(resizedBitmap);
// Adjust the layout parameters of the ImageView to match the new dimensions
ViewGroup.LayoutParams params = dispimage.getLayoutParams();
params.width = newWidth;
params.height = newHeight;
dispimage.setLayoutParams(params);
}
});
uploadtext.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// Start file picker activity
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
intent.setType("*/*");
startActivityForResult(intent, READ_REQUEST_CODE);
}
});
rotate.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (angle.getText().toString().isEmpty()) {
// Display a toast message
Toast.makeText(MainActivity.this, "Field cannot be empty!!", Toast.LENGTH_SHORT).show();
} else {
// Set the rotation of the image view
float mAngleRotate = Float.parseFloat(angle.getText().toString());
dispimage.setRotation(mAngleRotate);
}
}
});
zeroGB.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// Zero out the green and blue components of an image
Bitmap originalBitmap = ((BitmapDrawable) dispimage.getDrawable()).getBitmap();
int width = originalBitmap.getWidth();
int height = originalBitmap.getHeight();
Bitmap recolorBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
int[] pixels = new int[width * height];
originalBitmap.getPixels(pixels, 0, width, 0, 0, width, height);
for (int i = 0; i < pixels.length; i++) {
int red = Color.red(pixels[i]);
int recolorPixel = Color.rgb(red, 0, 0);
pixels[i] = recolorPixel;
}
recolorBitmap.setPixels(pixels, 0, width, 0, 0, width, height);
dispimage.setImageBitmap(recolorBitmap);
}
});
blur.setOnClickListener(new View.OnClickListener() {
// Image blur algorithm
@Override
public void onClick(View v) {
Bitmap originalBitmap = ((BitmapDrawable) dispimage.getDrawable()).getBitmap();
int width = originalBitmap.getWidth();
int height = originalBitmap.getHeight();
Bitmap blurredBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
int[] pixels = new int[width * height];
int[] blurredPixels = new int[width * height];
originalBitmap.getPixels(pixels, 0, width, 0, 0, width, height);
// For each pixel in the image, calculate the average color value of its neighbors
for (int row = 0; row < height; row++) {
for (int col = 0; col < width; col++) {
int rTotal = 0, gTotal = 0, bTotal = 0, count = 0;
for (int rowOffset = -1; rowOffset <= 1; rowOffset++) {
int neighborRow = row + rowOffset;
if (neighborRow < 0 || neighborRow >= height) {
continue;
}
for (int colOffset = -1; colOffset <= 1; colOffset++) {
int neighborCol = col + colOffset;
if (neighborCol < 0 || neighborCol >= width) {
continue;
}
int neighborPixelIndex = neighborRow * width + neighborCol;
int neighborPixel = pixels[neighborPixelIndex];
int r = Color.red(neighborPixel);
int g = Color.green(neighborPixel);
int b = Color.blue(neighborPixel);
rTotal += r;
gTotal += g;
bTotal += b;
count++;
}
}
int pixelIndex = row * width + col;
int pixel = pixels[pixelIndex];
int r = Color.red(pixel);
int g = Color.green(pixel);
int b = Color.blue(pixel);
int newR = (rTotal + r) / (count + 1);
int newG = (gTotal + g) / (count + 1);
int newB = (bTotal + b) / (count + 1);
blurredPixels[pixelIndex] = Color.rgb(newR, newG, newB);
}
}
blurredBitmap.setPixels(blurredPixels, 0, width, 0, 0, width, height);
dispimage.setImageBitmap(blurredBitmap);
}
});
grayscale.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Bitmap originalBitmap = ((BitmapDrawable) dispimage.getDrawable()).getBitmap();
Bitmap grayscaleBitmap = Bitmap.createBitmap(originalBitmap.getWidth(), originalBitmap.getHeight(), Bitmap.Config.ARGB_8888);
for (int x = 0; x < originalBitmap.getWidth(); x++) {
for (int y = 0; y < originalBitmap.getHeight(); y++) {
int pixel = originalBitmap.getPixel(x, y);
int red = Color.red(pixel);
int green = Color.green(pixel);
int blue = Color.blue(pixel);
// Calculate the average of the RGB values to get the grayscale value}
int gray = (red + green + blue) / 3;
grayscaleBitmap.setPixel(x, y, Color.rgb(gray, gray, gray));
}
}
dispimage.setImageBitmap(grayscaleBitmap);
}
});
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
// Logic that displays the user uploaded image onto the ImageView template
if (requestCode == PICK_FILE_REQUEST_CODE && resultCode == RESULT_OK) {
Uri uri = data.getData();
try {
Bitmap bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), uri);
dispimage.setImageBitmap(bitmap);
} catch (IOException e) {
e.printStackTrace();
}
} else if (requestCode == READ_REQUEST_CODE && resultCode == RESULT_OK) {
Uri uri = null;
int count = 0;
if (data != null) {
uri = data.getData();
Log.i("TAG", "Uri: " + uri.toString());
}
if (uri != null) {
try {
InputStream inputStream = getContentResolver().openInputStream(uri);
BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
String line = br.readLine();
try {
int width = Integer.parseInt(line.trim());
int height = Integer.parseInt(br.readLine().trim());
br.mark(1000);
if (width <= 0 || height <= 0) {
count += 1; // one error
}
int expectedNumLines = width * height;
int currentNumLines = 0;
while ((line = br.readLine()) != null) {
currentNumLines += 1;
}
if (expectedNumLines != currentNumLines) {
count += 1; //one error
}
br.reset();
while ((line = br.readLine()) != null) {
String[] tokens = line.split("\\s+");
if (tokens.length != 3) {
count += 1; //one error
}
for (String token : tokens) {
int value = Integer.parseInt(token);
if (value < 0 || value > 100) {
count += 1; // one error
}
}
}
} catch (NumberFormatException e) {
Toast.makeText(MainActivity.this, "Wrong file format", Toast.LENGTH_SHORT).show();
return;
}
br.close();
inputStream.close();
} catch (IOException e) {
Log.e("MainActivity", "Unable to read file", e);
}
}
if (count == 0) {
try {
// read the image data from the file
Scanner scanner = new Scanner(getContentResolver().openInputStream(uri));
// read the dimensions of the image
int width = scanner.nextInt();
int height = scanner.nextInt();
// create a Bitmap to store the pixel data
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
// read in the pixel data
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
int r = scanner.nextInt() * 255 / 100;
int g = scanner.nextInt() * 255 / 100;
int b = scanner.nextInt() * 255 / 100;
int rgb = Color.rgb(r, g, b);
bitmap.setPixel(x, y, rgb);
}
}
ImageView dispimage = findViewById(R.id.dispimage);
dispimage.setImageBitmap(bitmap);
} catch (IOException e) {
Log.e("TAG", "Error reading file", e);
}
} else {
}
}
}
}
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
<aapt:attr name="android:fillColor">
<gradient
android:endX="85.84757"
android:endY="92.4963"
android:startX="42.9492"
android:startY="49.59793"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0" />
<item
android:color="#00000000"
android:offset="1.0" />
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#FFFFFF"
android:fillType="nonZero"
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
android:strokeWidth="1"
android:strokeColor="#00000000" />
</vector>
\ No newline at end of file