Я работаю над проектом Swiftui, где я применяю перспективную деформацию к изображению с использованием основного изображения. Я позволяю пользователям перемещать контрольные точки (углы изображения), чтобы регулировать преобразование. Точки, они могут выйти за пределы границы изображения, что приводит к нежелательным искажениям. Я хочу ограничить контрольные точки, чтобы они всегда оставались на границе изображения.
код:
import SwiftUI
import CoreImage
import CoreImage.CIFilterBuiltins
struct PerspectiveWarpImageView: View {
// Control points for the four corners of the image’s frame.
@State private var points: [CGPoint] = []
// Position used to move the warped image around
@State var position: CGPoint = CGPoint(x: 200, y: 300)
@State var position2: CGPoint = CGPoint(x: 200, y: 300)
@State private var initialPosition: CGPoint = .zero
// This offset stores the image’s top‐left origin (computed onAppear).
@State private var offset: CGPoint = .zero
// Change this to your asset’s name
let imageName = "imgMusic"
var body: some View {
GeometryReader { geometry in
ZStack {
Color.gray
.edgesIgnoringSafeArea(.all)
// When the control points are set, display the warped image.
if !points.isEmpty, let transformedImage = transformImage() {
Image(uiImage: transformedImage)
.resizable()
.scaledToFit()
// .frame(width: 300, height: 200)
// The image view is positioned using the same state as before.
.position(position)
// Allow dragging the entire image (and its control points)
// Overlay the control points so you can adjust the corners.
PointsView(points: $points)
.position(position2)
.onAppear {
// If the control points haven’t been set yet, initialize them.
if points.isEmpty {
let screenWidth = geometry.size.width
let screenHeight = geometry.size.height
let offsetX = (screenWidth - 400) / 2 // center horizontally
let offsetY = (screenHeight - 300) / 2 // center vertically
offset = CGPoint(x: offsetX, y: offsetY)
points = [
CGPoint(x: offsetX + 0, y: offsetY + 0), // Top-left
CGPoint(x: offsetX + 400, y: offsetY + 0), // Top-right
CGPoint(x: offsetX + 400, y: offsetY + 300), // Bottom-right
CGPoint(x: offsetX + 0, y: offsetY + 300) // Bottom-left
]
}
}
.gesture(
DragGesture()
.onChanged { value in
if initialPosition == .zero {
initialPosition = position
}
let newPosition = CGPoint(
x: initialPosition.x + value.translation.width,
y: initialPosition.y + value.translation.height
)
DispatchQueue.main.async {
position = newPosition
position2 = newPosition
}
}
.onEnded { _ in
initialPosition = .zero
}
)
}
}
.onAppear {
// In case the PointsView onAppear did not run, initialize here.
if points.isEmpty {
let screenWidth = geometry.size.width
let screenHeight = geometry.size.height
let offsetX = (screenWidth - 400) / 2
let offsetY = (screenHeight - 300) / 2
offset = CGPoint(x: offsetX, y: offsetY)
points = [
CGPoint(x: offsetX + 0, y: offsetY + 0), // Top-left
CGPoint(x: offsetX + 400, y: offsetY + 0), // Top-right
CGPoint(x: offsetX + 400, y: offsetY + 300), // Bottom-right
CGPoint(x: offsetX + 0, y: offsetY + 300) // Bottom-left
]
}
}
}
}
/// Applies a perspective warp to the image using Core Image.
func transformImage() -> UIImage? {
// Load the image from your assets.
guard let uiImage = UIImage(named: imageName) else { return nil }
guard let ciImage = CIImage(image: uiImage) else { return nil }
// We assume the image is shown in a 300×200 frame.
let displaySize = CGSize(width: uiImage.size.width, height: uiImage.size.height)
// Set up the perspective transform filter.
let filter = CIFilter(name: "CIPerspectiveTransform")!
filter.setValue(ciImage, forKey: kCIInputImageKey)
// Convert each of the four control points into the image’s coordinate system.
// (Remember: SwiftUI’s coordinate space origin is at the top-left, while Core Image’s
// coordinate space origin is at the bottom-left.)
guard points.count == 4 else { return nil }
let topLeft = convertToImageCoordinates(points[0], displaySize: displaySize, offset: offset)
let topRight = convertToImageCoordinates(points[1], displaySize: displaySize, offset: offset)
let bottomRight = convertToImageCoordinates(points[2], displaySize: displaySize, offset: offset)
let bottomLeft = convertToImageCoordinates(points[3], displaySize: displaySize, offset: offset)
let clampFilter = CIFilter.affineClamp()
clampFilter.inputImage = ciImage
clampFilter.transform = .identity
guard let clampedImage = clampFilter.outputImage else { return nil }
guard points.count == 4 else { return nil }
filter.setValue(CIVector(cgPoint: topLeft), forKey: "inputTopLeft")
filter.setValue(CIVector(cgPoint: topRight), forKey: "inputTopRight")
filter.setValue(CIVector(cgPoint: bottomRight), forKey: "inputBottomRight")
filter.setValue(CIVector(cgPoint: bottomLeft), forKey: "inputBottomLeft")
// Render the output image.
guard let outputImage = filter.outputImage else { return nil }
// let context = CIContext(options: nil)
//
// if let cgimg = context.createCGImage(outputImage, from: CGRect(origin: .zero, size: displaySize)) {
// return UIImage(cgImage: cgimg)
// }
return outputImage.toUIImage()
}
func scaleImage(_ image: UIImage, to newSize: CGSize) -> UIImage {
let renderer = UIGraphicsImageRenderer(size: newSize)
return renderer.image { _ in
image.draw(in: CGRect(origin: .zero, size: newSize))
}
}
/// Converts a point from SwiftUI’s coordinate space (global) into the image’s coordinate space.
func convertToImageCoordinates(_ point: CGPoint, displaySize: CGSize, offset: CGPoint) -> CGPoint {
// The image’s frame starts at the given offset.
let relativeX = point.x - offset.x
let relativeY = point.y - offset.y
// Flip the y coordinate so that the origin is at the bottom.
let flippedY = displaySize.height - relativeY
return CGPoint(x: relativeX, y: flippedY)
}
}
extension CIImage {
func toUIImage() -> UIImage? {
let context = CIContext(options: nil)
if let cgImage = context.createCGImage(self, from: self.extent) {
return UIImage(cgImage: cgImage, scale: 1.0, orientation: .up)
}
return nil
}
}
struct PerspectiveWarpImageView_Previews: PreviewProvider {
static var previews: some View {
PerspectiveWarpImageView()
}
}
< /code>
ожидаемое поведение: < /strong> < /p>
Управляющие точки никогда не должны оставлять границы изображения. /li>
Пользователи должны иметь возможность перетаскивать их только по краям изображения. < /li>
< /ul>
image < /strong>
myimage
Подробнее здесь: https://stackoverflow.com/questions/794 ... age-bounds
Swiftui перспективная деформация - сохранить контрольные точки в пределах границ изображений ⇐ IOS
Программируем под IOS
1739195832
Anonymous
Я работаю над проектом Swiftui, где я применяю перспективную деформацию к изображению с использованием основного изображения. Я позволяю пользователям перемещать контрольные точки (углы изображения), чтобы регулировать преобразование. Точки, они могут выйти за пределы границы изображения, что приводит к нежелательным искажениям. Я хочу ограничить контрольные точки, чтобы они всегда оставались на границе изображения.
[b] код: [/b]
import SwiftUI
import CoreImage
import CoreImage.CIFilterBuiltins
struct PerspectiveWarpImageView: View {
// Control points for the four corners of the image’s frame.
@State private var points: [CGPoint] = []
// Position used to move the warped image around
@State var position: CGPoint = CGPoint(x: 200, y: 300)
@State var position2: CGPoint = CGPoint(x: 200, y: 300)
@State private var initialPosition: CGPoint = .zero
// This offset stores the image’s top‐left origin (computed onAppear).
@State private var offset: CGPoint = .zero
// Change this to your asset’s name
let imageName = "imgMusic"
var body: some View {
GeometryReader { geometry in
ZStack {
Color.gray
.edgesIgnoringSafeArea(.all)
// When the control points are set, display the warped image.
if !points.isEmpty, let transformedImage = transformImage() {
Image(uiImage: transformedImage)
.resizable()
.scaledToFit()
// .frame(width: 300, height: 200)
// The image view is positioned using the same state as before.
.position(position)
// Allow dragging the entire image (and its control points)
// Overlay the control points so you can adjust the corners.
PointsView(points: $points)
.position(position2)
.onAppear {
// If the control points haven’t been set yet, initialize them.
if points.isEmpty {
let screenWidth = geometry.size.width
let screenHeight = geometry.size.height
let offsetX = (screenWidth - 400) / 2 // center horizontally
let offsetY = (screenHeight - 300) / 2 // center vertically
offset = CGPoint(x: offsetX, y: offsetY)
points = [
CGPoint(x: offsetX + 0, y: offsetY + 0), // Top-left
CGPoint(x: offsetX + 400, y: offsetY + 0), // Top-right
CGPoint(x: offsetX + 400, y: offsetY + 300), // Bottom-right
CGPoint(x: offsetX + 0, y: offsetY + 300) // Bottom-left
]
}
}
.gesture(
DragGesture()
.onChanged { value in
if initialPosition == .zero {
initialPosition = position
}
let newPosition = CGPoint(
x: initialPosition.x + value.translation.width,
y: initialPosition.y + value.translation.height
)
DispatchQueue.main.async {
position = newPosition
position2 = newPosition
}
}
.onEnded { _ in
initialPosition = .zero
}
)
}
}
.onAppear {
// In case the PointsView onAppear did not run, initialize here.
if points.isEmpty {
let screenWidth = geometry.size.width
let screenHeight = geometry.size.height
let offsetX = (screenWidth - 400) / 2
let offsetY = (screenHeight - 300) / 2
offset = CGPoint(x: offsetX, y: offsetY)
points = [
CGPoint(x: offsetX + 0, y: offsetY + 0), // Top-left
CGPoint(x: offsetX + 400, y: offsetY + 0), // Top-right
CGPoint(x: offsetX + 400, y: offsetY + 300), // Bottom-right
CGPoint(x: offsetX + 0, y: offsetY + 300) // Bottom-left
]
}
}
}
}
/// Applies a perspective warp to the image using Core Image.
func transformImage() -> UIImage? {
// Load the image from your assets.
guard let uiImage = UIImage(named: imageName) else { return nil }
guard let ciImage = CIImage(image: uiImage) else { return nil }
// We assume the image is shown in a 300×200 frame.
let displaySize = CGSize(width: uiImage.size.width, height: uiImage.size.height)
// Set up the perspective transform filter.
let filter = CIFilter(name: "CIPerspectiveTransform")!
filter.setValue(ciImage, forKey: kCIInputImageKey)
// Convert each of the four control points into the image’s coordinate system.
// (Remember: SwiftUI’s coordinate space origin is at the top-left, while Core Image’s
// coordinate space origin is at the bottom-left.)
guard points.count == 4 else { return nil }
let topLeft = convertToImageCoordinates(points[0], displaySize: displaySize, offset: offset)
let topRight = convertToImageCoordinates(points[1], displaySize: displaySize, offset: offset)
let bottomRight = convertToImageCoordinates(points[2], displaySize: displaySize, offset: offset)
let bottomLeft = convertToImageCoordinates(points[3], displaySize: displaySize, offset: offset)
let clampFilter = CIFilter.affineClamp()
clampFilter.inputImage = ciImage
clampFilter.transform = .identity
guard let clampedImage = clampFilter.outputImage else { return nil }
guard points.count == 4 else { return nil }
filter.setValue(CIVector(cgPoint: topLeft), forKey: "inputTopLeft")
filter.setValue(CIVector(cgPoint: topRight), forKey: "inputTopRight")
filter.setValue(CIVector(cgPoint: bottomRight), forKey: "inputBottomRight")
filter.setValue(CIVector(cgPoint: bottomLeft), forKey: "inputBottomLeft")
// Render the output image.
guard let outputImage = filter.outputImage else { return nil }
// let context = CIContext(options: nil)
//
// if let cgimg = context.createCGImage(outputImage, from: CGRect(origin: .zero, size: displaySize)) {
// return UIImage(cgImage: cgimg)
// }
return outputImage.toUIImage()
}
func scaleImage(_ image: UIImage, to newSize: CGSize) -> UIImage {
let renderer = UIGraphicsImageRenderer(size: newSize)
return renderer.image { _ in
image.draw(in: CGRect(origin: .zero, size: newSize))
}
}
/// Converts a point from SwiftUI’s coordinate space (global) into the image’s coordinate space.
func convertToImageCoordinates(_ point: CGPoint, displaySize: CGSize, offset: CGPoint) -> CGPoint {
// The image’s frame starts at the given offset.
let relativeX = point.x - offset.x
let relativeY = point.y - offset.y
// Flip the y coordinate so that the origin is at the bottom.
let flippedY = displaySize.height - relativeY
return CGPoint(x: relativeX, y: flippedY)
}
}
extension CIImage {
func toUIImage() -> UIImage? {
let context = CIContext(options: nil)
if let cgImage = context.createCGImage(self, from: self.extent) {
return UIImage(cgImage: cgImage, scale: 1.0, orientation: .up)
}
return nil
}
}
struct PerspectiveWarpImageView_Previews: PreviewProvider {
static var previews: some View {
PerspectiveWarpImageView()
}
}
< /code>
ожидаемое поведение: < /strong> < /p>
Управляющие точки никогда не должны оставлять границы изображения. /li>
Пользователи должны иметь возможность перетаскивать их только по краям изображения. < /li>
< /ul>
image < /strong>
myimage
Подробнее здесь: [url]https://stackoverflow.com/questions/79427295/swiftui-perspective-warp-keep-control-points-within-image-bounds[/url]
Ответить
1 сообщение
• Страница 1 из 1
Перейти
- Кемерово-IT
- ↳ Javascript
- ↳ C#
- ↳ JAVA
- ↳ Elasticsearch aggregation
- ↳ Python
- ↳ Php
- ↳ Android
- ↳ Html
- ↳ Jquery
- ↳ C++
- ↳ IOS
- ↳ CSS
- ↳ Excel
- ↳ Linux
- ↳ Apache
- ↳ MySql
- Детский мир
- Для души
- ↳ Музыкальные инструменты даром
- ↳ Печатная продукция даром
- Внешняя красота и здоровье
- ↳ Одежда и обувь для взрослых даром
- ↳ Товары для здоровья
- ↳ Физкультура и спорт
- Техника - даром!
- ↳ Автомобилистам
- ↳ Компьютерная техника
- ↳ Плиты: газовые и электрические
- ↳ Холодильники
- ↳ Стиральные машины
- ↳ Телевизоры
- ↳ Телефоны, смартфоны, плашеты
- ↳ Швейные машинки
- ↳ Прочая электроника и техника
- ↳ Фототехника
- Ремонт и интерьер
- ↳ Стройматериалы, инструмент
- ↳ Мебель и предметы интерьера даром
- ↳ Cантехника
- Другие темы
- ↳ Разное даром
- ↳ Давай меняться!
- ↳ Отдам\возьму за копеечку
- ↳ Работа и подработка в Кемерове
- ↳ Давай с тобой поговорим...
Мобильная версия