From 0d9a6473aaa7a3dbec9acf8596c6ed227f97daec Mon Sep 17 00:00:00 2001 From: Cheshire <126002367+SSHAARVARI@users.noreply.github.com> Date: Sun, 11 Feb 2024 20:18:59 +0530 Subject: [PATCH 1/5] GIF feature added --- .../org/catrobat/paintroid/DrawingSurface.kt | 5 + .../java/org/catrobat/paintroid/FileIO.kt | 5 +- .../org/catrobat/paintroid/MainActivity.kt | 2 +- .../paintroid/PaintroidApplication.kt | 28 +++- .../contract/MainActivityContracts.kt | 1 + .../paintroid/dialog/AnimatedGifEncoder.kt | 151 ++++++++++++++++++ .../paintroid/dialog/SaveInformationDialog.kt | 94 ++++++++++- .../catrobat/paintroid/iotasks/SaveImage.kt | 2 +- .../catrobat/paintroid/ui/DrawingSurface.kt | 4 + .../res/layout/dialog_pocketpaint_save.xml | 17 ++ ...dialog_pocketpaint_save_gif_sub_dialog.xml | 23 +++ Paintroid/src/main/res/values/strings.xml | 4 + app/build.gradle | 1 + 13 files changed, 318 insertions(+), 19 deletions(-) create mode 100644 Paintroid/src/main/java/org/catrobat/paintroid/DrawingSurface.kt create mode 100644 Paintroid/src/main/java/org/catrobat/paintroid/dialog/AnimatedGifEncoder.kt create mode 100644 Paintroid/src/main/res/layout/dialog_pocketpaint_save_gif_sub_dialog.xml create mode 100644 Paintroid/src/main/res/values/strings.xml diff --git a/Paintroid/src/main/java/org/catrobat/paintroid/DrawingSurface.kt b/Paintroid/src/main/java/org/catrobat/paintroid/DrawingSurface.kt new file mode 100644 index 0000000000..6b2fb1b8c7 --- /dev/null +++ b/Paintroid/src/main/java/org/catrobat/paintroid/DrawingSurface.kt @@ -0,0 +1,5 @@ +package org.catrobat.paintroid + +class DrawingSurface { + +} diff --git a/Paintroid/src/main/java/org/catrobat/paintroid/FileIO.kt b/Paintroid/src/main/java/org/catrobat/paintroid/FileIO.kt index 864f069b0c..190981aa0d 100644 --- a/Paintroid/src/main/java/org/catrobat/paintroid/FileIO.kt +++ b/Paintroid/src/main/java/org/catrobat/paintroid/FileIO.kt @@ -104,7 +104,8 @@ object FileIO { PNG("png"), JPG("jpg"), ORA("ora"), - CATROBAT("catrobat-image"); + CATROBAT("catrobat-image"), + GIF("gif"); fun toExtension(): String = ".$value" } @@ -132,7 +133,7 @@ object FileIO { } @Throws(IOException::class) - fun saveBitmapToUri(uri: Uri, bitmap: Bitmap?, context: Context): Uri { + fun saveBitmapToUri(uri: Uri, bitmap: Bitmap?, context: Context): Uri { val uid = UUID.randomUUID() val cachedImageUri = saveBitmapToCache(bitmap, context as MainActivity, uid.toString()) var cachedFile: File? = null diff --git a/Paintroid/src/main/java/org/catrobat/paintroid/MainActivity.kt b/Paintroid/src/main/java/org/catrobat/paintroid/MainActivity.kt index e393a5d841..6c43f5089d 100644 --- a/Paintroid/src/main/java/org/catrobat/paintroid/MainActivity.kt +++ b/Paintroid/src/main/java/org/catrobat/paintroid/MainActivity.kt @@ -114,7 +114,7 @@ private const val MILLI_SEC_TO_SEC = 1000 private const val TEMP_IMAGE_SAVE_INTERVAL = 60 private const val TEMP_IMAGE_IDLE_INTERVAL = 2 * TEMP_IMAGE_COROUTINE_DELAY_MILLI_SEC -class MainActivity : AppCompatActivity(), MainView, CommandListener { +class zMainActivity : AppCompatActivity(), MainView, CommandListener { @VisibleForTesting lateinit var perspective: Perspective diff --git a/Paintroid/src/main/java/org/catrobat/paintroid/PaintroidApplication.kt b/Paintroid/src/main/java/org/catrobat/paintroid/PaintroidApplication.kt index b93795d6d6..cd9fec72c6 100644 --- a/Paintroid/src/main/java/org/catrobat/paintroid/PaintroidApplication.kt +++ b/Paintroid/src/main/java/org/catrobat/paintroid/PaintroidApplication.kt @@ -18,17 +18,31 @@ */ package org.catrobat.paintroid +import android.graphics.Bitmap +import org.catrobat.paintroid.ui.DrawingSurface import java.io.File import java.lang.IllegalArgumentException @SuppressWarnings("ThrowingExceptionsWithoutMessageOrCause") -class PaintroidApplication private constructor() { - companion object { - @JvmStatic - var cacheDir: File? = null - } +class PaintroidApplication() { + object DrawingSurface { + fun copyBitmap(): Bitmap { - init { - throw IllegalArgumentException() + return Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888) + } } } + + + + + +//@JvmStatic +// var cacheDir: File? = null +// } +// +// +// init { +// throw IllegalArgumentException() +// } +//} diff --git a/Paintroid/src/main/java/org/catrobat/paintroid/contract/MainActivityContracts.kt b/Paintroid/src/main/java/org/catrobat/paintroid/contract/MainActivityContracts.kt index 84fef55bab..517bb8a02b 100644 --- a/Paintroid/src/main/java/org/catrobat/paintroid/contract/MainActivityContracts.kt +++ b/Paintroid/src/main/java/org/catrobat/paintroid/contract/MainActivityContracts.kt @@ -308,6 +308,7 @@ interface MainActivityContracts { fun checkForTemporaryFile(): Boolean fun setColorHistoryAfterLoadImage(colorHistory: ColorHistory?) + fun showGifInformationDialog() } interface Model { diff --git a/Paintroid/src/main/java/org/catrobat/paintroid/dialog/AnimatedGifEncoder.kt b/Paintroid/src/main/java/org/catrobat/paintroid/dialog/AnimatedGifEncoder.kt new file mode 100644 index 0000000000..e144868b8d --- /dev/null +++ b/Paintroid/src/main/java/org/catrobat/paintroid/dialog/AnimatedGifEncoder.kt @@ -0,0 +1,151 @@ +package org.catrobat.paintroid.dialog + + + +import android.graphics.Bitmap +import android.graphics.Color +import java.io.BufferedOutputStream +import java.io.FileOutputStream +import java.io.IOException + +class AnimatedGifEncoder { + + private var width: Int = 0 + private var height: Int = 0 + private lateinit var indexedPixels: ByteArray + private var colorDepth: Int = 0 + private lateinit var colorTab: ByteArray + private lateinit var usedEntry: BooleanArray + private var palSize: Int = 0 + private var dispose: Int = -1 + private var closeStream: Boolean = false + private var firstFrame: Boolean = true + private var sample: Int = 10 + private var delay: Int = 0 + private lateinit var outputStream: FileOutputStream + private lateinit var bufferedOutputStream: BufferedOutputStream + private var transIndex: Int = 0 + private var started: Boolean = false + + fun start(fileOutputStream: FileOutputStream) { + if (!started) { + outputStream = fileOutputStream + bufferedOutputStream = BufferedOutputStream(outputStream) + writeString("GIF89a") // header + started = true + } + } + + fun setDelay(ms: Int) { + delay = Math.round(ms / 10.0f) + } + + fun addFrame(image: Bitmap) { + if (!started || image == null) return + + try { + if (!firstFrame) { + writeByte(0x21) // extension + writeByte(0xF9) // graphic control extension + writeByte(4) // length + writeByte((dispose shl 2) or 0x01) // packed fields + writeShort(delay) // delay x 1/100 sec + writeByte(transIndex) // transparent color index + writeByte(0) // block terminator + } + val transparent = -1 + val width = image.width + val height = image.height + if (width != this.width || height != this.height) { + throw IllegalArgumentException("Gif frame dimension mismatch") + } + val pixels = IntArray(width * height) + image.getPixels(pixels, 0, width, 0, 0, width, height) + if (firstFrame) { + indexedPixels = ByteArray(width * height) + usedEntry = BooleanArray(256) + var nPix = 0 + for (i in 0 until height) { + for (j in 0 until width) { + val idx = i * width + j + val c = pixels[idx] + val r = Color.red(c) + val g = Color.green(c) + val b = Color.blue(c) + if (r == 255 && g == 255 && b == 255) { + transIndex = idx + } + if (!usedEntry[c]) { + usedEntry[c] = true + nPix++ + } + indexedPixels[idx] = c.toByte() + } + } + palSize = nPix + colorDepth = (Math.log(palSize.toDouble()) / Math.log(2.0) + 0.5).toInt() + if (transIndex != -1) { + transIndex = findClosest(transIndex) + } + } + // Further processing logic for pixels and palette + // Write pixels to GIF + // Write palette to GIF + // Write extension blocks if not first frame + firstFrame = false + } catch (e: IOException) { + e.printStackTrace() + } + } + + fun finish() { + if (!started) return + + try { + bufferedOutputStream.write(0x3b) // gif trailer + bufferedOutputStream.flush() + if (closeStream) { + bufferedOutputStream.close() + } + outputStream.close() + } catch (e: IOException) { + e.printStackTrace() + } + started = false + } + + private fun writeByte(value: Int) { + bufferedOutputStream.write(value) + } + + private fun writeShort(value: Int) { + bufferedOutputStream.write(value and 0xff) + bufferedOutputStream.write((value shr 8) and 0xff) + } + + private fun writeString(string: String) { + for (i in 0 until string.length) { + bufferedOutputStream.write(string[i].toInt()) + } + } + + private fun findClosest(color: Int): Int { + var minpos = 0 + var dmin = 256 * 256 * 256 + val len = colorTab.size + for (i in 0 until len step 3) { + val dr = Color.red(color) - (colorTab[i].toInt() and 0xff) + val dg = Color.green(color) - (colorTab[i + 1].toInt() and 0xff) + val db = Color.blue(color) - (colorTab[i + 2].toInt() and 0xff) + val d = dr * dr + dg * dg + db * db + val index = i / 3 + if (usedEntry[index] && d < dmin) { + dmin = d + minpos = index + } + } + return minpos + + } +} + diff --git a/Paintroid/src/main/java/org/catrobat/paintroid/dialog/SaveInformationDialog.kt b/Paintroid/src/main/java/org/catrobat/paintroid/dialog/SaveInformationDialog.kt index b58f914105..4760991449 100644 --- a/Paintroid/src/main/java/org/catrobat/paintroid/dialog/SaveInformationDialog.kt +++ b/Paintroid/src/main/java/org/catrobat/paintroid/dialog/SaveInformationDialog.kt @@ -22,6 +22,7 @@ import android.annotation.SuppressLint import android.app.Dialog import android.graphics.Bitmap import android.os.Bundle +import android.os.Environment import android.view.LayoutInflater import android.view.View import android.view.ViewGroup @@ -36,18 +37,35 @@ import androidx.appcompat.widget.AppCompatEditText import androidx.appcompat.widget.AppCompatImageButton import androidx.appcompat.widget.AppCompatTextView import org.catrobat.paintroid.FileIO -import org.catrobat.paintroid.FileIO.FileType + import org.catrobat.paintroid.FileIO.FileType.PNG import org.catrobat.paintroid.FileIO.FileType.JPG import org.catrobat.paintroid.FileIO.FileType.CATROBAT import org.catrobat.paintroid.FileIO.FileType.ORA +import org.catrobat.paintroid.FileIO.FileType +import org.catrobat.paintroid.PaintroidApplication import org.catrobat.paintroid.R import java.util.Locale +import org.catrobat.paintroid.dialog.FileType +import java.io.File +import java.io.FileOutputStream +import java.io.IOException + + + +//import com.example.library.AnimatedGifEncoder + + private const val STANDARD_FILE_NAME = "image" private const val SET_NAME = "setName" private const val PERMISSION = "permission" private const val IS_EXPORT = "isExport" +private lateinit var gifView: View +private lateinit var delaySeekBar: SeekBar +private lateinit var delayTextView: AppCompatTextView + + class SaveInformationDialog : MainActivityDialogFragment(), @@ -57,6 +75,7 @@ class SaveInformationDialog : private lateinit var inflater: LayoutInflater private lateinit var specificFormatLayout: ViewGroup private lateinit var jpgView: View + private lateinit var delaySeekBar: SeekBar private lateinit var percentage: AppCompatTextView private lateinit var imageName: AppCompatEditText private lateinit var fileName: String @@ -73,7 +92,7 @@ class SaveInformationDialog : if (isStandard) { FileIO.filename = STANDARD_FILE_NAME FileIO.compressFormat = Bitmap.CompressFormat.PNG - FileIO.fileType = PNG + FileIO.fileType = FileType.PNG } return SaveInformationDialog().apply { arguments = Bundle().apply { @@ -114,12 +133,15 @@ class SaveInformationDialog : .setTitle(R.string.dialog_save_image_title) .setView(customLayout) .setPositiveButton(R.string.save_button_text) { _, _ -> - FileIO.filename = imageName.text.toString() - FileIO.storeImageUri = null - if (FileIO.checkFileExists(FileIO.fileType, FileIO.defaultFileName, requireContext().contentResolver)) { - presenter.showOverwriteDialog(permission, isExport) + val selectedFileType = spinner.selectedItem.toString().toLowerCase(Locale.getDefault()) + if (selectedFileType == "gif") { + val delay = delaySeekBar.progress + val gifFileName = imageName.text.toString() + ".gif" + val gifFilePath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).absolutePath + File.separator + gifFileName + val bitmap = PaintroidApplication.DrawingSurface.copyBitmap() + saveBitmapAsGif(bitmap, gifFilePath, delay) } else { - presenter.switchBetweenVersions(permission, isExport) + // Handle other file formats } dismiss() } @@ -127,8 +149,30 @@ class SaveInformationDialog : .create() } + private fun saveBitmapAsGif(bitmap: Bitmap, filePath: String, delay: Int) { + val outputStream: FileOutputStream + try { + outputStream = FileOutputStream(filePath) + + val encoder = AnimatedGifEncoder() + encoder.start(outputStream) + encoder.setDelay(delay * 10) + encoder.addFrame(bitmap) + encoder.finish() + outputStream.close() + + } catch (e: IOException) { + e.printStackTrace() + + } + } + private fun initViews(customLayout: View) { initSpecificFormatLayout(customLayout) + initGifView() + initDelaySeekBar() + initDelayTextView() + initJpgView() initSeekBar() initPercentage() @@ -141,6 +185,26 @@ class SaveInformationDialog : specificFormatLayout = view.findViewById(R.id.pocketpaint_save_format_specific_options) } + private fun initGifView() { + gifView = inflater.inflate(R.layout.dialog_pocketpaint_save_gif_sub_dialog, specificFormatLayout, false) + } + + private fun initDelaySeekBar() { + delaySeekBar = gifView.findViewById(R.id.pocketpaint_gif_delay_seekbar_save_info) + delaySeekBar.setOnSeekBarChangeListener(this) + } + + private fun initDelayTextView() { + delayTextView = gifView.findViewById(R.id.pocketpaint_gif_delay_text) + updateDelayTextView(delaySeekBar.progress) + } + + @SuppressLint("StringFormatInvalid") + private fun updateDelayTextView(delay: Int) { + val delayText = getString(R.string.gif_delay_text, delay) + delayTextView.text = delayText + } + private fun initJpgView() { jpgView = inflater.inflate( R.layout.dialog_pocketpaint_save_jpg_sub_dialog, @@ -168,16 +232,19 @@ class SaveInformationDialog : JPG -> presenter.showJpgInformationDialog() ORA -> presenter.showOraInformationDialog() CATROBAT -> presenter.showCatrobatInformationDialog() + FileType.GIF -> presenter.showGifInformationDialog() else -> presenter.showPngInformationDialog() } } } + + private fun initSpinner(view: View) { spinner = view.findViewById(R.id.pocketpaint_save_dialog_spinner) val spinnerArray = FileType.values().map { it.value } val adapter = ArrayAdapter(spinner.context, android.R.layout.simple_spinner_item, spinnerArray) - adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) + adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) //xml file spinner.adapter = adapter spinner.onItemSelectedListener = this } @@ -204,6 +271,7 @@ class SaveInformationDialog : JPG -> spinner.setSelection(JPG.ordinal) ORA -> spinner.setSelection(ORA.ordinal) CATROBAT -> spinner.setSelection(CATROBAT.ordinal) + FileType.GIF -> spinner.setSelection(FileType.GIF.ordinal) else -> spinner.setSelection(PNG.ordinal) } } @@ -212,8 +280,10 @@ class SaveInformationDialog : when (parent?.getItemAtPosition(position).toString().toLowerCase(Locale.getDefault())) { JPG.value -> setFileDetails(Bitmap.CompressFormat.JPEG, JPG) PNG.value -> setFileDetails(Bitmap.CompressFormat.PNG, PNG) + ORA.value -> setFileDetails(Bitmap.CompressFormat.PNG, ORA) CATROBAT.value -> setFileDetails(Bitmap.CompressFormat.PNG, CATROBAT) + FileType.GIF.value-> setFileDetails(Bitmap.CompressFormat.PNG, FileType.GIF) } } @@ -226,3 +296,11 @@ class SaveInformationDialog : override fun onStartTrackingTouch(seekBar: SeekBar) = Unit override fun onStopTrackingTouch(seekBar: SeekBar) = Unit } + +object FileIO { + var filename: String = "" + var compressFormat: Bitmap.CompressFormat = Bitmap.CompressFormat.PNG + var fileType: FileType = FileType.PNG + var compressQuality: Int = 100 +} + diff --git a/Paintroid/src/main/java/org/catrobat/paintroid/iotasks/SaveImage.kt b/Paintroid/src/main/java/org/catrobat/paintroid/iotasks/SaveImage.kt index 70de33a490..324b04c794 100644 --- a/Paintroid/src/main/java/org/catrobat/paintroid/iotasks/SaveImage.kt +++ b/Paintroid/src/main/java/org/catrobat/paintroid/iotasks/SaveImage.kt @@ -60,7 +60,7 @@ class SaveImage( val imageUri = FileIO.saveBitmapToFile(filename, bitmap, callback.contentResolver, context) imageUri } else { - uri?.let { FileIO.saveBitmapToUri(it, bitmap, context) } + uri?.let { FileIO.saveBitmapToUri(it, bitmap, context) } } } diff --git a/Paintroid/src/main/java/org/catrobat/paintroid/ui/DrawingSurface.kt b/Paintroid/src/main/java/org/catrobat/paintroid/ui/DrawingSurface.kt index 3a0eaecf3a..ae8512a08d 100644 --- a/Paintroid/src/main/java/org/catrobat/paintroid/ui/DrawingSurface.kt +++ b/Paintroid/src/main/java/org/catrobat/paintroid/ui/DrawingSurface.kt @@ -244,6 +244,10 @@ open class DrawingSurface : SurfaceView, SurfaceHolder.Callback { drawingThread?.stop() } + fun copyBitmap() { + + } + private inner class DrawLoop : Runnable { val holder: SurfaceHolder = getHolder() override fun run() { diff --git a/Paintroid/src/main/res/layout/dialog_pocketpaint_save.xml b/Paintroid/src/main/res/layout/dialog_pocketpaint_save.xml index 3cb7da04bf..f4d85ca548 100644 --- a/Paintroid/src/main/res/layout/dialog_pocketpaint_save.xml +++ b/Paintroid/src/main/res/layout/dialog_pocketpaint_save.xml @@ -98,4 +98,21 @@ android:clipChildren="false" android:clipToPadding="false" /> + + + + + + + + diff --git a/Paintroid/src/main/res/layout/dialog_pocketpaint_save_gif_sub_dialog.xml b/Paintroid/src/main/res/layout/dialog_pocketpaint_save_gif_sub_dialog.xml new file mode 100644 index 0000000000..1c85a6521f --- /dev/null +++ b/Paintroid/src/main/res/layout/dialog_pocketpaint_save_gif_sub_dialog.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + diff --git a/Paintroid/src/main/res/values/strings.xml b/Paintroid/src/main/res/values/strings.xml new file mode 100644 index 0000000000..4eda354fb5 --- /dev/null +++ b/Paintroid/src/main/res/values/strings.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 2c7e76738b..b5ab9e4716 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -102,4 +102,5 @@ dependencies { implementation project(':Paintroid') implementation 'com.android.support:support-core-utils:28.0.0' + implementation 'com.example:library:1.0.0' } From bd2a34b7f291f22b5e87355495d106985f5f47d5 Mon Sep 17 00:00:00 2001 From: Cheshire <126002367+SSHAARVARI@users.noreply.github.com> Date: Fri, 16 Feb 2024 15:05:03 +0530 Subject: [PATCH 2/5] GIF : bug fix --- .../paintroid/dialog/AnimatedGifEncoder.kt | 14 +++++++------- .../paintroid/dialog/SaveInformationDialog.kt | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Paintroid/src/main/java/org/catrobat/paintroid/dialog/AnimatedGifEncoder.kt b/Paintroid/src/main/java/org/catrobat/paintroid/dialog/AnimatedGifEncoder.kt index e144868b8d..d4592b7589 100644 --- a/Paintroid/src/main/java/org/catrobat/paintroid/dialog/AnimatedGifEncoder.kt +++ b/Paintroid/src/main/java/org/catrobat/paintroid/dialog/AnimatedGifEncoder.kt @@ -45,13 +45,13 @@ class AnimatedGifEncoder { try { if (!firstFrame) { - writeByte(0x21) // extension - writeByte(0xF9) // graphic control extension - writeByte(4) // length - writeByte((dispose shl 2) or 0x01) // packed fields - writeShort(delay) // delay x 1/100 sec - writeByte(transIndex) // transparent color index - writeByte(0) // block terminator + writeByte(0x21) + writeByte(0xF9) + writeByte(4) + writeByte((dispose shl 2) or 0x01) + writeShort(delay) + writeByte(transIndex) + writeByte(0) } val transparent = -1 val width = image.width diff --git a/Paintroid/src/main/java/org/catrobat/paintroid/dialog/SaveInformationDialog.kt b/Paintroid/src/main/java/org/catrobat/paintroid/dialog/SaveInformationDialog.kt index 4760991449..0a77463762 100644 --- a/Paintroid/src/main/java/org/catrobat/paintroid/dialog/SaveInformationDialog.kt +++ b/Paintroid/src/main/java/org/catrobat/paintroid/dialog/SaveInformationDialog.kt @@ -46,14 +46,14 @@ import org.catrobat.paintroid.FileIO.FileType import org.catrobat.paintroid.PaintroidApplication import org.catrobat.paintroid.R import java.util.Locale -import org.catrobat.paintroid.dialog.FileType + import java.io.File import java.io.FileOutputStream import java.io.IOException -//import com.example.library.AnimatedGifEncoder + From 9eed4340b1793b78f57632a5c24c01f1af8454f6 Mon Sep 17 00:00:00 2001 From: Cheshire <126002367+SSHAARVARI@users.noreply.github.com> Date: Wed, 21 Feb 2024 11:47:12 +0530 Subject: [PATCH 3/5] Added more shapes to tools --- .../org/catrobat/paintroid/DrawingSurface.kt | 5 -- .../paintroid/dialog/AnimatedGifEncoder.kt | 2 +- .../tools/drawable/DrawableFactory.kt | 3 ++ .../paintroid/tools/drawable/DrawableShape.kt | 2 +- .../tools/drawable/HexagonDrawable.kt | 31 ++++++++++++ .../tools/drawable/PentagonDrawable.kt | 33 +++++++++++++ .../tools/drawable/TriangleDrawable.kt | 22 +++++++++ .../ui/tools/DefaultShapeToolOptionsView.kt | 47 ++++++++++++++++++- .../res/drawable/ic_pocketpaint_hexagon.xml | 10 ++++ .../drawable/ic_pocketpaint_hexagon_out.xml | 11 +++++ .../res/drawable/ic_pocketpaint_pentagon.xml | 10 ++++ .../drawable/ic_pocketpaint_pentagon_out.xml | 13 +++++ .../res/drawable/ic_pocketpaint_triangle.xml | 10 ++++ .../drawable/ic_pocketpaint_triangle_out.xml | 13 +++++ .../res/layout/dialog_pocketpaint_shapes.xml | 27 +++++++++++ Paintroid/src/main/res/values/string.xml | 3 ++ Paintroid/src/main/res/values/strings.xml | 6 ++- 17 files changed, 239 insertions(+), 9 deletions(-) delete mode 100644 Paintroid/src/main/java/org/catrobat/paintroid/DrawingSurface.kt create mode 100644 Paintroid/src/main/java/org/catrobat/paintroid/tools/drawable/HexagonDrawable.kt create mode 100644 Paintroid/src/main/java/org/catrobat/paintroid/tools/drawable/PentagonDrawable.kt create mode 100644 Paintroid/src/main/java/org/catrobat/paintroid/tools/drawable/TriangleDrawable.kt create mode 100644 Paintroid/src/main/res/drawable/ic_pocketpaint_hexagon.xml create mode 100644 Paintroid/src/main/res/drawable/ic_pocketpaint_hexagon_out.xml create mode 100644 Paintroid/src/main/res/drawable/ic_pocketpaint_pentagon.xml create mode 100644 Paintroid/src/main/res/drawable/ic_pocketpaint_pentagon_out.xml create mode 100644 Paintroid/src/main/res/drawable/ic_pocketpaint_triangle.xml create mode 100644 Paintroid/src/main/res/drawable/ic_pocketpaint_triangle_out.xml diff --git a/Paintroid/src/main/java/org/catrobat/paintroid/DrawingSurface.kt b/Paintroid/src/main/java/org/catrobat/paintroid/DrawingSurface.kt deleted file mode 100644 index 6b2fb1b8c7..0000000000 --- a/Paintroid/src/main/java/org/catrobat/paintroid/DrawingSurface.kt +++ /dev/null @@ -1,5 +0,0 @@ -package org.catrobat.paintroid - -class DrawingSurface { - -} diff --git a/Paintroid/src/main/java/org/catrobat/paintroid/dialog/AnimatedGifEncoder.kt b/Paintroid/src/main/java/org/catrobat/paintroid/dialog/AnimatedGifEncoder.kt index d4592b7589..44dc4c96bb 100644 --- a/Paintroid/src/main/java/org/catrobat/paintroid/dialog/AnimatedGifEncoder.kt +++ b/Paintroid/src/main/java/org/catrobat/paintroid/dialog/AnimatedGifEncoder.kt @@ -8,7 +8,7 @@ import java.io.BufferedOutputStream import java.io.FileOutputStream import java.io.IOException -class AnimatedGifEncoder { +class AnimatedGifEncoder { private var width: Int = 0 private var height: Int = 0 diff --git a/Paintroid/src/main/java/org/catrobat/paintroid/tools/drawable/DrawableFactory.kt b/Paintroid/src/main/java/org/catrobat/paintroid/tools/drawable/DrawableFactory.kt index 0658b7e59d..ca32287827 100644 --- a/Paintroid/src/main/java/org/catrobat/paintroid/tools/drawable/DrawableFactory.kt +++ b/Paintroid/src/main/java/org/catrobat/paintroid/tools/drawable/DrawableFactory.kt @@ -25,6 +25,9 @@ class DrawableFactory { DrawableShape.OVAL -> OvalDrawable() DrawableShape.HEART -> HeartDrawable() DrawableShape.STAR -> StarDrawable() + DrawableShape.PENTAGON -> PentagonDrawable() + DrawableShape.TRIANGLE -> TriangleDrawable() + DrawableShape.HEXAGON -> HexagonDrawable() } } } diff --git a/Paintroid/src/main/java/org/catrobat/paintroid/tools/drawable/DrawableShape.kt b/Paintroid/src/main/java/org/catrobat/paintroid/tools/drawable/DrawableShape.kt index cc76fae877..30eed1cb17 100644 --- a/Paintroid/src/main/java/org/catrobat/paintroid/tools/drawable/DrawableShape.kt +++ b/Paintroid/src/main/java/org/catrobat/paintroid/tools/drawable/DrawableShape.kt @@ -19,5 +19,5 @@ package org.catrobat.paintroid.tools.drawable enum class DrawableShape { - RECTANGLE, OVAL, HEART, STAR + RECTANGLE, OVAL, HEART, STAR , PENTAGON, TRIANGLE, HEXAGON } diff --git a/Paintroid/src/main/java/org/catrobat/paintroid/tools/drawable/HexagonDrawable.kt b/Paintroid/src/main/java/org/catrobat/paintroid/tools/drawable/HexagonDrawable.kt new file mode 100644 index 0000000000..f48574fb96 --- /dev/null +++ b/Paintroid/src/main/java/org/catrobat/paintroid/tools/drawable/HexagonDrawable.kt @@ -0,0 +1,31 @@ +package org.catrobat.paintroid.tools.drawable +import android.graphics.Canvas +import android.graphics.Paint +import android.graphics.Path +import android.graphics.RectF + +private const val CONSTANT_1 = 2f +private const val CONSTANT_2 = 1.7f +class HexagonDrawable:ShapeDrawable { + private val path = Path() + override fun draw(canvas: Canvas, shapeRect: RectF, drawPaint: Paint) { + val midWidth = shapeRect.width() / 2 + val midHeight = shapeRect.height() / 2 + val height = shapeRect.height() / CONSTANT_2 + val width = shapeRect.width() / CONSTANT_1 + path.run { + reset() + moveTo(midWidth - width, midHeight) + lineTo(midWidth - width/2, midHeight - height) + lineTo(midWidth + width/2, midHeight - height) + lineTo(midWidth + width, midHeight) + lineTo(midWidth + width/2, midHeight + height) + lineTo(midWidth - width/2, midHeight + height) + lineTo(midWidth - width, midHeight) + close() + offset(shapeRect.left, shapeRect.top) + } + canvas.drawPath(path, drawPaint) + } +} + diff --git a/Paintroid/src/main/java/org/catrobat/paintroid/tools/drawable/PentagonDrawable.kt b/Paintroid/src/main/java/org/catrobat/paintroid/tools/drawable/PentagonDrawable.kt new file mode 100644 index 0000000000..3da3ce9fcb --- /dev/null +++ b/Paintroid/src/main/java/org/catrobat/paintroid/tools/drawable/PentagonDrawable.kt @@ -0,0 +1,33 @@ +package org.catrobat.paintroid.tools.drawable + +import android.graphics.Canvas +import android.graphics.Paint +import android.graphics.Path +import android.graphics.RectF + +private const val CONSTANT_1 = 0.95f +private const val CONSTANT_2 = 0.31f +private const val CONSTANT_3 = 0.59f +class PentagonDrawable : ShapeDrawable{ + + private val path = Path() + + override fun draw(canvas: Canvas, shapeRect: RectF, drawPaint: Paint) { + val midWidth = shapeRect.width() / 2 + val midHeight = shapeRect.height() / 2 + val height = shapeRect.height() + val width = shapeRect.width() + path.run { + reset() + moveTo(midWidth, 0f) + lineTo(midWidth + CONSTANT_1 * width / 2, CONSTANT_2 * height) + lineTo(midWidth + CONSTANT_3 * width / 2, height) + lineTo(midWidth - CONSTANT_3 * width / 2, height) + lineTo(midWidth - CONSTANT_1 * width / 2, CONSTANT_2 * height) + lineTo(midWidth, 0f) + close() + offset(shapeRect.left, shapeRect.top) + } + canvas.drawPath(path, drawPaint) + } +} \ No newline at end of file diff --git a/Paintroid/src/main/java/org/catrobat/paintroid/tools/drawable/TriangleDrawable.kt b/Paintroid/src/main/java/org/catrobat/paintroid/tools/drawable/TriangleDrawable.kt new file mode 100644 index 0000000000..b5346bb1ea --- /dev/null +++ b/Paintroid/src/main/java/org/catrobat/paintroid/tools/drawable/TriangleDrawable.kt @@ -0,0 +1,22 @@ +package org.catrobat.paintroid.tools.drawable + +import android.graphics.Canvas +import android.graphics.Paint +import android.graphics.Path +import android.graphics.RectF +class TriangleDrawable :ShapeDrawable{ + private val path = Path() + + override fun draw(canvas: Canvas, shapeRect: RectF, drawPaint: Paint) { + path.run { + reset() + moveTo(shapeRect.left, shapeRect.bottom) + lineTo(shapeRect.right, shapeRect.bottom) + lineTo(shapeRect.centerX(), shapeRect.top) + lineTo(shapeRect.left, shapeRect.bottom) + close() + } + canvas.drawPath(path, drawPaint) + } + +} \ No newline at end of file diff --git a/Paintroid/src/main/java/org/catrobat/paintroid/ui/tools/DefaultShapeToolOptionsView.kt b/Paintroid/src/main/java/org/catrobat/paintroid/ui/tools/DefaultShapeToolOptionsView.kt index 44f78af782..097e12f197 100644 --- a/Paintroid/src/main/java/org/catrobat/paintroid/ui/tools/DefaultShapeToolOptionsView.kt +++ b/Paintroid/src/main/java/org/catrobat/paintroid/ui/tools/DefaultShapeToolOptionsView.kt @@ -57,6 +57,9 @@ class DefaultShapeToolOptionsView(rootView: ViewGroup) : ShapeToolOptionsView { private val outlineWidthEditText: AppCompatEditText private val shapeToolDialogTitle: AppCompatTextView private val shapeToolFillOutline: AppCompatTextView + private val triangleButton: AppCompatImageButton + private val pentagonButton: AppCompatImageButton + private val hexagonButton: AppCompatImageButton init { val inflater = LayoutInflater.from(rootView.context) @@ -74,6 +77,9 @@ class DefaultShapeToolOptionsView(rootView: ViewGroup) : ShapeToolOptionsView { outlineTextView = findViewById(R.id.pocketpaint_outline_view_text_view) outlineWidthSeekBar = findViewById(R.id.pocketpaint_shape_stroke_width_seek_bar) outlineWidthEditText = findViewById(R.id.pocketpaint_shape_outline_edit) + triangleButton = findViewById(R.id.pocketpaint_shapes_triangle_btn) + pentagonButton = findViewById(R.id.pocketpaint_shapes_pentagon_btn) + hexagonButton = findViewById(R.id.pocketpaint_shapes_hexagon_btn) } outlineWidthEditText.filters = arrayOf(DefaultNumberRangeFilter(MIN_VAL, MAX_VAL)) @@ -89,6 +95,10 @@ class DefaultShapeToolOptionsView(rootView: ViewGroup) : ShapeToolOptionsView { circleButton.setOnClickListener { onShapeClicked(DrawableShape.OVAL) } heartButton.setOnClickListener { onShapeClicked(DrawableShape.HEART) } starButton.setOnClickListener { onShapeClicked(DrawableShape.STAR) } + triangleButton.setOnClickListener { onShapeClicked(DrawableShape.TRIANGLE) } + pentagonButton.setOnClickListener { onShapeClicked(DrawableShape.PENTAGON) } + hexagonButton.setOnClickListener { onShapeClicked(DrawableShape.HEXAGON) } + fillButton.setOnClickListener { onDrawTypeClicked(DrawableStyle.FILL) } outlineButton.setOnClickListener { onDrawTypeClicked(DrawableStyle.STROKE) } outlineWidthSeekBar.setOnSeekBarChangeListener(object : OnSeekBarChangeListener { @@ -141,7 +151,16 @@ class DefaultShapeToolOptionsView(rootView: ViewGroup) : ShapeToolOptionsView { } private fun resetShapeActivated() { - val buttons = arrayOf(squareButton, circleButton, heartButton, starButton) + //val buttons = arrayOf(squareButton, circleButton, heartButton, starButton,) + val buttons = arrayOf( + squareButton, + circleButton, + heartButton, + starButton, + triangleButton, + pentagonButton, + hexagonButton + ) for (button in buttons) { button.isSelected = false } @@ -175,6 +194,18 @@ class DefaultShapeToolOptionsView(rootView: ViewGroup) : ShapeToolOptionsView { starButton.isSelected = true setShapeToolDialogTitle(R.string.shape_tool_dialog_star_title) } + DrawableShape.TRIANGLE -> { + triangleButton.isSelected = true + setShapeToolDialogTitle(R.string.shape_tool_dialog_triangle_title) + } + DrawableShape.PENTAGON -> { + pentagonButton.isSelected = true + setShapeToolDialogTitle(R.string.shape_tool_dialog_pentagon_title) + } + DrawableShape.HEXAGON -> { + hexagonButton.isSelected = true + setShapeToolDialogTitle(R.string.shape_tool_dialog_hexagon_title) + } } } @@ -184,6 +215,10 @@ class DefaultShapeToolOptionsView(rootView: ViewGroup) : ShapeToolOptionsView { circleButtonResource: Int, heartButtonResource: Int, starButtonResource: Int, + triangleButtonResource: Int, + pentagonButtonResource: Int, + hexagonButtonResource: Int, + visibility: Int ) { shapeToolFillOutline.setText(fillTitle) @@ -191,6 +226,10 @@ class DefaultShapeToolOptionsView(rootView: ViewGroup) : ShapeToolOptionsView { circleButton.setImageResource(circleButtonResource) heartButton.setImageResource(heartButtonResource) starButton.setImageResource(starButtonResource) + triangleButton.setImageResource(triangleButtonResource) + pentagonButton.setImageResource(pentagonButtonResource) + hexagonButton.setImageResource(hexagonButtonResource) + outlineWidthSeekBar.visibility = visibility outlineWidthEditText.visibility = visibility outlineView.visibility = visibility @@ -208,6 +247,9 @@ class DefaultShapeToolOptionsView(rootView: ViewGroup) : ShapeToolOptionsView { R.drawable.ic_pocketpaint_circle, R.drawable.ic_pocketpaint_heart, R.drawable.ic_pocketpaint_star, + R.drawable.ic_pocketpaint_triangle, + R.drawable.ic_pocketpaint_pentagon, + R.drawable.ic_pocketpaint_hexagon, View.GONE ) } @@ -219,6 +261,9 @@ class DefaultShapeToolOptionsView(rootView: ViewGroup) : ShapeToolOptionsView { R.drawable.ic_pocketpaint_circle_out, R.drawable.ic_pocketpaint_heart_out, R.drawable.ic_pocketpaint_star_out, + R.drawable.ic_pocketpaint_triangle_out, + R.drawable.ic_pocketpaint_pentagon_out, + R.drawable.ic_pocketpaint_hexagon_out, View.VISIBLE ) } diff --git a/Paintroid/src/main/res/drawable/ic_pocketpaint_hexagon.xml b/Paintroid/src/main/res/drawable/ic_pocketpaint_hexagon.xml new file mode 100644 index 0000000000..1d44f876f2 --- /dev/null +++ b/Paintroid/src/main/res/drawable/ic_pocketpaint_hexagon.xml @@ -0,0 +1,10 @@ + + + + \ No newline at end of file diff --git a/Paintroid/src/main/res/drawable/ic_pocketpaint_hexagon_out.xml b/Paintroid/src/main/res/drawable/ic_pocketpaint_hexagon_out.xml new file mode 100644 index 0000000000..8751339730 --- /dev/null +++ b/Paintroid/src/main/res/drawable/ic_pocketpaint_hexagon_out.xml @@ -0,0 +1,11 @@ + + + + \ No newline at end of file diff --git a/Paintroid/src/main/res/drawable/ic_pocketpaint_pentagon.xml b/Paintroid/src/main/res/drawable/ic_pocketpaint_pentagon.xml new file mode 100644 index 0000000000..cad4566cb4 --- /dev/null +++ b/Paintroid/src/main/res/drawable/ic_pocketpaint_pentagon.xml @@ -0,0 +1,10 @@ + + + + \ No newline at end of file diff --git a/Paintroid/src/main/res/drawable/ic_pocketpaint_pentagon_out.xml b/Paintroid/src/main/res/drawable/ic_pocketpaint_pentagon_out.xml new file mode 100644 index 0000000000..3ce29057b6 --- /dev/null +++ b/Paintroid/src/main/res/drawable/ic_pocketpaint_pentagon_out.xml @@ -0,0 +1,13 @@ + + + + \ No newline at end of file diff --git a/Paintroid/src/main/res/drawable/ic_pocketpaint_triangle.xml b/Paintroid/src/main/res/drawable/ic_pocketpaint_triangle.xml new file mode 100644 index 0000000000..425c02b54e --- /dev/null +++ b/Paintroid/src/main/res/drawable/ic_pocketpaint_triangle.xml @@ -0,0 +1,10 @@ + + + + \ No newline at end of file diff --git a/Paintroid/src/main/res/drawable/ic_pocketpaint_triangle_out.xml b/Paintroid/src/main/res/drawable/ic_pocketpaint_triangle_out.xml new file mode 100644 index 0000000000..2b197abfc2 --- /dev/null +++ b/Paintroid/src/main/res/drawable/ic_pocketpaint_triangle_out.xml @@ -0,0 +1,13 @@ + + + + \ No newline at end of file diff --git a/Paintroid/src/main/res/layout/dialog_pocketpaint_shapes.xml b/Paintroid/src/main/res/layout/dialog_pocketpaint_shapes.xml index 53849476ed..a0fc963140 100644 --- a/Paintroid/src/main/res/layout/dialog_pocketpaint_shapes.xml +++ b/Paintroid/src/main/res/layout/dialog_pocketpaint_shapes.xml @@ -139,6 +139,33 @@ android:layout_weight="1" android:contentDescription="@string/shape_tool_dialog_star_title" android:src="@drawable/ic_pocketpaint_star" /> + + + + + + diff --git a/Paintroid/src/main/res/values/string.xml b/Paintroid/src/main/res/values/string.xml index de2ea72fb6..2ec01f42de 100644 --- a/Paintroid/src/main/res/values/string.xml +++ b/Paintroid/src/main/res/values/string.xml @@ -128,6 +128,9 @@ Ellipse Star Heart + Triangle + Pentagon + Hexagon Fill Outline diff --git a/Paintroid/src/main/res/values/strings.xml b/Paintroid/src/main/res/values/strings.xml index 4eda354fb5..9d4b18e6b9 100644 --- a/Paintroid/src/main/res/values/strings.xml +++ b/Paintroid/src/main/res/values/strings.xml @@ -1,4 +1,8 @@ - + + + + + \ No newline at end of file From a4409410d0d3f4881f50b959b04502feff6f0c1b Mon Sep 17 00:00:00 2001 From: Cheshire <126002367+SSHAARVARI@users.noreply.github.com> Date: Wed, 21 Feb 2024 12:15:08 +0530 Subject: [PATCH 4/5] new shapes --- Paintroid/src/main/java/org/catrobat/paintroid/MainActivity.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Paintroid/src/main/java/org/catrobat/paintroid/MainActivity.kt b/Paintroid/src/main/java/org/catrobat/paintroid/MainActivity.kt index 6c43f5089d..e393a5d841 100644 --- a/Paintroid/src/main/java/org/catrobat/paintroid/MainActivity.kt +++ b/Paintroid/src/main/java/org/catrobat/paintroid/MainActivity.kt @@ -114,7 +114,7 @@ private const val MILLI_SEC_TO_SEC = 1000 private const val TEMP_IMAGE_SAVE_INTERVAL = 60 private const val TEMP_IMAGE_IDLE_INTERVAL = 2 * TEMP_IMAGE_COROUTINE_DELAY_MILLI_SEC -class zMainActivity : AppCompatActivity(), MainView, CommandListener { +class MainActivity : AppCompatActivity(), MainView, CommandListener { @VisibleForTesting lateinit var perspective: Perspective From 5d21d215bcfae199a3398555cdb45946f4f829b8 Mon Sep 17 00:00:00 2001 From: Cheshire <126002367+SSHAARVARI@users.noreply.github.com> Date: Sun, 3 Mar 2024 14:58:16 +0530 Subject: [PATCH 5/5] branch modification --- .../java/org/catrobat/paintroid/FileIO.kt | 4 +- .../paintroid/PaintroidApplication.kt | 23 ++- .../contract/MainActivityContracts.kt | 2 +- .../paintroid/dialog/AnimatedGifEncoder.kt | 151 ------------------ .../paintroid/dialog/SaveInformationDialog.kt | 79 +++------ .../catrobat/paintroid/iotasks/SaveImage.kt | 2 +- app/build.gradle | 2 +- 7 files changed, 32 insertions(+), 231 deletions(-) delete mode 100644 Paintroid/src/main/java/org/catrobat/paintroid/dialog/AnimatedGifEncoder.kt diff --git a/Paintroid/src/main/java/org/catrobat/paintroid/FileIO.kt b/Paintroid/src/main/java/org/catrobat/paintroid/FileIO.kt index 190981aa0d..045be32caf 100644 --- a/Paintroid/src/main/java/org/catrobat/paintroid/FileIO.kt +++ b/Paintroid/src/main/java/org/catrobat/paintroid/FileIO.kt @@ -105,7 +105,7 @@ object FileIO { JPG("jpg"), ORA("ora"), CATROBAT("catrobat-image"), - GIF("gif"); + fun toExtension(): String = ".$value" } @@ -133,7 +133,7 @@ object FileIO { } @Throws(IOException::class) - fun saveBitmapToUri(uri: Uri, bitmap: Bitmap?, context: Context): Uri { + fun saveBitmapToUri(uri: Uri, bitmap: Bitmap?, context: Context): Uri { val uid = UUID.randomUUID() val cachedImageUri = saveBitmapToCache(bitmap, context as MainActivity, uid.toString()) var cachedFile: File? = null diff --git a/Paintroid/src/main/java/org/catrobat/paintroid/PaintroidApplication.kt b/Paintroid/src/main/java/org/catrobat/paintroid/PaintroidApplication.kt index cd9fec72c6..f697af06a8 100644 --- a/Paintroid/src/main/java/org/catrobat/paintroid/PaintroidApplication.kt +++ b/Paintroid/src/main/java/org/catrobat/paintroid/PaintroidApplication.kt @@ -18,17 +18,20 @@ */ package org.catrobat.paintroid + import android.graphics.Bitmap -import org.catrobat.paintroid.ui.DrawingSurface import java.io.File import java.lang.IllegalArgumentException + @SuppressWarnings("ThrowingExceptionsWithoutMessageOrCause") -class PaintroidApplication() { - object DrawingSurface { - fun copyBitmap(): Bitmap { +class PaintroidApplication private constructor() { + companion object { + @JvmStatic + var cacheDir: File? = null - return Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888) + init { + throw IllegalArgumentException() } } } @@ -37,12 +40,4 @@ class PaintroidApplication() { -//@JvmStatic -// var cacheDir: File? = null -// } -// -// -// init { -// throw IllegalArgumentException() -// } -//} + diff --git a/Paintroid/src/main/java/org/catrobat/paintroid/contract/MainActivityContracts.kt b/Paintroid/src/main/java/org/catrobat/paintroid/contract/MainActivityContracts.kt index 517bb8a02b..cec5631c1b 100644 --- a/Paintroid/src/main/java/org/catrobat/paintroid/contract/MainActivityContracts.kt +++ b/Paintroid/src/main/java/org/catrobat/paintroid/contract/MainActivityContracts.kt @@ -308,7 +308,7 @@ interface MainActivityContracts { fun checkForTemporaryFile(): Boolean fun setColorHistoryAfterLoadImage(colorHistory: ColorHistory?) - fun showGifInformationDialog() + } interface Model { diff --git a/Paintroid/src/main/java/org/catrobat/paintroid/dialog/AnimatedGifEncoder.kt b/Paintroid/src/main/java/org/catrobat/paintroid/dialog/AnimatedGifEncoder.kt deleted file mode 100644 index 44dc4c96bb..0000000000 --- a/Paintroid/src/main/java/org/catrobat/paintroid/dialog/AnimatedGifEncoder.kt +++ /dev/null @@ -1,151 +0,0 @@ -package org.catrobat.paintroid.dialog - - - -import android.graphics.Bitmap -import android.graphics.Color -import java.io.BufferedOutputStream -import java.io.FileOutputStream -import java.io.IOException - -class AnimatedGifEncoder { - - private var width: Int = 0 - private var height: Int = 0 - private lateinit var indexedPixels: ByteArray - private var colorDepth: Int = 0 - private lateinit var colorTab: ByteArray - private lateinit var usedEntry: BooleanArray - private var palSize: Int = 0 - private var dispose: Int = -1 - private var closeStream: Boolean = false - private var firstFrame: Boolean = true - private var sample: Int = 10 - private var delay: Int = 0 - private lateinit var outputStream: FileOutputStream - private lateinit var bufferedOutputStream: BufferedOutputStream - private var transIndex: Int = 0 - private var started: Boolean = false - - fun start(fileOutputStream: FileOutputStream) { - if (!started) { - outputStream = fileOutputStream - bufferedOutputStream = BufferedOutputStream(outputStream) - writeString("GIF89a") // header - started = true - } - } - - fun setDelay(ms: Int) { - delay = Math.round(ms / 10.0f) - } - - fun addFrame(image: Bitmap) { - if (!started || image == null) return - - try { - if (!firstFrame) { - writeByte(0x21) - writeByte(0xF9) - writeByte(4) - writeByte((dispose shl 2) or 0x01) - writeShort(delay) - writeByte(transIndex) - writeByte(0) - } - val transparent = -1 - val width = image.width - val height = image.height - if (width != this.width || height != this.height) { - throw IllegalArgumentException("Gif frame dimension mismatch") - } - val pixels = IntArray(width * height) - image.getPixels(pixels, 0, width, 0, 0, width, height) - if (firstFrame) { - indexedPixels = ByteArray(width * height) - usedEntry = BooleanArray(256) - var nPix = 0 - for (i in 0 until height) { - for (j in 0 until width) { - val idx = i * width + j - val c = pixels[idx] - val r = Color.red(c) - val g = Color.green(c) - val b = Color.blue(c) - if (r == 255 && g == 255 && b == 255) { - transIndex = idx - } - if (!usedEntry[c]) { - usedEntry[c] = true - nPix++ - } - indexedPixels[idx] = c.toByte() - } - } - palSize = nPix - colorDepth = (Math.log(palSize.toDouble()) / Math.log(2.0) + 0.5).toInt() - if (transIndex != -1) { - transIndex = findClosest(transIndex) - } - } - // Further processing logic for pixels and palette - // Write pixels to GIF - // Write palette to GIF - // Write extension blocks if not first frame - firstFrame = false - } catch (e: IOException) { - e.printStackTrace() - } - } - - fun finish() { - if (!started) return - - try { - bufferedOutputStream.write(0x3b) // gif trailer - bufferedOutputStream.flush() - if (closeStream) { - bufferedOutputStream.close() - } - outputStream.close() - } catch (e: IOException) { - e.printStackTrace() - } - started = false - } - - private fun writeByte(value: Int) { - bufferedOutputStream.write(value) - } - - private fun writeShort(value: Int) { - bufferedOutputStream.write(value and 0xff) - bufferedOutputStream.write((value shr 8) and 0xff) - } - - private fun writeString(string: String) { - for (i in 0 until string.length) { - bufferedOutputStream.write(string[i].toInt()) - } - } - - private fun findClosest(color: Int): Int { - var minpos = 0 - var dmin = 256 * 256 * 256 - val len = colorTab.size - for (i in 0 until len step 3) { - val dr = Color.red(color) - (colorTab[i].toInt() and 0xff) - val dg = Color.green(color) - (colorTab[i + 1].toInt() and 0xff) - val db = Color.blue(color) - (colorTab[i + 2].toInt() and 0xff) - val d = dr * dr + dg * dg + db * db - val index = i / 3 - if (usedEntry[index] && d < dmin) { - dmin = d - minpos = index - } - } - return minpos - - } -} - diff --git a/Paintroid/src/main/java/org/catrobat/paintroid/dialog/SaveInformationDialog.kt b/Paintroid/src/main/java/org/catrobat/paintroid/dialog/SaveInformationDialog.kt index 0a77463762..389680786d 100644 --- a/Paintroid/src/main/java/org/catrobat/paintroid/dialog/SaveInformationDialog.kt +++ b/Paintroid/src/main/java/org/catrobat/paintroid/dialog/SaveInformationDialog.kt @@ -37,19 +37,20 @@ import androidx.appcompat.widget.AppCompatEditText import androidx.appcompat.widget.AppCompatImageButton import androidx.appcompat.widget.AppCompatTextView import org.catrobat.paintroid.FileIO - +import org.catrobat.paintroid.FileIO.FileType import org.catrobat.paintroid.FileIO.FileType.PNG import org.catrobat.paintroid.FileIO.FileType.JPG import org.catrobat.paintroid.FileIO.FileType.CATROBAT import org.catrobat.paintroid.FileIO.FileType.ORA -import org.catrobat.paintroid.FileIO.FileType import org.catrobat.paintroid.PaintroidApplication -import org.catrobat.paintroid.R -import java.util.Locale + +import org.catrobat.paintroid.R import java.io.File import java.io.FileOutputStream import java.io.IOException +import java.util.Locale + @@ -61,9 +62,7 @@ private const val STANDARD_FILE_NAME = "image" private const val SET_NAME = "setName" private const val PERMISSION = "permission" private const val IS_EXPORT = "isExport" -private lateinit var gifView: View -private lateinit var delaySeekBar: SeekBar -private lateinit var delayTextView: AppCompatTextView + @@ -75,7 +74,6 @@ class SaveInformationDialog : private lateinit var inflater: LayoutInflater private lateinit var specificFormatLayout: ViewGroup private lateinit var jpgView: View - private lateinit var delaySeekBar: SeekBar private lateinit var percentage: AppCompatTextView private lateinit var imageName: AppCompatEditText private lateinit var fileName: String @@ -92,7 +90,7 @@ class SaveInformationDialog : if (isStandard) { FileIO.filename = STANDARD_FILE_NAME FileIO.compressFormat = Bitmap.CompressFormat.PNG - FileIO.fileType = FileType.PNG + FileIO.fileType = PNG } return SaveInformationDialog().apply { arguments = Bundle().apply { @@ -133,15 +131,13 @@ class SaveInformationDialog : .setTitle(R.string.dialog_save_image_title) .setView(customLayout) .setPositiveButton(R.string.save_button_text) { _, _ -> - val selectedFileType = spinner.selectedItem.toString().toLowerCase(Locale.getDefault()) - if (selectedFileType == "gif") { - val delay = delaySeekBar.progress - val gifFileName = imageName.text.toString() + ".gif" - val gifFilePath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).absolutePath + File.separator + gifFileName - val bitmap = PaintroidApplication.DrawingSurface.copyBitmap() - saveBitmapAsGif(bitmap, gifFilePath, delay) + FileIO.filename = imageName.text.toString() + FileIO.storeImageUri = null + if (FileIO.checkFileExists(FileIO.fileType, FileIO.defaultFileName, requireContext().contentResolver)) { + presenter.showOverwriteDialog(permission, isExport) + } else { - // Handle other file formats + presenter.switchBetweenVersions(permission, isExport) } dismiss() } @@ -149,29 +145,11 @@ class SaveInformationDialog : .create() } - private fun saveBitmapAsGif(bitmap: Bitmap, filePath: String, delay: Int) { - val outputStream: FileOutputStream - try { - outputStream = FileOutputStream(filePath) - - val encoder = AnimatedGifEncoder() - encoder.start(outputStream) - encoder.setDelay(delay * 10) - encoder.addFrame(bitmap) - encoder.finish() - outputStream.close() - } catch (e: IOException) { - e.printStackTrace() - - } - } private fun initViews(customLayout: View) { initSpecificFormatLayout(customLayout) - initGifView() - initDelaySeekBar() - initDelayTextView() + initJpgView() initSeekBar() @@ -185,25 +163,9 @@ class SaveInformationDialog : specificFormatLayout = view.findViewById(R.id.pocketpaint_save_format_specific_options) } - private fun initGifView() { - gifView = inflater.inflate(R.layout.dialog_pocketpaint_save_gif_sub_dialog, specificFormatLayout, false) - } - private fun initDelaySeekBar() { - delaySeekBar = gifView.findViewById(R.id.pocketpaint_gif_delay_seekbar_save_info) - delaySeekBar.setOnSeekBarChangeListener(this) - } - private fun initDelayTextView() { - delayTextView = gifView.findViewById(R.id.pocketpaint_gif_delay_text) - updateDelayTextView(delaySeekBar.progress) - } - @SuppressLint("StringFormatInvalid") - private fun updateDelayTextView(delay: Int) { - val delayText = getString(R.string.gif_delay_text, delay) - delayTextView.text = delayText - } private fun initJpgView() { jpgView = inflater.inflate( @@ -244,7 +206,7 @@ class SaveInformationDialog : spinner = view.findViewById(R.id.pocketpaint_save_dialog_spinner) val spinnerArray = FileType.values().map { it.value } val adapter = ArrayAdapter(spinner.context, android.R.layout.simple_spinner_item, spinnerArray) - adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) //xml file + adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) spinner.adapter = adapter spinner.onItemSelectedListener = this } @@ -271,7 +233,7 @@ class SaveInformationDialog : JPG -> spinner.setSelection(JPG.ordinal) ORA -> spinner.setSelection(ORA.ordinal) CATROBAT -> spinner.setSelection(CATROBAT.ordinal) - FileType.GIF -> spinner.setSelection(FileType.GIF.ordinal) + else -> spinner.setSelection(PNG.ordinal) } } @@ -283,7 +245,7 @@ class SaveInformationDialog : ORA.value -> setFileDetails(Bitmap.CompressFormat.PNG, ORA) CATROBAT.value -> setFileDetails(Bitmap.CompressFormat.PNG, CATROBAT) - FileType.GIF.value-> setFileDetails(Bitmap.CompressFormat.PNG, FileType.GIF) + } } @@ -297,10 +259,5 @@ class SaveInformationDialog : override fun onStopTrackingTouch(seekBar: SeekBar) = Unit } -object FileIO { - var filename: String = "" - var compressFormat: Bitmap.CompressFormat = Bitmap.CompressFormat.PNG - var fileType: FileType = FileType.PNG - var compressQuality: Int = 100 -} + diff --git a/Paintroid/src/main/java/org/catrobat/paintroid/iotasks/SaveImage.kt b/Paintroid/src/main/java/org/catrobat/paintroid/iotasks/SaveImage.kt index 324b04c794..70de33a490 100644 --- a/Paintroid/src/main/java/org/catrobat/paintroid/iotasks/SaveImage.kt +++ b/Paintroid/src/main/java/org/catrobat/paintroid/iotasks/SaveImage.kt @@ -60,7 +60,7 @@ class SaveImage( val imageUri = FileIO.saveBitmapToFile(filename, bitmap, callback.contentResolver, context) imageUri } else { - uri?.let { FileIO.saveBitmapToUri(it, bitmap, context) } + uri?.let { FileIO.saveBitmapToUri(it, bitmap, context) } } } diff --git a/app/build.gradle b/app/build.gradle index b5ab9e4716..dd08cd86b9 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -102,5 +102,5 @@ dependencies { implementation project(':Paintroid') implementation 'com.android.support:support-core-utils:28.0.0' - implementation 'com.example:library:1.0.0' + }