Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PrintPhotoUseCase #41

Open
2 tasks
fetiu opened this issue Sep 27, 2024 · 4 comments
Open
2 tasks

PrintPhotoUseCase #41

fetiu opened this issue Sep 27, 2024 · 4 comments
Assignees
Labels
feature/external feature-external New Implementation New feature
Milestone

Comments

@fetiu
Copy link
Member

fetiu commented Sep 27, 2024

[Description]
(#30 에서 분리됨)

  • 인화지 특성에 맞춰 프레임 디자인 조정 및 프린터 출력 테스트
  • 출력 결과물에 같이네컷 로고 경계가 다소 번지는 현상 해결
    • 프린터 설정에서 검정 잉크 유량 조정 가능한지 확인 (e.g. flow rate)
    • 안된다면, 프레임 색상을 밝거나 옅은 색으로 조정하는 것도 고려하기 (e.g. 바탕 흰색 + 민트색 로고 or 민트색 바탕 + 흰색로고)
image
@fetiu fetiu added New Implementation New feature feature/external feature-external labels Sep 27, 2024
@fetiu fetiu added this to the Phase 2 milestone Sep 27, 2024
@ing03201
Copy link
Member

ing03201 commented Oct 4, 2024

@OptIn(ExperimentalPermissionsApi::class)
@Preview
@Composable
fun BitmapFromComposableFullSnippet() {
    val context = LocalContext.current
    val coroutineScope = rememberCoroutineScope()
    val snackbarHostState = remember { SnackbarHostState() }
    val graphicsLayer = rememberGraphicsLayer()

    val writeStorageAccessState = rememberMultiplePermissionsState(
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            // No permissions are needed on Android 10+ to add files in the shared storage
            emptyList()
        } else {
            listOf(Manifest.permission.WRITE_EXTERNAL_STORAGE)
        }
    )

    // This logic should live in your ViewModel - trigger a side effect to invoke URI sharing.
    // checks permissions granted, and then saves the bitmap from a Picture that is already capturing content
    // and shares it with the default share sheet.
    fun shareBitmapFromComposable() {
        if (writeStorageAccessState.allPermissionsGranted) {
            coroutineScope.launch {
                val bitmap = graphicsLayer.toImageBitmap()
                val uri = bitmap.asAndroidBitmap().saveToDisk(context)
                shareBitmap(context, uri)
            }
        } else if (writeStorageAccessState.shouldShowRationale) {
            coroutineScope.launch {
                val result = snackbarHostState.showSnackbar(
                    message = "The storage permission is needed to save the image",
                    actionLabel = "Grant Access"
                )

                if (result == SnackbarResult.ActionPerformed) {
                    writeStorageAccessState.launchMultiplePermissionRequest()
                }
            }
        } else {
            writeStorageAccessState.launchMultiplePermissionRequest()
        }
    }

    Scaffold(
        snackbarHost = { SnackbarHost(snackbarHostState) },
        floatingActionButton = {
            FloatingActionButton(onClick = {
                shareBitmapFromComposable()
            }) {
                Icon(Icons.Default.Share, "share")
            }
        }
    ) { padding ->
        Column(
            modifier = Modifier
                .padding(padding)
                .fillMaxSize()
                .drawWithCache {
                    onDrawWithContent {
                        graphicsLayer.record {
                            this@onDrawWithContent.drawContent()
                        }
                        drawLayer(graphicsLayer)
                    }
                }

        ) {
            ScreenContentToCapture()
        }
    }
}

@Composable
private fun ScreenContentToCapture() {
    Column(
        horizontalAlignment = Alignment.CenterHorizontally,
        verticalArrangement = Arrangement.Center,
        modifier = Modifier
            .fillMaxSize()
            .background(
                Brush.linearGradient(
                    listOf(
                        Color(0xFFF5D5C0),
                        Color(0xFFF8E8E3)
                    )
                )
            )
    ) {
        Image(
            painterResource(id = R.drawable.sunset),
            contentDescription = null,
            modifier = Modifier
                .aspectRatio(1f)
                .padding(32.dp),
            contentScale = ContentScale.Crop
        )
        Text(
            "Into the Ocean depths",
            fontSize = 18.sp
        )
    }
}

private suspend fun Bitmap.saveToDisk(context: Context): Uri {
    val file = File(
        Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),
        "screenshot-${System.currentTimeMillis()}.png"
    )

    file.writeBitmap(this, Bitmap.CompressFormat.PNG, 100)

    return scanFilePath(context, file.path) ?: throw Exception("File could not be saved")
}

/**
 * We call [MediaScannerConnection] to index the newly created image inside MediaStore to be visible
 * for other apps, as well as returning its [MediaStore] Uri
 */
private suspend fun scanFilePath(context: Context, filePath: String): Uri? {
    return suspendCancellableCoroutine { continuation ->
        MediaScannerConnection.scanFile(
            context,
            arrayOf(filePath),
            arrayOf("image/png")
        ) { _, scannedUri ->
            if (scannedUri == null) {
                continuation.cancel(Exception("File $filePath could not be scanned"))
            } else {
                continuation.resume(scannedUri)
            }
        }
    }
}

private fun File.writeBitmap(bitmap: Bitmap, format: Bitmap.CompressFormat, quality: Int) {
    outputStream().use { out ->
        bitmap.compress(format, quality, out)
        out.flush()
    }
}

private fun shareBitmap(context: Context, uri: Uri) {
    val intent = Intent(Intent.ACTION_SEND).apply {
        type = "image/png"
        putExtra(Intent.EXTRA_STREAM, uri)
        addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
    }
    startActivity(context, createChooser(intent, "Share your image"), null)
}

@ing03201
Copy link
Member

ing03201 commented Oct 7, 2024

androidx print 하는 함수

private void doPhotoPrint() {
    PrintHelper photoPrinter = new PrintHelper(this);//can use getActivity() here

    photoPrinter.setScaleMode(PrintHelper.SCALE_MODE_FIT);

    Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.logontig);

    photoPrinter.printBitmap("myLogo.jpg", bitmap);
}

@ing03201 ing03201 changed the title 프레임 출력 품질 개선 PrintPhotoUseCase Oct 7, 2024
@ing03201 ing03201 closed this as completed Oct 8, 2024
@FoKE-Developers FoKE-Developers deleted a comment from ing03201 Oct 10, 2024
@DokySp DokySp modified the milestones: Phase 2, Phase 3 Oct 11, 2024
@DokySp DokySp reopened this Oct 11, 2024
@DokySp
Copy link
Member

DokySp commented Oct 11, 2024

해당 기능은 구현되었으나, UseCase가 없어 다시 오픈했습니다~
현재 ViewModel에서 UseCase없이 구현되어있음.

@fetiu
Copy link
Member Author

fetiu commented Nov 12, 2024

@DokySp 가 PNG 오버레이하는 방식으로 구현 수정 예정

@DokySp DokySp self-assigned this Nov 12, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature/external feature-external New Implementation New feature
Projects
None yet
Development

No branches or pull requests

3 participants