From bb90821044960a0fa7d7de2e153dbdb438008d36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Bo=CC=88hn?= Date: Mon, 7 Jul 2014 21:51:02 -0700 Subject: [PATCH 01/81] First stab at GPUImage integration --- PlotDevice.xcodeproj/project.pbxproj | 29 ++++ app/Frameworks/GPUImage.framework/GPUImage | 1 + app/Frameworks/GPUImage.framework/Headers | 1 + app/Frameworks/GPUImage.framework/Resources | 1 + .../GPUImage.framework/Versions/A/GPUImage | Bin 0 -> 1029280 bytes .../Versions/A/Headers/GLProgram.h | 42 +++++ .../Versions/A/Headers/GPUImage.h | 155 ++++++++++++++++++ .../A/Headers/GPUImage3x3ConvolutionFilter.h | 18 ++ .../GPUImage3x3TextureSamplingFilter.h | 18 ++ .../Versions/A/Headers/GPUImageAVCamera.h | 132 +++++++++++++++ .../Headers/GPUImageAdaptiveThresholdFilter.h | 9 + .../A/Headers/GPUImageAddBlendFilter.h | 5 + .../A/Headers/GPUImageAlphaBlendFilter.h | 11 ++ .../A/Headers/GPUImageAmatorkaFilter.h | 17 ++ .../Versions/A/Headers/GPUImageAverageColor.h | 20 +++ .../GPUImageAverageLuminanceThresholdFilter.h | 8 + .../A/Headers/GPUImageBilateralFilter.h | 10 ++ .../A/Headers/GPUImageBoxBlurFilter.h | 7 + .../A/Headers/GPUImageBrightnessFilter.h | 11 ++ .../Versions/A/Headers/GPUImageBuffer.h | 10 ++ .../A/Headers/GPUImageBulgeDistortionFilter.h | 16 ++ .../A/Headers/GPUImageCGAColorspaceFilter.h | 5 + .../GPUImageCannyEdgeDetectionFilter.h | 62 +++++++ .../A/Headers/GPUImageChromaKeyBlendFilter.h | 32 ++++ .../A/Headers/GPUImageChromaKeyFilter.h | 30 ++++ .../A/Headers/GPUImageClosingFilter.h | 19 +++ .../A/Headers/GPUImageColorBlendFilter.h | 5 + .../A/Headers/GPUImageColorBurnBlendFilter.h | 9 + .../A/Headers/GPUImageColorDodgeBlendFilter.h | 9 + .../A/Headers/GPUImageColorInvertFilter.h | 7 + .../A/Headers/GPUImageColorMatrixFilter.h | 19 +++ .../A/Headers/GPUImageColorPackingFilter.h | 10 ++ .../Versions/A/Headers/GPUImageContext.h | 54 ++++++ .../A/Headers/GPUImageContrastFilter.h | 14 ++ .../Versions/A/Headers/GPUImageCropFilter.h | 14 ++ .../A/Headers/GPUImageCrosshairGenerator.h | 17 ++ .../A/Headers/GPUImageCrosshatchFilter.h | 13 ++ .../A/Headers/GPUImageDarkenBlendFilter.h | 7 + .../A/Headers/GPUImageDifferenceBlendFilter.h | 7 + .../A/Headers/GPUImageDilationFilter.h | 16 ++ ...geDirectionalNonMaximumSuppressionFilter.h | 19 +++ .../A/Headers/GPUImageDissolveBlendFilter.h | 11 ++ .../A/Headers/GPUImageDivideBlendFilter.h | 5 + .../Versions/A/Headers/GPUImageEmbossFilter.h | 8 + .../A/Headers/GPUImageErosionFilter.h | 11 ++ .../A/Headers/GPUImageExclusionBlendFilter.h | 7 + .../A/Headers/GPUImageExposureFilter.h | 11 ++ .../A/Headers/GPUImageFalseColorFilter.h | 15 ++ .../Versions/A/Headers/GPUImageFilter.h | 134 +++++++++++++++ .../Versions/A/Headers/GPUImageFilterGroup.h | 19 +++ .../Versions/A/Headers/GPUImageFramebuffer.h | 58 +++++++ .../A/Headers/GPUImageFramebufferCache.h | 15 ++ .../Versions/A/Headers/GPUImageGammaFilter.h | 11 ++ .../A/Headers/GPUImageGaussianBlurFilter.h | 36 ++++ .../GPUImageGaussianBlurPositionFilter.h | 22 +++ .../GPUImageGaussianSelectiveBlurFilter.h | 30 ++++ .../A/Headers/GPUImageGlassSphereFilter.h | 5 + .../A/Headers/GPUImageGrayscaleFilter.h | 9 + .../A/Headers/GPUImageHalftoneFilter.h | 5 + .../A/Headers/GPUImageHardLightBlendFilter.h | 7 + .../GPUImageHarrisCornerDetectionFilter.h | 53 ++++++ .../Versions/A/Headers/GPUImageHazeFilter.h | 29 ++++ .../A/Headers/GPUImageHighPassFilter.h | 14 ++ .../A/Headers/GPUImageHighlightShadowFilter.h | 20 +++ .../A/Headers/GPUImageHistogramFilter.h | 25 +++ .../A/Headers/GPUImageHistogramGenerator.h | 8 + .../GPUImageHoughTransformLineDetector.h | 49 ++++++ .../A/Headers/GPUImageHueBlendFilter.h | 5 + .../Versions/A/Headers/GPUImageHueFilter.h | 11 ++ .../A/Headers/GPUImageJFAVoronoiFilter.h | 17 ++ .../A/Headers/GPUImageKuwaharaFilter.h | 13 ++ .../A/Headers/GPUImageKuwaharaRadius3Filter.h | 8 + .../Headers/GPUImageLanczosResamplingFilter.h | 7 + .../A/Headers/GPUImageLaplacianFilter.h | 5 + .../Versions/A/Headers/GPUImageLevelsFilter.h | 45 +++++ .../A/Headers/GPUImageLightenBlendFilter.h | 8 + .../A/Headers/GPUImageLineGenerator.h | 18 ++ .../A/Headers/GPUImageLinearBurnBlendFilter.h | 5 + .../GPUImageLocalBinaryPatternFilter.h | 5 + .../Versions/A/Headers/GPUImageLookupFilter.h | 28 ++++ .../A/Headers/GPUImageLowPassFilter.h | 14 ++ .../GPUImageLuminanceThresholdFilter.h | 14 ++ .../Versions/A/Headers/GPUImageLuminosity.h | 17 ++ .../A/Headers/GPUImageLuminosityBlendFilter.h | 5 + .../Versions/A/Headers/GPUImageMaskFilter.h | 5 + .../Versions/A/Headers/GPUImageMedianFilter.h | 5 + .../A/Headers/GPUImageMissEtikateFilter.h | 17 ++ .../A/Headers/GPUImageMonochromeFilter.h | 13 ++ .../Versions/A/Headers/GPUImageMosaicFilter.h | 27 +++ .../A/Headers/GPUImageMotionBlurFilter.h | 13 ++ .../A/Headers/GPUImageMotionDetector.h | 18 ++ .../Versions/A/Headers/GPUImageMovieWriter.h | 57 +++++++ .../A/Headers/GPUImageMultiplyBlendFilter.h | 7 + .../GPUImageNobleCornerDetectionFilter.h | 12 ++ .../GPUImageNonMaximumSuppressionFilter.h | 5 + .../A/Headers/GPUImageNormalBlendFilter.h | 8 + .../A/Headers/GPUImageOpacityFilter.h | 11 ++ .../A/Headers/GPUImageOpeningFilter.h | 19 +++ .../Versions/A/Headers/GPUImageOutput.h | 127 ++++++++++++++ .../A/Headers/GPUImageOverlayBlendFilter.h | 5 + ...ageParallelCoordinateLineTransformFilter.h | 16 ++ .../A/Headers/GPUImagePerlinNoiseFilter.h | 13 ++ .../Versions/A/Headers/GPUImagePicture.h | 25 +++ .../A/Headers/GPUImagePinchDistortionFilter.h | 20 +++ .../A/Headers/GPUImagePixellateFilter.h | 12 ++ .../Headers/GPUImagePixellatePositionFilter.h | 17 ++ .../A/Headers/GPUImagePoissonBlendFilter.h | 18 ++ .../A/Headers/GPUImagePolarPixellateFilter.h | 13 ++ .../A/Headers/GPUImagePolkaDotFilter.h | 10 ++ .../A/Headers/GPUImagePosterizeFilter.h | 14 ++ .../GPUImagePrewittEdgeDetectionFilter.h | 5 + .../A/Headers/GPUImageRGBClosingFilter.h | 18 ++ .../A/Headers/GPUImageRGBDilationFilter.h | 11 ++ .../A/Headers/GPUImageRGBErosionFilter.h | 11 ++ .../Versions/A/Headers/GPUImageRGBFilter.h | 15 ++ .../A/Headers/GPUImageRGBOpeningFilter.h | 17 ++ .../Versions/A/Headers/GPUImageRawDataInput.h | 42 +++++ .../A/Headers/GPUImageRawDataOutput.h | 44 +++++ .../A/Headers/GPUImageSaturationBlendFilter.h | 5 + .../A/Headers/GPUImageSaturationFilter.h | 14 ++ .../A/Headers/GPUImageScreenBlendFilter.h | 7 + .../Versions/A/Headers/GPUImageSepiaFilter.h | 6 + .../A/Headers/GPUImageSharpenFilter.h | 12 ++ .../GPUImageShiTomasiFeatureDetectionFilter.h | 13 ++ ...PUImageSingleComponentGaussianBlurFilter.h | 7 + .../Versions/A/Headers/GPUImageSketchFilter.h | 11 ++ .../A/Headers/GPUImageSmoothToonFilter.h | 28 ++++ .../GPUImageSobelEdgeDetectionFilter.h | 16 ++ .../A/Headers/GPUImageSoftEleganceFilter.h | 19 +++ .../A/Headers/GPUImageSoftLightBlendFilter.h | 7 + .../A/Headers/GPUImageSolidColorGenerator.h | 19 +++ .../A/Headers/GPUImageSourceOverBlendFilter.h | 5 + .../Headers/GPUImageSphereRefractionFilter.h | 15 ++ .../Headers/GPUImageStretchDistortionFilter.h | 13 ++ .../A/Headers/GPUImageSubtractBlendFilter.h | 5 + .../Versions/A/Headers/GPUImageSwirlFilter.h | 17 ++ .../A/Headers/GPUImageThreeInputFilter.h | 21 +++ .../GPUImageThresholdEdgeDetectionFilter.h | 12 ++ .../A/Headers/GPUImageThresholdSketchFilter.h | 5 + ...geThresholdedNonMaximumSuppressionFilter.h | 14 ++ .../A/Headers/GPUImageTiltShiftFilter.h | 24 +++ .../A/Headers/GPUImageToneCurveFilter.h | 30 ++++ .../Versions/A/Headers/GPUImageToonFilter.h | 19 +++ .../A/Headers/GPUImageTransformFilter.h | 19 +++ ...UImageTwoInputCrossTextureSamplingFilter.h | 15 ++ .../A/Headers/GPUImageTwoInputFilter.h | 21 +++ .../A/Headers/GPUImageTwoPassFilter.h | 19 +++ .../GPUImageTwoPassTextureSamplingFilter.h | 13 ++ .../A/Headers/GPUImageUnsharpMaskFilter.h | 16 ++ .../Versions/A/Headers/GPUImageView.h | 39 +++++ .../A/Headers/GPUImageVignetteFilter.h | 22 +++ .../A/Headers/GPUImageVoronoiConsumerFilter.h | 10 ++ .../GPUImageWeakPixelInclusionFilter.h | 5 + .../A/Headers/GPUImageWhiteBalanceFilter.h | 17 ++ .../A/Headers/GPUImageXYDerivativeFilter.h | 5 + .../A/Headers/GPUImageZoomBlurFilter.h | 13 ++ ...imageDirectionalSobelEdgeDetectionFilter.h | 5 + .../Versions/A/Resources/Info.plist | 42 +++++ .../GPUImage.framework/Versions/Current | 1 + app/deps/tensor/Filter.h | 27 +++ app/deps/tensor/Filter.m | 30 ++++ app/deps/tensor/module.m | 11 ++ app/deps/tensor/setup.py | 35 ++++ app/deps/tensor/tensor.so | Bin 0 -> 11668 bytes 164 files changed, 3110 insertions(+) create mode 120000 app/Frameworks/GPUImage.framework/GPUImage create mode 120000 app/Frameworks/GPUImage.framework/Headers create mode 120000 app/Frameworks/GPUImage.framework/Resources create mode 100755 app/Frameworks/GPUImage.framework/Versions/A/GPUImage create mode 100755 app/Frameworks/GPUImage.framework/Versions/A/Headers/GLProgram.h create mode 100755 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImage.h create mode 100755 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImage3x3ConvolutionFilter.h create mode 100644 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImage3x3TextureSamplingFilter.h create mode 100755 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageAVCamera.h create mode 100755 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageAdaptiveThresholdFilter.h create mode 100644 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageAddBlendFilter.h create mode 100755 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageAlphaBlendFilter.h create mode 100755 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageAmatorkaFilter.h create mode 100644 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageAverageColor.h create mode 100644 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageAverageLuminanceThresholdFilter.h create mode 100644 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageBilateralFilter.h create mode 100755 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageBoxBlurFilter.h create mode 100755 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageBrightnessFilter.h create mode 100644 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageBuffer.h create mode 100755 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageBulgeDistortionFilter.h create mode 100755 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageCGAColorspaceFilter.h create mode 100755 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageCannyEdgeDetectionFilter.h create mode 100755 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageChromaKeyBlendFilter.h create mode 100644 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageChromaKeyFilter.h create mode 100644 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageClosingFilter.h create mode 100644 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageColorBlendFilter.h create mode 100755 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageColorBurnBlendFilter.h create mode 100755 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageColorDodgeBlendFilter.h create mode 100755 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageColorInvertFilter.h create mode 100755 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageColorMatrixFilter.h create mode 100644 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageColorPackingFilter.h create mode 100755 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageContext.h create mode 100755 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageContrastFilter.h create mode 100755 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageCropFilter.h create mode 100644 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageCrosshairGenerator.h create mode 100755 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageCrosshatchFilter.h create mode 100755 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageDarkenBlendFilter.h create mode 100755 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageDifferenceBlendFilter.h create mode 100644 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageDilationFilter.h create mode 100644 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageDirectionalNonMaximumSuppressionFilter.h create mode 100755 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageDissolveBlendFilter.h create mode 100644 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageDivideBlendFilter.h create mode 100755 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageEmbossFilter.h create mode 100644 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageErosionFilter.h create mode 100755 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageExclusionBlendFilter.h create mode 100755 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageExposureFilter.h create mode 100644 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageFalseColorFilter.h create mode 100755 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageFilter.h create mode 100755 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageFilterGroup.h create mode 100644 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageFramebuffer.h create mode 100644 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageFramebufferCache.h create mode 100755 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageGammaFilter.h create mode 100755 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageGaussianBlurFilter.h create mode 100755 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageGaussianBlurPositionFilter.h create mode 100755 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageGaussianSelectiveBlurFilter.h create mode 100644 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageGlassSphereFilter.h create mode 100755 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageGrayscaleFilter.h create mode 100644 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageHalftoneFilter.h create mode 100755 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageHardLightBlendFilter.h create mode 100755 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageHarrisCornerDetectionFilter.h create mode 100755 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageHazeFilter.h create mode 100644 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageHighPassFilter.h create mode 100644 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageHighlightShadowFilter.h create mode 100755 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageHistogramFilter.h create mode 100755 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageHistogramGenerator.h create mode 100644 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageHoughTransformLineDetector.h create mode 100644 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageHueBlendFilter.h create mode 100644 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageHueFilter.h create mode 100644 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageJFAVoronoiFilter.h create mode 100755 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageKuwaharaFilter.h create mode 100644 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageKuwaharaRadius3Filter.h create mode 100644 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageLanczosResamplingFilter.h create mode 100644 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageLaplacianFilter.h create mode 100644 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageLevelsFilter.h create mode 100755 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageLightenBlendFilter.h create mode 100644 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageLineGenerator.h create mode 100644 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageLinearBurnBlendFilter.h create mode 100644 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageLocalBinaryPatternFilter.h create mode 100644 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageLookupFilter.h create mode 100644 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageLowPassFilter.h create mode 100755 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageLuminanceThresholdFilter.h create mode 100644 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageLuminosity.h create mode 100644 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageLuminosityBlendFilter.h create mode 100755 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageMaskFilter.h create mode 100644 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageMedianFilter.h create mode 100755 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageMissEtikateFilter.h create mode 100644 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageMonochromeFilter.h create mode 100644 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageMosaicFilter.h create mode 100644 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageMotionBlurFilter.h create mode 100644 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageMotionDetector.h create mode 100755 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageMovieWriter.h create mode 100755 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageMultiplyBlendFilter.h create mode 100644 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageNobleCornerDetectionFilter.h create mode 100644 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageNonMaximumSuppressionFilter.h create mode 100644 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageNormalBlendFilter.h create mode 100644 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageOpacityFilter.h create mode 100644 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageOpeningFilter.h create mode 100755 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageOutput.h create mode 100755 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageOverlayBlendFilter.h create mode 100644 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageParallelCoordinateLineTransformFilter.h create mode 100644 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImagePerlinNoiseFilter.h create mode 100755 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImagePicture.h create mode 100755 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImagePinchDistortionFilter.h create mode 100755 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImagePixellateFilter.h create mode 100755 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImagePixellatePositionFilter.h create mode 100644 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImagePoissonBlendFilter.h create mode 100755 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImagePolarPixellateFilter.h create mode 100644 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImagePolkaDotFilter.h create mode 100755 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImagePosterizeFilter.h create mode 100755 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImagePrewittEdgeDetectionFilter.h create mode 100644 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageRGBClosingFilter.h create mode 100644 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageRGBDilationFilter.h create mode 100644 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageRGBErosionFilter.h create mode 100755 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageRGBFilter.h create mode 100644 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageRGBOpeningFilter.h create mode 100644 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageRawDataInput.h create mode 100755 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageRawDataOutput.h create mode 100644 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSaturationBlendFilter.h create mode 100755 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSaturationFilter.h create mode 100755 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageScreenBlendFilter.h create mode 100755 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSepiaFilter.h create mode 100755 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSharpenFilter.h create mode 100644 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageShiTomasiFeatureDetectionFilter.h create mode 100644 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSingleComponentGaussianBlurFilter.h create mode 100755 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSketchFilter.h create mode 100755 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSmoothToonFilter.h create mode 100755 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSobelEdgeDetectionFilter.h create mode 100755 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSoftEleganceFilter.h create mode 100755 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSoftLightBlendFilter.h create mode 100644 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSolidColorGenerator.h create mode 100644 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSourceOverBlendFilter.h create mode 100644 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSphereRefractionFilter.h create mode 100755 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageStretchDistortionFilter.h create mode 100755 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSubtractBlendFilter.h create mode 100755 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSwirlFilter.h create mode 100644 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageThreeInputFilter.h create mode 100755 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageThresholdEdgeDetectionFilter.h create mode 100644 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageThresholdSketchFilter.h create mode 100644 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageThresholdedNonMaximumSuppressionFilter.h create mode 100755 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageTiltShiftFilter.h create mode 100755 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageToneCurveFilter.h create mode 100755 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageToonFilter.h create mode 100755 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageTransformFilter.h create mode 100644 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageTwoInputCrossTextureSamplingFilter.h create mode 100644 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageTwoInputFilter.h create mode 100755 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageTwoPassFilter.h create mode 100644 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageTwoPassTextureSamplingFilter.h create mode 100755 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageUnsharpMaskFilter.h create mode 100755 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageView.h create mode 100755 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageVignetteFilter.h create mode 100644 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageVoronoiConsumerFilter.h create mode 100644 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageWeakPixelInclusionFilter.h create mode 100644 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageWhiteBalanceFilter.h create mode 100755 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageXYDerivativeFilter.h create mode 100644 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageZoomBlurFilter.h create mode 100644 app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUimageDirectionalSobelEdgeDetectionFilter.h create mode 100644 app/Frameworks/GPUImage.framework/Versions/A/Resources/Info.plist create mode 120000 app/Frameworks/GPUImage.framework/Versions/Current create mode 100644 app/deps/tensor/Filter.h create mode 100644 app/deps/tensor/Filter.m create mode 100644 app/deps/tensor/module.m create mode 100644 app/deps/tensor/setup.py create mode 100755 app/deps/tensor/tensor.so diff --git a/PlotDevice.xcodeproj/project.pbxproj b/PlotDevice.xcodeproj/project.pbxproj index 932929b3..c202da47 100644 --- a/PlotDevice.xcodeproj/project.pbxproj +++ b/PlotDevice.xcodeproj/project.pbxproj @@ -37,6 +37,8 @@ 6155D9F413E2B79E00675A92 /* CHANGES.md in Resources */ = {isa = PBXBuildFile; fileRef = 6155D9F213E2B79E00675A92 /* CHANGES.md */; }; 6155D9F513E2B79E00675A92 /* README.md in Resources */ = {isa = PBXBuildFile; fileRef = 6155D9F313E2B79E00675A92 /* README.md */; }; 8D15AC340486D014006FF6A4 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A7FEA54F5311CA2CBB /* Cocoa.framework */; }; + CF04731D196B71C200E3C358 /* GPUImage.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CF04731C196B71C200E3C358 /* GPUImage.framework */; }; + CF047321196B744C00E3C358 /* GPUImage.framework in Copy Private Frameworks */ = {isa = PBXBuildFile; fileRef = CF04731C196B71C200E3C358 /* GPUImage.framework */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -79,6 +81,17 @@ name = "Copy 'plotdevice' Tool"; runOnlyForDeploymentPostprocessing = 0; }; + CF04731E196B73F700E3C358 /* Copy Private Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + CF047321196B744C00E3C358 /* GPUImage.framework in Copy Private Frameworks */, + ); + name = "Copy Private Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ @@ -154,6 +167,7 @@ 6155D9F213E2B79E00675A92 /* CHANGES.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CHANGES.md; sourceTree = ""; }; 6155D9F313E2B79E00675A92 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = README.md; sourceTree = ""; }; 8D15AC370486D014006FF6A4 /* PlotDevice.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = PlotDevice.app; sourceTree = BUILT_PRODUCTS_DIR; }; + CF04731C196B71C200E3C358 /* GPUImage.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GPUImage.framework; path = app/Frameworks/GPUImage.framework; sourceTree = SOURCE_ROOT; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -161,6 +175,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + CF04731D196B71C200E3C358 /* GPUImage.framework in Frameworks */, 2AA40EBF184BF9CB00981ADC /* libpython2.7.dylib in Frameworks */, 2ABBB2FC18540246001C4E0A /* CoreVideo.framework in Frameworks */, 2ABBB2FE185402AC001C4E0A /* CoreMedia.framework in Frameworks */, @@ -284,6 +299,7 @@ 2A37F4C3FDCFA73011CA2CEA /* Frameworks */ = { isa = PBXGroup; children = ( + CF04731C196B71C200E3C358 /* GPUImage.framework */, 2AEE843D18B5603900CF91D4 /* CoreText.framework */, 2A15C42C18A1FA14006BDFF0 /* WebKit.framework */, 2A591FEF185C17D200D1833D /* Security.framework */, @@ -381,6 +397,7 @@ isa = PBXNativeTarget; buildConfigurationList = C05733C708A9546B00998B17 /* Build configuration list for PBXNativeTarget "PlotDevice" */; buildPhases = ( + CF04731E196B73F700E3C358 /* Copy Private Frameworks */, 8D15AC2B0486D014006FF6A4 /* Resources */, 2A15C43718A20929006BDFF0 /* Copy Editor Assets */, 2A66ECEA18A99303002903DE /* Copy Editor Scripts */, @@ -553,6 +570,11 @@ COMBINE_HIDPI_IMAGES = YES; CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)"; COPY_PHASE_STRIP = NO; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)", + "$(PROJECT_DIR)/app/Frameworks", + ); GCC_DYNAMIC_NO_PIC = NO; GCC_MODEL_TUNING = G5; GCC_OPTIMIZATION_LEVEL = 0; @@ -581,6 +603,11 @@ COMBINE_HIDPI_IMAGES = YES; CONFIGURATION_BUILD_DIR = dist; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)", + "$(PROJECT_DIR)/app/Frameworks", + ); GCC_MODEL_TUNING = G5; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = app/PlotDevice_Prefix.pch; @@ -605,6 +632,7 @@ MACOSX_DEPLOYMENT_TARGET = 10.9; ONLY_ACTIVE_ARCH = YES; PRODUCT_NAME = PlotDevice; + SCAN_ALL_SOURCE_FILES_FOR_INCLUDES = YES; }; name = Debug; }; @@ -613,6 +641,7 @@ buildSettings = { MACOSX_DEPLOYMENT_TARGET = 10.9; PRODUCT_NAME = PlotDevice; + SCAN_ALL_SOURCE_FILES_FOR_INCLUDES = YES; }; name = Release; }; diff --git a/app/Frameworks/GPUImage.framework/GPUImage b/app/Frameworks/GPUImage.framework/GPUImage new file mode 120000 index 00000000..28a19818 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/GPUImage @@ -0,0 +1 @@ +Versions/Current/GPUImage \ No newline at end of file diff --git a/app/Frameworks/GPUImage.framework/Headers b/app/Frameworks/GPUImage.framework/Headers new file mode 120000 index 00000000..a177d2a6 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Headers @@ -0,0 +1 @@ +Versions/Current/Headers \ No newline at end of file diff --git a/app/Frameworks/GPUImage.framework/Resources b/app/Frameworks/GPUImage.framework/Resources new file mode 120000 index 00000000..953ee36f --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Resources @@ -0,0 +1 @@ +Versions/Current/Resources \ No newline at end of file diff --git a/app/Frameworks/GPUImage.framework/Versions/A/GPUImage b/app/Frameworks/GPUImage.framework/Versions/A/GPUImage new file mode 100755 index 0000000000000000000000000000000000000000..924fdf077ed72b44859b76e9cb137b33a83f0f35 GIT binary patch literal 1029280 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]v3a9!oS?7so; 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 Cr3R+} literal 0 HcmV?d00001 diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GLProgram.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GLProgram.h new file mode 100755 index 00000000..572d8ae9 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GLProgram.h @@ -0,0 +1,42 @@ +// This is Jeff LaMarche's GLProgram OpenGL shader wrapper class from his OpenGL ES 2.0 book. +// A description of this can be found at his page on the topic: +// http://iphonedevelopment.blogspot.com/2010/11/opengl-es-20-for-ios-chapter-4.html +// I've extended this to be able to take programs as NSStrings in addition to files, for baked-in shaders + +#import + +#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE +#import +#import +#else +#import +#import +#endif + +@interface GLProgram : NSObject +{ + NSMutableArray *attributes; + NSMutableArray *uniforms; + GLuint program, + vertShader, + fragShader; +} + +@property(readwrite, nonatomic) BOOL initialized; + +- (id)initWithVertexShaderString:(NSString *)vShaderString + fragmentShaderString:(NSString *)fShaderString; +- (id)initWithVertexShaderString:(NSString *)vShaderString + fragmentShaderFilename:(NSString *)fShaderFilename; +- (id)initWithVertexShaderFilename:(NSString *)vShaderFilename + fragmentShaderFilename:(NSString *)fShaderFilename; +- (void)addAttribute:(NSString *)attributeName; +- (GLuint)attributeIndex:(NSString *)attributeName; +- (GLuint)uniformIndex:(NSString *)uniformName; +- (BOOL)link; +- (void)use; +- (NSString *)vertexShaderLog; +- (NSString *)fragmentShaderLog; +- (NSString *)programLog; +- (void)validate; +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImage.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImage.h new file mode 100755 index 00000000..5a2374aa --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImage.h @@ -0,0 +1,155 @@ +#import + +// Base classes +#import +#import + +// Sources +#import +#import +#import +#import +#import + +// Filters +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import + +// Outputs +#import +#import diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImage3x3ConvolutionFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImage3x3ConvolutionFilter.h new file mode 100755 index 00000000..67e68def --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImage3x3ConvolutionFilter.h @@ -0,0 +1,18 @@ +#import "GPUImage3x3TextureSamplingFilter.h" + +/** Runs a 3x3 convolution kernel against the image + */ +@interface GPUImage3x3ConvolutionFilter : GPUImage3x3TextureSamplingFilter +{ + GLint convolutionMatrixUniform; +} + +/** Convolution kernel to run against the image + + The convolution kernel is a 3x3 matrix of values to apply to the pixel and its 8 surrounding pixels. + The matrix is specified in row-major order, with the top left pixel being one.one and the bottom right three.three + If the values in the matrix don't add up to 1.0, the image could be brightened or darkened. + */ +@property(readwrite, nonatomic) GPUMatrix3x3 convolutionKernel; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImage3x3TextureSamplingFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImage3x3TextureSamplingFilter.h new file mode 100644 index 00000000..5599e156 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImage3x3TextureSamplingFilter.h @@ -0,0 +1,18 @@ +#import "GPUImageFilter.h" + +extern NSString *const kGPUImageNearbyTexelSamplingVertexShaderString; + +@interface GPUImage3x3TextureSamplingFilter : GPUImageFilter +{ + GLint texelWidthUniform, texelHeightUniform; + + CGFloat texelWidth, texelHeight; + BOOL hasOverriddenImageSizeFactor; +} + +// The texel width and height determines how far out to sample from this texel. By default, this is the normalized width of a pixel, but this can be overridden for different effects. +@property(readwrite, nonatomic) CGFloat texelWidth; +@property(readwrite, nonatomic) CGFloat texelHeight; + + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageAVCamera.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageAVCamera.h new file mode 100755 index 00000000..54c1a2f7 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageAVCamera.h @@ -0,0 +1,132 @@ +#import +#import +#import +#import "GPUImageContext.h" +#import "GPUImageOutput.h" + +//Delegate Protocal for Face Detection. +@protocol GPUImageVideoCameraDelegate + +@optional +- (void)willOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer; +@end + + +/** + A GPUImageOutput that provides frames from either camera +*/ +@interface GPUImageAVCamera : GPUImageOutput +{ + NSUInteger numberOfFramesCaptured; + CGFloat totalFrameTimeDuringCapture; + + AVCaptureSession *_captureSession; + AVCaptureDevice *_inputCamera; + AVCaptureDevice *_microphone; + AVCaptureDeviceInput *videoInput; + AVCaptureVideoDataOutput *videoOutput; + + BOOL capturePaused; + GPUImageRotationMode outputRotation; + dispatch_semaphore_t frameRenderingSemaphore; + + BOOL captureAsYUV; + GLuint luminanceTexture, chrominanceTexture; + + __unsafe_unretained id _delegate; +} + +/// The AVCaptureSession used to capture from the camera +@property(readonly, retain, nonatomic) AVCaptureSession *captureSession; + +/// This enables the capture session preset to be changed on the fly +@property (readwrite, nonatomic, copy) NSString *captureSessionPreset; + +/// This sets the frame rate of the camera (iOS 5 and above only) +/** + Setting this to 0 or below will set the frame rate back to the default setting for a particular preset. + */ +@property (readwrite) NSInteger frameRate; + +/// Easy way to tell if front-facing camera is present on device +@property (readonly, getter = isFrontFacingCameraPresent) BOOL frontFacingCameraPresent; + +/// This enables the benchmarking mode, which logs out instantaneous and average frame times to the console +@property(readwrite, nonatomic) BOOL runBenchmark; + +/// Use this property to manage camera settings. Focus point, exposure point, etc. +@property(readonly) AVCaptureDevice *inputCamera; + +/// These properties determine whether or not the two camera orientations should be mirrored. By default, both are NO. +@property(readwrite, nonatomic) BOOL horizontallyMirrorFrontFacingCamera, horizontallyMirrorRearFacingCamera; + +@property(nonatomic, assign) id delegate; + +/// @name Initialization and teardown + ++ (NSArray *)connectedCameraDevices; + +/** Begin a capture session + + See AVCaptureSession for acceptable values + + @param sessionPreset Session preset to use + @param cameraPosition Camera to capture from + */ +- (id)initWithDeviceUniqueID:(NSString *)deviceUniqueID; +- (id)initWithSessionPreset:(NSString *)sessionPreset deviceUniqueID:(NSString *)deviceUniqueID; +- (id)initWithSessionPreset:(NSString *)sessionPreset cameraDevice:(AVCaptureDevice *)cameraDevice; + +/** Tear down the capture session + */ +- (void)removeInputsAndOutputs; + +/// @name Manage the camera video stream + +/** Start camera capturing + */ +- (void)startCameraCapture; + +/** Stop camera capturing + */ +- (void)stopCameraCapture; + +/** Pause camera capturing + */ +- (void)pauseCameraCapture; + +/** Resume camera capturing + */ +- (void)resumeCameraCapture; + +/** Process a video sample + @param sampleBuffer Buffer to process + */ +- (void)processVideoSampleBuffer:(CMSampleBufferRef)sampleBuffer; + +/** Process an audio sample + @param sampleBuffer Buffer to process + */ +- (void)processAudioSampleBuffer:(CMSampleBufferRef)sampleBuffer; + +/** Get the position (front, rear) of the source camera + */ +- (AVCaptureDevicePosition)cameraPosition; + +/** Get the AVCaptureConnection of the source camera + */ +- (AVCaptureConnection *)videoCaptureConnection; + +/** This flips between the front and rear cameras + */ +- (void)rotateCamera; + +/// @name Benchmarking + +/** When benchmarking is enabled, this will keep a running average of the time from uploading, processing, and final recording or display + */ +- (CGFloat)averageFrameDurationDuringCapture; + +- (void)printSupportedPixelFormats; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageAdaptiveThresholdFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageAdaptiveThresholdFilter.h new file mode 100755 index 00000000..32785560 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageAdaptiveThresholdFilter.h @@ -0,0 +1,9 @@ +#import "GPUImageFilterGroup.h" + +@interface GPUImageAdaptiveThresholdFilter : GPUImageFilterGroup + +/** A multiplier for the background averaging blur radius in pixels, with a default of 4 + */ +@property(readwrite, nonatomic) CGFloat blurRadiusInPixels; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageAddBlendFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageAddBlendFilter.h new file mode 100644 index 00000000..b14c60c6 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageAddBlendFilter.h @@ -0,0 +1,5 @@ +#import "GPUImageTwoInputFilter.h" + +@interface GPUImageAddBlendFilter : GPUImageTwoInputFilter + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageAlphaBlendFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageAlphaBlendFilter.h new file mode 100755 index 00000000..c4d75759 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageAlphaBlendFilter.h @@ -0,0 +1,11 @@ +#import "GPUImageTwoInputFilter.h" + +@interface GPUImageAlphaBlendFilter : GPUImageTwoInputFilter +{ + GLint mixUniform; +} + +// Mix ranges from 0.0 (only image 1) to 1.0 (only image 2), with 1.0 as the normal level +@property(readwrite, nonatomic) CGFloat mix; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageAmatorkaFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageAmatorkaFilter.h new file mode 100755 index 00000000..1dbe096d --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageAmatorkaFilter.h @@ -0,0 +1,17 @@ +#import "GPUImageFilterGroup.h" + +@class GPUImagePicture; + +/** A photo filter based on Photoshop action by Amatorka + http://amatorka.deviantart.com/art/Amatorka-Action-2-121069631 + */ + +// Note: If you want to use this effect you have to add lookup_amatorka.png +// from Resources folder to your application bundle. + +@interface GPUImageAmatorkaFilter : GPUImageFilterGroup +{ + GPUImagePicture *lookupImageSource; +} + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageAverageColor.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageAverageColor.h new file mode 100644 index 00000000..e3d957d0 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageAverageColor.h @@ -0,0 +1,20 @@ +#import "GPUImageFilter.h" + +extern NSString *const kGPUImageColorAveragingVertexShaderString; + +@interface GPUImageAverageColor : GPUImageFilter +{ + GLint texelWidthUniform, texelHeightUniform; + + NSUInteger numberOfStages; + + GLubyte *rawImagePixels; + CGSize finalStageSize; +} + +// This block is called on the completion of color averaging for a frame +@property(nonatomic, copy) void(^colorAverageProcessingFinishedBlock)(CGFloat redComponent, CGFloat greenComponent, CGFloat blueComponent, CGFloat alphaComponent, CMTime frameTime); + +- (void)extractAverageColorAtFrameTime:(CMTime)frameTime; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageAverageLuminanceThresholdFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageAverageLuminanceThresholdFilter.h new file mode 100644 index 00000000..7f1ae464 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageAverageLuminanceThresholdFilter.h @@ -0,0 +1,8 @@ +#import "GPUImageFilterGroup.h" + +@interface GPUImageAverageLuminanceThresholdFilter : GPUImageFilterGroup + +// This is multiplied by the continually calculated average image luminosity to arrive at the final threshold. Default is 1.0. +@property(readwrite, nonatomic) CGFloat thresholdMultiplier; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageBilateralFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageBilateralFilter.h new file mode 100644 index 00000000..6b736ccf --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageBilateralFilter.h @@ -0,0 +1,10 @@ +#import "GPUImageGaussianBlurFilter.h" + +@interface GPUImageBilateralFilter : GPUImageGaussianBlurFilter +{ + CGFloat firstDistanceNormalizationFactorUniform; + CGFloat secondDistanceNormalizationFactorUniform; +} +// A normalization factor for the distance between central color and sample color. +@property(nonatomic, readwrite) CGFloat distanceNormalizationFactor; +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageBoxBlurFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageBoxBlurFilter.h new file mode 100755 index 00000000..3fd880bf --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageBoxBlurFilter.h @@ -0,0 +1,7 @@ +#import "GPUImageGaussianBlurFilter.h" + +/** A hardware-accelerated box blur of an image + */ +@interface GPUImageBoxBlurFilter : GPUImageGaussianBlurFilter + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageBrightnessFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageBrightnessFilter.h new file mode 100755 index 00000000..046473b9 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageBrightnessFilter.h @@ -0,0 +1,11 @@ +#import "GPUImageFilter.h" + +@interface GPUImageBrightnessFilter : GPUImageFilter +{ + GLint brightnessUniform; +} + +// Brightness ranges from -1.0 to 1.0, with 0.0 as the normal level +@property(readwrite, nonatomic) CGFloat brightness; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageBuffer.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageBuffer.h new file mode 100644 index 00000000..caf09c8d --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageBuffer.h @@ -0,0 +1,10 @@ +#import "GPUImageFilter.h" + +@interface GPUImageBuffer : GPUImageFilter +{ + NSMutableArray *bufferedFramebuffers; +} + +@property(readwrite, nonatomic) NSUInteger bufferSize; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageBulgeDistortionFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageBulgeDistortionFilter.h new file mode 100755 index 00000000..d416e536 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageBulgeDistortionFilter.h @@ -0,0 +1,16 @@ +#import "GPUImageFilter.h" + +/// Creates a bulge distortion on the image +@interface GPUImageBulgeDistortionFilter : GPUImageFilter +{ + GLint aspectRatioUniform, radiusUniform, centerUniform, scaleUniform; +} + +/// The center about which to apply the distortion, with a default of (0.5, 0.5) +@property(readwrite, nonatomic) CGPoint center; +/// The radius of the distortion, ranging from 0.0 to 1.0, with a default of 0.25 +@property(readwrite, nonatomic) CGFloat radius; +/// The amount of distortion to apply, from -1.0 to 1.0, with a default of 0.5 +@property(readwrite, nonatomic) CGFloat scale; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageCGAColorspaceFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageCGAColorspaceFilter.h new file mode 100755 index 00000000..4f97804b --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageCGAColorspaceFilter.h @@ -0,0 +1,5 @@ +#import "GPUImageFilter.h" + +@interface GPUImageCGAColorspaceFilter : GPUImageFilter + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageCannyEdgeDetectionFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageCannyEdgeDetectionFilter.h new file mode 100755 index 00000000..e01a6433 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageCannyEdgeDetectionFilter.h @@ -0,0 +1,62 @@ +#import "GPUImageFilterGroup.h" + +@class GPUImageGrayscaleFilter; +@class GPUImageSingleComponentGaussianBlurFilter; +@class GPUimageDirectionalSobelEdgeDetectionFilter; +@class GPUImageDirectionalNonMaximumSuppressionFilter; +@class GPUImageWeakPixelInclusionFilter; + +/** This applies the edge detection process described by John Canny in + + Canny, J., A Computational Approach To Edge Detection, IEEE Trans. Pattern Analysis and Machine Intelligence, 8(6):679–698, 1986. + + and implemented in OpenGL ES by + + A. Ensor, S. Hall. GPU-based Image Analysis on Mobile Devices. Proceedings of Image and Vision Computing New Zealand 2011. + + It starts with a conversion to luminance, followed by an accelerated 9-hit Gaussian blur. A Sobel operator is applied to obtain the overall + gradient strength in the blurred image, as well as the direction (in texture sampling steps) of the gradient. A non-maximum suppression filter + acts along the direction of the gradient, highlighting strong edges that pass the threshold and completely removing those that fail the lower + threshold. Finally, pixels from in-between these thresholds are either included in edges or rejected based on neighboring pixels. + */ +@interface GPUImageCannyEdgeDetectionFilter : GPUImageFilterGroup +{ + GPUImageGrayscaleFilter *luminanceFilter; + GPUImageSingleComponentGaussianBlurFilter *blurFilter; + GPUimageDirectionalSobelEdgeDetectionFilter *edgeDetectionFilter; + GPUImageDirectionalNonMaximumSuppressionFilter *nonMaximumSuppressionFilter; + GPUImageWeakPixelInclusionFilter *weakPixelInclusionFilter; +} + +/** The image width and height factors tweak the appearance of the edges. + + These parameters affect the visibility of the detected edges + + By default, they match the inverse of the filter size in pixels + */ +@property(readwrite, nonatomic) CGFloat texelWidth; +/** The image width and height factors tweak the appearance of the edges. + + These parameters affect the visibility of the detected edges + + By default, they match the inverse of the filter size in pixels + */ +@property(readwrite, nonatomic) CGFloat texelHeight; + +/** The underlying blur radius for the Gaussian blur. Default is 2.0. + */ +@property (readwrite, nonatomic) CGFloat blurRadiusInPixels; + +/** The underlying blur texel spacing multiplier. Default is 1.0. + */ +@property (readwrite, nonatomic) CGFloat blurTexelSpacingMultiplier; + +/** Any edge with a gradient magnitude above this threshold will pass and show up in the final result. + */ +@property(readwrite, nonatomic) CGFloat upperThreshold; + +/** Any edge with a gradient magnitude below this threshold will fail and be removed from the final result. + */ +@property(readwrite, nonatomic) CGFloat lowerThreshold; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageChromaKeyBlendFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageChromaKeyBlendFilter.h new file mode 100755 index 00000000..47f5acbc --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageChromaKeyBlendFilter.h @@ -0,0 +1,32 @@ +#import "GPUImageTwoInputFilter.h" + +/** Selectively replaces a color in the first image with the second image + */ +@interface GPUImageChromaKeyBlendFilter : GPUImageTwoInputFilter +{ + GLint colorToReplaceUniform, thresholdSensitivityUniform, smoothingUniform; +} + +/** The threshold sensitivity controls how similar pixels need to be colored to be replaced + + The default value is 0.3 + */ +@property(readwrite, nonatomic) GLfloat thresholdSensitivity; + +/** The degree of smoothing controls how gradually similar colors are replaced in the image + + The default value is 0.1 + */ +@property(readwrite, nonatomic) GLfloat smoothing; + +/** The color to be replaced is specified using individual red, green, and blue components (normalized to 1.0). + + The default is green: (0.0, 1.0, 0.0). + + @param redComponent Red component of color to be replaced + @param greenComponent Green component of color to be replaced + @param blueComponent Blue component of color to be replaced + */ +- (void)setColorToReplaceRed:(GLfloat)redComponent green:(GLfloat)greenComponent blue:(GLfloat)blueComponent; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageChromaKeyFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageChromaKeyFilter.h new file mode 100644 index 00000000..a3d073c8 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageChromaKeyFilter.h @@ -0,0 +1,30 @@ +#import "GPUImageFilter.h" + +@interface GPUImageChromaKeyFilter : GPUImageFilter +{ + GLint colorToReplaceUniform, thresholdSensitivityUniform, smoothingUniform; +} + +/** The threshold sensitivity controls how similar pixels need to be colored to be replaced + + The default value is 0.3 + */ +@property(readwrite, nonatomic) GLfloat thresholdSensitivity; + +/** The degree of smoothing controls how gradually similar colors are replaced in the image + + The default value is 0.1 + */ +@property(readwrite, nonatomic) GLfloat smoothing; + +/** The color to be replaced is specified using individual red, green, and blue components (normalized to 1.0). + + The default is green: (0.0, 1.0, 0.0). + + @param redComponent Red component of color to be replaced + @param greenComponent Green component of color to be replaced + @param blueComponent Blue component of color to be replaced + */ +- (void)setColorToReplaceRed:(GLfloat)redComponent green:(GLfloat)greenComponent blue:(GLfloat)blueComponent; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageClosingFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageClosingFilter.h new file mode 100644 index 00000000..61e34c41 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageClosingFilter.h @@ -0,0 +1,19 @@ +#import "GPUImageFilterGroup.h" + +@class GPUImageErosionFilter; +@class GPUImageDilationFilter; + +// A filter that first performs a dilation on the red channel of an image, followed by an erosion of the same radius. +// This helps to filter out smaller dark elements. + +@interface GPUImageClosingFilter : GPUImageFilterGroup +{ + GPUImageErosionFilter *erosionFilter; + GPUImageDilationFilter *dilationFilter; +} + +@property(readwrite, nonatomic) CGFloat verticalTexelSpacing, horizontalTexelSpacing; + +- (id)initWithRadius:(NSUInteger)radius; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageColorBlendFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageColorBlendFilter.h new file mode 100644 index 00000000..302a16c6 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageColorBlendFilter.h @@ -0,0 +1,5 @@ +#import "GPUImageTwoInputFilter.h" + +@interface GPUImageColorBlendFilter : GPUImageTwoInputFilter + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageColorBurnBlendFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageColorBurnBlendFilter.h new file mode 100755 index 00000000..50ebb3f4 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageColorBurnBlendFilter.h @@ -0,0 +1,9 @@ +#import "GPUImageTwoInputFilter.h" + +/** Applies a color burn blend of two images + */ +@interface GPUImageColorBurnBlendFilter : GPUImageTwoInputFilter +{ +} + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageColorDodgeBlendFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageColorDodgeBlendFilter.h new file mode 100755 index 00000000..0f541c42 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageColorDodgeBlendFilter.h @@ -0,0 +1,9 @@ +#import "GPUImageTwoInputFilter.h" + +/** Applies a color dodge blend of two images + */ +@interface GPUImageColorDodgeBlendFilter : GPUImageTwoInputFilter +{ +} + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageColorInvertFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageColorInvertFilter.h new file mode 100755 index 00000000..aaeec438 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageColorInvertFilter.h @@ -0,0 +1,7 @@ +#import "GPUImageFilter.h" + +@interface GPUImageColorInvertFilter : GPUImageFilter +{ +} + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageColorMatrixFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageColorMatrixFilter.h new file mode 100755 index 00000000..75887276 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageColorMatrixFilter.h @@ -0,0 +1,19 @@ +#import "GPUImageFilter.h" + +/** Transforms the colors of an image by applying a matrix to them + */ +@interface GPUImageColorMatrixFilter : GPUImageFilter +{ + GLint colorMatrixUniform; + GLint intensityUniform; +} + +/** A 4x4 matrix used to transform each color in an image + */ +@property(readwrite, nonatomic) GPUMatrix4x4 colorMatrix; + +/** The degree to which the new transformed color replaces the original color for each pixel + */ +@property(readwrite, nonatomic) CGFloat intensity; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageColorPackingFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageColorPackingFilter.h new file mode 100644 index 00000000..c2edca51 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageColorPackingFilter.h @@ -0,0 +1,10 @@ +#import "GPUImageFilter.h" + +@interface GPUImageColorPackingFilter : GPUImageFilter +{ + GLint texelWidthUniform, texelHeightUniform; + + CGFloat texelWidth, texelHeight; +} + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageContext.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageContext.h new file mode 100755 index 00000000..356b288a --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageContext.h @@ -0,0 +1,54 @@ +#import +#import +#import +#import "GLProgram.h" +#import "GPUImageFramebuffer.h" +#import "GPUImageFramebufferCache.h" + +#define GPUImageRotationSwapsWidthAndHeight(rotation) (((rotation) == kGPUImageRotateLeft) || ((rotation) == kGPUImageRotateRight) || ((rotation) == kGPUImageRotateRightFlipVertical) ) + +typedef enum { kGPUImageNoRotation, kGPUImageRotateLeft, kGPUImageRotateRight, kGPUImageFlipVertical, kGPUImageFlipHorizonal, kGPUImageRotateRightFlipVertical, kGPUImageRotateRightFlipHorizontal, kGPUImageRotate180 } GPUImageRotationMode; + +@interface GPUImageContext : NSObject + +@property(readonly, nonatomic) dispatch_queue_t contextQueue; +@property(readwrite, retain, nonatomic) GLProgram *currentShaderProgram; +@property(readonly, retain, nonatomic) NSOpenGLContext *context; +@property(readonly) GPUImageFramebufferCache *framebufferCache; + ++ (void *)contextKey; ++ (GPUImageContext *)sharedImageProcessingContext; ++ (dispatch_queue_t)sharedContextQueue; ++ (GPUImageFramebufferCache *)sharedFramebufferCache; ++ (void)useImageProcessingContext; ++ (void)setActiveShaderProgram:(GLProgram *)shaderProgram; ++ (GLint)maximumTextureSizeForThisDevice; ++ (GLint)maximumTextureUnitsForThisDevice; ++ (BOOL)deviceSupportsOpenGLESExtension:(NSString *)extension; ++ (BOOL)deviceSupportsRedTextures; ++ (BOOL)deviceSupportsFramebufferReads; ++ (CGSize)sizeThatFitsWithinATextureForSize:(CGSize)inputSize; + +- (void)presentBufferForDisplay; +- (GLProgram *)programForVertexShaderString:(NSString *)vertexShaderString fragmentShaderString:(NSString *)fragmentShaderString; + +- (void)useSharegroup:(CGLShareGroupObj *)sharegroup; + +// Manage fast texture upload ++ (BOOL)supportsFastTextureUpload; + +@end + +@protocol GPUImageInput +- (void)newFrameReadyAtTime:(CMTime)frameTime atIndex:(NSInteger)textureIndex; +- (void)setInputFramebuffer:(GPUImageFramebuffer *)newInputFramebuffer atIndex:(NSInteger)textureIndex; +- (NSInteger)nextAvailableTextureIndex; +- (void)setInputSize:(CGSize)newSize atIndex:(NSInteger)textureIndex; +- (void)setInputRotation:(GPUImageRotationMode)newInputRotation atIndex:(NSInteger)textureIndex; +- (CGSize)maximumOutputSize; +- (void)endProcessing; +- (BOOL)shouldIgnoreUpdatesToThisTarget; +- (BOOL)enabled; +- (BOOL)wantsMonochromeInput; +- (void)setCurrentlyReceivingMonochromeInput:(BOOL)newValue; +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageContrastFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageContrastFilter.h new file mode 100755 index 00000000..e09e6dc4 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageContrastFilter.h @@ -0,0 +1,14 @@ +#import "GPUImageFilter.h" + +/** Adjusts the contrast of the image + */ +@interface GPUImageContrastFilter : GPUImageFilter +{ + GLint contrastUniform; +} + +/** Contrast ranges from 0.0 to 4.0 (max contrast), with 1.0 as the normal level + */ +@property(readwrite, nonatomic) CGFloat contrast; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageCropFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageCropFilter.h new file mode 100755 index 00000000..641fb7bf --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageCropFilter.h @@ -0,0 +1,14 @@ +#import "GPUImageFilter.h" + +@interface GPUImageCropFilter : GPUImageFilter +{ + GLfloat cropTextureCoordinates[8]; +} + +// The crop region is the rectangle within the image to crop. It is normalized to a coordinate space from 0.0 to 1.0, with 0.0, 0.0 being the upper left corner of the image +@property(readwrite, nonatomic) CGRect cropRegion; + +// Initialization and teardown +- (id)initWithCropRegion:(CGRect)newCropRegion; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageCrosshairGenerator.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageCrosshairGenerator.h new file mode 100644 index 00000000..569774f5 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageCrosshairGenerator.h @@ -0,0 +1,17 @@ +#import "GPUImageFilter.h" + +@interface GPUImageCrosshairGenerator : GPUImageFilter +{ + GLint crosshairWidthUniform, crosshairColorUniform; +} + +// The width of the displayed crosshairs, in pixels. Currently this only works well for odd widths. The default is 5. +@property(readwrite, nonatomic) CGFloat crosshairWidth; + +// The color of the crosshairs is specified using individual red, green, and blue components (normalized to 1.0). The default is green: (0.0, 1.0, 0.0). +- (void)setCrosshairColorRed:(GLfloat)redComponent green:(GLfloat)greenComponent blue:(GLfloat)blueComponent; + +// Rendering +- (void)renderCrosshairsFromArray:(GLfloat *)crosshairCoordinates count:(NSUInteger)numberOfCrosshairs frameTime:(CMTime)frameTime; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageCrosshatchFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageCrosshatchFilter.h new file mode 100755 index 00000000..dab18967 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageCrosshatchFilter.h @@ -0,0 +1,13 @@ +#import "GPUImageFilter.h" + +@interface GPUImageCrosshatchFilter : GPUImageFilter +{ + GLint crossHatchSpacingUniform, lineWidthUniform; +} +// The fractional width of the image to use as the spacing for the crosshatch. The default is 0.03. +@property(readwrite, nonatomic) CGFloat crossHatchSpacing; + +// A relative width for the crosshatch lines. The default is 0.003. +@property(readwrite, nonatomic) CGFloat lineWidth; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageDarkenBlendFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageDarkenBlendFilter.h new file mode 100755 index 00000000..5dfe3405 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageDarkenBlendFilter.h @@ -0,0 +1,7 @@ +#import "GPUImageTwoInputFilter.h" + +@interface GPUImageDarkenBlendFilter : GPUImageTwoInputFilter +{ +} + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageDifferenceBlendFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageDifferenceBlendFilter.h new file mode 100755 index 00000000..7c7dfc23 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageDifferenceBlendFilter.h @@ -0,0 +1,7 @@ +#import "GPUImageTwoInputFilter.h" + +@interface GPUImageDifferenceBlendFilter : GPUImageTwoInputFilter +{ +} + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageDilationFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageDilationFilter.h new file mode 100644 index 00000000..59423a37 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageDilationFilter.h @@ -0,0 +1,16 @@ +#import "GPUImageTwoPassTextureSamplingFilter.h" + +// For each pixel, this sets it to the maximum value of the red channel in a rectangular neighborhood extending out dilationRadius pixels from the center. +// This extends out bright features, and is most commonly used with black-and-white thresholded images. + +extern NSString *const kGPUImageDilationRadiusOneVertexShaderString; +extern NSString *const kGPUImageDilationRadiusTwoVertexShaderString; +extern NSString *const kGPUImageDilationRadiusThreeVertexShaderString; +extern NSString *const kGPUImageDilationRadiusFourVertexShaderString; + +@interface GPUImageDilationFilter : GPUImageTwoPassTextureSamplingFilter + +// Acceptable values for dilationRadius, which sets the distance in pixels to sample out from the center, are 1, 2, 3, and 4. +- (id)initWithRadius:(NSUInteger)dilationRadius; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageDirectionalNonMaximumSuppressionFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageDirectionalNonMaximumSuppressionFilter.h new file mode 100644 index 00000000..fdffb9fb --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageDirectionalNonMaximumSuppressionFilter.h @@ -0,0 +1,19 @@ +#import "GPUImageFilter.h" + +@interface GPUImageDirectionalNonMaximumSuppressionFilter : GPUImageFilter +{ + GLint texelWidthUniform, texelHeightUniform; + GLint upperThresholdUniform, lowerThresholdUniform; + + BOOL hasOverriddenImageSizeFactor; +} + +// The texel width and height determines how far out to sample from this texel. By default, this is the normalized width of a pixel, but this can be overridden for different effects. +@property(readwrite, nonatomic) CGFloat texelWidth; +@property(readwrite, nonatomic) CGFloat texelHeight; + +// These thresholds set cutoffs for the intensities that definitely get registered (upper threshold) and those that definitely don't (lower threshold) +@property(readwrite, nonatomic) CGFloat upperThreshold; +@property(readwrite, nonatomic) CGFloat lowerThreshold; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageDissolveBlendFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageDissolveBlendFilter.h new file mode 100755 index 00000000..b4e5720a --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageDissolveBlendFilter.h @@ -0,0 +1,11 @@ +#import "GPUImageTwoInputFilter.h" + +@interface GPUImageDissolveBlendFilter : GPUImageTwoInputFilter +{ + GLint mixUniform; +} + +// Mix ranges from 0.0 (only image 1) to 1.0 (only image 2), with 0.5 (half of either) as the normal level +@property(readwrite, nonatomic) CGFloat mix; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageDivideBlendFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageDivideBlendFilter.h new file mode 100644 index 00000000..ad798e29 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageDivideBlendFilter.h @@ -0,0 +1,5 @@ +#import "GPUImageTwoInputFilter.h" + +@interface GPUImageDivideBlendFilter : GPUImageTwoInputFilter + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageEmbossFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageEmbossFilter.h new file mode 100755 index 00000000..dbd21e82 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageEmbossFilter.h @@ -0,0 +1,8 @@ +#import "GPUImage3x3ConvolutionFilter.h" + +@interface GPUImageEmbossFilter : GPUImage3x3ConvolutionFilter + +// The strength of the embossing, from 0.0 to 4.0, with 1.0 as the normal level +@property(readwrite, nonatomic) CGFloat intensity; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageErosionFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageErosionFilter.h new file mode 100644 index 00000000..b311a265 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageErosionFilter.h @@ -0,0 +1,11 @@ +#import "GPUImageTwoPassTextureSamplingFilter.h" + +// For each pixel, this sets it to the minimum value of the red channel in a rectangular neighborhood extending out dilationRadius pixels from the center. +// This extends out dark features, and is most commonly used with black-and-white thresholded images. + +@interface GPUImageErosionFilter : GPUImageTwoPassTextureSamplingFilter + +// Acceptable values for erosionRadius, which sets the distance in pixels to sample out from the center, are 1, 2, 3, and 4. +- (id)initWithRadius:(NSUInteger)erosionRadius; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageExclusionBlendFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageExclusionBlendFilter.h new file mode 100755 index 00000000..f7c83f57 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageExclusionBlendFilter.h @@ -0,0 +1,7 @@ +#import "GPUImageTwoInputFilter.h" + +@interface GPUImageExclusionBlendFilter : GPUImageTwoInputFilter +{ +} + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageExposureFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageExposureFilter.h new file mode 100755 index 00000000..886a052f --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageExposureFilter.h @@ -0,0 +1,11 @@ +#import "GPUImageFilter.h" + +@interface GPUImageExposureFilter : GPUImageFilter +{ + GLint exposureUniform; +} + +// Exposure ranges from -10.0 to 10.0, with 0.0 as the normal level +@property(readwrite, nonatomic) CGFloat exposure; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageFalseColorFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageFalseColorFilter.h new file mode 100644 index 00000000..cb0b82f7 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageFalseColorFilter.h @@ -0,0 +1,15 @@ +#import "GPUImageFilter.h" + +@interface GPUImageFalseColorFilter : GPUImageFilter +{ + GLint firstColorUniform, secondColorUniform; +} + +// The first and second colors specify what colors replace the dark and light areas of the image, respectively. The defaults are (0.0, 0.0, 0.5) amd (1.0, 0.0, 0.0). +@property(readwrite, nonatomic) GPUVector4 firstColor; +@property(readwrite, nonatomic) GPUVector4 secondColor; + +- (void)setFirstColorRed:(GLfloat)redComponent green:(GLfloat)greenComponent blue:(GLfloat)blueComponent; +- (void)setSecondColorRed:(GLfloat)redComponent green:(GLfloat)greenComponent blue:(GLfloat)blueComponent; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageFilter.h new file mode 100755 index 00000000..0171aa80 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageFilter.h @@ -0,0 +1,134 @@ +#import "GPUImageOutput.h" + +#define STRINGIZE(x) #x +#define STRINGIZE2(x) STRINGIZE(x) +#define SHADER_STRING(text) @ STRINGIZE2(text) + +#define GPUImageHashIdentifier # +#define GPUImageWrappedLabel(x) x +#define GPUImageEscapedHashIdentifier(a) GPUImageWrappedLabel(GPUImageHashIdentifier)a + +extern NSString *const kGPUImageVertexShaderString; +extern NSString *const kGPUImagePassthroughFragmentShaderString; + +struct GPUVector4 { + GLfloat one; + GLfloat two; + GLfloat three; + GLfloat four; +}; +typedef struct GPUVector4 GPUVector4; + +struct GPUVector3 { + GLfloat one; + GLfloat two; + GLfloat three; +}; +typedef struct GPUVector3 GPUVector3; + +struct GPUMatrix4x4 { + GPUVector4 one; + GPUVector4 two; + GPUVector4 three; + GPUVector4 four; +}; +typedef struct GPUMatrix4x4 GPUMatrix4x4; + +struct GPUMatrix3x3 { + GPUVector3 one; + GPUVector3 two; + GPUVector3 three; +}; +typedef struct GPUMatrix3x3 GPUMatrix3x3; + +/** GPUImage's base filter class + + Filters and other subsequent elements in the chain conform to the GPUImageInput protocol, which lets them take in the supplied or processed texture from the previous link in the chain and do something with it. Objects one step further down the chain are considered targets, and processing can be branched by adding multiple targets to a single output or filter. + */ +@interface GPUImageFilter : GPUImageOutput +{ + GPUImageFramebuffer *firstInputFramebuffer; + + GLProgram *filterProgram; + GLint filterPositionAttribute, filterTextureCoordinateAttribute; + GLint filterInputTextureUniform; + GLfloat backgroundColorRed, backgroundColorGreen, backgroundColorBlue, backgroundColorAlpha; + + BOOL isEndProcessing; + + CGSize currentFilterSize; + GPUImageRotationMode inputRotation; + + BOOL currentlyReceivingMonochromeInput; + + NSMutableDictionary *uniformStateRestorationBlocks; + dispatch_semaphore_t imageCaptureSemaphore; +} + +@property(readonly) CVPixelBufferRef renderTarget; +@property(readwrite, nonatomic) BOOL preventRendering; +@property(readwrite, nonatomic) BOOL currentlyReceivingMonochromeInput; + +/// @name Initialization and teardown + +/** + Initialize with vertex and fragment shaders + + You make take advantage of the SHADER_STRING macro to write your shaders in-line. + @param vertexShaderString Source code of the vertex shader to use + @param fragmentShaderString Source code of the fragment shader to use + */ +- (id)initWithVertexShaderFromString:(NSString *)vertexShaderString fragmentShaderFromString:(NSString *)fragmentShaderString; + +/** + Initialize with a fragment shader + + You may take advantage of the SHADER_STRING macro to write your shader in-line. + @param fragmentShaderString Source code of fragment shader to use + */ +- (id)initWithFragmentShaderFromString:(NSString *)fragmentShaderString; +/** + Initialize with a fragment shader + @param fragmentShaderFilename Filename of fragment shader to load + */ +- (id)initWithFragmentShaderFromFile:(NSString *)fragmentShaderFilename; +- (void)initializeAttributes; +- (void)setupFilterForSize:(CGSize)filterFrameSize; +- (CGSize)rotatedSize:(CGSize)sizeToRotate forIndex:(NSInteger)textureIndex; +- (CGPoint)rotatedPoint:(CGPoint)pointToRotate forRotation:(GPUImageRotationMode)rotation; + +/// @name Managing the display FBOs +/** Size of the frame buffer object + */ +- (CGSize)sizeOfFBO; + +/// @name Rendering ++ (const GLfloat *)textureCoordinatesForRotation:(GPUImageRotationMode)rotationMode; +- (void)renderToTextureWithVertices:(const GLfloat *)vertices textureCoordinates:(const GLfloat *)textureCoordinates; +- (void)informTargetsAboutNewFrameAtTime:(CMTime)frameTime; +- (CGSize)outputFrameSize; + +/// @name Input parameters +- (void)setBackgroundColorRed:(GLfloat)redComponent green:(GLfloat)greenComponent blue:(GLfloat)blueComponent alpha:(GLfloat)alphaComponent; +- (void)setInteger:(GLint)newInteger forUniformName:(NSString *)uniformName; +- (void)setFloat:(GLfloat)newFloat forUniformName:(NSString *)uniformName; +- (void)setSize:(CGSize)newSize forUniformName:(NSString *)uniformName; +- (void)setPoint:(CGPoint)newPoint forUniformName:(NSString *)uniformName; +- (void)setFloatVec3:(GPUVector3)newVec3 forUniformName:(NSString *)uniformName; +- (void)setFloatVec4:(GPUVector4)newVec4 forUniform:(NSString *)uniformName; +- (void)setFloatArray:(GLfloat *)array length:(GLsizei)count forUniform:(NSString*)uniformName; + +- (void)setMatrix3f:(GPUMatrix3x3)matrix forUniform:(GLint)uniform program:(GLProgram *)shaderProgram; +- (void)setMatrix4f:(GPUMatrix4x4)matrix forUniform:(GLint)uniform program:(GLProgram *)shaderProgram; +- (void)setFloat:(GLfloat)floatValue forUniform:(GLint)uniform program:(GLProgram *)shaderProgram; +- (void)setPoint:(CGPoint)pointValue forUniform:(GLint)uniform program:(GLProgram *)shaderProgram; +- (void)setSize:(CGSize)sizeValue forUniform:(GLint)uniform program:(GLProgram *)shaderProgram; +- (void)setVec3:(GPUVector3)vectorValue forUniform:(GLint)uniform program:(GLProgram *)shaderProgram; +- (void)setVec4:(GPUVector4)vectorValue forUniform:(GLint)uniform program:(GLProgram *)shaderProgram; +- (void)setFloatArray:(GLfloat *)arrayValue length:(GLsizei)arrayLength forUniform:(GLint)uniform program:(GLProgram *)shaderProgram; +- (void)setInteger:(GLint)intValue forUniform:(GLint)uniform program:(GLProgram *)shaderProgram; + +- (void)setAndExecuteUniformStateCallbackAtIndex:(GLint)uniform forProgram:(GLProgram *)shaderProgram toBlock:(dispatch_block_t)uniformStateBlock; +- (void)setUniformsForProgramAtIndex:(NSUInteger)programIndex; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageFilterGroup.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageFilterGroup.h new file mode 100755 index 00000000..6817cdf0 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageFilterGroup.h @@ -0,0 +1,19 @@ +#import "GPUImageOutput.h" +#import "GPUImageFilter.h" + +@interface GPUImageFilterGroup : GPUImageOutput +{ + NSMutableArray *filters; + BOOL isEndProcessing; +} + +@property(readwrite, nonatomic, strong) GPUImageOutput *terminalFilter; +@property(readwrite, nonatomic, strong) NSArray *initialFilters; +@property(readwrite, nonatomic, strong) GPUImageOutput *inputFilterToIgnoreForUpdates; + +// Filter management +- (void)addFilter:(GPUImageOutput *)newFilter; +- (GPUImageOutput *)filterAtIndex:(NSUInteger)filterIndex; +- (NSUInteger)filterCount; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageFramebuffer.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageFramebuffer.h new file mode 100644 index 00000000..5cf20dd3 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageFramebuffer.h @@ -0,0 +1,58 @@ +#import + +#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE +#import +#import +#import +#else +#import +#import +#endif + +#import +#import + + +typedef struct GPUTextureOptions { + GLenum minFilter; + GLenum magFilter; + GLenum wrapS; + GLenum wrapT; + GLenum internalFormat; + GLenum format; + GLenum type; +} GPUTextureOptions; + +@interface GPUImageFramebuffer : NSObject + +@property(readonly) CGSize size; +@property(readonly) GPUTextureOptions textureOptions; +@property(readonly) GLuint texture; +@property(readonly) BOOL missingFramebuffer; + +// Initialization and teardown +- (id)initWithSize:(CGSize)framebufferSize; +- (id)initWithSize:(CGSize)framebufferSize textureOptions:(GPUTextureOptions)fboTextureOptions onlyTexture:(BOOL)onlyGenerateTexture; +- (id)initWithSize:(CGSize)framebufferSize overriddenTexture:(GLuint)inputTexture; + +// Usage +- (void)activateFramebuffer; + +// Reference counting +- (void)lock; +- (void)unlock; +- (void)clearAllLocks; +- (void)disableReferenceCounting; +- (void)enableReferenceCounting; + +// Image capture +- (CGImageRef)newCGImageFromFramebufferContents; +- (void)restoreRenderTarget; + +// Raw data bytes +- (void)lockForReading; +- (void)unlockAfterReading; +- (NSUInteger)bytesPerRow; +- (GLubyte *)byteBuffer; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageFramebufferCache.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageFramebufferCache.h new file mode 100644 index 00000000..e56a3456 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageFramebufferCache.h @@ -0,0 +1,15 @@ +#import +#import +#import "GPUImageFramebuffer.h" + +@interface GPUImageFramebufferCache : NSObject + +// Framebuffer management +- (GPUImageFramebuffer *)fetchFramebufferForSize:(CGSize)framebufferSize textureOptions:(GPUTextureOptions)textureOptions onlyTexture:(BOOL)onlyTexture; +- (GPUImageFramebuffer *)fetchFramebufferForSize:(CGSize)framebufferSize onlyTexture:(BOOL)onlyTexture; +- (void)returnFramebufferToCache:(GPUImageFramebuffer *)framebuffer; +- (void)purgeAllUnassignedFramebuffers; +- (void)addFramebufferToActiveImageCaptureList:(GPUImageFramebuffer *)framebuffer; +- (void)removeFramebufferFromActiveImageCaptureList:(GPUImageFramebuffer *)framebuffer; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageGammaFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageGammaFilter.h new file mode 100755 index 00000000..0521d089 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageGammaFilter.h @@ -0,0 +1,11 @@ +#import "GPUImageFilter.h" + +@interface GPUImageGammaFilter : GPUImageFilter +{ + GLint gammaUniform; +} + +// Gamma ranges from 0.0 to 3.0, with 1.0 as the normal level +@property(readwrite, nonatomic) CGFloat gamma; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageGaussianBlurFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageGaussianBlurFilter.h new file mode 100755 index 00000000..dc2bb785 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageGaussianBlurFilter.h @@ -0,0 +1,36 @@ +#import "GPUImageTwoPassTextureSamplingFilter.h" + +/** A Gaussian blur filter + Interpolated optimization based on Daniel Rákos' work at http://rastergrid.com/blog/2010/09/efficient-gaussian-blur-with-linear-sampling/ + */ + +@interface GPUImageGaussianBlurFilter : GPUImageTwoPassTextureSamplingFilter +{ + BOOL shouldResizeBlurRadiusWithImageSize; + CGFloat _blurRadiusInPixels; +} + +/** A multiplier for the spacing between texels, ranging from 0.0 on up, with a default of 1.0. Adjusting this may slightly increase the blur strength, but will introduce artifacts in the result. + */ +@property (readwrite, nonatomic) CGFloat texelSpacingMultiplier; + +/** A radius in pixels to use for the blur, with a default of 2.0. This adjusts the sigma variable in the Gaussian distribution function. + */ +@property (readwrite, nonatomic) CGFloat blurRadiusInPixels; + +/** Setting these properties will allow the blur radius to scale with the size of the image + */ +@property (readwrite, nonatomic) CGFloat blurRadiusAsFractionOfImageWidth; +@property (readwrite, nonatomic) CGFloat blurRadiusAsFractionOfImageHeight; + +/// The number of times to sequentially blur the incoming image. The more passes, the slower the filter. +@property(readwrite, nonatomic) NSUInteger blurPasses; + ++ (NSString *)vertexShaderForStandardBlurOfRadius:(NSUInteger)blurRadius sigma:(CGFloat)sigma; ++ (NSString *)fragmentShaderForStandardBlurOfRadius:(NSUInteger)blurRadius sigma:(CGFloat)sigma; ++ (NSString *)vertexShaderForOptimizedBlurOfRadius:(NSUInteger)blurRadius sigma:(CGFloat)sigma; ++ (NSString *)fragmentShaderForOptimizedBlurOfRadius:(NSUInteger)blurRadius sigma:(CGFloat)sigma; + +- (void)switchToVertexShader:(NSString *)newVertexShader fragmentShader:(NSString *)newFragmentShader; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageGaussianBlurPositionFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageGaussianBlurPositionFilter.h new file mode 100755 index 00000000..dc88a563 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageGaussianBlurPositionFilter.h @@ -0,0 +1,22 @@ +#import "GPUImageTwoPassTextureSamplingFilter.h" + +/** A more generalized 9x9 Gaussian blur filter + */ +@interface GPUImageGaussianBlurPositionFilter : GPUImageTwoPassTextureSamplingFilter +{ + GLint blurCenterUniform, blurRadiusUniform, aspectRatioUniform; +} + +/** A multiplier for the blur size, ranging from 0.0 on up, with a default of 1.0 + */ +@property (readwrite, nonatomic) CGFloat blurSize; + +/** Center for the blur, defaults to 0.5, 0.5 + */ +@property (readwrite, nonatomic) CGPoint blurCenter; + +/** Radius for the blur, defaults to 1.0 + */ +@property (readwrite, nonatomic) CGFloat blurRadius; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageGaussianSelectiveBlurFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageGaussianSelectiveBlurFilter.h new file mode 100755 index 00000000..02324566 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageGaussianSelectiveBlurFilter.h @@ -0,0 +1,30 @@ +#import "GPUImageFilterGroup.h" + +@class GPUImageGaussianBlurFilter; + +/** A Gaussian blur that preserves focus within a circular region + */ +@interface GPUImageGaussianSelectiveBlurFilter : GPUImageFilterGroup +{ + GPUImageGaussianBlurFilter *blurFilter; + GPUImageFilter *selectiveFocusFilter; + BOOL hasOverriddenAspectRatio; +} + +/** The radius of the circular area being excluded from the blur + */ +@property (readwrite, nonatomic) CGFloat excludeCircleRadius; +/** The center of the circular area being excluded from the blur + */ +@property (readwrite, nonatomic) CGPoint excludeCirclePoint; +/** The size of the area between the blurred portion and the clear circle + */ +@property (readwrite, nonatomic) CGFloat excludeBlurSize; +/** A radius in pixels to use for the blur, with a default of 5.0. This adjusts the sigma variable in the Gaussian distribution function. + */ +@property (readwrite, nonatomic) CGFloat blurRadiusInPixels; +/** The aspect ratio of the image, used to adjust the circularity of the in-focus region. By default, this matches the image aspect ratio, but you can override this value. + */ +@property (readwrite, nonatomic) CGFloat aspectRatio; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageGlassSphereFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageGlassSphereFilter.h new file mode 100644 index 00000000..809a4ee8 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageGlassSphereFilter.h @@ -0,0 +1,5 @@ +#import "GPUImageSphereRefractionFilter.h" + +@interface GPUImageGlassSphereFilter : GPUImageSphereRefractionFilter + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageGrayscaleFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageGrayscaleFilter.h new file mode 100755 index 00000000..2d97f8c3 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageGrayscaleFilter.h @@ -0,0 +1,9 @@ +#import "GPUImageFilter.h" + +extern NSString *const kGPUImageLuminanceFragmentShaderString; + +/** Converts an image to grayscale (a slightly faster implementation of the saturation filter, without the ability to vary the color contribution) + */ +@interface GPUImageGrayscaleFilter : GPUImageFilter + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageHalftoneFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageHalftoneFilter.h new file mode 100644 index 00000000..1860bc97 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageHalftoneFilter.h @@ -0,0 +1,5 @@ +#import "GPUImagePixellateFilter.h" + +@interface GPUImageHalftoneFilter : GPUImagePixellateFilter + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageHardLightBlendFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageHardLightBlendFilter.h new file mode 100755 index 00000000..47d62609 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageHardLightBlendFilter.h @@ -0,0 +1,7 @@ +#import "GPUImageTwoInputFilter.h" + +@interface GPUImageHardLightBlendFilter : GPUImageTwoInputFilter +{ +} + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageHarrisCornerDetectionFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageHarrisCornerDetectionFilter.h new file mode 100755 index 00000000..1492b8b8 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageHarrisCornerDetectionFilter.h @@ -0,0 +1,53 @@ +#import "GPUImageFilterGroup.h" + +@class GPUImageGaussianBlurFilter; +@class GPUImageXYDerivativeFilter; +@class GPUImageGrayscaleFilter; +@class GPUImageGaussianBlurFilter; +@class GPUImageThresholdedNonMaximumSuppressionFilter; +@class GPUImageColorPackingFilter; + +//#define DEBUGFEATUREDETECTION + +/** Harris corner detector + + First pass: reduce to luminance and take the derivative of the luminance texture (GPUImageXYDerivativeFilter) + + Second pass: blur the derivative (GPUImageGaussianBlurFilter) + + Third pass: apply the Harris corner detection calculation + + This is the Harris corner detector, as described in + C. Harris and M. Stephens. A Combined Corner and Edge Detector. Proc. Alvey Vision Conf., Univ. Manchester, pp. 147-151, 1988. + */ +@interface GPUImageHarrisCornerDetectionFilter : GPUImageFilterGroup +{ + GPUImageXYDerivativeFilter *derivativeFilter; + GPUImageGaussianBlurFilter *blurFilter; + GPUImageFilter *harrisCornerDetectionFilter; + GPUImageThresholdedNonMaximumSuppressionFilter *nonMaximumSuppressionFilter; + GPUImageColorPackingFilter *colorPackingFilter; + GLfloat *cornersArray; + GLubyte *rawImagePixels; +} + +/** The radius of the underlying Gaussian blur. The default is 2.0. + */ +@property(readwrite, nonatomic) CGFloat blurRadiusInPixels; + +// This changes the dynamic range of the Harris corner detector by amplifying small cornerness values. Default is 5.0. +@property(readwrite, nonatomic) CGFloat sensitivity; + +// A threshold value at which a point is recognized as being a corner after the non-maximum suppression. Default is 0.20. +@property(readwrite, nonatomic) CGFloat threshold; + +// This block is called on the detection of new corner points, usually on every processed frame. A C array containing normalized coordinates in X, Y pairs is passed in, along with a count of the number of corners detected and the current timestamp of the video frame +@property(nonatomic, copy) void(^cornersDetectedBlock)(GLfloat* cornerArray, NSUInteger cornersDetected, CMTime frameTime); + +// These images are only enabled when built with DEBUGFEATUREDETECTION defined, and are used to examine the intermediate states of the feature detector +@property(nonatomic, readonly, strong) NSMutableArray *intermediateImages; + +// Initialization and teardown +- (id)initWithCornerDetectionFragmentShader:(NSString *)cornerDetectionFragmentShader; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageHazeFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageHazeFilter.h new file mode 100755 index 00000000..eb3fbca6 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageHazeFilter.h @@ -0,0 +1,29 @@ +#import "GPUImageFilter.h" + +/* + * The haze filter can be used to add or remove haze (similar to a UV filter) + * + * @author Alaric Cole + * @creationDate 03/10/12 + * + */ + +/** The haze filter can be used to add or remove haze + + This is similar to a UV filter + */ +@interface GPUImageHazeFilter : GPUImageFilter +{ + GLint distanceUniform; + GLint slopeUniform; +} + +/** Strength of the color applied. Default 0. Values between -.3 and .3 are best + */ +@property(readwrite, nonatomic) CGFloat distance; + +/** Amount of color change. Default 0. Values between -.3 and .3 are best + */ +@property(readwrite, nonatomic) CGFloat slope; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageHighPassFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageHighPassFilter.h new file mode 100644 index 00000000..263d8df1 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageHighPassFilter.h @@ -0,0 +1,14 @@ +#import "GPUImageFilterGroup.h" +#import "GPUImageLowPassFilter.h" +#import "GPUImageDifferenceBlendFilter.h" + +@interface GPUImageHighPassFilter : GPUImageFilterGroup +{ + GPUImageLowPassFilter *lowPassFilter; + GPUImageDifferenceBlendFilter *differenceBlendFilter; +} + +// This controls the degree by which the previous accumulated frames are blended and then subtracted from the current one. This ranges from 0.0 to 1.0, with a default of 0.5. +@property(readwrite, nonatomic) CGFloat filterStrength; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageHighlightShadowFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageHighlightShadowFilter.h new file mode 100644 index 00000000..35791298 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageHighlightShadowFilter.h @@ -0,0 +1,20 @@ +#import "GPUImageFilter.h" + +@interface GPUImageHighlightShadowFilter : GPUImageFilter +{ + GLint shadowsUniform, highlightsUniform; +} + +/** + * 0 - 1, increase to lighten shadows. + * @default 0 + */ +@property(readwrite, nonatomic) CGFloat shadows; + +/** + * 0 - 1, decrease to darken highlights. + * @default 1 + */ +@property(readwrite, nonatomic) CGFloat highlights; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageHistogramFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageHistogramFilter.h new file mode 100755 index 00000000..6016d5e6 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageHistogramFilter.h @@ -0,0 +1,25 @@ +#import "GPUImageFilter.h" + +typedef enum { kGPUImageHistogramRed, kGPUImageHistogramGreen, kGPUImageHistogramBlue, kGPUImageHistogramRGB, kGPUImageHistogramLuminance} GPUImageHistogramType; + +@interface GPUImageHistogramFilter : GPUImageFilter +{ + GPUImageHistogramType histogramType; + + GLubyte *vertexSamplingCoordinates; + + GLProgram *secondFilterProgram, *thirdFilterProgram; + GLint secondFilterPositionAttribute, thirdFilterPositionAttribute; +} + +// Rather than sampling every pixel, this dictates what fraction of the image is sampled. By default, this is 16 with a minimum of 1. +@property(readwrite, nonatomic) NSUInteger downsamplingFactor; + +// Initialization and teardown +- (id)initWithHistogramType:(GPUImageHistogramType)newHistogramType; +- (void)initializeSecondaryAttributes; + +// Rendering +- (void)generatePointCoordinates; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageHistogramGenerator.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageHistogramGenerator.h new file mode 100755 index 00000000..f80c50f3 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageHistogramGenerator.h @@ -0,0 +1,8 @@ +#import "GPUImageFilter.h" + +@interface GPUImageHistogramGenerator : GPUImageFilter +{ + GLint backgroundColorUniform; +} + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageHoughTransformLineDetector.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageHoughTransformLineDetector.h new file mode 100644 index 00000000..3ab6977f --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageHoughTransformLineDetector.h @@ -0,0 +1,49 @@ +#import "GPUImageFilterGroup.h" +#import "GPUImageThresholdEdgeDetectionFilter.h" +#import "GPUImageParallelCoordinateLineTransformFilter.h" +#import "GPUImageThresholdedNonMaximumSuppressionFilter.h" +#import "GPUImageCannyEdgeDetectionFilter.h" + +// This applies a Hough transform to detect lines in a scene. It starts with a thresholded Sobel edge detection pass, +// then takes those edge points in and applies a Hough transform to convert them to lines. The intersection of these lines +// is then determined via blending and accumulation, and a non-maximum suppression filter is applied to find local maxima. +// These local maxima are then converted back into lines in normal space and returned via a callback block. +// +// Rather than using one of the standard Hough transform types, this filter uses parallel coordinate space which is far more efficient +// to rasterize on a GPU. +// +// This approach is based entirely on the PC lines process developed by the Graph@FIT research group at the Brno University of Technology +// and described in their publications: +// +// M. Dubská, J. Havel, and A. Herout. Real-Time Detection of Lines using Parallel Coordinates and OpenGL. Proceedings of SCCG 2011, Bratislava, SK, p. 7. +// http://medusa.fit.vutbr.cz/public/data/papers/2011-SCCG-Dubska-Real-Time-Line-Detection-Using-PC-and-OpenGL.pdf +// M. Dubská, J. Havel, and A. Herout. PClines — Line detection using parallel coordinates. 2011 IEEE Conference on Computer Vision and Pattern Recognition (CVPR), p. 1489- 1494. +// http://medusa.fit.vutbr.cz/public/data/papers/2011-CVPR-Dubska-PClines.pdf + +//#define DEBUGLINEDETECTION + +@interface GPUImageHoughTransformLineDetector : GPUImageFilterGroup +{ + GPUImageOutput *thresholdEdgeDetectionFilter; + +// GPUImageThresholdEdgeDetectionFilter *thresholdEdgeDetectionFilter; + GPUImageParallelCoordinateLineTransformFilter *parallelCoordinateLineTransformFilter; + GPUImageThresholdedNonMaximumSuppressionFilter *nonMaximumSuppressionFilter; + + GLfloat *linesArray; + GLubyte *rawImagePixels; +} + +// A threshold value for which a point is detected as belonging to an edge for determining lines. Default is 0.9. +@property(readwrite, nonatomic) CGFloat edgeThreshold; + +// A threshold value for which a local maximum is detected as belonging to a line in parallel coordinate space. Default is 0.20. +@property(readwrite, nonatomic) CGFloat lineDetectionThreshold; + +// This block is called on the detection of lines, usually on every processed frame. A C array containing normalized slopes and intercepts in m, b pairs (y=mx+b) is passed in, along with a count of the number of lines detected and the current timestamp of the video frame +@property(nonatomic, copy) void(^linesDetectedBlock)(GLfloat* lineArray, NSUInteger linesDetected, CMTime frameTime); + +// These images are only enabled when built with DEBUGLINEDETECTION defined, and are used to examine the intermediate states of the Hough transform +@property(nonatomic, readonly, strong) NSMutableArray *intermediateImages; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageHueBlendFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageHueBlendFilter.h new file mode 100644 index 00000000..4399ffcf --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageHueBlendFilter.h @@ -0,0 +1,5 @@ +#import "GPUImageTwoInputFilter.h" + +@interface GPUImageHueBlendFilter : GPUImageTwoInputFilter + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageHueFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageHueFilter.h new file mode 100644 index 00000000..eef24651 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageHueFilter.h @@ -0,0 +1,11 @@ + +#import "GPUImageFilter.h" + +@interface GPUImageHueFilter : GPUImageFilter +{ + GLint hueAdjustUniform; + +} +@property (nonatomic, readwrite) CGFloat hue; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageJFAVoronoiFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageJFAVoronoiFilter.h new file mode 100644 index 00000000..4c50cc37 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageJFAVoronoiFilter.h @@ -0,0 +1,17 @@ +#import "GPUImageFilter.h" + +@interface GPUImageJFAVoronoiFilter : GPUImageFilter +{ + GLuint secondFilterOutputTexture; + GLuint secondFilterFramebuffer; + + + GLint sampleStepUniform; + GLint sizeUniform; + NSUInteger numPasses; + +} + +@property (nonatomic, readwrite) CGSize sizeInPixels; + +@end \ No newline at end of file diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageKuwaharaFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageKuwaharaFilter.h new file mode 100755 index 00000000..ef4ff479 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageKuwaharaFilter.h @@ -0,0 +1,13 @@ +#import "GPUImageFilter.h" + +/** Kuwahara image abstraction, drawn from the work of Kyprianidis, et. al. in their publication "Anisotropic Kuwahara Filtering on the GPU" within the GPU Pro collection. This produces an oil-painting-like image, but it is extremely computationally expensive, so it can take seconds to render a frame on an iPad 2. This might be best used for still images. + */ +@interface GPUImageKuwaharaFilter : GPUImageFilter +{ + GLint radiusUniform; +} + +/// The radius to sample from when creating the brush-stroke effect, with a default of 3. The larger the radius, the slower the filter. +@property(readwrite, nonatomic) GLuint radius; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageKuwaharaRadius3Filter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageKuwaharaRadius3Filter.h new file mode 100644 index 00000000..c4591b81 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageKuwaharaRadius3Filter.h @@ -0,0 +1,8 @@ +// +// GPUImageKuwaharaRadius3Filter.h + +#import "GPUImageFilter.h" + +@interface GPUImageKuwaharaRadius3Filter : GPUImageFilter + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageLanczosResamplingFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageLanczosResamplingFilter.h new file mode 100644 index 00000000..5d7409f5 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageLanczosResamplingFilter.h @@ -0,0 +1,7 @@ +#import "GPUImageTwoPassTextureSamplingFilter.h" + +@interface GPUImageLanczosResamplingFilter : GPUImageTwoPassTextureSamplingFilter + +@property(readwrite, nonatomic) CGSize originalImageSize; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageLaplacianFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageLaplacianFilter.h new file mode 100644 index 00000000..267c1bab --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageLaplacianFilter.h @@ -0,0 +1,5 @@ +#import "GPUImage3x3ConvolutionFilter.h" + +@interface GPUImageLaplacianFilter : GPUImage3x3ConvolutionFilter + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageLevelsFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageLevelsFilter.h new file mode 100644 index 00000000..d0948fbf --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageLevelsFilter.h @@ -0,0 +1,45 @@ +#import "GPUImageFilter.h" + +/** + * Levels like Photoshop. + * + * The min, max, minOut and maxOut parameters are floats in the range [0, 1]. + * If you have parameters from Photoshop in the range [0, 255] you must first + * convert them to be [0, 1]. + * The gamma/mid parameter is a float >= 0. This matches the value from Photoshop. + * + * If you want to apply levels to RGB as well as individual channels you need to use + * this filter twice - first for the individual channels and then for all channels. + */ +@interface GPUImageLevelsFilter : GPUImageFilter +{ + GLint minUniform; + GLint midUniform; + GLint maxUniform; + GLint minOutputUniform; + GLint maxOutputUniform; + + GPUVector3 minVector, midVector, maxVector, minOutputVector, maxOutputVector; +} + +/** Set levels for the red channel */ +- (void)setRedMin:(CGFloat)min gamma:(CGFloat)mid max:(CGFloat)max minOut:(CGFloat)minOut maxOut:(CGFloat)maxOut; + +- (void)setRedMin:(CGFloat)min gamma:(CGFloat)mid max:(CGFloat)max; + +/** Set levels for the green channel */ +- (void)setGreenMin:(CGFloat)min gamma:(CGFloat)mid max:(CGFloat)max minOut:(CGFloat)minOut maxOut:(CGFloat)maxOut; + +- (void)setGreenMin:(CGFloat)min gamma:(CGFloat)mid max:(CGFloat)max; + +/** Set levels for the blue channel */ +- (void)setBlueMin:(CGFloat)min gamma:(CGFloat)mid max:(CGFloat)max minOut:(CGFloat)minOut maxOut:(CGFloat)maxOut; + +- (void)setBlueMin:(CGFloat)min gamma:(CGFloat)mid max:(CGFloat)max; + +/** Set levels for all channels at once */ +- (void)setMin:(CGFloat)min gamma:(CGFloat)mid max:(CGFloat)max minOut:(CGFloat)minOut maxOut:(CGFloat)maxOut; +- (void)setMin:(CGFloat)min gamma:(CGFloat)mid max:(CGFloat)max; + +@end + diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageLightenBlendFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageLightenBlendFilter.h new file mode 100755 index 00000000..b0287c13 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageLightenBlendFilter.h @@ -0,0 +1,8 @@ +#import "GPUImageTwoInputFilter.h" + +/// Blends two images by taking the maximum value of each color component between the images +@interface GPUImageLightenBlendFilter : GPUImageTwoInputFilter +{ +} + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageLineGenerator.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageLineGenerator.h new file mode 100644 index 00000000..4c467366 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageLineGenerator.h @@ -0,0 +1,18 @@ +#import "GPUImageFilter.h" + +@interface GPUImageLineGenerator : GPUImageFilter +{ + GLint lineWidthUniform, lineColorUniform; + GLfloat *lineCoordinates; +} + +// The width of the displayed lines, in pixels. The default is 1. +@property(readwrite, nonatomic) CGFloat lineWidth; + +// The color of the lines is specified using individual red, green, and blue components (normalized to 1.0). The default is green: (0.0, 1.0, 0.0). +- (void)setLineColorRed:(GLfloat)redComponent green:(GLfloat)greenComponent blue:(GLfloat)blueComponent; + +// Rendering +- (void)renderLinesFromArray:(GLfloat *)lineSlopeAndIntercepts count:(NSUInteger)numberOfLines frameTime:(CMTime)frameTime; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageLinearBurnBlendFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageLinearBurnBlendFilter.h new file mode 100644 index 00000000..7e5e415c --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageLinearBurnBlendFilter.h @@ -0,0 +1,5 @@ +#import "GPUImageTwoInputFilter.h" + +@interface GPUImageLinearBurnBlendFilter : GPUImageTwoInputFilter + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageLocalBinaryPatternFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageLocalBinaryPatternFilter.h new file mode 100644 index 00000000..431dbbd4 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageLocalBinaryPatternFilter.h @@ -0,0 +1,5 @@ +#import "GPUImage3x3TextureSamplingFilter.h" + +@interface GPUImageLocalBinaryPatternFilter : GPUImage3x3TextureSamplingFilter + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageLookupFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageLookupFilter.h new file mode 100644 index 00000000..f1487048 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageLookupFilter.h @@ -0,0 +1,28 @@ +#import "GPUImageTwoInputFilter.h" + +@interface GPUImageLookupFilter : GPUImageTwoInputFilter + +// How To Use: +// 1) Use your favourite photo editing application to apply a filter to lookup.png from GPUImage/framework/Resources. +// For this to work properly each pixel color must not depend on other pixels (e.g. blur will not work). +// If you need more complex filter you can create as many lookup tables as required. +// E.g. color_balance_lookup_1.png -> GPUImageGaussianBlurFilter -> color_balance_lookup_2.png +// 2) Use you new lookup.png file as a second input for GPUImageLookupFilter. + +// See GPUImageAmatorkaFilter, GPUImageMissEtikateFilter, and GPUImageSoftEleganceFilter for example. + +// Additional Info: +// Lookup texture is organised as 8x8 quads of 64x64 pixels representing all possible RGB colors: +//for (int by = 0; by < 8; by++) { +// for (int bx = 0; bx < 8; bx++) { +// for (int g = 0; g < 64; g++) { +// for (int r = 0; r < 64; r++) { +// image.setPixel(r + bx * 64, g + by * 64, qRgb((int)(r * 255.0 / 63.0 + 0.5), +// (int)(g * 255.0 / 63.0 + 0.5), +// (int)((bx + by * 8.0) * 255.0 / 63.0 + 0.5))); +// } +// } +// } +//} + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageLowPassFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageLowPassFilter.h new file mode 100644 index 00000000..be5c397e --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageLowPassFilter.h @@ -0,0 +1,14 @@ +#import "GPUImageFilterGroup.h" +#import "GPUImageBuffer.h" +#import "GPUImageDissolveBlendFilter.h" + +@interface GPUImageLowPassFilter : GPUImageFilterGroup +{ + GPUImageBuffer *bufferFilter; + GPUImageDissolveBlendFilter *dissolveBlendFilter; +} + +// This controls the degree by which the previous accumulated frames are blended with the current one. This ranges from 0.0 to 1.0, with a default of 0.5. +@property(readwrite, nonatomic) CGFloat filterStrength; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageLuminanceThresholdFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageLuminanceThresholdFilter.h new file mode 100755 index 00000000..0abb9a1e --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageLuminanceThresholdFilter.h @@ -0,0 +1,14 @@ +#import "GPUImageFilter.h" + +/** Pixels with a luminance above the threshold will appear white, and those below will be black + */ +@interface GPUImageLuminanceThresholdFilter : GPUImageFilter +{ + GLint thresholdUniform; +} + +/** Anything above this luminance will be white, and anything below black. Ranges from 0.0 to 1.0, with 0.5 as the default + */ +@property(readwrite, nonatomic) CGFloat threshold; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageLuminosity.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageLuminosity.h new file mode 100644 index 00000000..b2d2458f --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageLuminosity.h @@ -0,0 +1,17 @@ +#import "GPUImageAverageColor.h" + +@interface GPUImageLuminosity : GPUImageAverageColor +{ + GLProgram *secondFilterProgram; + GLint secondFilterPositionAttribute, secondFilterTextureCoordinateAttribute; + GLint secondFilterInputTextureUniform, secondFilterInputTextureUniform2; + GLint secondFilterTexelWidthUniform, secondFilterTexelHeightUniform; +} + +// This block is called on the completion of color averaging for a frame +@property(nonatomic, copy) void(^luminosityProcessingFinishedBlock)(CGFloat luminosity, CMTime frameTime); + +- (void)extractLuminosityAtFrameTime:(CMTime)frameTime; +- (void)initializeSecondaryAttributes; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageLuminosityBlendFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageLuminosityBlendFilter.h new file mode 100644 index 00000000..03b5e4c9 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageLuminosityBlendFilter.h @@ -0,0 +1,5 @@ +#import "GPUImageTwoInputFilter.h" + +@interface GPUImageLuminosityBlendFilter : GPUImageTwoInputFilter + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageMaskFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageMaskFilter.h new file mode 100755 index 00000000..94cf0648 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageMaskFilter.h @@ -0,0 +1,5 @@ +#import "GPUImageTwoInputFilter.h" + +@interface GPUImageMaskFilter : GPUImageTwoInputFilter + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageMedianFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageMedianFilter.h new file mode 100644 index 00000000..80225789 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageMedianFilter.h @@ -0,0 +1,5 @@ +#import "GPUImage3x3TextureSamplingFilter.h" + +@interface GPUImageMedianFilter : GPUImage3x3TextureSamplingFilter + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageMissEtikateFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageMissEtikateFilter.h new file mode 100755 index 00000000..de170647 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageMissEtikateFilter.h @@ -0,0 +1,17 @@ +#import "GPUImageFilterGroup.h" + +@class GPUImagePicture; + +/** A photo filter based on Photoshop action by Miss Etikate: + http://miss-etikate.deviantart.com/art/Photoshop-Action-15-120151961 + */ + +// Note: If you want to use this effect you have to add lookup_miss_etikate.png +// from Resources folder to your application bundle. + +@interface GPUImageMissEtikateFilter : GPUImageFilterGroup +{ + GPUImagePicture *lookupImageSource; +} + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageMonochromeFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageMonochromeFilter.h new file mode 100644 index 00000000..66a0e773 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageMonochromeFilter.h @@ -0,0 +1,13 @@ +#import "GPUImageFilter.h" + +@interface GPUImageMonochromeFilter : GPUImageFilter +{ + GLint intensityUniform, filterColorUniform; +} + +@property(readwrite, nonatomic) CGFloat intensity; +@property(readwrite, nonatomic) GPUVector4 color; + +- (void)setColorRed:(GLfloat)redComponent green:(GLfloat)greenComponent blue:(GLfloat)blueComponent; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageMosaicFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageMosaicFilter.h new file mode 100644 index 00000000..ae829ec4 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageMosaicFilter.h @@ -0,0 +1,27 @@ + +// This needs a little more work, it's rotating the input tileset and there are some artifacts (I think from GL_LINEAR interpolation), but it's working + +#import "GPUImageTwoInputFilter.h" +#import "GPUImagePicture.h" + +@interface GPUImageMosaicFilter : GPUImageTwoInputFilter { + GLint inputTileSizeUniform, numTilesUniform, displayTileSizeUniform, colorOnUniform; + GPUImagePicture *pic; +} + +// This filter takes an input tileset, the tiles must ascend in luminance +// It looks at the input image and replaces each display tile with an input tile +// according to the luminance of that tile. The idea was to replicate the ASCII +// video filters seen in other apps, but the tileset can be anything. +@property(readwrite, nonatomic) CGSize inputTileSize; +@property(readwrite, nonatomic) float numTiles; +@property(readwrite, nonatomic) CGSize displayTileSize; +@property(readwrite, nonatomic) BOOL colorOn; + +- (void)setNumTiles:(float)numTiles; +- (void)setDisplayTileSize:(CGSize)displayTileSize; +- (void)setInputTileSize:(CGSize)inputTileSize; +- (void)setTileSet:(NSString *)tileSet; +- (void)setColorOn:(BOOL)yes; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageMotionBlurFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageMotionBlurFilter.h new file mode 100644 index 00000000..dcca712f --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageMotionBlurFilter.h @@ -0,0 +1,13 @@ +#import "GPUImageFilter.h" + +@interface GPUImageMotionBlurFilter : GPUImageFilter + +/** A multiplier for the blur size, ranging from 0.0 on up, with a default of 1.0 + */ +@property (readwrite, nonatomic) CGFloat blurSize; + +/** The angular direction of the blur, in degrees. 0 degrees by default + */ +@property (readwrite, nonatomic) CGFloat blurAngle; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageMotionDetector.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageMotionDetector.h new file mode 100644 index 00000000..01329145 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageMotionDetector.h @@ -0,0 +1,18 @@ +#import "GPUImageFilterGroup.h" +#import "GPUImageLowPassFilter.h" +#import "GPUImageAverageColor.h" + +@interface GPUImageMotionDetector : GPUImageFilterGroup +{ + GPUImageLowPassFilter *lowPassFilter; + GPUImageTwoInputFilter *frameComparisonFilter; + GPUImageAverageColor *averageColor; +} + +// This controls the low pass filter strength used to compare the current frame with previous ones to detect motion. This ranges from 0.0 to 1.0, with a default of 0.5. +@property(readwrite, nonatomic) CGFloat lowPassFilterStrength; + +// For every frame, this will feed back the calculated centroid of the motion, as well as a relative intensity. +@property(nonatomic, copy) void(^motionDetectionBlock)(CGPoint motionCentroid, CGFloat motionIntensity, CMTime frameTime); + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageMovieWriter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageMovieWriter.h new file mode 100755 index 00000000..530e5a61 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageMovieWriter.h @@ -0,0 +1,57 @@ +#import +#import +#import "GPUImageContext.h" + +extern NSString *const kGPUImageColorSwizzlingFragmentShaderString; + +@protocol GPUImageMovieWriterDelegate + +@optional +- (void)movieRecordingCompleted; +- (void)movieRecordingFailedWithError:(NSError*)error; + +@end + +@interface GPUImageMovieWriter : NSObject +{ + CMVideoDimensions videoDimensions; + CMVideoCodecType videoType; + + NSURL *movieURL; + NSString *fileType; + AVAssetWriter *assetWriter; + AVAssetWriterInput *assetWriterAudioInput; + AVAssetWriterInput *assetWriterVideoInput; + AVAssetWriterInputPixelBufferAdaptor *assetWriterPixelBufferInput; + dispatch_queue_t movieWritingQueue; + + CGSize videoSize; + GPUImageRotationMode inputRotation; +} + +@property(readwrite, nonatomic) BOOL hasAudioTrack; +@property(readwrite, nonatomic) BOOL shouldPassthroughAudio; +@property(nonatomic, copy) void(^completionBlock)(void); +@property(nonatomic, copy) void(^failureBlock)(NSError*); +@property(nonatomic, assign) id delegate; +@property(readwrite, nonatomic) BOOL encodingLiveVideo; +@property(nonatomic, copy) void(^videoInputReadyCallback)(void); +@property(nonatomic, copy) void(^audioInputReadyCallback)(void); +@property(nonatomic) BOOL enabled; + +// Initialization and teardown +- (id)initWithMovieURL:(NSURL *)newMovieURL size:(CGSize)newSize; +- (id)initWithMovieURL:(NSURL *)newMovieURL size:(CGSize)newSize fileType:(NSString *)newFileType outputSettings:(NSMutableDictionary *)outputSettings; + +- (void)setHasAudioTrack:(BOOL)hasAudioTrack audioSettings:(NSDictionary *)audioOutputSettings; + +// Movie recording +- (void)startRecording; +- (void)startRecordingInOrientation:(CGAffineTransform)orientationTransform; +- (void)finishRecording; +- (void)finishRecordingWithCompletionHandler:(void (^)(void))handler; +- (void)cancelRecording; +- (void)processAudioBuffer:(CMSampleBufferRef)audioBuffer; +- (void)enableSynchronizationCallbacks; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageMultiplyBlendFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageMultiplyBlendFilter.h new file mode 100755 index 00000000..5ebc28bb --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageMultiplyBlendFilter.h @@ -0,0 +1,7 @@ +#import "GPUImageTwoInputFilter.h" + +@interface GPUImageMultiplyBlendFilter : GPUImageTwoInputFilter +{ +} + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageNobleCornerDetectionFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageNobleCornerDetectionFilter.h new file mode 100644 index 00000000..963fd66a --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageNobleCornerDetectionFilter.h @@ -0,0 +1,12 @@ +#import "GPUImageHarrisCornerDetectionFilter.h" + +/** Noble corner detector + + This is the Noble variant on the Harris detector, from + Alison Noble, "Descriptions of Image Surfaces", PhD thesis, Department of Engineering Science, Oxford University 1989, p45. +*/ + + +@interface GPUImageNobleCornerDetectionFilter : GPUImageHarrisCornerDetectionFilter + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageNonMaximumSuppressionFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageNonMaximumSuppressionFilter.h new file mode 100644 index 00000000..fd8fe6d6 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageNonMaximumSuppressionFilter.h @@ -0,0 +1,5 @@ +#import "GPUImage3x3TextureSamplingFilter.h" + +@interface GPUImageNonMaximumSuppressionFilter : GPUImage3x3TextureSamplingFilter + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageNormalBlendFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageNormalBlendFilter.h new file mode 100644 index 00000000..ce5e22b4 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageNormalBlendFilter.h @@ -0,0 +1,8 @@ +// Created by Jorge Garcia on 9/5/12. +// + +#import "GPUImageTwoInputFilter.h" + +@interface GPUImageNormalBlendFilter : GPUImageTwoInputFilter + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageOpacityFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageOpacityFilter.h new file mode 100644 index 00000000..826749fb --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageOpacityFilter.h @@ -0,0 +1,11 @@ +#import "GPUImageFilter.h" + +@interface GPUImageOpacityFilter : GPUImageFilter +{ + GLint opacityUniform; +} + +// Opacity ranges from 0.0 to 1.0, with 1.0 as the normal setting +@property(readwrite, nonatomic) CGFloat opacity; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageOpeningFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageOpeningFilter.h new file mode 100644 index 00000000..3e4f7545 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageOpeningFilter.h @@ -0,0 +1,19 @@ +#import "GPUImageFilterGroup.h" + +@class GPUImageErosionFilter; +@class GPUImageDilationFilter; + +// A filter that first performs an erosion on the red channel of an image, followed by a dilation of the same radius. +// This helps to filter out smaller bright elements. + +@interface GPUImageOpeningFilter : GPUImageFilterGroup +{ + GPUImageErosionFilter *erosionFilter; + GPUImageDilationFilter *dilationFilter; +} + +@property(readwrite, nonatomic) CGFloat verticalTexelSpacing, horizontalTexelSpacing; + +- (id)initWithRadius:(NSUInteger)radius; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageOutput.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageOutput.h new file mode 100755 index 00000000..a1af54d7 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageOutput.h @@ -0,0 +1,127 @@ +#import "GPUImageContext.h" +#import "GPUImageFramebuffer.h" + +#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE +#import +#else +// For now, just redefine this on the Mac +typedef NS_ENUM(NSInteger, UIImageOrientation) { + UIImageOrientationUp, // default orientation + UIImageOrientationDown, // 180 deg rotation + UIImageOrientationLeft, // 90 deg CCW + UIImageOrientationRight, // 90 deg CW + UIImageOrientationUpMirrored, // as above but image mirrored along other axis. horizontal flip + UIImageOrientationDownMirrored, // horizontal flip + UIImageOrientationLeftMirrored, // vertical flip + UIImageOrientationRightMirrored, // vertical flip +}; +#endif + +void runOnMainQueueWithoutDeadlocking(void (^block)(void)); +void runSynchronouslyOnVideoProcessingQueue(void (^block)(void)); +void runAsynchronouslyOnVideoProcessingQueue(void (^block)(void)); +void runSynchronouslyOnContextQueue(GPUImageContext *context, void (^block)(void)); +void runAsynchronouslyOnContextQueue(GPUImageContext *context, void (^block)(void)); +void reportAvailableMemoryForGPUImage(NSString *tag); + +@class GPUImageMovieWriter; + +/** GPUImage's base source object + + Images or frames of video are uploaded from source objects, which are subclasses of GPUImageOutput. These include: + + - GPUImageVideoCamera (for live video from an iOS camera) + - GPUImageStillCamera (for taking photos with the camera) + - GPUImagePicture (for still images) + - GPUImageMovie (for movies) + + Source objects upload still image frames to OpenGL ES as textures, then hand those textures off to the next objects in the processing chain. + */ +@interface GPUImageOutput : NSObject +{ + GPUImageFramebuffer *outputFramebuffer; + + NSMutableArray *targets, *targetTextureIndices; + + CGSize inputTextureSize, cachedMaximumOutputSize, forcedMaximumSize; + + BOOL overrideInputSize; + + BOOL allTargetsWantMonochromeData; + BOOL usingNextFrameForImageCapture; +} + +@property(readwrite, nonatomic) BOOL shouldSmoothlyScaleOutput; +@property(readwrite, nonatomic) BOOL shouldIgnoreUpdatesToThisTarget; +@property(readwrite, nonatomic, retain) GPUImageMovieWriter *audioEncodingTarget; +@property(readwrite, nonatomic, unsafe_unretained) id targetToIgnoreForUpdates; +@property(nonatomic, copy) void(^frameProcessingCompletionBlock)(GPUImageOutput*, CMTime); +@property(nonatomic) BOOL enabled; +@property(readwrite, nonatomic) GPUTextureOptions outputTextureOptions; + +/// @name Managing targets +- (void)setInputFramebufferForTarget:(id)target atIndex:(NSInteger)inputTextureIndex; +- (GPUImageFramebuffer *)framebufferForOutput; +- (void)removeOutputFramebuffer; +- (void)notifyTargetsAboutNewOutputTexture; + +/** Returns an array of the current targets. + */ +- (NSArray*)targets; + +/** Adds a target to receive notifications when new frames are available. + + The target will be asked for its next available texture. + + See [GPUImageInput newFrameReadyAtTime:] + + @param newTarget Target to be added + */ +- (void)addTarget:(id)newTarget; + +/** Adds a target to receive notifications when new frames are available. + + See [GPUImageInput newFrameReadyAtTime:] + + @param newTarget Target to be added + */ +- (void)addTarget:(id)newTarget atTextureLocation:(NSInteger)textureLocation; + +/** Removes a target. The target will no longer receive notifications when new frames are available. + + @param targetToRemove Target to be removed + */ +- (void)removeTarget:(id)targetToRemove; + +/** Removes all targets. + */ +- (void)removeAllTargets; + +/// @name Manage the output texture + +- (void)forceProcessingAtSize:(CGSize)frameSize; +- (void)forceProcessingAtSizeRespectingAspectRatio:(CGSize)frameSize; + +/// @name Still image processing + +- (void)useNextFrameForImageCapture; +- (CGImageRef)newCGImageFromCurrentlyProcessedOutput; +- (CGImageRef)newCGImageByFilteringCGImage:(CGImageRef)imageToFilter; + +// Platform-specific image output methods +// If you're trying to use these methods, remember that you need to set -useNextFrameForImageCapture before running -processImage or running video and calling any of these methods, or you will get a nil image +#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE +- (UIImage *)imageFromCurrentFramebuffer; +- (UIImage *)imageFromCurrentFramebufferWithOrientation:(UIImageOrientation)imageOrientation; +- (UIImage *)imageByFilteringImage:(UIImage *)imageToFilter; +- (CGImageRef)newCGImageByFilteringImage:(UIImage *)imageToFilter; +#else +- (NSImage *)imageFromCurrentFramebuffer; +- (NSImage *)imageFromCurrentFramebufferWithOrientation:(UIImageOrientation)imageOrientation; +- (NSImage *)imageByFilteringImage:(NSImage *)imageToFilter; +- (CGImageRef)newCGImageByFilteringImage:(NSImage *)imageToFilter; +#endif + +- (BOOL)providesMonochromeOutput; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageOverlayBlendFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageOverlayBlendFilter.h new file mode 100755 index 00000000..57eb8402 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageOverlayBlendFilter.h @@ -0,0 +1,5 @@ +#import "GPUImageTwoInputFilter.h" + +@interface GPUImageOverlayBlendFilter : GPUImageTwoInputFilter + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageParallelCoordinateLineTransformFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageParallelCoordinateLineTransformFilter.h new file mode 100644 index 00000000..aa8f3f47 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageParallelCoordinateLineTransformFilter.h @@ -0,0 +1,16 @@ +#import "GPUImageFilter.h" + +// This is an accumulator that uses a Hough transform in parallel coordinate space to identify probable lines in a scene. +// +// It is entirely based on the work of the Graph@FIT research group at the Brno University of Technology and their publications: +// M. Dubská, J. Havel, and A. Herout. Real-Time Detection of Lines using Parallel Coordinates and OpenGL. Proceedings of SCCG 2011, Bratislava, SK, p. 7. +// M. Dubská, J. Havel, and A. Herout. PClines — Line detection using parallel coordinates. 2011 IEEE Conference on Computer Vision and Pattern Recognition (CVPR), p. 1489- 1494. + +@interface GPUImageParallelCoordinateLineTransformFilter : GPUImageFilter +{ + GLubyte *rawImagePixels; + GLfloat *lineCoordinates; + unsigned int maxLinePairsToRender, linePairsToRender; +} + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImagePerlinNoiseFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImagePerlinNoiseFilter.h new file mode 100644 index 00000000..922f4d30 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImagePerlinNoiseFilter.h @@ -0,0 +1,13 @@ +#import "GPUImageFilter.h" + +@interface GPUImagePerlinNoiseFilter : GPUImageFilter +{ + GLint scaleUniform, colorStartUniform, colorFinishUniform; +} + +@property (readwrite, nonatomic) GPUVector4 colorStart; +@property (readwrite, nonatomic) GPUVector4 colorFinish; + +@property (readwrite, nonatomic) float scale; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImagePicture.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImagePicture.h new file mode 100755 index 00000000..65970535 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImagePicture.h @@ -0,0 +1,25 @@ +#import +#import "GPUImageOutput.h" + +@interface GPUImagePicture : GPUImageOutput +{ + CGSize pixelSizeOfImage; + BOOL hasProcessedImage; + + dispatch_semaphore_t imageUpdateSemaphore; +} + +// Initialization and teardown +- (id)initWithURL:(NSURL *)url; +- (id)initWithImage:(NSImage *)newImageSource; +- (id)initWithCGImage:(CGImageRef)newImageSource; +- (id)initWithImage:(NSImage *)newImageSource smoothlyScaleOutput:(BOOL)smoothlyScaleOutput; +- (id)initWithCGImage:(CGImageRef)newImageSource smoothlyScaleOutput:(BOOL)smoothlyScaleOutput; + +// Image rendering +- (void)processImage; +- (BOOL)processImageWithCompletionHandler:(void (^)(void))completion; +- (void)processImageUpToFilter:(GPUImageOutput *)finalFilterInChain withCompletionHandler:(void (^)(NSImage *processedImage))block; +- (CGSize)outputImageSize; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImagePinchDistortionFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImagePinchDistortionFilter.h new file mode 100755 index 00000000..994774fd --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImagePinchDistortionFilter.h @@ -0,0 +1,20 @@ +#import "GPUImageFilter.h" + +/** Creates a pinch distortion of the image + */ +@interface GPUImagePinchDistortionFilter : GPUImageFilter +{ + GLint aspectRatioUniform, radiusUniform, centerUniform, scaleUniform; +} + +/** The center about which to apply the distortion, with a default of (0.5, 0.5) + */ +@property(readwrite, nonatomic) CGPoint center; +/** The radius of the distortion, ranging from 0.0 to 2.0, with a default of 1.0 + */ +@property(readwrite, nonatomic) CGFloat radius; +/** The amount of distortion to apply, from -2.0 to 2.0, with a default of 0.5 + */ +@property(readwrite, nonatomic) CGFloat scale; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImagePixellateFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImagePixellateFilter.h new file mode 100755 index 00000000..d0f6ae04 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImagePixellateFilter.h @@ -0,0 +1,12 @@ +#import "GPUImageFilter.h" + +@interface GPUImagePixellateFilter : GPUImageFilter +{ + GLint fractionalWidthOfAPixelUniform, aspectRatioUniform; +} + +// The fractional width of the image to use as a size for the pixels in the resulting image. Values below one pixel width in the source image are ignored. +@property(readwrite, nonatomic) CGFloat fractionalWidthOfAPixel; + + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImagePixellatePositionFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImagePixellatePositionFilter.h new file mode 100755 index 00000000..9d304c93 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImagePixellatePositionFilter.h @@ -0,0 +1,17 @@ +#import "GPUImageFilter.h" + +@interface GPUImagePixellatePositionFilter : GPUImageFilter +{ + GLint fractionalWidthOfAPixelUniform, aspectRatioUniform, centerUniform, radiusUniform; +} + +// The fractional width of the image to use as a size for the pixels in the resulting image. Values below one pixel width in the source image are ignored. +@property(readwrite, nonatomic) CGFloat fractionalWidthOfAPixel; + +// the center point to start pixelation in texture coordinates, default 0.5, 0.5 +@property(readwrite, nonatomic) CGPoint center; + +// the radius (0.0 - 1.0) in which to pixelate, default 1.0 +@property(readwrite, nonatomic) CGFloat radius; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImagePoissonBlendFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImagePoissonBlendFilter.h new file mode 100644 index 00000000..58eff225 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImagePoissonBlendFilter.h @@ -0,0 +1,18 @@ +#import "GPUImageTwoInputCrossTextureSamplingFilter.h" +#import "GPUImageFilterGroup.h" + +@interface GPUImagePoissonBlendFilter : GPUImageTwoInputCrossTextureSamplingFilter +{ + GLint mixUniform; + + GPUImageFramebuffer *secondOutputFramebuffer; +} + +// Mix ranges from 0.0 (only image 1) to 1.0 (only image 2 gradients), with 1.0 as the normal level +@property(readwrite, nonatomic) CGFloat mix; + +// The number of times to propagate the gradients. +// Crank this up to 100 or even 1000 if you want to get anywhere near convergence. Yes, this will be slow. +@property(readwrite, nonatomic) NSUInteger numIterations; + +@end \ No newline at end of file diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImagePolarPixellateFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImagePolarPixellateFilter.h new file mode 100755 index 00000000..3de6a4d3 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImagePolarPixellateFilter.h @@ -0,0 +1,13 @@ +#import "GPUImageFilter.h" + +@interface GPUImagePolarPixellateFilter : GPUImageFilter { + GLint centerUniform, pixelSizeUniform; +} + +// The center about which to apply the distortion, with a default of (0.5, 0.5) +@property(readwrite, nonatomic) CGPoint center; +// The amount of distortion to apply, from (-2.0, -2.0) to (2.0, 2.0), with a default of (0.05, 0.05) +@property(readwrite, nonatomic) CGSize pixelSize; + + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImagePolkaDotFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImagePolkaDotFilter.h new file mode 100644 index 00000000..369b7737 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImagePolkaDotFilter.h @@ -0,0 +1,10 @@ +#import "GPUImagePixellateFilter.h" + +@interface GPUImagePolkaDotFilter : GPUImagePixellateFilter +{ + GLint dotScalingUniform; +} + +@property(readwrite, nonatomic) CGFloat dotScaling; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImagePosterizeFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImagePosterizeFilter.h new file mode 100755 index 00000000..6f655b3e --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImagePosterizeFilter.h @@ -0,0 +1,14 @@ +#import "GPUImageFilter.h" + +/** This reduces the color dynamic range into the number of steps specified, leading to a cartoon-like simple shading of the image. + */ +@interface GPUImagePosterizeFilter : GPUImageFilter +{ + GLint colorLevelsUniform; +} + +/** The number of color levels to reduce the image space to. This ranges from 1 to 256, with a default of 10. + */ +@property(readwrite, nonatomic) NSUInteger colorLevels; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImagePrewittEdgeDetectionFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImagePrewittEdgeDetectionFilter.h new file mode 100755 index 00000000..141f8c5f --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImagePrewittEdgeDetectionFilter.h @@ -0,0 +1,5 @@ +#import "GPUImageSobelEdgeDetectionFilter.h" + +@interface GPUImagePrewittEdgeDetectionFilter : GPUImageSobelEdgeDetectionFilter + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageRGBClosingFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageRGBClosingFilter.h new file mode 100644 index 00000000..08d13f88 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageRGBClosingFilter.h @@ -0,0 +1,18 @@ +#import "GPUImageFilterGroup.h" + +@class GPUImageRGBErosionFilter; +@class GPUImageRGBDilationFilter; + +// A filter that first performs a dilation on each color channel of an image, followed by an erosion of the same radius. +// This helps to filter out smaller dark elements. + +@interface GPUImageRGBClosingFilter : GPUImageFilterGroup +{ + GPUImageRGBErosionFilter *erosionFilter; + GPUImageRGBDilationFilter *dilationFilter; +} + +- (id)initWithRadius:(NSUInteger)radius; + + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageRGBDilationFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageRGBDilationFilter.h new file mode 100644 index 00000000..68276f84 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageRGBDilationFilter.h @@ -0,0 +1,11 @@ +#import "GPUImageTwoPassTextureSamplingFilter.h" + +// For each pixel, this sets it to the maximum value of each color channel in a rectangular neighborhood extending out dilationRadius pixels from the center. +// This extends out brighter colors, and can be used for abstraction of color images. + +@interface GPUImageRGBDilationFilter : GPUImageTwoPassTextureSamplingFilter + +// Acceptable values for dilationRadius, which sets the distance in pixels to sample out from the center, are 1, 2, 3, and 4. +- (id)initWithRadius:(NSUInteger)dilationRadius; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageRGBErosionFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageRGBErosionFilter.h new file mode 100644 index 00000000..5979cb7e --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageRGBErosionFilter.h @@ -0,0 +1,11 @@ +#import "GPUImageTwoPassTextureSamplingFilter.h" + +// For each pixel, this sets it to the minimum value of each color channel in a rectangular neighborhood extending out dilationRadius pixels from the center. +// This extends out dark features, and can be used for abstraction of color images. + +@interface GPUImageRGBErosionFilter : GPUImageTwoPassTextureSamplingFilter + +// Acceptable values for erosionRadius, which sets the distance in pixels to sample out from the center, are 1, 2, 3, and 4. +- (id)initWithRadius:(NSUInteger)erosionRadius; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageRGBFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageRGBFilter.h new file mode 100755 index 00000000..18966b1b --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageRGBFilter.h @@ -0,0 +1,15 @@ +#import "GPUImageFilter.h" + +@interface GPUImageRGBFilter : GPUImageFilter +{ + GLint redUniform; + GLint greenUniform; + GLint blueUniform; +} + +// Normalized values by which each color channel is multiplied. The range is from 0.0 up, with 1.0 as the default. +@property (readwrite, nonatomic) CGFloat red; +@property (readwrite, nonatomic) CGFloat green; +@property (readwrite, nonatomic) CGFloat blue; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageRGBOpeningFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageRGBOpeningFilter.h new file mode 100644 index 00000000..dbec75fb --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageRGBOpeningFilter.h @@ -0,0 +1,17 @@ +#import "GPUImageFilterGroup.h" + +@class GPUImageRGBErosionFilter; +@class GPUImageRGBDilationFilter; + +// A filter that first performs an erosion on each color channel of an image, followed by a dilation of the same radius. +// This helps to filter out smaller bright elements. + +@interface GPUImageRGBOpeningFilter : GPUImageFilterGroup +{ + GPUImageRGBErosionFilter *erosionFilter; + GPUImageRGBDilationFilter *dilationFilter; +} + +- (id)initWithRadius:(NSUInteger)radius; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageRawDataInput.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageRawDataInput.h new file mode 100644 index 00000000..64858180 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageRawDataInput.h @@ -0,0 +1,42 @@ +#import "GPUImageOutput.h" + +// The bytes passed into this input are not copied or retained, but you are free to deallocate them after they are used by this filter. +// The bytes are uploaded and stored within a texture, so nothing is kept locally. +// The default format for input bytes is GPUPixelFormatBGRA, unless specified with pixelFormat: +// The default type for input bytes is GPUPixelTypeUByte, unless specified with pixelType: + +typedef enum { + GPUPixelFormatBGRA = GL_BGRA, + GPUPixelFormatRGBA = GL_RGBA, + GPUPixelFormatRGB = GL_RGB +} GPUPixelFormat; + +typedef enum { + GPUPixelTypeUByte = GL_UNSIGNED_BYTE, + GPUPixelTypeFloat = GL_FLOAT +} GPUPixelType; + +@interface GPUImageRawDataInput : GPUImageOutput +{ + CGSize uploadedImageSize; + + dispatch_semaphore_t dataUpdateSemaphore; +} + +// Initialization and teardown +- (id)initWithBytes:(GLubyte *)bytesToUpload size:(CGSize)imageSize; +- (id)initWithBytes:(GLubyte *)bytesToUpload size:(CGSize)imageSize pixelFormat:(GPUPixelFormat)pixelFormat; +- (id)initWithBytes:(GLubyte *)bytesToUpload size:(CGSize)imageSize pixelFormat:(GPUPixelFormat)pixelFormat type:(GPUPixelType)pixelType; + +/** Input data pixel format + */ +@property (readwrite, nonatomic) GPUPixelFormat pixelFormat; +@property (readwrite, nonatomic) GPUPixelType pixelType; + +// Image rendering +- (void)updateDataFromBytes:(GLubyte *)bytesToUpload size:(CGSize)imageSize; +- (void)processData; +- (void)processDataForTimestamp:(CMTime)frameTime; +- (CGSize)outputImageSize; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageRawDataOutput.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageRawDataOutput.h new file mode 100755 index 00000000..5a4538c1 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageRawDataOutput.h @@ -0,0 +1,44 @@ +#import +#import "GPUImageContext.h" + +struct GPUByteColorVector { + GLubyte red; + GLubyte green; + GLubyte blue; + GLubyte alpha; +}; +typedef struct GPUByteColorVector GPUByteColorVector; + +@protocol GPUImageRawDataProcessor; + +#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE +@interface GPUImageRawDataOutput : NSObject { + CGSize imageSize; + GPUImageRotationMode inputRotation; + BOOL outputBGRA; +} +#else +@interface GPUImageRawDataOutput : NSObject { + CGSize imageSize; + GPUImageRotationMode inputRotation; + BOOL outputBGRA; +} +#endif + +@property(readonly) GLubyte *rawBytesForImage; +@property(nonatomic, copy) void(^newFrameAvailableBlock)(void); +@property(nonatomic) BOOL enabled; + +// Initialization and teardown +- (id)initWithImageSize:(CGSize)newImageSize resultsInBGRAFormat:(BOOL)resultsInBGRAFormat; + +// Data access +- (GPUByteColorVector)colorAtLocation:(CGPoint)locationInImage; +- (NSUInteger)bytesPerRowInOutput; + +- (void)setImageSize:(CGSize)newImageSize; + +- (void)lockFramebufferForReading; +- (void)unlockFramebufferAfterReading; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSaturationBlendFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSaturationBlendFilter.h new file mode 100644 index 00000000..767892a5 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSaturationBlendFilter.h @@ -0,0 +1,5 @@ +#import "GPUImageTwoInputFilter.h" + +@interface GPUImageSaturationBlendFilter : GPUImageTwoInputFilter + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSaturationFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSaturationFilter.h new file mode 100755 index 00000000..1c6ff5bd --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSaturationFilter.h @@ -0,0 +1,14 @@ +#import "GPUImageFilter.h" + +/** Adjusts the saturation of an image + */ +@interface GPUImageSaturationFilter : GPUImageFilter +{ + GLint saturationUniform; +} + +/** Saturation ranges from 0.0 (fully desaturated) to 2.0 (max saturation), with 1.0 as the normal level + */ +@property(readwrite, nonatomic) CGFloat saturation; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageScreenBlendFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageScreenBlendFilter.h new file mode 100755 index 00000000..2df3abf3 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageScreenBlendFilter.h @@ -0,0 +1,7 @@ +#import "GPUImageTwoInputFilter.h" + +@interface GPUImageScreenBlendFilter : GPUImageTwoInputFilter +{ +} + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSepiaFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSepiaFilter.h new file mode 100755 index 00000000..a45164fe --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSepiaFilter.h @@ -0,0 +1,6 @@ +#import "GPUImageColorMatrixFilter.h" + +/// Simple sepia tone filter +@interface GPUImageSepiaFilter : GPUImageColorMatrixFilter + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSharpenFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSharpenFilter.h new file mode 100755 index 00000000..739df503 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSharpenFilter.h @@ -0,0 +1,12 @@ +#import "GPUImageFilter.h" + +@interface GPUImageSharpenFilter : GPUImageFilter +{ + GLint sharpnessUniform; + GLint imageWidthFactorUniform, imageHeightFactorUniform; +} + +// Sharpness ranges from -4.0 to 4.0, with 0.0 as the normal level +@property(readwrite, nonatomic) CGFloat sharpness; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageShiTomasiFeatureDetectionFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageShiTomasiFeatureDetectionFilter.h new file mode 100644 index 00000000..b16ebc01 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageShiTomasiFeatureDetectionFilter.h @@ -0,0 +1,13 @@ +#import "GPUImageHarrisCornerDetectionFilter.h" + +/** Shi-Tomasi feature detector + + This is the Shi-Tomasi feature detector, as described in + J. Shi and C. Tomasi. Good features to track. Proceedings of the IEEE Conference on Computer Vision and Pattern Recognition, pages 593-600, June 1994. + */ + +@interface GPUImageShiTomasiFeatureDetectionFilter : GPUImageHarrisCornerDetectionFilter + +// Compared to the Harris corner detector, the default sensitivity value for this detector is set to 1.5 + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSingleComponentGaussianBlurFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSingleComponentGaussianBlurFilter.h new file mode 100644 index 00000000..934b1e3a --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSingleComponentGaussianBlurFilter.h @@ -0,0 +1,7 @@ +#import "GPUImageGaussianBlurFilter.h" + +// This filter merely performs the standard Gaussian blur on the red color channel (assuming a luminance image) + +@interface GPUImageSingleComponentGaussianBlurFilter : GPUImageGaussianBlurFilter + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSketchFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSketchFilter.h new file mode 100755 index 00000000..598145ae --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSketchFilter.h @@ -0,0 +1,11 @@ +#import "GPUImageSobelEdgeDetectionFilter.h" + +/** Converts video to look like a sketch. + + This is just the Sobel edge detection filter with the colors inverted. + */ +@interface GPUImageSketchFilter : GPUImageSobelEdgeDetectionFilter +{ +} + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSmoothToonFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSmoothToonFilter.h new file mode 100755 index 00000000..f89caac5 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSmoothToonFilter.h @@ -0,0 +1,28 @@ +#import "GPUImageFilterGroup.h" + +@class GPUImageGaussianBlurFilter; +@class GPUImageToonFilter; + +/** This uses a similar process as the GPUImageToonFilter, only it precedes the toon effect with a Gaussian blur to smooth out noise. + */ +@interface GPUImageSmoothToonFilter : GPUImageFilterGroup +{ + GPUImageGaussianBlurFilter *blurFilter; + GPUImageToonFilter *toonFilter; +} + +/// The image width and height factors tweak the appearance of the edges. By default, they match the filter size in pixels +@property(readwrite, nonatomic) CGFloat texelWidth; +/// The image width and height factors tweak the appearance of the edges. By default, they match the filter size in pixels +@property(readwrite, nonatomic) CGFloat texelHeight; + +/// The radius of the underlying Gaussian blur. The default is 2.0. +@property (readwrite, nonatomic) CGFloat blurRadiusInPixels; + +/// The threshold at which to apply the edges, default of 0.2 +@property(readwrite, nonatomic) CGFloat threshold; + +/// The levels of quantization for the posterization of colors within the scene, with a default of 10.0 +@property(readwrite, nonatomic) CGFloat quantizationLevels; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSobelEdgeDetectionFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSobelEdgeDetectionFilter.h new file mode 100755 index 00000000..d6b2c13a --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSobelEdgeDetectionFilter.h @@ -0,0 +1,16 @@ +#import "GPUImageTwoPassFilter.h" + +@interface GPUImageSobelEdgeDetectionFilter : GPUImageTwoPassFilter +{ + GLint texelWidthUniform, texelHeightUniform, edgeStrengthUniform; + BOOL hasOverriddenImageSizeFactor; +} + +// The texel width and height factors tweak the appearance of the edges. By default, they match the inverse of the filter size in pixels +@property(readwrite, nonatomic) CGFloat texelWidth; +@property(readwrite, nonatomic) CGFloat texelHeight; + +// The filter strength property affects the dynamic range of the filter. High values can make edges more visible, but can lead to saturation. Default of 1.0. +@property(readwrite, nonatomic) CGFloat edgeStrength; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSoftEleganceFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSoftEleganceFilter.h new file mode 100755 index 00000000..596e1567 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSoftEleganceFilter.h @@ -0,0 +1,19 @@ +#import "GPUImageFilterGroup.h" + +@class GPUImagePicture; + +/** A photo filter based on Soft Elegance Photoshop action + http://h-d-stock.deviantart.com/art/H-D-A-soft-elegance-70107603 + */ + +// Note: If you want to use this effect you have to add +// lookup_soft_elegance_1.png and lookup_soft_elegance_2.png +// from Resources folder to your application bundle. + +@interface GPUImageSoftEleganceFilter : GPUImageFilterGroup +{ + GPUImagePicture *lookupImageSource1; + GPUImagePicture *lookupImageSource2; +} + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSoftLightBlendFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSoftLightBlendFilter.h new file mode 100755 index 00000000..13fc877c --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSoftLightBlendFilter.h @@ -0,0 +1,7 @@ +#import "GPUImageTwoInputFilter.h" + +@interface GPUImageSoftLightBlendFilter : GPUImageTwoInputFilter +{ +} + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSolidColorGenerator.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSolidColorGenerator.h new file mode 100644 index 00000000..8d7a5ed1 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSolidColorGenerator.h @@ -0,0 +1,19 @@ +#import "GPUImageFilter.h" + +// This outputs an image with a constant color. You need to use -forceProcessingAtSize: in order to set the output image +// dimensions, or this won't work correctly + + +@interface GPUImageSolidColorGenerator : GPUImageFilter +{ + GLint colorUniform; + GLint useExistingAlphaUniform; +} + +// This color dictates what the output image will be filled with +@property(readwrite, nonatomic) GPUVector4 color; +@property(readwrite, nonatomic, assign) BOOL useExistingAlpha; // whether to use the alpha of the existing image or not, default is NO + +- (void)setColorRed:(GLfloat)redComponent green:(GLfloat)greenComponent blue:(GLfloat)blueComponent alpha:(GLfloat)alphaComponent; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSourceOverBlendFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSourceOverBlendFilter.h new file mode 100644 index 00000000..29e30635 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSourceOverBlendFilter.h @@ -0,0 +1,5 @@ +#import "GPUImageTwoInputFilter.h" + +@interface GPUImageSourceOverBlendFilter : GPUImageTwoInputFilter + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSphereRefractionFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSphereRefractionFilter.h new file mode 100644 index 00000000..cbbd2afa --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSphereRefractionFilter.h @@ -0,0 +1,15 @@ +#import "GPUImageFilter.h" + +@interface GPUImageSphereRefractionFilter : GPUImageFilter +{ + GLint radiusUniform, centerUniform, aspectRatioUniform, refractiveIndexUniform; +} + +/// The center about which to apply the distortion, with a default of (0.5, 0.5) +@property(readwrite, nonatomic) CGPoint center; +/// The radius of the distortion, ranging from 0.0 to 1.0, with a default of 0.25 +@property(readwrite, nonatomic) CGFloat radius; +/// The index of refraction for the sphere, with a default of 0.71 +@property(readwrite, nonatomic) CGFloat refractiveIndex; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageStretchDistortionFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageStretchDistortionFilter.h new file mode 100755 index 00000000..07803095 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageStretchDistortionFilter.h @@ -0,0 +1,13 @@ +#import "GPUImageFilter.h" + +/** Creates a stretch distortion of the image + */ +@interface GPUImageStretchDistortionFilter : GPUImageFilter { + GLint centerUniform; +} + +/** The center about which to apply the distortion, with a default of (0.5, 0.5) + */ +@property(readwrite, nonatomic) CGPoint center; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSubtractBlendFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSubtractBlendFilter.h new file mode 100755 index 00000000..8dee8215 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSubtractBlendFilter.h @@ -0,0 +1,5 @@ +#import "GPUImageTwoInputFilter.h" + +@interface GPUImageSubtractBlendFilter : GPUImageTwoInputFilter + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSwirlFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSwirlFilter.h new file mode 100755 index 00000000..ed7d0122 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSwirlFilter.h @@ -0,0 +1,17 @@ +#import "GPUImageFilter.h" + +/** Creates a swirl distortion on the image + */ +@interface GPUImageSwirlFilter : GPUImageFilter +{ + GLint radiusUniform, centerUniform, angleUniform; +} + +/// The center about which to apply the distortion, with a default of (0.5, 0.5) +@property(readwrite, nonatomic) CGPoint center; +/// The radius of the distortion, ranging from 0.0 to 1.0, with a default of 0.5 +@property(readwrite, nonatomic) CGFloat radius; +/// The amount of distortion to apply, with a minimum of 0.0 and a default of 1.0 +@property(readwrite, nonatomic) CGFloat angle; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageThreeInputFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageThreeInputFilter.h new file mode 100644 index 00000000..5ecd53e0 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageThreeInputFilter.h @@ -0,0 +1,21 @@ +#import "GPUImageTwoInputFilter.h" + +extern NSString *const kGPUImageThreeInputTextureVertexShaderString; + +@interface GPUImageThreeInputFilter : GPUImageTwoInputFilter +{ + GPUImageFramebuffer *thirdInputFramebuffer; + + GLint filterThirdTextureCoordinateAttribute; + GLint filterInputTextureUniform3; + GPUImageRotationMode inputRotation3; + GLuint filterSourceTexture3; + CMTime thirdFrameTime; + + BOOL hasSetSecondTexture, hasReceivedThirdFrame, thirdFrameWasVideo; + BOOL thirdFrameCheckDisabled; +} + +- (void)disableThirdFrameCheck; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageThresholdEdgeDetectionFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageThresholdEdgeDetectionFilter.h new file mode 100755 index 00000000..2036030c --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageThresholdEdgeDetectionFilter.h @@ -0,0 +1,12 @@ +#import "GPUImageSobelEdgeDetectionFilter.h" + +@interface GPUImageThresholdEdgeDetectionFilter : GPUImageSobelEdgeDetectionFilter +{ + GLint thresholdUniform; +} + +/** Any edge above this threshold will be black, and anything below white. Ranges from 0.0 to 1.0, with 0.8 as the default + */ +@property(readwrite, nonatomic) CGFloat threshold; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageThresholdSketchFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageThresholdSketchFilter.h new file mode 100644 index 00000000..fda58979 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageThresholdSketchFilter.h @@ -0,0 +1,5 @@ +#import "GPUImageThresholdEdgeDetectionFilter.h" + +@interface GPUImageThresholdSketchFilter : GPUImageThresholdEdgeDetectionFilter + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageThresholdedNonMaximumSuppressionFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageThresholdedNonMaximumSuppressionFilter.h new file mode 100644 index 00000000..9c6e5d72 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageThresholdedNonMaximumSuppressionFilter.h @@ -0,0 +1,14 @@ +#import "GPUImage3x3TextureSamplingFilter.h" + +@interface GPUImageThresholdedNonMaximumSuppressionFilter : GPUImage3x3TextureSamplingFilter +{ + GLint thresholdUniform; +} + +/** Any local maximum above this threshold will be white, and anything below black. Ranges from 0.0 to 1.0, with 0.8 as the default + */ +@property(readwrite, nonatomic) CGFloat threshold; + +- (id)initWithPackedColorspace:(BOOL)inputUsesPackedColorspace; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageTiltShiftFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageTiltShiftFilter.h new file mode 100755 index 00000000..e41adee7 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageTiltShiftFilter.h @@ -0,0 +1,24 @@ +#import "GPUImageFilterGroup.h" + +@class GPUImageGaussianBlurFilter; + +/// A simulated tilt shift lens effect +@interface GPUImageTiltShiftFilter : GPUImageFilterGroup +{ + GPUImageGaussianBlurFilter *blurFilter; + GPUImageFilter *tiltShiftFilter; +} + +/// The radius of the underlying blur, in pixels. This is 7.0 by default. +@property(readwrite, nonatomic) CGFloat blurRadiusInPixels; + +/// The normalized location of the top of the in-focus area in the image, this value should be lower than bottomFocusLevel, default 0.4 +@property(readwrite, nonatomic) CGFloat topFocusLevel; + +/// The normalized location of the bottom of the in-focus area in the image, this value should be higher than topFocusLevel, default 0.6 +@property(readwrite, nonatomic) CGFloat bottomFocusLevel; + +/// The rate at which the image gets blurry away from the in-focus region, default 0.2 +@property(readwrite, nonatomic) CGFloat focusFallOffRate; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageToneCurveFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageToneCurveFilter.h new file mode 100755 index 00000000..ff4ae92e --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageToneCurveFilter.h @@ -0,0 +1,30 @@ +#import "GPUImageFilter.h" + +@interface GPUImageToneCurveFilter : GPUImageFilter + +@property(readwrite, nonatomic, copy) NSArray *redControlPoints; +@property(readwrite, nonatomic, copy) NSArray *greenControlPoints; +@property(readwrite, nonatomic, copy) NSArray *blueControlPoints; +@property(readwrite, nonatomic, copy) NSArray *rgbCompositeControlPoints; + +// Initialization and teardown +- (id)initWithACVData:(NSData*)data; + +- (id)initWithACV:(NSString*)curveFilename; +- (id)initWithACVURL:(NSURL*)curveFileURL; + +// This lets you set all three red, green, and blue tone curves at once. +// NOTE: Deprecated this function because this effect can be accomplished +// using the rgbComposite channel rather then setting all 3 R, G, and B channels. +- (void)setRGBControlPoints:(NSArray *)points DEPRECATED_ATTRIBUTE; + +- (void)setPointsWithACV:(NSString*)curveFilename; +- (void)setPointsWithACVURL:(NSURL*)curveFileURL; + +// Curve calculation +- (NSMutableArray *)getPreparedSplineCurve:(NSArray *)points; +- (NSMutableArray *)splineCurve:(NSArray *)points; +- (NSMutableArray *)secondDerivative:(NSArray *)cgPoints; +- (void)updateToneCurveTexture; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageToonFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageToonFilter.h new file mode 100755 index 00000000..ef8e17c3 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageToonFilter.h @@ -0,0 +1,19 @@ +#import "GPUImage3x3TextureSamplingFilter.h" + +/** This uses Sobel edge detection to place a black border around objects, + and then it quantizes the colors present in the image to give a cartoon-like quality to the image. + */ +@interface GPUImageToonFilter : GPUImage3x3TextureSamplingFilter +{ + GLint thresholdUniform, quantizationLevelsUniform; +} + +/** The threshold at which to apply the edges, default of 0.2 + */ +@property(readwrite, nonatomic) CGFloat threshold; + +/** The levels of quantization for the posterization of colors within the scene, with a default of 10.0 + */ +@property(readwrite, nonatomic) CGFloat quantizationLevels; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageTransformFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageTransformFilter.h new file mode 100755 index 00000000..9865b853 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageTransformFilter.h @@ -0,0 +1,19 @@ +#import "GPUImageFilter.h" + +@interface GPUImageTransformFilter : GPUImageFilter +{ + GLint transformMatrixUniform, orthographicMatrixUniform; + GPUMatrix4x4 orthographicMatrix; +} + +// You can either set the transform to apply to be a 2-D affine transform or a 3-D transform. The default is the identity transform (the output image is identical to the input). +@property(readwrite, nonatomic) CGAffineTransform affineTransform; +@property(readwrite, nonatomic) CATransform3D transform3D; + +// This applies the transform to the raw frame data if set to YES, the default of NO takes the aspect ratio of the image input into account when rotating +@property(readwrite, nonatomic) BOOL ignoreAspectRatio; + +// sets the anchor point to top left corner +@property(readwrite, nonatomic) BOOL anchorTopLeft; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageTwoInputCrossTextureSamplingFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageTwoInputCrossTextureSamplingFilter.h new file mode 100644 index 00000000..64eac9dc --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageTwoInputCrossTextureSamplingFilter.h @@ -0,0 +1,15 @@ +#import "GPUImageTwoInputFilter.h" + +@interface GPUImageTwoInputCrossTextureSamplingFilter : GPUImageTwoInputFilter +{ + GLint texelWidthUniform, texelHeightUniform; + + CGFloat texelWidth, texelHeight; + BOOL hasOverriddenImageSizeFactor; +} + +// The texel width and height determines how far out to sample from this texel. By default, this is the normalized width of a pixel, but this can be overridden for different effects. +@property(readwrite, nonatomic) CGFloat texelWidth; +@property(readwrite, nonatomic) CGFloat texelHeight; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageTwoInputFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageTwoInputFilter.h new file mode 100644 index 00000000..da3a1345 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageTwoInputFilter.h @@ -0,0 +1,21 @@ +#import "GPUImageFilter.h" + +extern NSString *const kGPUImageTwoInputTextureVertexShaderString; + +@interface GPUImageTwoInputFilter : GPUImageFilter +{ + GPUImageFramebuffer *secondInputFramebuffer; + + GLint filterSecondTextureCoordinateAttribute; + GLint filterInputTextureUniform2; + GPUImageRotationMode inputRotation2; + CMTime firstFrameTime, secondFrameTime; + + BOOL hasSetFirstTexture, hasReceivedFirstFrame, hasReceivedSecondFrame, firstFrameWasVideo, secondFrameWasVideo; + BOOL firstFrameCheckDisabled, secondFrameCheckDisabled; +} + +- (void)disableFirstFrameCheck; +- (void)disableSecondFrameCheck; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageTwoPassFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageTwoPassFilter.h new file mode 100755 index 00000000..23087f35 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageTwoPassFilter.h @@ -0,0 +1,19 @@ +#import "GPUImageFilter.h" + +@interface GPUImageTwoPassFilter : GPUImageFilter +{ + GPUImageFramebuffer *secondOutputFramebuffer; + + GLProgram *secondFilterProgram; + GLint secondFilterPositionAttribute, secondFilterTextureCoordinateAttribute; + GLint secondFilterInputTextureUniform, secondFilterInputTextureUniform2; + + NSMutableDictionary *secondProgramUniformStateRestorationBlocks; +} + +// Initialization and teardown +- (id)initWithFirstStageVertexShaderFromString:(NSString *)firstStageVertexShaderString firstStageFragmentShaderFromString:(NSString *)firstStageFragmentShaderString secondStageVertexShaderFromString:(NSString *)secondStageVertexShaderString secondStageFragmentShaderFromString:(NSString *)secondStageFragmentShaderString; +- (id)initWithFirstStageFragmentShaderFromString:(NSString *)firstStageFragmentShaderString secondStageFragmentShaderFromString:(NSString *)secondStageFragmentShaderString; +- (void)initializeSecondaryAttributes; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageTwoPassTextureSamplingFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageTwoPassTextureSamplingFilter.h new file mode 100644 index 00000000..73ab79d3 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageTwoPassTextureSamplingFilter.h @@ -0,0 +1,13 @@ +#import "GPUImageTwoPassFilter.h" + +@interface GPUImageTwoPassTextureSamplingFilter : GPUImageTwoPassFilter +{ + GLint verticalPassTexelWidthOffsetUniform, verticalPassTexelHeightOffsetUniform, horizontalPassTexelWidthOffsetUniform, horizontalPassTexelHeightOffsetUniform; + GLfloat verticalPassTexelWidthOffset, verticalPassTexelHeightOffset, horizontalPassTexelWidthOffset, horizontalPassTexelHeightOffset; + CGFloat _verticalTexelSpacing, _horizontalTexelSpacing; +} + +// This sets the spacing between texels (in pixels) when sampling for the first. By default, this is 1.0 +@property(readwrite, nonatomic) CGFloat verticalTexelSpacing, horizontalTexelSpacing; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageUnsharpMaskFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageUnsharpMaskFilter.h new file mode 100755 index 00000000..9d8aff01 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageUnsharpMaskFilter.h @@ -0,0 +1,16 @@ +#import "GPUImageFilterGroup.h" + +@class GPUImageGaussianBlurFilter; + +@interface GPUImageUnsharpMaskFilter : GPUImageFilterGroup +{ + GPUImageGaussianBlurFilter *blurFilter; + GPUImageFilter *unsharpMaskFilter; +} +// The blur radius of the underlying Gaussian blur. The default is 4.0. +@property (readwrite, nonatomic) CGFloat blurRadiusInPixels; + +// The strength of the sharpening, from 0.0 on up, with a default of 1.0 +@property(readwrite, nonatomic) CGFloat intensity; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageView.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageView.h new file mode 100755 index 00000000..029883a1 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageView.h @@ -0,0 +1,39 @@ +#import +#import "GPUImageContext.h" + +typedef enum { + kGPUImageFillModeStretch, // Stretch to fill the full view, which may distort the image outside of its normal aspect ratio + kGPUImageFillModePreserveAspectRatio, // Maintains the aspect ratio of the source image, adding bars of the specified background color + kGPUImageFillModePreserveAspectRatioAndFill // Maintains the aspect ratio of the source image, zooming in on its center to fill the view +} GPUImageFillModeType; + +/** + UIView subclass to use as an endpoint for displaying GPUImage outputs + */ +@interface GPUImageView : NSOpenGLView +{ + GPUImageRotationMode inputRotation; +} + +/** The fill mode dictates how images are fit in the view, with the default being kGPUImageFillModePreserveAspectRatio + */ +@property(readwrite, nonatomic) GPUImageFillModeType fillMode; + +/** This calculates the current display size, in pixels, taking into account Retina scaling factors + */ +@property(readonly, nonatomic) CGSize sizeInPixels; + +@property(nonatomic) BOOL enabled; + +/** Handling fill mode + + @param redComponent Red component for background color + @param greenComponent Green component for background color + @param blueComponent Blue component for background color + @param alphaComponent Alpha component for background color + */ +- (void)setBackgroundColorRed:(GLfloat)redComponent green:(GLfloat)greenComponent blue:(GLfloat)blueComponent alpha:(GLfloat)alphaComponent; + +- (void)setCurrentlyReceivingMonochromeInput:(BOOL)newValue; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageVignetteFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageVignetteFilter.h new file mode 100755 index 00000000..37be9449 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageVignetteFilter.h @@ -0,0 +1,22 @@ +#import "GPUImageFilter.h" + +/** Performs a vignetting effect, fading out the image at the edges + */ +@interface GPUImageVignetteFilter : GPUImageFilter +{ + GLint vignetteCenterUniform, vignetteColorUniform, vignetteStartUniform, vignetteEndUniform; +} + +// the center for the vignette in tex coords (defaults to 0.5, 0.5) +@property (nonatomic, readwrite) CGPoint vignetteCenter; + +// The color to use for the Vignette (defaults to black) +@property (nonatomic, readwrite) GPUVector3 vignetteColor; + +// The normalized distance from the center where the vignette effect starts. Default of 0.5. +@property (nonatomic, readwrite) CGFloat vignetteStart; + +// The normalized distance from the center where the vignette effect ends. Default of 0.75. +@property (nonatomic, readwrite) CGFloat vignetteEnd; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageVoronoiConsumerFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageVoronoiConsumerFilter.h new file mode 100644 index 00000000..659e39d5 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageVoronoiConsumerFilter.h @@ -0,0 +1,10 @@ +#import "GPUImageTwoInputFilter.h" + +@interface GPUImageVoronoiConsumerFilter : GPUImageTwoInputFilter +{ + GLint sizeUniform; +} + +@property (nonatomic, readwrite) CGSize sizeInPixels; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageWeakPixelInclusionFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageWeakPixelInclusionFilter.h new file mode 100644 index 00000000..44b76c6a --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageWeakPixelInclusionFilter.h @@ -0,0 +1,5 @@ +#import "GPUImage3x3TextureSamplingFilter.h" + +@interface GPUImageWeakPixelInclusionFilter : GPUImage3x3TextureSamplingFilter + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageWhiteBalanceFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageWhiteBalanceFilter.h new file mode 100644 index 00000000..eafd65a0 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageWhiteBalanceFilter.h @@ -0,0 +1,17 @@ +#import "GPUImageFilter.h" +/** + * Created by Alaric Cole + * Allows adjustment of color temperature in terms of what an image was effectively shot in. This means higher Kelvin values will warm the image, while lower values will cool it. + + */ +@interface GPUImageWhiteBalanceFilter : GPUImageFilter +{ + GLint temperatureUniform, tintUniform; +} +//choose color temperature, in degrees Kelvin +@property(readwrite, nonatomic) int temperature; + +//adjust tint to compensate +@property(readwrite, nonatomic) int tint; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageXYDerivativeFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageXYDerivativeFilter.h new file mode 100755 index 00000000..8db57457 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageXYDerivativeFilter.h @@ -0,0 +1,5 @@ +#import "GPUImageSobelEdgeDetectionFilter.h" + +@interface GPUImageXYDerivativeFilter : GPUImageSobelEdgeDetectionFilter + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageZoomBlurFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageZoomBlurFilter.h new file mode 100644 index 00000000..744a72cb --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageZoomBlurFilter.h @@ -0,0 +1,13 @@ +#import "GPUImageFilter.h" + +@interface GPUImageZoomBlurFilter : GPUImageFilter + +/** A multiplier for the blur size, ranging from 0.0 on up, with a default of 1.0 + */ +@property (readwrite, nonatomic) CGFloat blurSize; + +/** The normalized center of the blur. (0.5, 0.5) by default + */ +@property (readwrite, nonatomic) CGPoint blurCenter; + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUimageDirectionalSobelEdgeDetectionFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUimageDirectionalSobelEdgeDetectionFilter.h new file mode 100644 index 00000000..3aca7463 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUimageDirectionalSobelEdgeDetectionFilter.h @@ -0,0 +1,5 @@ +#import "GPUImage3x3TextureSamplingFilter.h" + +@interface GPUimageDirectionalSobelEdgeDetectionFilter : GPUImage3x3TextureSamplingFilter + +@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Resources/Info.plist b/app/Frameworks/GPUImage.framework/Versions/A/Resources/Info.plist new file mode 100644 index 00000000..66b42e21 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/A/Resources/Info.plist @@ -0,0 +1,42 @@ + + + + + BuildMachineOSBuild + 13A603 + CFBundleDevelopmentRegion + English + CFBundleExecutable + GPUImage + CFBundleIdentifier + com.sunsetlakesoftware.GPUImage + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + GPUImage + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + DTCompiler + com.apple.compilers.llvm.clang.1_0 + DTPlatformBuild + 5B1008 + DTPlatformVersion + GM + DTSDKBuild + 13C64 + DTSDKName + macosx10.9 + DTXcode + 0511 + DTXcodeBuild + 5B1008 + NSHumanReadableCopyright + Copyright © 2013 Sunset Lake Software LLC. All rights reserved. + + diff --git a/app/Frameworks/GPUImage.framework/Versions/Current b/app/Frameworks/GPUImage.framework/Versions/Current new file mode 120000 index 00000000..8c7e5a66 --- /dev/null +++ b/app/Frameworks/GPUImage.framework/Versions/Current @@ -0,0 +1 @@ +A \ No newline at end of file diff --git a/app/deps/tensor/Filter.h b/app/deps/tensor/Filter.h new file mode 100644 index 00000000..282c085c --- /dev/null +++ b/app/deps/tensor/Filter.h @@ -0,0 +1,27 @@ +// +// filters.h +// PlotDevice +// +// Created by fish2k on 12/7/13. +// +// + +#import +#import +#import + +@interface Filter : NSObject { + NSImage *inputImage; + NSImage *outputImage; + GPUImageHalftoneFilter *filter; +} + +@property(nonatomic, copy) NSImage *inputImage; +@property(nonatomic, copy) NSImage *outputImage; +@property(nonatomic, retain) GPUImageHalftoneFilter *filter; + + +- (id)init; +- (NSImage *)process:(NSImage *)input; + +@end \ No newline at end of file diff --git a/app/deps/tensor/Filter.m b/app/deps/tensor/Filter.m new file mode 100644 index 00000000..8ff63c82 --- /dev/null +++ b/app/deps/tensor/Filter.m @@ -0,0 +1,30 @@ +// +// Filter.m +// PlotDevice +// +// Created by fish2k on 12/13/13. +// +// + +#import "Filter.h" + +@implementation Filter + +@synthesize inputImage, outputImage, filter; + +- (id)init { + self = [super init]; + if (self) { + filter = [GPUImageHalftoneFilter init]; + } + return self; +} + +- (NSImage *)process:(NSImage *)input { + /// - (NSImage *)imageByFilteringImage:(NSImage *)imageToFilter; + inputImage = input; + outputImage = [filter imageByFilteringImage:input]; + return outputImage; +} + +@end \ No newline at end of file diff --git a/app/deps/tensor/module.m b/app/deps/tensor/module.m new file mode 100644 index 00000000..84ca6b3a --- /dev/null +++ b/app/deps/tensor/module.m @@ -0,0 +1,11 @@ +#import + +PyMethodDef methods[] = { + {NULL, NULL}, +}; + +void inittensor() + { + (void)Py_InitModule("tensor", methods); + } + diff --git a/app/deps/tensor/setup.py b/app/deps/tensor/setup.py new file mode 100644 index 00000000..6bea1116 --- /dev/null +++ b/app/deps/tensor/setup.py @@ -0,0 +1,35 @@ +from os import getcwd +from os.path import dirname, join +# from distutils.core import setup, Extension +from setuptools import setup, find_packages +from setuptools.extension import Extension + +frameworks = join(dirname(dirname(getcwd())), 'Frameworks') +gpuimage_libs = join(frameworks, 'GPUImage.framework', 'Versions', 'A') +gpuimage_headers = join(gpuimage_libs, 'Headers') + +tensor = Extension('tensor', + sources=[ + 'module.m', + 'Filter.m'], + extra_compile_args=[ + '-Wno-error=unused-command-line-argument-hard-error-in-future', + '-Qunused-arguments', + '-F%s' % frameworks], + extra_link_args=[ + '-Wno-error=unused-command-line-argument-hard-error-in-future', + '-L%s' % gpuimage_libs, + '-F%s' % frameworks, + '-framework', 'AppKit', + '-framework', 'Foundation', + '-framework', 'Quartz', + '-framework', 'Security', + '-framework', 'CoreMedia', + '-framework', 'GPUImage']) + +setup(name="tensor", + version="1.0", + author="fish2k", + description="GPU-based image processing", + ext_modules=[tensor], + include_dirs=[gpuimage_headers]) \ No newline at end of file diff --git a/app/deps/tensor/tensor.so b/app/deps/tensor/tensor.so new file mode 100755 index 0000000000000000000000000000000000000000..cbae236be1ab94a4f2888a359322a7e055717027 GIT binary patch literal 11668 zcmeHNeP~xw|8%UyhaFLix8p>aSLK`oe(b~rLYyz522== z*njGTEOK8qxuIYTPO%zsEsHhH(l1ywT`%A0dRz82pPdqJt*H~JIH9JQR(Zl)D)RE( z++d47!y1H{T9&ji-vcbS`Lv9lE9xbbdHFtIz9H5pyo&QOS>|8Tv`X2+8P@Ug^*&?^ zR6i@MC|%qr)HGw_xullYtxO@2*O&SCOXkZnfx`FTOXd=$NrYbic5JjQX&fmiY$H$G zQRwi`nk+8&uZ#HxnLy#jeC5LVY$2s(3u#00yYIgu^Ql`>Va4Z7HBHZG=@NCF4Bqz6 zFkd$t5~gROQK07n_Ym4W6gd%bXsPF+K}!8eynMUEzL3+*$^3+o(~4H9A)lh7=ga9A z-M{plsi0|R498=(jBgVY(X&p0u$NDbImtCGmsrU^KlAM*Wdy=bKH^e!k(}=ndEe!- zrseIwu*W~bPCihu2C*&iW%G$MI^8N>zNm+fu=m-rne40b&nTF(8@+s^%y&nP#yLJNYoSN+cDPfAriEqnGa#^Qk^3?BoMUJwCIH*Iqro zxQCDMeek6cR)YO?KOY(98?~D)2z&TgVkg|*?72j#F5flg^RpG+<@}v;oM@siFwYjZBh{H(NKPAN1;V3@cLiO!l58@;LpmE z@UBaQVw0w&=R+geiBh6889G3(fyvOvY~k;V zi;I~a%Ke3MhbVWGakaqvs$*0wS=7Z4NTf{EViTz{i0YhlDcX3J6$w& zYk0}we&MVbqN6n@`vup4Vw<>M*r^Ej>(B61~`41Q#GGcMC1&n5;CeXO1tJykHR)YwT@Nm#R|QM z5&ppS@8)&e`&|AWmn;1MPihvpJk0uGF2Cc^k8^pe(&Mzk<(nBR{;OR6xJUm6mj~c0 zjol5NS1SJwu|CPDoii*~{&?kTo~!B~^Vrijgt+!{dk%0q!D)fhX->bzDNJPj0m?Xn z8m}uv>hcwf>^}g97y(1&^C{Ve{JTfo2ah zd!X3^%^qm>K(hy$J<#ldW)C!bpxFaUJ@D|8{;{EAcibO|(ci$>;PFVYEfzUGSPUG4 z)?;Dq=)l22ZEz$Ki)kHN{jC{s?Ce}?^;2PN%%g=&Pa~XZ>FcYon9eFt&{j8>wXY#0>T7BSy}eSzwB*r)CNwQu?yn{zMuoEu@U zqN;1#p?`xeGjy4SC52gkcRU=RAfdSX-g<0F`rZXnKk=ZGFWUa8Akuc$PY`KKVjdCO zlRjFq!$t<|3;UwT;b_WNM2cm+@4Mh6VJ9N-(9t&WY{H3MFi|Y#^q_r2gt8Xa?MB|I zySb)Y+v0cV_j&ZU*7VQHW1OYaCnzE`s^^iKoyo^EE9yU5(|4V#DE^(WcD7@kF(?A3N8 zVd_7HuOqMe5+d=tM)Lr){ov1v7LUn(gWUTI&4C4U%f01#R@hgnu zjDNtm!uU6guQL84;~R``0dK^4kJ?|QAMkC&X204e-o{w%JMU$z_L)x;hP~RCwFsj< z>UpjZ#*YEj?;)muA*Oe-3_r3l-rII~+k@Y?@yAO3FB_|Gg?OM<@-1P%2k-FUeh(h= z;PW=7pE}5}AJ=CQhY=4V(lOQuB0@NdOFel&gif0H%|R%gH8Y_h%mpTl3!!4puu}TD zY*G*5BNR&MMKff7szV|#XA;5uCpDZXXLBjA; zhnU$A_yOF~)Ik3HkLCpYeg7}i%gl!8I&EhIRR4Gls(L_JRxR%#>_x_jJjoXB)Su*2KDEM?-4O{$w4u z)ZhQ}-g3A6Khr68ch?(-dbhWGC>ty}+)7J}h2=HXM9b&@bru!N7X$8vg$wbbz%Ikc Q)maX#AhQ<&%N9-l2JmdBkN^Mx literal 0 HcmV?d00001 From 29424cb9fbebf67d98033b6f6a3ae50e63f65df6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Bo=CC=88hn?= Date: Mon, 7 Jul 2014 23:09:10 -0700 Subject: [PATCH 02/81] Ignoring .so files --- .gitignore | 1 + app/deps/tensor/module.m | 7 +++---- app/deps/tensor/tensor.so | Bin 11668 -> 0 bytes 3 files changed, 4 insertions(+), 4 deletions(-) delete mode 100755 app/deps/tensor/tensor.so diff --git a/.gitignore b/.gitignore index 86043d16..6d01aa67 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ .DS_Store *.pyc +*.so build/ dist/ app/deps/Sparkle* diff --git a/app/deps/tensor/module.m b/app/deps/tensor/module.m index 84ca6b3a..f73e193b 100644 --- a/app/deps/tensor/module.m +++ b/app/deps/tensor/module.m @@ -1,11 +1,10 @@ #import PyMethodDef methods[] = { - {NULL, NULL}, + { NULL, NULL }, }; -void inittensor() - { +void inittensor() { (void)Py_InitModule("tensor", methods); - } +} diff --git a/app/deps/tensor/tensor.so b/app/deps/tensor/tensor.so deleted file mode 100755 index cbae236be1ab94a4f2888a359322a7e055717027..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11668 zcmeHNeP~xw|8%UyhaFLix8p>aSLK`oe(b~rLYyz522== z*njGTEOK8qxuIYTPO%zsEsHhH(l1ywT`%A0dRz82pPdqJt*H~JIH9JQR(Zl)D)RE( z++d47!y1H{T9&ji-vcbS`Lv9lE9xbbdHFtIz9H5pyo&QOS>|8Tv`X2+8P@Ug^*&?^ zR6i@MC|%qr)HGw_xullYtxO@2*O&SCOXkZnfx`FTOXd=$NrYbic5JjQX&fmiY$H$G zQRwi`nk+8&uZ#HxnLy#jeC5LVY$2s(3u#00yYIgu^Ql`>Va4Z7HBHZG=@NCF4Bqz6 zFkd$t5~gROQK07n_Ym4W6gd%bXsPF+K}!8eynMUEzL3+*$^3+o(~4H9A)lh7=ga9A z-M{plsi0|R498=(jBgVY(X&p0u$NDbImtCGmsrU^KlAM*Wdy=bKH^e!k(}=ndEe!- zrseIwu*W~bPCihu2C*&iW%G$MI^8N>zNm+fu=m-rne40b&nTF(8@+s^%y&nP#yLJNYoSN+cDPfAriEqnGa#^Qk^3?BoMUJwCIH*Iqro zxQCDMeek6cR)YO?KOY(98?~D)2z&TgVkg|*?72j#F5flg^RpG+<@}v;oM@siFwYjZBh{H(NKPAN1;V3@cLiO!l58@;LpmE z@UBaQVw0w&=R+geiBh6889G3(fyvOvY~k;V zi;I~a%Ke3MhbVWGakaqvs$*0wS=7Z4NTf{EViTz{i0YhlDcX3J6$w& zYk0}we&MVbqN6n@`vup4Vw<>M*r^Ej>(B61~`41Q#GGcMC1&n5;CeXO1tJykHR)YwT@Nm#R|QM z5&ppS@8)&e`&|AWmn;1MPihvpJk0uGF2Cc^k8^pe(&Mzk<(nBR{;OR6xJUm6mj~c0 zjol5NS1SJwu|CPDoii*~{&?kTo~!B~^Vrijgt+!{dk%0q!D)fhX->bzDNJPj0m?Xn z8m}uv>hcwf>^}g97y(1&^C{Ve{JTfo2ah zd!X3^%^qm>K(hy$J<#ldW)C!bpxFaUJ@D|8{;{EAcibO|(ci$>;PFVYEfzUGSPUG4 z)?;Dq=)l22ZEz$Ki)kHN{jC{s?Ce}?^;2PN%%g=&Pa~XZ>FcYon9eFt&{j8>wXY#0>T7BSy}eSzwB*r)CNwQu?yn{zMuoEu@U zqN;1#p?`xeGjy4SC52gkcRU=RAfdSX-g<0F`rZXnKk=ZGFWUa8Akuc$PY`KKVjdCO zlRjFq!$t<|3;UwT;b_WNM2cm+@4Mh6VJ9N-(9t&WY{H3MFi|Y#^q_r2gt8Xa?MB|I zySb)Y+v0cV_j&ZU*7VQHW1OYaCnzE`s^^iKoyo^EE9yU5(|4V#DE^(WcD7@kF(?A3N8 zVd_7HuOqMe5+d=tM)Lr){ov1v7LUn(gWUTI&4C4U%f01#R@hgnu zjDNtm!uU6guQL84;~R``0dK^4kJ?|QAMkC&X204e-o{w%JMU$z_L)x;hP~RCwFsj< z>UpjZ#*YEj?;)muA*Oe-3_r3l-rII~+k@Y?@yAO3FB_|Gg?OM<@-1P%2k-FUeh(h= z;PW=7pE}5}AJ=CQhY=4V(lOQuB0@NdOFel&gif0H%|R%gH8Y_h%mpTl3!!4puu}TD zY*G*5BNR&MMKff7szV|#XA;5uCpDZXXLBjA; zhnU$A_yOF~)Ik3HkLCpYeg7}i%gl!8I&EhIRR4Gls(L_JRxR%#>_x_jJjoXB)Su*2KDEM?-4O{$w4u z)ZhQ}-g3A6Khr68ch?(-dbhWGC>ty}+)7J}h2=HXM9b&@bru!N7X$8vg$wbbz%Ikc Q)maX#AhQ<&%N9-l2JmdBkN^Mx From 0567175b5527554d8181f7bca9e263f7b4ed5c17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Bo=CC=88hn?= Date: Tue, 8 Jul 2014 02:45:19 -0700 Subject: [PATCH 03/81] Disable directory asserting in setup.py --- plotdevice/lib/tensor.py | 140 +++++++++++++++++++++++++++++++++++++++ setup.py | 2 +- 2 files changed, 141 insertions(+), 1 deletion(-) create mode 100644 plotdevice/lib/tensor.py diff --git a/plotdevice/lib/tensor.py b/plotdevice/lib/tensor.py new file mode 100644 index 00000000..52c55d7f --- /dev/null +++ b/plotdevice/lib/tensor.py @@ -0,0 +1,140 @@ + +import objc +from PyObjCTools import AppHelper +import tensor +for cls in ["Filter"]: + globals()[cls] = objc.lookUpClass(cls) + +""" Wrapper classes around the Tensor image filters """ + +# NSUnknownColorSpaceModel = -1, +NSColorSpaceModels = ( + "NSGrayColorSpaceModel", + "NSRGBColorSpaceModel", + "NSCMYKColorSpaceModel", + "NSLABColorSpaceModel", + "NSDeviceNColorSpaceModel", + "NSIndexedColorSpaceModel", + "NSPatternColorSpaceModel" +) + +class Pipe(list): + """ A linear pipeline of processors to be applied en masse. """ + def process(self, img): + for p in self: + img = p.process(img) + return img + +class NOOp(object): + """ A no-op processor. """ + def process(self, img): + return img + +class ChannelFork(defaultdict): + """ A processor wrapper that, for each image channel: + - applies a channel-specific processor, or + - applies a default processor. """ + + default_mode = 1 # 'NSRGBColorSpaceModel' + + def __init__(self, default_factory, *args, **kwargs): + if default_factory is None: + default_factory = NOOp + if not callable(default_factory): + raise AttributeError( + "ChannelFork() requires a callable default_factory.") + + self.channels = NSColorSpaceModels[int(kwargs.pop('mode', self.default_mode))] + + super(ChannelFork, self).__init__(default_factory, *args, **kwargs) + + def __setitem__(self, idx, value): + if value in (None, NOOp): + value = NOOp() + super(ChannelFork, self).__setitem__(idx, value) + + @property + def mode(self): + return self.channels.mode + + @mode.setter + def mode(self, mode_string): + self._set_mode(mode_string) + + def _set_mode(self, mode_string): + self.channels = ImageMode.getmode(mode_string) + + def compose(self, *channels): + return Image.merge( + self.channels.mode, + channels) + + def process(self, img): + if img.mode != self.channels.mode: + img = img.convert(self.channels.mode) + + processed_channels = [] + for idx, channel in enumerate(img.split()): + processed_channels.append( + self[self.channels.bands[idx]].process(channel)) + + return self.compose(*processed_channels) + +class CMYKInk(object): + """ Renders an input L-mode image, + by simulating a CMYK primary ink color. + """ + + WHITE = (255, 255, 255) + CYAN = (0, 250, 250) + MAGENTA = (250, 0, 250) + YELLOW = (250, 250, 0) + KEY = (0, 0, 0) + CMYK = (CYAN, MAGENTA, YELLOW, KEY) + + def __init__(self, ink_value=None): + if ink_value is None: + ink_value = self.KEY + self.ink_value = ink_value + + def process(self, img): + from PIL import ImageOps + return ImageOps.colorize( + img.convert('L'), + self.WHITE, + self.ink_value) + + +class ChannelOverprinter(ChannelFork): + """ A ChannelFork subclass that rebuilds its output image using + multiply-mode to simulate CMYK overprinting effects. + """ + default_mode = 'CMYK' + + def _set_mode(self, mode_string): + if mode_string != self.default_mode: + raise AttributeError( + "ChannelOverprinter can operate in %s mode only" % + self.default_mode) + + def compose(self, *channels): + from PIL import ImageChops + return reduce(ImageChops.multiply, channels) + + def process(self, img): + inks = zip(self.default_mode, + [CMYKInk(ink_label) \ + for ink_label in CMYKInk.CMYK]) + + clone = ChannelOverprinter( + self.default_factory, + mode=self.channels.mode) + + for channel_name, ink in inks: + clone[channel_name] = Pipe([ + self[channel_name], ink]) + + return super(ChannelOverprinter, clone).process(img) + + + diff --git a/setup.py b/setup.py index 878ef779..4591dbb0 100644 --- a/setup.py +++ b/setup.py @@ -248,7 +248,7 @@ def finalize_options(self): self.verbose=0 build_py2app.finalize_options(self) def run(self): - assert os.getcwd() == self.cwd, 'Must be in package root: %s' % self.cwd + #assert os.getcwd() == self.cwd, 'Must be in package root: %s' % self.cwd build_py2app.run(self) if self.dry_run: return From 1010403da51a613cde183f2c66e741e90b544a5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Bo=CC=88hn?= Date: Tue, 8 Jul 2014 07:34:35 -0700 Subject: [PATCH 04/81] PyObjC wrapper class with pythonic syntax sugar --- app/deps/tensor/Filter.h | 5 ---- app/deps/tensor/Filter.m | 7 ++---- app/deps/tensor/module.m | 4 +-- app/deps/tensor/setup.py | 6 ++--- plotdevice/lib/rtclass.py | 53 +++++++++++++++++++++++++++++++++++++++ plotdevice/lib/tensor.py | 26 ++++++++++++------- 6 files changed, 77 insertions(+), 24 deletions(-) create mode 100644 plotdevice/lib/rtclass.py diff --git a/app/deps/tensor/Filter.h b/app/deps/tensor/Filter.h index 282c085c..45510129 100644 --- a/app/deps/tensor/Filter.h +++ b/app/deps/tensor/Filter.h @@ -11,16 +11,11 @@ #import @interface Filter : NSObject { - NSImage *inputImage; - NSImage *outputImage; GPUImageHalftoneFilter *filter; } -@property(nonatomic, copy) NSImage *inputImage; -@property(nonatomic, copy) NSImage *outputImage; @property(nonatomic, retain) GPUImageHalftoneFilter *filter; - - (id)init; - (NSImage *)process:(NSImage *)input; diff --git a/app/deps/tensor/Filter.m b/app/deps/tensor/Filter.m index 8ff63c82..29a54b5d 100644 --- a/app/deps/tensor/Filter.m +++ b/app/deps/tensor/Filter.m @@ -10,7 +10,7 @@ @implementation Filter -@synthesize inputImage, outputImage, filter; +@synthesize filter; - (id)init { self = [super init]; @@ -21,10 +21,7 @@ - (id)init { } - (NSImage *)process:(NSImage *)input { - /// - (NSImage *)imageByFilteringImage:(NSImage *)imageToFilter; - inputImage = input; - outputImage = [filter imageByFilteringImage:input]; - return outputImage; + return [filter imageByFilteringImage:input]; } @end \ No newline at end of file diff --git a/app/deps/tensor/module.m b/app/deps/tensor/module.m index f73e193b..ff1185c5 100644 --- a/app/deps/tensor/module.m +++ b/app/deps/tensor/module.m @@ -4,7 +4,7 @@ { NULL, NULL }, }; -void inittensor() { - (void)Py_InitModule("tensor", methods); +PyMODINIT_FUNC inittensorlib() { + (void)Py_InitModule("tensorlib", methods); } diff --git a/app/deps/tensor/setup.py b/app/deps/tensor/setup.py index 6bea1116..4727813d 100644 --- a/app/deps/tensor/setup.py +++ b/app/deps/tensor/setup.py @@ -8,7 +8,7 @@ gpuimage_libs = join(frameworks, 'GPUImage.framework', 'Versions', 'A') gpuimage_headers = join(gpuimage_libs, 'Headers') -tensor = Extension('tensor', +tensorlib = Extension('tensorlib', sources=[ 'module.m', 'Filter.m'], @@ -27,9 +27,9 @@ '-framework', 'CoreMedia', '-framework', 'GPUImage']) -setup(name="tensor", +setup(name="tensorlib", version="1.0", author="fish2k", description="GPU-based image processing", - ext_modules=[tensor], + ext_modules=[tensorlib], include_dirs=[gpuimage_headers]) \ No newline at end of file diff --git a/plotdevice/lib/rtclass.py b/plotdevice/lib/rtclass.py new file mode 100644 index 00000000..d90ebe9e --- /dev/null +++ b/plotdevice/lib/rtclass.py @@ -0,0 +1,53 @@ + +from __future__ import print_function + +import objc, warnings +#from PyObjCTools import AppHelper + +OBJ_COLON = '_' + +class RTClass(object): + class __metaclass__(type): + """ Subclass RTClass using the name of an Objective-C class + to generate a pythonic wrapper (if you like your syntax sweet) + """ + def __new__(cls, name, bases, attrs): + create = super(RTClass, cls).__new__ + try: + cls.__rtbase__ = objc.lookUpClass(name) + except objc.nosuchclass_error: + warnings.warn("RTClass: Objective-C class '%s' not found" % name) + return create(name, bases, attrs) + return create(name, tuple([cls.__rtbase__] + list(bases)), attrs) + + def __new__(cls, *args, **kwargs): + """ Allow PyObjC-based RTClass subclasses to initialize pythonically e.g. + + nsarray = NSArray() # or: + nsarray = NSArray(other_nsarray, + init='initWithArray') + + rather than having to do the ObjC allocation/initialization dance: + + nsarray = NSArray.alloc().initWithArray_(other_nsarray) # bah + """ + if hasattr(cls, '__rtbase__'): + init_method_name = kwargs.pop('init', 'init') + instance = cls.alloc() + init_method = getattr(instance, init_method_name) + return init_method(*args) + return super(RTClass, cls).__new__(cls, *args, **kwargs) + + def __getattr__(self, attr): + """ For unknown attributes ending in underscores, + look for their underscoreless counterpart before bailing. """ + if attr.endswith(OBJ_COLON): + alt_attr = attr.rstrip(OBJ_COLON) + if hasattr(self, alt_attr): + return getattr(self, alt_attr) + raise AttributeError('%s (tried w/o underscore)' % attr) + raise AttributeError(attr) + + def __repr__(self): + # This may be a bad idea, let's find out + return "[RT] " + super(RTClass, self).__repr__() diff --git a/plotdevice/lib/tensor.py b/plotdevice/lib/tensor.py index 52c55d7f..c3b242a5 100644 --- a/plotdevice/lib/tensor.py +++ b/plotdevice/lib/tensor.py @@ -1,11 +1,19 @@ -import objc -from PyObjCTools import AppHelper -import tensor -for cls in ["Filter"]: - globals()[cls] = objc.lookUpClass(cls) +from __future__ import print_function + +from .rtclass import RTClass +#from collections import defaultdict +#from PyObjCTools import AppHelper + +import tensorlib + +# for cls in ["Filter"]: +# globals()[cls] = objc.lookUpClass(cls) + +class Filter(RTClass): + """ Wrapper class around a basic Tensor image filter """ + pass -""" Wrapper classes around the Tensor image filters """ # NSUnknownColorSpaceModel = -1, NSColorSpaceModels = ( @@ -30,6 +38,7 @@ class NOOp(object): def process(self, img): return img +''' class ChannelFork(defaultdict): """ A processor wrapper that, for each image channel: - applies a channel-specific processor, or @@ -135,6 +144,5 @@ def process(self, img): self[channel_name], ink]) return super(ChannelOverprinter, clone).process(img) - - - +''' +dir(tensorlib) \ No newline at end of file From 5d16421131fd4a853009d6f40fcfcbd1ffe21709 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Bo=CC=88hn?= Date: Tue, 8 Jul 2014 07:46:28 -0700 Subject: [PATCH 05/81] I totally had the underscore attribute logic backwards --- plotdevice/lib/rtclass.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/plotdevice/lib/rtclass.py b/plotdevice/lib/rtclass.py index d90ebe9e..8c752dca 100644 --- a/plotdevice/lib/rtclass.py +++ b/plotdevice/lib/rtclass.py @@ -39,13 +39,13 @@ def __new__(cls, *args, **kwargs): return super(RTClass, cls).__new__(cls, *args, **kwargs) def __getattr__(self, attr): - """ For unknown attributes ending in underscores, - look for their underscoreless counterpart before bailing. """ - if attr.endswith(OBJ_COLON): - alt_attr = attr.rstrip(OBJ_COLON) + """ For unknown attributes that don't end in underscores, + look for their underscored counterpart before bailing. """ + if not attr.endswith(OBJ_COLON): + alt_attr = attr + OBJ_COLON if hasattr(self, alt_attr): return getattr(self, alt_attr) - raise AttributeError('%s (tried w/o underscore)' % attr) + raise AttributeError('%s (tried with underscore)' % attr) raise AttributeError(attr) def __repr__(self): From cba12c63adbdfb3732dc4c8a7d16ce330e0aaf43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Bo=CC=88hn?= Date: Tue, 8 Jul 2014 07:49:27 -0700 Subject: [PATCH 06/81] Renamed 'filter' properly to HalftoneFilter --- app/deps/tensor/{Filter.h => HalftoneFilter.h} | 2 +- app/deps/tensor/{Filter.m => HalftoneFilter.m} | 4 ++-- app/deps/tensor/setup.py | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) rename app/deps/tensor/{Filter.h => HalftoneFilter.h} (89%) rename app/deps/tensor/{Filter.m => HalftoneFilter.m} (84%) diff --git a/app/deps/tensor/Filter.h b/app/deps/tensor/HalftoneFilter.h similarity index 89% rename from app/deps/tensor/Filter.h rename to app/deps/tensor/HalftoneFilter.h index 45510129..30e064a4 100644 --- a/app/deps/tensor/Filter.h +++ b/app/deps/tensor/HalftoneFilter.h @@ -10,7 +10,7 @@ #import #import -@interface Filter : NSObject { +@interface HalftoneFilter : NSObject { GPUImageHalftoneFilter *filter; } diff --git a/app/deps/tensor/Filter.m b/app/deps/tensor/HalftoneFilter.m similarity index 84% rename from app/deps/tensor/Filter.m rename to app/deps/tensor/HalftoneFilter.m index 29a54b5d..357ac871 100644 --- a/app/deps/tensor/Filter.m +++ b/app/deps/tensor/HalftoneFilter.m @@ -6,9 +6,9 @@ // // -#import "Filter.h" +#import "HalftoneFilter.h" -@implementation Filter +@implementation HalftoneFilter @synthesize filter; diff --git a/app/deps/tensor/setup.py b/app/deps/tensor/setup.py index 4727813d..5cd7c6d9 100644 --- a/app/deps/tensor/setup.py +++ b/app/deps/tensor/setup.py @@ -11,7 +11,7 @@ tensorlib = Extension('tensorlib', sources=[ 'module.m', - 'Filter.m'], + 'HalftoneFilter.m'], extra_compile_args=[ '-Wno-error=unused-command-line-argument-hard-error-in-future', '-Qunused-arguments', From 374405f06bf2d9d436fd8a55738e4ace722732af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Bo=CC=88hn?= Date: Tue, 8 Jul 2014 07:56:06 -0700 Subject: [PATCH 07/81] Added SepiaFilter --- app/deps/tensor/SepiaFilter.h | 22 ++++++++++++++++++++++ app/deps/tensor/SepiaFilter.m | 27 +++++++++++++++++++++++++++ app/deps/tensor/setup.py | 3 ++- 3 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 app/deps/tensor/SepiaFilter.h create mode 100644 app/deps/tensor/SepiaFilter.m diff --git a/app/deps/tensor/SepiaFilter.h b/app/deps/tensor/SepiaFilter.h new file mode 100644 index 00000000..141aee31 --- /dev/null +++ b/app/deps/tensor/SepiaFilter.h @@ -0,0 +1,22 @@ +// +// filters.h +// PlotDevice +// +// Created by fish2k on 12/7/13. +// +// + +#import +#import +#import + +@interface SepiaFilter : NSObject { + GPUImageSepiaFilter *filter; +} + +@property(nonatomic, retain) GPUImageSepiaFilter *filter; + +- (id)init; +- (NSImage *)process:(NSImage *)input; + +@end \ No newline at end of file diff --git a/app/deps/tensor/SepiaFilter.m b/app/deps/tensor/SepiaFilter.m new file mode 100644 index 00000000..5549a877 --- /dev/null +++ b/app/deps/tensor/SepiaFilter.m @@ -0,0 +1,27 @@ +// +// Filter.m +// PlotDevice +// +// Created by fish2k on 12/13/13. +// +// + +#import "SepiaFilter.h" + +@implementation SepiaFilter + +@synthesize filter; + +- (id)init { + self = [super init]; + if (self) { + filter = [GPUImageSepiaFilter init]; + } + return self; +} + +- (NSImage *)process:(NSImage *)input { + return [filter imageByFilteringImage:input]; +} + +@end \ No newline at end of file diff --git a/app/deps/tensor/setup.py b/app/deps/tensor/setup.py index 5cd7c6d9..d5063a09 100644 --- a/app/deps/tensor/setup.py +++ b/app/deps/tensor/setup.py @@ -11,7 +11,8 @@ tensorlib = Extension('tensorlib', sources=[ 'module.m', - 'HalftoneFilter.m'], + 'HalftoneFilter.m', + 'SepiaFilter.m'], extra_compile_args=[ '-Wno-error=unused-command-line-argument-hard-error-in-future', '-Qunused-arguments', From 9bfab6ff9a1ca50f4edd3e82973623c429c509de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Bo=CC=88hn?= Date: Tue, 8 Jul 2014 08:15:30 -0700 Subject: [PATCH 08/81] Factored all the basic filter shit into a base class --- app/deps/tensor/FilterBase.h | 23 +++++++++++++++++++++++ app/deps/tensor/FilterBase.m | 27 +++++++++++++++++++++++++++ app/deps/tensor/HalftoneFilter.h | 10 +++------- app/deps/tensor/HalftoneFilter.m | 8 +------- app/deps/tensor/SepiaFilter.h | 10 +++------- app/deps/tensor/SepiaFilter.m | 8 +------- 6 files changed, 58 insertions(+), 28 deletions(-) create mode 100644 app/deps/tensor/FilterBase.h create mode 100644 app/deps/tensor/FilterBase.m diff --git a/app/deps/tensor/FilterBase.h b/app/deps/tensor/FilterBase.h new file mode 100644 index 00000000..7db56aff --- /dev/null +++ b/app/deps/tensor/FilterBase.h @@ -0,0 +1,23 @@ +// +// FilterBase.h +// PlotDevice +// +// Created by fish2k on 12/7/13. +// +// + +#import +#import +#import + +@interface FilterBase : NSObject { + /// GENERIC FILTER PLACEHOLDER + GPUImageFilter *filter; +} + +@property(nonatomic, retain) GPUImageFilter *filter; + +- (id)init; +- (NSImage *)process:(NSImage *)input; + +@end \ No newline at end of file diff --git a/app/deps/tensor/FilterBase.m b/app/deps/tensor/FilterBase.m new file mode 100644 index 00000000..96c01467 --- /dev/null +++ b/app/deps/tensor/FilterBase.m @@ -0,0 +1,27 @@ +// +// FilterBase.m +// PlotDevice +// +// Created by fish2k on 12/13/13. +// +// + +#import "FilterBase.h" + +@implementation FilterBase + +@synthesize filter; + +- (id)init { + self = [super init]; + if (!self) { + return nil; + } + return self; +} + +- (NSImage *)process:(NSImage *)input { + return [filter imageByFilteringImage:input]; +} + +@end \ No newline at end of file diff --git a/app/deps/tensor/HalftoneFilter.h b/app/deps/tensor/HalftoneFilter.h index 30e064a4..a1e1aaaf 100644 --- a/app/deps/tensor/HalftoneFilter.h +++ b/app/deps/tensor/HalftoneFilter.h @@ -10,13 +10,9 @@ #import #import -@interface HalftoneFilter : NSObject { - GPUImageHalftoneFilter *filter; -} - -@property(nonatomic, retain) GPUImageHalftoneFilter *filter; +#import "FilterBase.h" -- (id)init; -- (NSImage *)process:(NSImage *)input; +@interface HalftoneFilter : FilterBase { +} @end \ No newline at end of file diff --git a/app/deps/tensor/HalftoneFilter.m b/app/deps/tensor/HalftoneFilter.m index 357ac871..ab9a6130 100644 --- a/app/deps/tensor/HalftoneFilter.m +++ b/app/deps/tensor/HalftoneFilter.m @@ -10,18 +10,12 @@ @implementation HalftoneFilter -@synthesize filter; - - (id)init { self = [super init]; if (self) { - filter = [GPUImageHalftoneFilter init]; + filter = (GPUImageFilter *)[[GPUImageHalftoneFilter alloc] init]; } return self; } -- (NSImage *)process:(NSImage *)input { - return [filter imageByFilteringImage:input]; -} - @end \ No newline at end of file diff --git a/app/deps/tensor/SepiaFilter.h b/app/deps/tensor/SepiaFilter.h index 141aee31..2b34af46 100644 --- a/app/deps/tensor/SepiaFilter.h +++ b/app/deps/tensor/SepiaFilter.h @@ -10,13 +10,9 @@ #import #import -@interface SepiaFilter : NSObject { - GPUImageSepiaFilter *filter; -} - -@property(nonatomic, retain) GPUImageSepiaFilter *filter; +#import "FilterBase.h" -- (id)init; -- (NSImage *)process:(NSImage *)input; +@interface SepiaFilter : FilterBase { +} @end \ No newline at end of file diff --git a/app/deps/tensor/SepiaFilter.m b/app/deps/tensor/SepiaFilter.m index 5549a877..4cfe9c9d 100644 --- a/app/deps/tensor/SepiaFilter.m +++ b/app/deps/tensor/SepiaFilter.m @@ -10,18 +10,12 @@ @implementation SepiaFilter -@synthesize filter; - - (id)init { self = [super init]; if (self) { - filter = [GPUImageSepiaFilter init]; + filter = (GPUImageFilter *)[[GPUImageHalftoneFilter alloc] init] } return self; } -- (NSImage *)process:(NSImage *)input { - return [filter imageByFilteringImage:input]; -} - @end \ No newline at end of file From 00c423a3be970800035ae02d18eeb021f0764695 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Bo=CC=88hn?= Date: Tue, 8 Jul 2014 08:16:14 -0700 Subject: [PATCH 09/81] A fucking semicolon --- app/deps/tensor/SepiaFilter.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/deps/tensor/SepiaFilter.m b/app/deps/tensor/SepiaFilter.m index 4cfe9c9d..b2e19600 100644 --- a/app/deps/tensor/SepiaFilter.m +++ b/app/deps/tensor/SepiaFilter.m @@ -13,7 +13,7 @@ @implementation SepiaFilter - (id)init { self = [super init]; if (self) { - filter = (GPUImageFilter *)[[GPUImageHalftoneFilter alloc] init] + filter = (GPUImageFilter *)[[GPUImageHalftoneFilter alloc] init]; } return self; } From ef2af931a4ae3652a29762374416dd85a75ef6e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Bo=CC=88hn?= Date: Tue, 8 Jul 2014 08:18:38 -0700 Subject: [PATCH 10/81] Compile base filter class in setup.py --- app/deps/tensor/setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/app/deps/tensor/setup.py b/app/deps/tensor/setup.py index d5063a09..405d7c19 100644 --- a/app/deps/tensor/setup.py +++ b/app/deps/tensor/setup.py @@ -11,6 +11,7 @@ tensorlib = Extension('tensorlib', sources=[ 'module.m', + 'FilterBase.m', 'HalftoneFilter.m', 'SepiaFilter.m'], extra_compile_args=[ From 7b363d5ca1bf795311440a14517dac64b8105838 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Bo=CC=88hn?= Date: Tue, 8 Jul 2014 14:22:08 -0700 Subject: [PATCH 11/81] Scoured the project of hardcoded /usr/bin/python references --- PlotDevice.xcodeproj/project.pbxproj | 25 +++++++++++++--------- app/PlotDevice_Prefix.pch | 4 ++++ app/deps/tensor/module.m | 6 ++++++ app/deps/tensor/setup.py | 3 +-- app/main.m | 6 +++++- app/plotdevice | 7 ++++--- app/plotdevice-app.py | 24 ++++++++++++++++++--- etc/old-python-include-link-paths.sh | 4 ++++ setup.py | 31 ++++++++++++++++------------ 9 files changed, 78 insertions(+), 32 deletions(-) create mode 100644 etc/old-python-include-link-paths.sh diff --git a/PlotDevice.xcodeproj/project.pbxproj b/PlotDevice.xcodeproj/project.pbxproj index c202da47..b9e59a71 100644 --- a/PlotDevice.xcodeproj/project.pbxproj +++ b/PlotDevice.xcodeproj/project.pbxproj @@ -19,7 +19,6 @@ 2A66ECEF18A99328002903DE /* underscore-1.5.2.min.js in Copy Editor Scripts */ = {isa = PBXBuildFile; fileRef = 2A66ECE218A992BD002903DE /* underscore-1.5.2.min.js */; }; 2A7AF5C818D2AFAA00F8FFC2 /* examples in Resources */ = {isa = PBXBuildFile; fileRef = 2A7AF5C718D2AFAA00F8FFC2 /* examples */; }; 2A93AE751903326E00C6144D /* placeholder.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 2A93AE731903326E00C6144D /* placeholder.pdf */; }; - 2AA40EBF184BF9CB00981ADC /* libpython2.7.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 2AA40EBE184BF9CB00981ADC /* libpython2.7.dylib */; }; 2ABBB2FA1854018B001C4E0A /* AVFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2ABBB2F91854018B001C4E0A /* AVFoundation.framework */; }; 2ABBB2FC18540246001C4E0A /* CoreVideo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2ABBB2FB18540246001C4E0A /* CoreVideo.framework */; }; 2ABBB2FE185402AC001C4E0A /* CoreMedia.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2ABBB2FD185402AC001C4E0A /* CoreMedia.framework */; }; @@ -39,6 +38,7 @@ 8D15AC340486D014006FF6A4 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A7FEA54F5311CA2CBB /* Cocoa.framework */; }; CF04731D196B71C200E3C358 /* GPUImage.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CF04731C196B71C200E3C358 /* GPUImage.framework */; }; CF047321196B744C00E3C358 /* GPUImage.framework in Copy Private Frameworks */ = {isa = PBXBuildFile; fileRef = CF04731C196B71C200E3C358 /* GPUImage.framework */; }; + CF29B4BE196C51B70092593E /* Python.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CF29B4BC196C51410092593E /* Python.framework */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -123,7 +123,6 @@ 2A7AF5C718D2AFAA00F8FFC2 /* examples */ = {isa = PBXFileReference; lastKnownFileType = folder; path = examples; sourceTree = ""; }; 2A827CC91859E9FE00A126BA /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; 2A93AE741903326E00C6144D /* English */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; name = English; path = Resources/English.lproj/placeholder.pdf; sourceTree = ""; }; - 2AA40EBE184BF9CB00981ADC /* libpython2.7.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libpython2.7.dylib; path = ../../../../../../usr/lib/libpython2.7.dylib; sourceTree = ""; }; 2ABBB2F91854018B001C4E0A /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = System/Library/Frameworks/AVFoundation.framework; sourceTree = SDKROOT; }; 2ABBB2FB18540246001C4E0A /* CoreVideo.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreVideo.framework; path = System/Library/Frameworks/CoreVideo.framework; sourceTree = SDKROOT; }; 2ABBB2FD185402AC001C4E0A /* CoreMedia.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreMedia.framework; path = System/Library/Frameworks/CoreMedia.framework; sourceTree = SDKROOT; }; @@ -168,6 +167,7 @@ 6155D9F313E2B79E00675A92 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = README.md; sourceTree = ""; }; 8D15AC370486D014006FF6A4 /* PlotDevice.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = PlotDevice.app; sourceTree = BUILT_PRODUCTS_DIR; }; CF04731C196B71C200E3C358 /* GPUImage.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GPUImage.framework; path = app/Frameworks/GPUImage.framework; sourceTree = SOURCE_ROOT; }; + CF29B4BC196C51410092593E /* Python.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Python.framework; path = /usr/local/Cellar/python/2.7.8/Frameworks/Python.framework; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -175,8 +175,8 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + CF29B4BE196C51B70092593E /* Python.framework in Frameworks */, CF04731D196B71C200E3C358 /* GPUImage.framework in Frameworks */, - 2AA40EBF184BF9CB00981ADC /* libpython2.7.dylib in Frameworks */, 2ABBB2FC18540246001C4E0A /* CoreVideo.framework in Frameworks */, 2ABBB2FE185402AC001C4E0A /* CoreMedia.framework in Frameworks */, 2ABBB2FA1854018B001C4E0A /* AVFoundation.framework in Frameworks */, @@ -192,7 +192,7 @@ 1058C7A6FEA54F5311CA2CBB /* Linked Frameworks */ = { isa = PBXGroup; children = ( - 2AA40EBE184BF9CB00981ADC /* libpython2.7.dylib */, + CF29B4BC196C51410092593E /* Python.framework */, 1058C7A7FEA54F5311CA2CBB /* Cocoa.framework */, ); name = "Linked Frameworks"; @@ -478,7 +478,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "# let the setup script handle updating\n/usr/bin/python setup.py build\n\n# copy the up-to-date module contents into the app bundle\nEXT_DIR=\"$TARGET_BUILD_DIR/$UNLOCALIZED_RESOURCES_FOLDER_PATH/python/\"\nmkdir -p $EXT_DIR\nditto build/lib/plotdevice \"$EXT_DIR/plotdevice\"\n\n# make sure everything has a .pyc (so code-signing doesn't break on first run)\n/usr/bin/python -m compileall \"$EXT_DIR/plotdevice\""; + shellScript = "python=\"/usr/bin/python\"\nif [ -x /usr/local/bin/python ]; then\n python=\"/usr/local/bin/python\"\nfi\n\n# let the setup script handle updating\neval \"${python} setup.py build\"\n\n# copy the up-to-date module contents into the app bundle\nEXT_DIR=\"$TARGET_BUILD_DIR/$UNLOCALIZED_RESOURCES_FOLDER_PATH/python/\"\nmkdir -p $EXT_DIR\nditto build/lib/plotdevice \"$EXT_DIR/plotdevice\"\n\n# make sure everything has a .pyc (so code-signing doesn't break on first run)\neval \"${python} -m compileall ${EXT_DIR}/plotdevice\""; }; /* End PBXShellScriptBuildPhase section */ @@ -574,6 +574,7 @@ "$(inherited)", "$(PROJECT_DIR)", "$(PROJECT_DIR)/app/Frameworks", + /usr/local/Cellar/python/2.7.8/Frameworks, ); GCC_DYNAMIC_NO_PIC = NO; GCC_MODEL_TUNING = G5; @@ -582,17 +583,18 @@ GCC_PREFIX_HEADER = app/PlotDevice_Prefix.pch; HEADER_SEARCH_PATHS = ( "$(inherited)", + /usr/local/opt/python/Frameworks/Python.framework/Headers, /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, - /System/Library/Frameworks/Python.framework/Versions/2.7/include/python2.7, ); INFOPLIST_FILE = "app/PlotDevice-Info.plist"; INSTALL_PATH = /Applications; - LIBRARY_SEARCH_PATHS = /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/config; + LIBRARY_SEARCH_PATHS = /usr/local/Cellar/python/2.7.8/Frameworks/Python.framework/Versions/2.7; MACOSX_DEPLOYMENT_TARGET = 10.9; - ONLY_ACTIVE_ARCH = NO; + ONLY_ACTIVE_ARCH = YES; OTHER_LDFLAGS = ""; PRODUCT_NAME = PlotDevice; SDKROOT = macosx; + VALID_ARCHS = x86_64; }; name = Debug; }; @@ -607,22 +609,25 @@ "$(inherited)", "$(PROJECT_DIR)", "$(PROJECT_DIR)/app/Frameworks", + /usr/local/Cellar/python/2.7.8/Frameworks, ); GCC_MODEL_TUNING = G5; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = app/PlotDevice_Prefix.pch; HEADER_SEARCH_PATHS = ( "$(inherited)", + /usr/local/opt/python/Frameworks/Python.framework/Headers, /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, - /System/Library/Frameworks/Python.framework/Versions/2.7/include/python2.7, ); INFOPLIST_FILE = "app/PlotDevice-Info.plist"; INSTALL_PATH = /Applications; - LIBRARY_SEARCH_PATHS = /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/config; + LIBRARY_SEARCH_PATHS = /usr/local/Cellar/python/2.7.8/Frameworks/Python.framework/Versions/2.7; MACOSX_DEPLOYMENT_TARGET = 10.9; + ONLY_ACTIVE_ARCH = YES; OTHER_LDFLAGS = ""; PRODUCT_NAME = PlotDevice; SDKROOT = macosx; + VALID_ARCHS = x86_64; }; name = Release; }; diff --git a/app/PlotDevice_Prefix.pch b/app/PlotDevice_Prefix.pch index f29f26f6..eeefc690 100644 --- a/app/PlotDevice_Prefix.pch +++ b/app/PlotDevice_Prefix.pch @@ -5,3 +5,7 @@ #ifdef __OBJC__ #import #endif + +#ifndef PLOTDEVICE_PYTHON + #define PLOTDEVICE_PYTHON "/usr/local/bin/python" +#endif diff --git a/app/deps/tensor/module.m b/app/deps/tensor/module.m index ff1185c5..fef14763 100644 --- a/app/deps/tensor/module.m +++ b/app/deps/tensor/module.m @@ -1,5 +1,11 @@ #import +/* + * Stub python module declaration -- + * Allows Objective-C classes with which it is linked + * to be found and loaded from python via `objc.lookUpClass()` + */ + PyMethodDef methods[] = { { NULL, NULL }, }; diff --git a/app/deps/tensor/setup.py b/app/deps/tensor/setup.py index 405d7c19..f5698c6b 100644 --- a/app/deps/tensor/setup.py +++ b/app/deps/tensor/setup.py @@ -1,7 +1,6 @@ from os import getcwd from os.path import dirname, join -# from distutils.core import setup, Extension -from setuptools import setup, find_packages +from setuptools import setup from setuptools.extension import Extension frameworks = join(dirname(dirname(getcwd())), 'Frameworks') diff --git a/app/main.m b/app/main.m index ead820e7..dc3783c9 100644 --- a/app/main.m +++ b/app/main.m @@ -1,9 +1,13 @@ #import +#ifndef PLOTDEVICE_PYTHON + #define PLOTDEVICE_PYTHON "/usr/bin/python" +#endif + int main(int argc, char *argv[]) { @autoreleasepool{ - Py_SetProgramName("/usr/bin/python"); + Py_SetProgramName(PLOTDEVICE_PYTHON); Py_Initialize(); PySys_SetArgv(argc, (char **)argv); NSString *mainFilePath = [[NSBundle mainBundle] pathForResource:@"plotdevice-app" ofType:@"py"]; diff --git a/app/plotdevice b/app/plotdevice index b452a4be..3c180ba3 100755 --- a/app/plotdevice +++ b/app/plotdevice @@ -58,6 +58,7 @@ import argparse import json import signal from subprocess import Popen, PIPE +from distutils.spawn import find_executable as which from os.path import exists, islink, dirname, abspath, realpath, join def parse_args(): @@ -170,11 +171,11 @@ def main(): signal.signal(signal.SIGINT, cancel) # launch the back-end of the console-runner and pipe in our params - py_path = filter(None, env.get('PYTHONPATH','').split(':')) # BUG: should it be unfiltered? - py_path.append(root) + py_path = filter(exists, env.get('PYTHONPATH', '').split(':')) + py_path.insert(0, root) env['PYTHONPATH'] = ":".join(py_path) script = join(root, 'plotdevice/run/console.py') - p = Popen(['/usr/bin/python', script], env=env, stdin=PIPE) + p = Popen([which('python'), script], env=env, stdin=PIPE) p.stdin.write(json.dumps(vars(opts))+"\n") p.wait() diff --git a/app/plotdevice-app.py b/app/plotdevice-app.py index 2a7bf874..5ab623de 100644 --- a/app/plotdevice-app.py +++ b/app/plotdevice-app.py @@ -3,14 +3,32 @@ import Foundation import AppKit from signal import signal, SIGINT -from os.path import dirname, abspath, join +from os.path import dirname, abspath, join, isdir, exists from PyObjCTools import AppHelper +# if there's a python installed into /usr/local, it's probably homebrew -- +# let's use it! +local_packages = '/usr/local/lib/python2.7/site-packages' +if isdir(local_packages): + sys.path.insert(0, local_packages) + # rather than hijacking PYTHONPATH in the .m loader, add the module directory now -sys.path.append('%s/Contents/Resources/python'%abspath(Foundation.NSBundle.mainBundle().bundlePath())) +sys.path.insert(0, + '%s/Contents/Resources/python' % abspath( + Foundation.NSBundle.mainBundle().bundlePath())) + +# remove dupes from sys.path -- for an explanation see: +# http://stackoverflow.com/a/480227/298171 +seen = set() +seen_add = seen.add +clean_path = tuple(directory for directory in sys.path \ + if exists(directory) and \ + directory not in seen and \ + not seen_add(directory)) +sys.path = list(clean_path) # install a signal handler to quit on ^c (should the app ever be launched from terminal) -signal(SIGINT, lambda m,n: AppKit.NSApplication.sharedApplication().terminate_(True)) +signal(SIGINT, lambda m, n: AppKit.NSApplication.sharedApplication().terminate_(True)) # PlotDevice is a typical document-based application. We'll import the PlotDeviceDocument # class et al from the gui module and the corresponding document-type defined in the diff --git a/etc/old-python-include-link-paths.sh b/etc/old-python-include-link-paths.sh new file mode 100644 index 00000000..8812a82e --- /dev/null +++ b/etc/old-python-include-link-paths.sh @@ -0,0 +1,4 @@ +/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/config +$(SYSTEM_LIBRARY_DIR)/Frameworks/Python.framework/Versions/2.7 + +/System/Library/Frameworks/Python.framework/Versions/2.7/include/python2.7 \ No newline at end of file diff --git a/setup.py b/setup.py index 4591dbb0..2477ad72 100644 --- a/setup.py +++ b/setup.py @@ -17,7 +17,7 @@ # - Mac OS X 10.9+ # - py2app or xcode or just pip # - PyObjC (should be in /System/Library/Frameworks/Python.framework/Versions/2.7/Extras) -# - cPathMatics, cGeo, cIO, cEvent, & polymagic (included in the "app/deps" folder) +# - cPathMatics, cGeo, cIO, cEvent, tensor, & polymagic (included in the "app/deps" folder) # - Sparkle.framework (auto-downloaded only for `dist` builds) import sys,os @@ -210,19 +210,22 @@ def run(self): os.unlink('MANIFEST.in') from distutils.command.build_py import build_py +from distutils.spawn import find_executable as which class BuildCommand(build_py): def run(self): # first let the real build_py routine do its thing build_py.run(self) # then compile the extensions into the just-built module - self.spawn(['/usr/bin/python', 'app/deps/build.py', abspath(self.build_lib)]) + self.spawn([which('python'), 'app/deps/build.py', abspath(self.build_lib)]) # include some ui resources for running a script from the command line rsrc_dir = '%s/plotdevice/rsrc'%self.build_lib self.mkpath(rsrc_dir) self.copy_file("app/Resources/colors.json", '%s/colors.json'%rsrc_dir) - self.spawn(['/usr/bin/ibtool','--compile', '%s/viewer.nib'%rsrc_dir, "app/Resources/English.lproj/PlotDeviceScript.xib"]) + self.spawn([which('ibtool'), '--compile', + '%s/viewer.nib'%rsrc_dir, + "app/Resources/English.lproj/PlotDeviceScript.xib"]) self.copy_file("app/Resources/PlotDeviceFile.icns", '%s/viewer.icns'%rsrc_dir) class BuildAppCommand(Command): @@ -266,12 +269,12 @@ def run(self): self.mkpath(pth) # install the module in Resources/python - self.spawn(['/usr/bin/ditto', MODULE, join(PY, 'plotdevice')]) + self.spawn([which('ditto'), MODULE, join(PY, 'plotdevice')]) # discard the eggery-pokery - remove_tree(join(RSRC,'lib'), dry_run=self.dry_run) - os.unlink(join(RSRC,'include')) - os.unlink(join(RSRC,'site.pyc')) + remove_tree(join(RSRC, 'lib'), dry_run=self.dry_run) + os.unlink(join(RSRC, 'include')) + os.unlink(join(RSRC, 'site.pyc')) # place the command line tool in SharedSupport self.copy_file("app/plotdevice", BIN) @@ -324,9 +327,10 @@ def run(self): if not exists(ORIG): print "Downloading Sparkle.framework" self.mkpath('app/deps') - os.system('curl -L %s | bunzip2 -c | tar xf - -C app/deps'%SPARKLE_URL) + os.system('%s -L %s | bunzip2 -c | tar xf - -C app/deps' % ( + which('curl'), SPARKLE_URL)) self.mkpath(dirname(SPARKLE)) - self.spawn(['ditto', ORIG, SPARKLE]) + self.spawn([which('ditto'), ORIG, SPARKLE]) # code-sign the app and sparkle bundles, then verify self.spawn(['codesign', '-f', '-v', '-s', "Developer ID Application", SPARKLE]) @@ -334,7 +338,7 @@ def run(self): self.spawn(['spctl', '--assess', '-v', 'dist/PlotDevice.app']) # create versioned zipfile of the app - self.spawn(['ditto','-ck', '--keepParent', APP, ZIP]) + self.spawn([which('ditto'), '-ck', '--keepParent', APP, ZIP]) # update the app.xml feed (pulled from the server) release = dict(zipfile=basename(ZIP), bytes=os.path.getsize(ZIP), @@ -356,7 +360,8 @@ def finalize_options(self): pass def run(self): print "Checking feed xml" - gosub('tidy -xml -utf8 -e dist/app.xml', on_err="app.xml didn't validate properly") + gosub('%s -xml -utf8 -e dist/app.xml' % which('tidy'), + on_err="app.xml didn't validate properly") tarfile = 'dist/plotdevice-%s.tar.gz'%VERSION zipfile = 'dist/PlotDevice_app-%s.zip'%VERSION @@ -369,10 +374,10 @@ def run(self): # print "posting dist/app.xml" - gosub('scp dist/app.xml plotdevice.io:plod') + gosub('%s dist/app.xml plotdevice.io:plod' % which('scp')) print "posting", zipfile - gosub('scp %s plotdevice.io:plod/app'%zipfile) + gosub('%s %s plotdevice.io:plod/app' % (which('scp'), zipfile)) # From 8ad9b313c4df4b3dc5cd5ce8644c459f29a383af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Bo=CC=88hn?= Date: Tue, 8 Jul 2014 20:58:31 -0700 Subject: [PATCH 12/81] Fleshed out filters version like 0.0.001 --- app/deps/tensor/ColorInvertFilter.h | 18 ++++++++++++++++ app/deps/tensor/ColorInvertFilter.m | 21 ++++++++++++++++++ app/deps/tensor/HalftoneFilter.h | 2 +- app/deps/tensor/HalftoneFilter.m | 2 +- app/deps/tensor/MissEtikateFilter.h | 18 ++++++++++++++++ app/deps/tensor/MissEtikateFilter.m | 21 ++++++++++++++++++ app/deps/tensor/PolkaDotFilter.h | 18 ++++++++++++++++ app/deps/tensor/PolkaDotFilter.m | 21 ++++++++++++++++++ app/deps/tensor/SepiaFilter.h | 2 +- app/deps/tensor/SepiaFilter.m | 4 ++-- app/deps/tensor/SoftEleganceFilter.h | 18 ++++++++++++++++ app/deps/tensor/SoftEleganceFilter.m | 21 ++++++++++++++++++ app/deps/tensor/VignetteFilter.h | 18 ++++++++++++++++ app/deps/tensor/VignetteFilter.m | 21 ++++++++++++++++++ app/deps/tensor/setup.py | 7 +++++- plotdevice/context.py | 13 ++++++++++- plotdevice/lib/rtclass.py | 6 ++++-- plotdevice/lib/tensor.py | 32 +++++++++++++++++++++++----- 18 files changed, 249 insertions(+), 14 deletions(-) create mode 100644 app/deps/tensor/ColorInvertFilter.h create mode 100644 app/deps/tensor/ColorInvertFilter.m create mode 100644 app/deps/tensor/MissEtikateFilter.h create mode 100644 app/deps/tensor/MissEtikateFilter.m create mode 100644 app/deps/tensor/PolkaDotFilter.h create mode 100644 app/deps/tensor/PolkaDotFilter.m create mode 100644 app/deps/tensor/SoftEleganceFilter.h create mode 100644 app/deps/tensor/SoftEleganceFilter.m create mode 100644 app/deps/tensor/VignetteFilter.h create mode 100644 app/deps/tensor/VignetteFilter.m diff --git a/app/deps/tensor/ColorInvertFilter.h b/app/deps/tensor/ColorInvertFilter.h new file mode 100644 index 00000000..0fd548ba --- /dev/null +++ b/app/deps/tensor/ColorInvertFilter.h @@ -0,0 +1,18 @@ +// +// ColorInvertFilter.h +// PlotDevice +// +// Created by fish2k on 12/7/13. +// +// + +#import +#import +#import + +#import "FilterBase.h" + +@interface ColorInvertFilter : FilterBase { +} + +@end \ No newline at end of file diff --git a/app/deps/tensor/ColorInvertFilter.m b/app/deps/tensor/ColorInvertFilter.m new file mode 100644 index 00000000..5a5a4add --- /dev/null +++ b/app/deps/tensor/ColorInvertFilter.m @@ -0,0 +1,21 @@ +// +// ColorInvertFilter.m +// PlotDevice +// +// Created by fish2k on 12/13/13. +// +// + +#import "ColorInvertFilter.h" + +@implementation ColorInvertFilter + +- (id)init { + self = [super init]; + if (self) { + filter = (GPUImageFilter *)[[GPUImageColorInvertFilter alloc] init]; + } + return self; +} + +@end \ No newline at end of file diff --git a/app/deps/tensor/HalftoneFilter.h b/app/deps/tensor/HalftoneFilter.h index a1e1aaaf..995d1696 100644 --- a/app/deps/tensor/HalftoneFilter.h +++ b/app/deps/tensor/HalftoneFilter.h @@ -1,5 +1,5 @@ // -// filters.h +// HalftoneFilter.h // PlotDevice // // Created by fish2k on 12/7/13. diff --git a/app/deps/tensor/HalftoneFilter.m b/app/deps/tensor/HalftoneFilter.m index ab9a6130..bfa8282c 100644 --- a/app/deps/tensor/HalftoneFilter.m +++ b/app/deps/tensor/HalftoneFilter.m @@ -1,5 +1,5 @@ // -// Filter.m +// HalftoneFilter.m // PlotDevice // // Created by fish2k on 12/13/13. diff --git a/app/deps/tensor/MissEtikateFilter.h b/app/deps/tensor/MissEtikateFilter.h new file mode 100644 index 00000000..b6d910e0 --- /dev/null +++ b/app/deps/tensor/MissEtikateFilter.h @@ -0,0 +1,18 @@ +// +// MissEtikateFilter.h +// PlotDevice +// +// Created by fish2k on 12/7/13. +// +// + +#import +#import +#import + +#import "FilterBase.h" + +@interface MissEtikateFilter : FilterBase { +} + +@end \ No newline at end of file diff --git a/app/deps/tensor/MissEtikateFilter.m b/app/deps/tensor/MissEtikateFilter.m new file mode 100644 index 00000000..c1391003 --- /dev/null +++ b/app/deps/tensor/MissEtikateFilter.m @@ -0,0 +1,21 @@ +// +// MissEtikateFilter.m +// PlotDevice +// +// Created by fish2k on 12/13/13. +// +// + +#import "MissEtikateFilter.h" + +@implementation MissEtikateFilter + +- (id)init { + self = [super init]; + if (self) { + filter = (GPUImageFilter *)[[GPUImageMissEtikateFilter alloc] init]; + } + return self; +} + +@end \ No newline at end of file diff --git a/app/deps/tensor/PolkaDotFilter.h b/app/deps/tensor/PolkaDotFilter.h new file mode 100644 index 00000000..9f013a63 --- /dev/null +++ b/app/deps/tensor/PolkaDotFilter.h @@ -0,0 +1,18 @@ +// +// PolkaDotFilter.h +// PlotDevice +// +// Created by fish2k on 12/7/13. +// +// + +#import +#import +#import + +#import "FilterBase.h" + +@interface PolkaDotFilter : FilterBase { +} + +@end \ No newline at end of file diff --git a/app/deps/tensor/PolkaDotFilter.m b/app/deps/tensor/PolkaDotFilter.m new file mode 100644 index 00000000..ef08834f --- /dev/null +++ b/app/deps/tensor/PolkaDotFilter.m @@ -0,0 +1,21 @@ +// +// PolkaDotFilter.m +// PlotDevice +// +// Created by fish2k on 12/13/13. +// +// + +#import "PolkaDotFilter.h" + +@implementation PolkaDotFilter + +- (id)init { + self = [super init]; + if (self) { + filter = (GPUImageFilter *)[[GPUImagePolkaDotFilter alloc] init]; + } + return self; +} + +@end \ No newline at end of file diff --git a/app/deps/tensor/SepiaFilter.h b/app/deps/tensor/SepiaFilter.h index 2b34af46..3da4a1df 100644 --- a/app/deps/tensor/SepiaFilter.h +++ b/app/deps/tensor/SepiaFilter.h @@ -1,5 +1,5 @@ // -// filters.h +// SepiaFilter.h // PlotDevice // // Created by fish2k on 12/7/13. diff --git a/app/deps/tensor/SepiaFilter.m b/app/deps/tensor/SepiaFilter.m index b2e19600..fe77eeba 100644 --- a/app/deps/tensor/SepiaFilter.m +++ b/app/deps/tensor/SepiaFilter.m @@ -1,5 +1,5 @@ // -// Filter.m +// SepiaFilter.m // PlotDevice // // Created by fish2k on 12/13/13. @@ -13,7 +13,7 @@ @implementation SepiaFilter - (id)init { self = [super init]; if (self) { - filter = (GPUImageFilter *)[[GPUImageHalftoneFilter alloc] init]; + filter = (GPUImageFilter *)[[GPUImageSepiaFilter alloc] init]; } return self; } diff --git a/app/deps/tensor/SoftEleganceFilter.h b/app/deps/tensor/SoftEleganceFilter.h new file mode 100644 index 00000000..ed3d0997 --- /dev/null +++ b/app/deps/tensor/SoftEleganceFilter.h @@ -0,0 +1,18 @@ +// +// SoftEleganceFilter.h +// PlotDevice +// +// Created by fish2k on 12/7/13. +// +// + +#import +#import +#import + +#import "FilterBase.h" + +@interface SoftEleganceFilter : FilterBase { +} + +@end \ No newline at end of file diff --git a/app/deps/tensor/SoftEleganceFilter.m b/app/deps/tensor/SoftEleganceFilter.m new file mode 100644 index 00000000..f9a347af --- /dev/null +++ b/app/deps/tensor/SoftEleganceFilter.m @@ -0,0 +1,21 @@ +// +// SoftEleganceFilter.m +// PlotDevice +// +// Created by fish2k on 12/13/13. +// +// + +#import "SoftEleganceFilter.h" + +@implementation SoftEleganceFilter + +- (id)init { + self = [super init]; + if (self) { + filter = (GPUImageFilter *)[[GPUImageSoftEleganceFilter alloc] init]; + } + return self; +} + +@end \ No newline at end of file diff --git a/app/deps/tensor/VignetteFilter.h b/app/deps/tensor/VignetteFilter.h new file mode 100644 index 00000000..d55de866 --- /dev/null +++ b/app/deps/tensor/VignetteFilter.h @@ -0,0 +1,18 @@ +// +// VignetteFilter.h +// PlotDevice +// +// Created by fish2k on 12/7/13. +// +// + +#import +#import +#import + +#import "FilterBase.h" + +@interface VignetteFilter : FilterBase { +} + +@end \ No newline at end of file diff --git a/app/deps/tensor/VignetteFilter.m b/app/deps/tensor/VignetteFilter.m new file mode 100644 index 00000000..a0749121 --- /dev/null +++ b/app/deps/tensor/VignetteFilter.m @@ -0,0 +1,21 @@ +// +// VignetteFilter.m +// PlotDevice +// +// Created by fish2k on 12/13/13. +// +// + +#import "VignetteFilter.h" + +@implementation VignetteFilter + +- (id)init { + self = [super init]; + if (self) { + filter = (GPUImageFilter *)[[GPUImageVignetteFilter alloc] init]; + } + return self; +} + +@end \ No newline at end of file diff --git a/app/deps/tensor/setup.py b/app/deps/tensor/setup.py index f5698c6b..e4647194 100644 --- a/app/deps/tensor/setup.py +++ b/app/deps/tensor/setup.py @@ -11,8 +11,13 @@ sources=[ 'module.m', 'FilterBase.m', + 'ColorInvertFilter.m', 'HalftoneFilter.m', - 'SepiaFilter.m'], + 'MissEtikateFilter.m', + 'PolkaDotFilter.m', + 'SepiaFilter.m', + 'SoftEleganceFilter.m', + 'VignetteFilter.m'], extra_compile_args=[ '-Wno-error=unused-command-line-argument-hard-error-in-future', '-Qunused-arguments', diff --git a/plotdevice/context.py b/plotdevice/context.py index af435dab..fc8587ae 100644 --- a/plotdevice/context.py +++ b/plotdevice/context.py @@ -5,7 +5,7 @@ from collections import namedtuple from .util import _copy_attr, _copy_attrs, _flatten, trim_zeroes -from .lib import geometry, pathmatics +from .lib import geometry, pathmatics, tensor from .gfx.transform import Dimension from .gfx import * from . import gfx, lib, util, Halted, DeviceError @@ -1072,6 +1072,13 @@ def textheight(self, txt, width=None, **kwargs): ### Image commands ### + def imagefilter(self, filter_name): + class_name = "%sFilter" % filter_name + if hasattr(tensor, class_name): + print "Loading %s" % class_name + AXFilter = getattr(tensor, class_name) + return AXFilter() + def image(self, *args, **kwargs): """Draw a bitmap or vector image @@ -1088,6 +1095,10 @@ def image(self, *args, **kwargs): """ draw = kwargs.pop('draw', self._autoplot) draw = kwargs.pop('plot', draw) + + image_filter = kwargs.pop('filter', None) + if image_filter: + pass img = Image(*args, **kwargs) if draw: diff --git a/plotdevice/lib/rtclass.py b/plotdevice/lib/rtclass.py index 8c752dca..8fc2e8f5 100644 --- a/plotdevice/lib/rtclass.py +++ b/plotdevice/lib/rtclass.py @@ -2,7 +2,6 @@ from __future__ import print_function import objc, warnings -#from PyObjCTools import AppHelper OBJ_COLON = '_' @@ -50,4 +49,7 @@ def __getattr__(self, attr): def __repr__(self): # This may be a bad idea, let's find out - return "[RT] " + super(RTClass, self).__repr__() + return "(%s) ->> %s" % ( + self.__class__.__name__, + super(RTClass, self).__repr__()) + diff --git a/plotdevice/lib/tensor.py b/plotdevice/lib/tensor.py index c3b242a5..fb11368f 100644 --- a/plotdevice/lib/tensor.py +++ b/plotdevice/lib/tensor.py @@ -1,17 +1,39 @@ from __future__ import print_function +import objc +import tensorlib from .rtclass import RTClass #from collections import defaultdict #from PyObjCTools import AppHelper -import tensorlib -# for cls in ["Filter"]: -# globals()[cls] = objc.lookUpClass(cls) +class ColorInvertFilter(RTClass): + """ Wrapper for tensorlib/ColorInvertFilter """ + pass + +class HalftoneFilter(RTClass): + """ Wrapper for tensorlib/HalftoneFilter """ + pass + +class MissEtikateFilter(RTClass): + """ Wrapper for tensorlib/MissEtikateFilter """ + pass + +class PolkaDotFilter(RTClass): + """ Wrapper for tensorlib/PolkaDotFilter """ + pass + +class SepiaFilter(RTClass): + """ Wrapper for tensorlib/SepiaFilter """ + pass + +class SoftEleganceFilter(RTClass): + """ Wrapper for tensorlib/SoftElegaceFilter """ + pass -class Filter(RTClass): - """ Wrapper class around a basic Tensor image filter """ +class VignetteFilter(RTClass): + """ Wrapper for tensorlib/VignetteFilter """ pass From 983d6900493de57995a72e35fe35657bb05ccbf6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Bo=CC=88hn?= Date: Wed, 9 Jul 2014 01:58:17 -0700 Subject: [PATCH 13/81] Saved project argh --- PlotDevice.xcodeproj/project.pbxproj | 12 +++++++++--- plotdevice/lib/tensor.py | 4 ++-- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/PlotDevice.xcodeproj/project.pbxproj b/PlotDevice.xcodeproj/project.pbxproj index b9e59a71..9305d818 100644 --- a/PlotDevice.xcodeproj/project.pbxproj +++ b/PlotDevice.xcodeproj/project.pbxproj @@ -39,6 +39,8 @@ CF04731D196B71C200E3C358 /* GPUImage.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CF04731C196B71C200E3C358 /* GPUImage.framework */; }; CF047321196B744C00E3C358 /* GPUImage.framework in Copy Private Frameworks */ = {isa = PBXBuildFile; fileRef = CF04731C196B71C200E3C358 /* GPUImage.framework */; }; CF29B4BE196C51B70092593E /* Python.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CF29B4BC196C51410092593E /* Python.framework */; }; + CFF92338196D31780095586A /* rtclass.py in Resources */ = {isa = PBXBuildFile; fileRef = CFF92336196D31780095586A /* rtclass.py */; }; + CFF92339196D31780095586A /* tensor.py in Resources */ = {isa = PBXBuildFile; fileRef = CFF92337196D31780095586A /* tensor.py */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -107,7 +109,6 @@ 2A294467185E575F00E9F650 /* document.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = document.py; sourceTree = ""; }; 2A294468185E575F00E9F650 /* preferences.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = preferences.py; sourceTree = ""; }; 2A32957218C59D0A00EEDD1C /* __init__.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = __init__.py; sourceTree = ""; }; - 2A32957418C59D0A00EEDD1C /* fsevents.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = fsevents.py; sourceTree = ""; }; 2A32957518C59D0A00EEDD1C /* geometry.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = geometry.py; sourceTree = ""; }; 2A32957718C59D0A00EEDD1C /* io.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = io.py; sourceTree = ""; }; 2A32957918C59D0A00EEDD1C /* pathmatics.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = pathmatics.py; sourceTree = ""; }; @@ -130,7 +131,7 @@ 2ABDB7681867D8160069EFC3 /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = app/main.m; sourceTree = ""; }; 2ABDB7691867D8160069EFC3 /* PlotDevice_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PlotDevice_Prefix.pch; path = app/PlotDevice_Prefix.pch; sourceTree = ""; }; 2ABDB76C1867D8210069EFC3 /* PlotDevice-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "PlotDevice-Info.plist"; sourceTree = ""; }; - 2ABDB7721867D9920069EFC3 /* plotdevice */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = plotdevice; path = app/plotdevice; sourceTree = ""; }; + 2ABDB7721867D9920069EFC3 /* plotdevice */ = {isa = PBXFileReference; explicitFileType = text.script.python; fileEncoding = 4; name = plotdevice; path = app/plotdevice; sourceTree = ""; }; 2ABDB7751867EB520069EFC3 /* app.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = app.py; sourceTree = ""; }; 2ABDB7761867EB520069EFC3 /* views.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = views.py; sourceTree = ""; }; 2AC07CB618EF8E7D00B75879 /* __init__.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = __init__.py; sourceTree = ""; }; @@ -168,6 +169,8 @@ 8D15AC370486D014006FF6A4 /* PlotDevice.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = PlotDevice.app; sourceTree = BUILT_PRODUCTS_DIR; }; CF04731C196B71C200E3C358 /* GPUImage.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GPUImage.framework; path = app/Frameworks/GPUImage.framework; sourceTree = SOURCE_ROOT; }; CF29B4BC196C51410092593E /* Python.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Python.framework; path = /usr/local/Cellar/python/2.7.8/Frameworks/Python.framework; sourceTree = ""; }; + CFF92336196D31780095586A /* rtclass.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = rtclass.py; sourceTree = ""; }; + CFF92337196D31780095586A /* tensor.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = tensor.py; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -241,7 +244,8 @@ isa = PBXGroup; children = ( 2A32957218C59D0A00EEDD1C /* __init__.py */, - 2A32957418C59D0A00EEDD1C /* fsevents.py */, + CFF92336196D31780095586A /* rtclass.py */, + CFF92337196D31780095586A /* tensor.py */, 2A32957518C59D0A00EEDD1C /* geometry.py */, 2A32957718C59D0A00EEDD1C /* io.py */, 2A32957918C59D0A00EEDD1C /* pathmatics.py */, @@ -452,6 +456,7 @@ 611CC49C10BA8B9E00B55455 /* InfoPlist.strings in Resources */, 611CC4A110BA8B9E00B55455 /* PlotDevice.icns in Resources */, 2A93AE751903326E00C6144D /* placeholder.pdf in Resources */, + CFF92339196D31780095586A /* tensor.py in Resources */, 611CC4A210BA8B9E00B55455 /* PlotDeviceFile.icns in Resources */, 611CC5A010BA908C00B55455 /* PlotDeviceDocument.xib in Resources */, 611CC5A810BA919A00B55455 /* PlotDevicePreferences.xib in Resources */, @@ -460,6 +465,7 @@ 2A7AF5C818D2AFAA00F8FFC2 /* examples in Resources */, 6155D9F413E2B79E00675A92 /* CHANGES.md in Resources */, 6155D9F513E2B79E00675A92 /* README.md in Resources */, + CFF92338196D31780095586A /* rtclass.py in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/plotdevice/lib/tensor.py b/plotdevice/lib/tensor.py index fb11368f..5956f404 100644 --- a/plotdevice/lib/tensor.py +++ b/plotdevice/lib/tensor.py @@ -7,7 +7,7 @@ #from collections import defaultdict #from PyObjCTools import AppHelper - +''' class ColorInvertFilter(RTClass): """ Wrapper for tensorlib/ColorInvertFilter """ pass @@ -35,7 +35,7 @@ class SoftEleganceFilter(RTClass): class VignetteFilter(RTClass): """ Wrapper for tensorlib/VignetteFilter """ pass - +''' # NSUnknownColorSpaceModel = -1, NSColorSpaceModels = ( From bd587394e281d2d5b0e89ad6cb7d5a922cb713b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Bo=CC=88hn?= Date: Wed, 9 Jul 2014 02:00:02 -0700 Subject: [PATCH 14/81] Typo in error message --- plotdevice/lib/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plotdevice/lib/__init__.py b/plotdevice/lib/__init__.py index 17721df9..4e232d68 100644 --- a/plotdevice/lib/__init__.py +++ b/plotdevice/lib/__init__.py @@ -9,7 +9,7 @@ so_dir = join(module_root, 'build/lib/plotdevice/lib') sys.path.append(so_dir) if not exists(so_dir): - unbuilt = 'Build the plotdevice module with `python setup.pt build\' before attempting import it.' + unbuilt = 'Build the plotdevice module with `python setup.py build\' before attempting import it.' raise RuntimeError(unbuilt) # test the sys.path by attempting to load the c-extensions From 9d3fcf05f6da803bc96466d18b73016b6243f06e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Bo=CC=88hn?= Date: Wed, 9 Jul 2014 02:02:09 -0700 Subject: [PATCH 15/81] Added tensorlib to path sanity check in lib --- plotdevice/lib/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plotdevice/lib/__init__.py b/plotdevice/lib/__init__.py index 4e232d68..bb7ecc4c 100644 --- a/plotdevice/lib/__init__.py +++ b/plotdevice/lib/__init__.py @@ -14,10 +14,10 @@ # test the sys.path by attempting to load the c-extensions try: - import geometry, io, pathmatics + import geometry, io, pathmatics, tensorlib except ImportError: from pprint import pformat - notfound = "Couldn't locate C extensions (cIO.so, cGeometry.so, & cPathmatics.so).\nSearched in:\n%s\nto no avail..."%pformat(sys.path) + notfound = "Couldn't locate C extensions (cIO.so, cGeometry.so, cPathmatics.so, & tensorlib.so).\nSearched in:\n%s\nto no avail..."%pformat(sys.path) raise RuntimeError(notfound) # allow Libraries to request a _ctx reference From fc026636333fa7d1286cdd128cbc32e7771c8ab8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Bo=CC=88hn?= Date: Wed, 9 Jul 2014 02:31:17 -0700 Subject: [PATCH 16/81] Project settings ARGH --- PlotDevice.xcodeproj/project.pbxproj | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/PlotDevice.xcodeproj/project.pbxproj b/PlotDevice.xcodeproj/project.pbxproj index 9305d818..5f36614b 100644 --- a/PlotDevice.xcodeproj/project.pbxproj +++ b/PlotDevice.xcodeproj/project.pbxproj @@ -39,8 +39,6 @@ CF04731D196B71C200E3C358 /* GPUImage.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CF04731C196B71C200E3C358 /* GPUImage.framework */; }; CF047321196B744C00E3C358 /* GPUImage.framework in Copy Private Frameworks */ = {isa = PBXBuildFile; fileRef = CF04731C196B71C200E3C358 /* GPUImage.framework */; }; CF29B4BE196C51B70092593E /* Python.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CF29B4BC196C51410092593E /* Python.framework */; }; - CFF92338196D31780095586A /* rtclass.py in Resources */ = {isa = PBXBuildFile; fileRef = CFF92336196D31780095586A /* rtclass.py */; }; - CFF92339196D31780095586A /* tensor.py in Resources */ = {isa = PBXBuildFile; fileRef = CFF92337196D31780095586A /* tensor.py */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -456,7 +454,6 @@ 611CC49C10BA8B9E00B55455 /* InfoPlist.strings in Resources */, 611CC4A110BA8B9E00B55455 /* PlotDevice.icns in Resources */, 2A93AE751903326E00C6144D /* placeholder.pdf in Resources */, - CFF92339196D31780095586A /* tensor.py in Resources */, 611CC4A210BA8B9E00B55455 /* PlotDeviceFile.icns in Resources */, 611CC5A010BA908C00B55455 /* PlotDeviceDocument.xib in Resources */, 611CC5A810BA919A00B55455 /* PlotDevicePreferences.xib in Resources */, @@ -465,7 +462,6 @@ 2A7AF5C818D2AFAA00F8FFC2 /* examples in Resources */, 6155D9F413E2B79E00675A92 /* CHANGES.md in Resources */, 6155D9F513E2B79E00675A92 /* README.md in Resources */, - CFF92338196D31780095586A /* rtclass.py in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -640,19 +636,30 @@ C05733CC08A9546B00998B17 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + COPY_PHASE_STRIP = NO; + "DEBUG_INFORMATION_FORMAT[sdk=*]" = ""; + FRAMEWORK_SEARCH_PATHS = /Users/fish/Dropbox/plotdevice/app/Frameworks; MACOSX_DEPLOYMENT_TARGET = 10.9; ONLY_ACTIVE_ARCH = YES; PRODUCT_NAME = PlotDevice; SCAN_ALL_SOURCE_FILES_FOR_INCLUDES = YES; + STRIP_INSTALLED_PRODUCT = NO; + VALID_ARCHS = x86_64; + "VALID_ARCHS[sdk=*]" = x86_64; }; name = Debug; }; C05733CD08A9546B00998B17 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + "DEBUG_INFORMATION_FORMAT[sdk=*]" = ""; + FRAMEWORK_SEARCH_PATHS = /Users/fish/Dropbox/plotdevice/app/Frameworks; MACOSX_DEPLOYMENT_TARGET = 10.9; + ONLY_ACTIVE_ARCH = YES; PRODUCT_NAME = PlotDevice; SCAN_ALL_SOURCE_FILES_FOR_INCLUDES = YES; + VALID_ARCHS = x86_64; + "VALID_ARCHS[sdk=*]" = x86_64; }; name = Release; }; From e34419dde4e77ab8032a5005cfe961c046223455 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Bo=CC=88hn?= Date: Wed, 9 Jul 2014 02:39:52 -0700 Subject: [PATCH 17/81] Git-ignoring some build artifacts --- .gitignore | 1 + PlotDevice.xcodeproj/project.pbxproj | 2 ++ 2 files changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 6d01aa67..b6832d36 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ *.so build/ dist/ +dist-* app/deps/Sparkle* # cds garbage diff --git a/PlotDevice.xcodeproj/project.pbxproj b/PlotDevice.xcodeproj/project.pbxproj index 5f36614b..9331295b 100644 --- a/PlotDevice.xcodeproj/project.pbxproj +++ b/PlotDevice.xcodeproj/project.pbxproj @@ -39,6 +39,7 @@ CF04731D196B71C200E3C358 /* GPUImage.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CF04731C196B71C200E3C358 /* GPUImage.framework */; }; CF047321196B744C00E3C358 /* GPUImage.framework in Copy Private Frameworks */ = {isa = PBXBuildFile; fileRef = CF04731C196B71C200E3C358 /* GPUImage.framework */; }; CF29B4BE196C51B70092593E /* Python.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CF29B4BC196C51410092593E /* Python.framework */; }; + CF8FE67D196D448F00DD6E87 /* PlotDevice.app in Resources */ = {isa = PBXBuildFile; fileRef = 8D15AC370486D014006FF6A4 /* PlotDevice.app */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -459,6 +460,7 @@ 611CC5A810BA919A00B55455 /* PlotDevicePreferences.xib in Resources */, 611CC68010BAA08300B55455 /* MainMenu.xib in Resources */, 611CC68710BAA0A600B55455 /* AskString.xib in Resources */, + CF8FE67D196D448F00DD6E87 /* PlotDevice.app in Resources */, 2A7AF5C818D2AFAA00F8FFC2 /* examples in Resources */, 6155D9F413E2B79E00675A92 /* CHANGES.md in Resources */, 6155D9F513E2B79E00675A92 /* README.md in Resources */, From 4a92f7c92e014df7250b382c8f124a3a409411b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Bo=CC=88hn?= Date: Wed, 9 Jul 2014 02:41:24 -0700 Subject: [PATCH 18/81] Project tweak --- PlotDevice.xcodeproj/project.pbxproj | 2 -- 1 file changed, 2 deletions(-) diff --git a/PlotDevice.xcodeproj/project.pbxproj b/PlotDevice.xcodeproj/project.pbxproj index 9331295b..5f36614b 100644 --- a/PlotDevice.xcodeproj/project.pbxproj +++ b/PlotDevice.xcodeproj/project.pbxproj @@ -39,7 +39,6 @@ CF04731D196B71C200E3C358 /* GPUImage.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CF04731C196B71C200E3C358 /* GPUImage.framework */; }; CF047321196B744C00E3C358 /* GPUImage.framework in Copy Private Frameworks */ = {isa = PBXBuildFile; fileRef = CF04731C196B71C200E3C358 /* GPUImage.framework */; }; CF29B4BE196C51B70092593E /* Python.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CF29B4BC196C51410092593E /* Python.framework */; }; - CF8FE67D196D448F00DD6E87 /* PlotDevice.app in Resources */ = {isa = PBXBuildFile; fileRef = 8D15AC370486D014006FF6A4 /* PlotDevice.app */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -460,7 +459,6 @@ 611CC5A810BA919A00B55455 /* PlotDevicePreferences.xib in Resources */, 611CC68010BAA08300B55455 /* MainMenu.xib in Resources */, 611CC68710BAA0A600B55455 /* AskString.xib in Resources */, - CF8FE67D196D448F00DD6E87 /* PlotDevice.app in Resources */, 2A7AF5C818D2AFAA00F8FFC2 /* examples in Resources */, 6155D9F413E2B79E00675A92 /* CHANGES.md in Resources */, 6155D9F513E2B79E00675A92 /* README.md in Resources */, From 2d395f0e88b5564dc73e24cb6246eed42bd9a71e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Bo=CC=88hn?= Date: Wed, 9 Jul 2014 04:50:36 -0700 Subject: [PATCH 19/81] Refactor objective-c runtime sugarclass --- plotdevice/lib/rtclass.py | 70 +++++++++++++++++++++++++++++---------- setup.py | 15 ++++++--- 2 files changed, 63 insertions(+), 22 deletions(-) diff --git a/plotdevice/lib/rtclass.py b/plotdevice/lib/rtclass.py index 8fc2e8f5..361b9d69 100644 --- a/plotdevice/lib/rtclass.py +++ b/plotdevice/lib/rtclass.py @@ -1,23 +1,31 @@ from __future__ import print_function - +from functools import partial import objc, warnings OBJ_COLON = '_' +class ObjCAncestor(type): + """ Subclass RTClass using the name of an Objective-C class + to generate a pythonic wrapper (if you like your syntax sweet) + """ + def __init__(cls, name, bases, attrs): + # print("%s, (%s) {%s}" % (name, bases, attrs.keys())) + creator = partial(cls.__new__, cls) + if name == 'RTClass': + # Don't search for something named RTClass + super(ObjCAncestor, cls).__init__(name, bases, attrs) + return + try: + cls.__rtbase__ = objc.lookUpClass(name) + except objc.nosuchclass_error: + warnings.warn("RTClass: Objective-C class '%s' not found" % name) + super(ObjCAncestor, cls).__init__(name, bases, attrs) + return + super(ObjCAncestor, cls).__init__(name, tuple([cls.__rtbase__] + list(bases) + [object]), attrs) + class RTClass(object): - class __metaclass__(type): - """ Subclass RTClass using the name of an Objective-C class - to generate a pythonic wrapper (if you like your syntax sweet) - """ - def __new__(cls, name, bases, attrs): - create = super(RTClass, cls).__new__ - try: - cls.__rtbase__ = objc.lookUpClass(name) - except objc.nosuchclass_error: - warnings.warn("RTClass: Objective-C class '%s' not found" % name) - return create(name, bases, attrs) - return create(name, tuple([cls.__rtbase__] + list(bases)), attrs) + __metaclass__ = ObjCAncestor def __new__(cls, *args, **kwargs): """ Allow PyObjC-based RTClass subclasses to initialize pythonically e.g. @@ -30,12 +38,20 @@ def __new__(cls, *args, **kwargs): nsarray = NSArray.alloc().initWithArray_(other_nsarray) # bah """ + print("__new__ shit that's how I do shit: %s" % cls) if hasattr(cls, '__rtbase__'): + objc_cls = cls.__rtbase__ init_method_name = kwargs.pop('init', 'init') - instance = cls.alloc() - init_method = getattr(instance, init_method_name) - return init_method(*args) - return super(RTClass, cls).__new__(cls, *args, **kwargs) + if hasattr(objc_cls, 'alloc'): + print("ALLOC") + instance = objc_cls.alloc() + init_method = getattr(instance, init_method_name) + return init_method(*args) + if hasattr(objc_cls, 'init'): + print("INIT") + init_method = getattr(objc_cls, init_method_name) + return init_method(*args) + return object.__new__(cls, *args, **kwargs) def __getattr__(self, attr): """ For unknown attributes that don't end in underscores, @@ -49,7 +65,25 @@ def __getattr__(self, attr): def __repr__(self): # This may be a bad idea, let's find out - return "(%s) ->> %s" % ( + return "(%s) <<- %s" % ( self.__class__.__name__, super(RTClass, self).__repr__()) + + +if __name__ == '__main__': + import tensorlib + + class NSImage(RTClass): + pass + + class PolkaDotFilter(RTClass): + pass + + polkadotter = PolkaDotFilter() + + print(polkadotter) + print(polkadotter.__class__) + print(polkadotter.__class__.__bases__) + #print(polkadotter.process) + print(polkadotter) diff --git a/setup.py b/setup.py index 2477ad72..81ba6c2b 100644 --- a/setup.py +++ b/setup.py @@ -262,14 +262,21 @@ def run(self): # set up internal paths and ensure destination dirs exist RSRC = self.resdir - BIN = join(dirname(RSRC), 'SharedSupport') - MODULE = join(self.bdist_base, 'lib/plotdevice') + CONTENTS = dirname(RSRC) + BIN = join(CONTENTS, 'SharedSupport') + WORKS = join(CONTENTS, 'Frameworks', 'GPUImage.framework') + MODULE = join(self.bdist_base, 'lib', 'plotdevice') PY = join(RSRC, 'python') - for pth in BIN, PY: + DITTO = which('ditto') + + for pth in BIN, WORKS, PY: self.mkpath(pth) # install the module in Resources/python - self.spawn([which('ditto'), MODULE, join(PY, 'plotdevice')]) + self.spawn([DITTO, MODULE, join(PY, 'plotdevice')]) + + # deposit a copy of GPUImage.framework in Frameworks + self.spawn([DITTO, 'app/Frameworks/GPUImage.framework', WORKS]) # discard the eggery-pokery remove_tree(join(RSRC, 'lib'), dry_run=self.dry_run) From adc5d87da14c08b26bb3af08848424954272657a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Bo=CC=88hn?= Date: Wed, 9 Jul 2014 05:25:56 -0700 Subject: [PATCH 20/81] More tweaks --- plotdevice/lib/rtclass.py | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/plotdevice/lib/rtclass.py b/plotdevice/lib/rtclass.py index 361b9d69..43b99f00 100644 --- a/plotdevice/lib/rtclass.py +++ b/plotdevice/lib/rtclass.py @@ -8,7 +8,7 @@ class ObjCAncestor(type): """ Subclass RTClass using the name of an Objective-C class to generate a pythonic wrapper (if you like your syntax sweet) - """ + """ def __init__(cls, name, bases, attrs): # print("%s, (%s) {%s}" % (name, bases, attrs.keys())) creator = partial(cls.__new__, cls) @@ -19,25 +19,25 @@ def __init__(cls, name, bases, attrs): try: cls.__rtbase__ = objc.lookUpClass(name) except objc.nosuchclass_error: - warnings.warn("RTClass: Objective-C class '%s' not found" % name) + warnings.warn("Objective-C class '%s' not found" % name) super(ObjCAncestor, cls).__init__(name, bases, attrs) return super(ObjCAncestor, cls).__init__(name, tuple([cls.__rtbase__] + list(bases) + [object]), attrs) class RTClass(object): __metaclass__ = ObjCAncestor - + def __new__(cls, *args, **kwargs): """ Allow PyObjC-based RTClass subclasses to initialize pythonically e.g. - - nsarray = NSArray() # or: - nsarray = NSArray(other_nsarray, - init='initWithArray') - + + nsarray = NSArray() # or: + nsarray = NSArray(other_nsarray, + init='initWithArray') + rather than having to do the ObjC allocation/initialization dance: - - nsarray = NSArray.alloc().initWithArray_(other_nsarray) # bah - """ + + nsarray = NSArray.alloc().initWithArray_(other_nsarray) # bah + """ print("__new__ shit that's how I do shit: %s" % cls) if hasattr(cls, '__rtbase__'): objc_cls = cls.__rtbase__ @@ -52,7 +52,7 @@ def __new__(cls, *args, **kwargs): init_method = getattr(objc_cls, init_method_name) return init_method(*args) return object.__new__(cls, *args, **kwargs) - + def __getattr__(self, attr): """ For unknown attributes that don't end in underscores, look for their underscored counterpart before bailing. """ @@ -62,26 +62,26 @@ def __getattr__(self, attr): return getattr(self, alt_attr) raise AttributeError('%s (tried with underscore)' % attr) raise AttributeError(attr) - + def __repr__(self): # This may be a bad idea, let's find out return "(%s) <<- %s" % ( - self.__class__.__name__, - super(RTClass, self).__repr__()) + self.__class__.__name__, + super(RTClass, self).__repr__()) if __name__ == '__main__': import tensorlib - + class NSImage(RTClass): pass - + class PolkaDotFilter(RTClass): pass - + polkadotter = PolkaDotFilter() - + print(polkadotter) print(polkadotter.__class__) print(polkadotter.__class__.__bases__) From 102c9ddb33fec825d993894c43a1c8a8e2019e58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Bo=CC=88hn?= Date: Wed, 9 Jul 2014 06:49:22 -0700 Subject: [PATCH 21/81] Whitespace --- plotdevice/lib/rtclass.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plotdevice/lib/rtclass.py b/plotdevice/lib/rtclass.py index 43b99f00..66b1d0f4 100644 --- a/plotdevice/lib/rtclass.py +++ b/plotdevice/lib/rtclass.py @@ -74,7 +74,7 @@ def __repr__(self): if __name__ == '__main__': import tensorlib - class NSImage(RTClass): + class NSImage(RTClass): pass class PolkaDotFilter(RTClass): From bdba5618529254e9cae652106780510eed238416 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Bo=CC=88hn?= Date: Wed, 9 Jul 2014 07:06:27 -0700 Subject: [PATCH 22/81] Git-ignoring local build artifacts --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index b6832d36..0b8d6391 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,5 @@ test.py # Xcode user files project.xcworkspace xcuserdata +DerivedData/ +Xcode/ From e8936a6e85ca781ec631eb81bc787f39cdba131f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Bo=CC=88hn?= Date: Wed, 9 Jul 2014 07:16:28 -0700 Subject: [PATCH 23/81] More granual error reportage, as regards issues when loading externals --- plotdevice/lib/__init__.py | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/plotdevice/lib/__init__.py b/plotdevice/lib/__init__.py index bb7ecc4c..c488361d 100644 --- a/plotdevice/lib/__init__.py +++ b/plotdevice/lib/__init__.py @@ -13,12 +13,32 @@ raise RuntimeError(unbuilt) # test the sys.path by attempting to load the c-extensions +# io, geometry, pathmatics, tensorlib -- (cIO.so, cGeometry.so, cPathmatics.so, & tensorlib.so) +from pprint import pformat +notfound = lambda lib_name: "Couldn't load extension: %s.so\nSearched in:\n%s\nto no avail..." % (pformat(sys.path), lib_name) try: - import geometry, io, pathmatics, tensorlib + import io except ImportError: - from pprint import pformat - notfound = "Couldn't locate C extensions (cIO.so, cGeometry.so, cPathmatics.so, & tensorlib.so).\nSearched in:\n%s\nto no avail..."%pformat(sys.path) - raise RuntimeError(notfound) + raise RuntimeError(notfound('cIO')) + +try: + import geometry +except ImportError: + raise RuntimeError(notfound('cGeometry')) + +try: + import pathmatics +except ImportError: + raise RuntimeError(notfound('cPathmatics')) + +try: + import tensorlib +except ImportError: + raise RuntimeError(notfound('tensorlib')) + +# FUCKING FLAKE-EIGHT ENOUGH ALREADY +io = geometry = pathmatics = tensorlib = None + # allow Libraries to request a _ctx reference def register(module): From c7dafafa2a05721e3e284f6a1bcf2fc3c7004960 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Bo=CC=88hn?= Date: Wed, 9 Jul 2014 07:21:03 -0700 Subject: [PATCH 24/81] More granual error reportage, as regards issues when loading externals --- plotdevice/lib/__init__.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/plotdevice/lib/__init__.py b/plotdevice/lib/__init__.py index c488361d..15644ef9 100644 --- a/plotdevice/lib/__init__.py +++ b/plotdevice/lib/__init__.py @@ -1,5 +1,6 @@ import sys from os.path import join, abspath, dirname, exists +from pprint import pformat # do some special-case handling when the module is imported from within the source dist # (determined by checking the existence project files at a known path). if we're in the @@ -14,8 +15,10 @@ # test the sys.path by attempting to load the c-extensions # io, geometry, pathmatics, tensorlib -- (cIO.so, cGeometry.so, cPathmatics.so, & tensorlib.so) -from pprint import pformat -notfound = lambda lib_name: "Couldn't load extension: %s.so\nSearched in:\n%s\nto no avail..." % (pformat(sys.path), lib_name) +notfound_tmpl = "Couldn't load extension: %s.so\nSearched in:\n%s\nto no avail..." +notfound = lambda lib_name: notfound_tmpl % ( + lib_name, pformat(sys.path)) + try: import io except ImportError: @@ -36,10 +39,9 @@ except ImportError: raise RuntimeError(notfound('tensorlib')) -# FUCKING FLAKE-EIGHT ENOUGH ALREADY +# FUCKING FLAKE-EIGHT ENOUGH ALREADY FOR FUCK'S SAKE io = geometry = pathmatics = tensorlib = None - # allow Libraries to request a _ctx reference def register(module): """When called within a library's __init__.py, returns the currently bound context. From 3862ab0d7f381cff49a77d09ed8cfbdf19ab2434 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Bo=CC=88hn?= Date: Wed, 9 Jul 2014 07:29:12 -0700 Subject: [PATCH 25/81] s/tensor/tensorlib/ (when referencing the ObjC externals), also miscellaneous cleanup --- plotdevice/context.py | 2 +- plotdevice/lib/tensor.py | 6 +----- plotdevice/util/__init__.py | 7 ++++++- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/plotdevice/context.py b/plotdevice/context.py index fc8587ae..28ce9bd5 100644 --- a/plotdevice/context.py +++ b/plotdevice/context.py @@ -5,7 +5,7 @@ from collections import namedtuple from .util import _copy_attr, _copy_attrs, _flatten, trim_zeroes -from .lib import geometry, pathmatics, tensor +from .lib import geometry, pathmatics, tensorlib from .gfx.transform import Dimension from .gfx import * from . import gfx, lib, util, Halted, DeviceError diff --git a/plotdevice/lib/tensor.py b/plotdevice/lib/tensor.py index 5956f404..2f214224 100644 --- a/plotdevice/lib/tensor.py +++ b/plotdevice/lib/tensor.py @@ -1,13 +1,10 @@ from __future__ import print_function -import objc -import tensorlib +import objc, tensorlib from .rtclass import RTClass #from collections import defaultdict -#from PyObjCTools import AppHelper -''' class ColorInvertFilter(RTClass): """ Wrapper for tensorlib/ColorInvertFilter """ pass @@ -35,7 +32,6 @@ class SoftEleganceFilter(RTClass): class VignetteFilter(RTClass): """ Wrapper for tensorlib/VignetteFilter """ pass -''' # NSUnknownColorSpaceModel = -1, NSColorSpaceModels = ( diff --git a/plotdevice/util/__init__.py b/plotdevice/util/__init__.py index b6c3c78b..7be702f7 100644 --- a/plotdevice/util/__init__.py +++ b/plotdevice/util/__init__.py @@ -9,7 +9,12 @@ from random import choice, shuffle from plotdevice import DeviceError -__all__ = ('grid', 'random', 'shuffled', 'choice', 'ordered', 'order', 'files', 'read', 'autotext', '_copy_attr', '_copy_attrs', 'odict', 'ddict', 'adict') +__all__ = ( + 'grid', 'random', 'shuffled', + 'choice', 'ordered', 'order', + 'files', 'read', 'autotext', + '_copy_attr', '_copy_attrs', + 'odict', 'ddict', 'adict') ### Utilities ### From 5127404c3344bd3cf836a0eb0d2e61f2e0d37703 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Bo=CC=88hn?= Date: Wed, 9 Jul 2014 07:37:14 -0700 Subject: [PATCH 26/81] Removing local Xcode artifacts in setup.py clean --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index 81ba6c2b..b4f8576d 100644 --- a/setup.py +++ b/setup.py @@ -189,6 +189,7 @@ def finalize_options(self): pass def run(self): os.system('rm -rf ./build ./dist') + os.system('rm -rf ./Xcode/Build ./Xcode/Intermediates ./DerivedData') os.system('rm -rf ./app/deps/*/build') os.system('rm -rf plotdevice.egg-info MANIFEST.in PKG') From 0102facbbe52def240f4e39f16afb70a12cc5f98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Bo=CC=88hn?= Date: Wed, 9 Jul 2014 07:53:49 -0700 Subject: [PATCH 27/81] Cleaned and clarified misc stuff in setup.py --- setup.py | 54 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 28 insertions(+), 26 deletions(-) diff --git a/setup.py b/setup.py index b4f8576d..f2d32161 100644 --- a/setup.py +++ b/setup.py @@ -141,7 +141,7 @@ def timestamp(): import urllib2 def last_release(): - from xml.etree.ElementTree import fromstring, tostring + from xml.etree.ElementTree import fromstring feed_xml = urllib2.urlopen('http://plotdevice.io/app.xml').read().decode('utf-8') for item in fromstring(feed_xml.encode('utf-8')).iter('revision'): return item.text @@ -183,10 +183,8 @@ def merged_feed(new_release): class CleanCommand(Command): description = "wipe out the ./build ./dist and app/deps/.../build dirs" user_options = [] - def initialize_options(self): - pass - def finalize_options(self): - pass + def initialize_options(self): pass + def finalize_options(self): pass def run(self): os.system('rm -rf ./build ./dist') os.system('rm -rf ./Xcode/Build ./Xcode/Intermediates ./DerivedData') @@ -232,17 +230,15 @@ def run(self): class BuildAppCommand(Command): description = "Build PlotDevice.app with xcode" user_options = [] - def initialize_options(self): - pass - def finalize_options(self): - pass + def initialize_options(self): pass + def finalize_options(self): pass def run(self): self.spawn(['xcodebuild']) remove_tree('dist/PlotDevice.app.dSYM') print "done building PlotDevice.app in ./dist" try: - import py2app + #import py2app from py2app.build_app import py2app as build_py2app class BuildPy2AppCommand(build_py2app): description = """Build PlotDevice.app with py2app (then undo some of its questionable layout defaults)""" @@ -265,7 +261,7 @@ def run(self): RSRC = self.resdir CONTENTS = dirname(RSRC) BIN = join(CONTENTS, 'SharedSupport') - WORKS = join(CONTENTS, 'Frameworks', 'GPUImage.framework') + GPUIMAGE = join(CONTENTS, 'Frameworks', 'GPUImage.framework') MODULE = join(self.bdist_base, 'lib', 'plotdevice') PY = join(RSRC, 'python') DITTO = which('ditto') @@ -277,7 +273,7 @@ def run(self): self.spawn([DITTO, MODULE, join(PY, 'plotdevice')]) # deposit a copy of GPUImage.framework in Frameworks - self.spawn([DITTO, 'app/Frameworks/GPUImage.framework', WORKS]) + self.spawn([DITTO, 'app/Frameworks/GPUImage.framework', GPUIMAGE]) # discard the eggery-pokery remove_tree(join(RSRC, 'lib'), dry_run=self.dry_run) @@ -297,7 +293,12 @@ def run(self): if 'py2app' in sys.argv: print """setup.py: py2app build failed Couldn't find the py2app module (perhaps because you've called setup.py from a virtualenv). - Make sure you're using the system's /usr/bin/python interpreter for py2app builds.""" + Make sure you're using either: + + * Apple's system-installed python: /usr/bin/python -- or, + * A Homebrew python install: /usr/local/bin/python + + ... for py2app builds (The latter option should be a framework build). """ sys.exit(1) @@ -306,10 +307,8 @@ def run(self): class DistCommand(Command): description = "Create distributable zip of the app and an updated app.xml feed" user_options = [] - def initialize_options(self): - pass - def finalize_options(self): - pass + def initialize_options(self): pass + def finalize_options(self): pass def run(self): APP = 'dist/PlotDevice.app' ZIP = 'dist/PlotDevice_app-%s.zip' % VERSION @@ -326,8 +325,7 @@ def run(self): CFBundleVersion = last_commit(), CFBundleShortVersionString = VERSION, SUFeedURL = 'http://plotdevice.io/app.xml', - SUEnableSystemProfiling = 'YES' - ) + SUEnableSystemProfiling = 'YES') # Download Sparkle (if necessary) and copy it into the bundle ORIG = 'app/deps/Sparkle-%s/Sparkle.framework'%SPARKLE_VERSION @@ -371,9 +369,8 @@ def run(self): gosub('%s -xml -utf8 -e dist/app.xml' % which('tidy'), on_err="app.xml didn't validate properly") - tarfile = 'dist/plotdevice-%s.tar.gz'%VERSION zipfile = 'dist/PlotDevice_app-%s.zip'%VERSION - from xml.etree.ElementTree import parse, dump + from xml.etree.ElementTree import parse for item in parse('dist/app.xml').getroot().iter('item'): release = item.find('enclosure').attrib assert release['url'].endswith(basename(zipfile)), "Version mismatch: %s vs %r" % (zipfile, release['url']) @@ -420,12 +417,17 @@ def run(self): }, ) - # py2app-specific config + # py2app-specific config + # Note how we're not adding the GPUImage framework here, + # despite what the paltry docs available, as regards + # the subject of py2app and framework-addery, + # seem to suggest -- we do it ourselves when executing + # the BuildPy2AppCommand stuf. if 'py2app' in sys.argv: config.update(dict( app = [{ 'script': "app/plotdevice-app.py", - "plist":info_plist(), + "plist": info_plist(), }], data_files = [ "app/Resources/ui", @@ -437,9 +439,9 @@ def run(self): options = { "py2app": { "iconfile": "app/Resources/PlotDevice.icns", - "semi_standalone":True, - "site_packages":True, - "strip":False, + "semi_standalone": True, + "site_packages": True, + "strip": False, } }, cmdclass={ From f4ec33b74c6413bfa76898fb0599d355ac0da04c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Bo=CC=88hn?= Date: Wed, 9 Jul 2014 07:56:00 -0700 Subject: [PATCH 28/81] One last s/WORKS/GPUIMAGE/ in setup.py --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index f2d32161..cb1c0ce2 100644 --- a/setup.py +++ b/setup.py @@ -266,7 +266,7 @@ def run(self): PY = join(RSRC, 'python') DITTO = which('ditto') - for pth in BIN, WORKS, PY: + for pth in BIN, GPUIMAGE, PY: self.mkpath(pth) # install the module in Resources/python From ba0b7b1571cf1e0a43870baae098309fd7e9b70e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Bo=CC=88hn?= Date: Wed, 9 Jul 2014 08:09:02 -0700 Subject: [PATCH 29/81] More cleanup (some of which is due to the last cleanup) --- plotdevice/context.py | 4 ++-- plotdevice/lib/rtclass.py | 15 ++++++++++----- setup.py | 2 +- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/plotdevice/context.py b/plotdevice/context.py index 28ce9bd5..a0063470 100644 --- a/plotdevice/context.py +++ b/plotdevice/context.py @@ -5,7 +5,7 @@ from collections import namedtuple from .util import _copy_attr, _copy_attrs, _flatten, trim_zeroes -from .lib import geometry, pathmatics, tensorlib +from .lib import geometry, pathmatics, tensor from .gfx.transform import Dimension from .gfx import * from . import gfx, lib, util, Halted, DeviceError @@ -1072,7 +1072,7 @@ def textheight(self, txt, width=None, **kwargs): ### Image commands ### - def imagefilter(self, filter_name): + def _imagefilter(self, filter_name): # DISABLED FOR NOW class_name = "%sFilter" % filter_name if hasattr(tensor, class_name): print "Loading %s" % class_name diff --git a/plotdevice/lib/rtclass.py b/plotdevice/lib/rtclass.py index 66b1d0f4..9ae8e2c4 100644 --- a/plotdevice/lib/rtclass.py +++ b/plotdevice/lib/rtclass.py @@ -1,7 +1,7 @@ from __future__ import print_function -from functools import partial -import objc, warnings +# from functools import partial +import sys, objc, warnings OBJ_COLON = '_' @@ -11,7 +11,7 @@ class ObjCAncestor(type): """ def __init__(cls, name, bases, attrs): # print("%s, (%s) {%s}" % (name, bases, attrs.keys())) - creator = partial(cls.__new__, cls) + # creator = partial(cls.__new__, cls) if name == 'RTClass': # Don't search for something named RTClass super(ObjCAncestor, cls).__init__(name, bases, attrs) @@ -72,9 +72,12 @@ def __repr__(self): if __name__ == '__main__': - import tensorlib + try: + import tensorlib + except ImportError: + sys.exit(1) - class NSImage(RTClass): + class NSImage(RTClass): pass class PolkaDotFilter(RTClass): @@ -87,3 +90,5 @@ class PolkaDotFilter(RTClass): print(polkadotter.__class__.__bases__) #print(polkadotter.process) print(polkadotter) + + print(dir(tensorlib)) diff --git a/setup.py b/setup.py index cb1c0ce2..d64eaf53 100644 --- a/setup.py +++ b/setup.py @@ -17,7 +17,7 @@ # - Mac OS X 10.9+ # - py2app or xcode or just pip # - PyObjC (should be in /System/Library/Frameworks/Python.framework/Versions/2.7/Extras) -# - cPathMatics, cGeo, cIO, cEvent, tensor, & polymagic (included in the "app/deps" folder) +# - cPathMatics, cGeo, cIO, cEvent, tensorlib, & polymagic (included in the "app/deps" folder) # - Sparkle.framework (auto-downloaded only for `dist` builds) import sys,os From 794e6a8934998c4b1c7b8e906889516ff6a4eb34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Bo=CC=88hn?= Date: Wed, 9 Jul 2014 08:17:28 -0700 Subject: [PATCH 30/81] Only import tensor inside (currently disabled) imagefilter() user-facing function --- plotdevice/context.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plotdevice/context.py b/plotdevice/context.py index a0063470..6997f3d4 100644 --- a/plotdevice/context.py +++ b/plotdevice/context.py @@ -5,7 +5,7 @@ from collections import namedtuple from .util import _copy_attr, _copy_attrs, _flatten, trim_zeroes -from .lib import geometry, pathmatics, tensor +from .lib import geometry, pathmatics from .gfx.transform import Dimension from .gfx import * from . import gfx, lib, util, Halted, DeviceError @@ -1073,6 +1073,7 @@ def textheight(self, txt, width=None, **kwargs): ### Image commands ### def _imagefilter(self, filter_name): # DISABLED FOR NOW + import tensor class_name = "%sFilter" % filter_name if hasattr(tensor, class_name): print "Loading %s" % class_name From 9391a319a4f5fda8e099cec44aca657c491aebe8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Bo=CC=88hn?= Date: Wed, 9 Jul 2014 08:20:49 -0700 Subject: [PATCH 31/81] Changed from raising RuntimeError to spitting out a warning when we can't find tensorlib.so --- plotdevice/lib/__init__.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/plotdevice/lib/__init__.py b/plotdevice/lib/__init__.py index 15644ef9..94b870fe 100644 --- a/plotdevice/lib/__init__.py +++ b/plotdevice/lib/__init__.py @@ -1,4 +1,4 @@ -import sys +import sys, warnings from os.path import join, abspath, dirname, exists from pprint import pformat @@ -37,7 +37,8 @@ try: import tensorlib except ImportError: - raise RuntimeError(notfound('tensorlib')) + #raise RuntimeError(notfound('tensorlib')) + warnings.warn(notfound('tensorlib')) # FUCKING FLAKE-EIGHT ENOUGH ALREADY FOR FUCK'S SAKE io = geometry = pathmatics = tensorlib = None From 6c3fcb02f856146bf4cd1017349ae2d67aaf3741 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Bo=CC=88hn?= Date: Wed, 9 Jul 2014 08:26:04 -0700 Subject: [PATCH 32/81] app/deps/{tensor -----> tensorlib} --- app/deps/{tensor => tensorlib}/ColorInvertFilter.h | 0 app/deps/{tensor => tensorlib}/ColorInvertFilter.m | 0 app/deps/{tensor => tensorlib}/FilterBase.h | 0 app/deps/{tensor => tensorlib}/FilterBase.m | 0 app/deps/{tensor => tensorlib}/HalftoneFilter.h | 0 app/deps/{tensor => tensorlib}/HalftoneFilter.m | 0 app/deps/{tensor => tensorlib}/MissEtikateFilter.h | 0 app/deps/{tensor => tensorlib}/MissEtikateFilter.m | 0 app/deps/{tensor => tensorlib}/PolkaDotFilter.h | 0 app/deps/{tensor => tensorlib}/PolkaDotFilter.m | 0 app/deps/{tensor => tensorlib}/SepiaFilter.h | 0 app/deps/{tensor => tensorlib}/SepiaFilter.m | 0 app/deps/{tensor => tensorlib}/SoftEleganceFilter.h | 0 app/deps/{tensor => tensorlib}/SoftEleganceFilter.m | 0 app/deps/{tensor => tensorlib}/VignetteFilter.h | 0 app/deps/{tensor => tensorlib}/VignetteFilter.m | 0 app/deps/{tensor => tensorlib}/module.m | 0 app/deps/{tensor => tensorlib}/setup.py | 0 18 files changed, 0 insertions(+), 0 deletions(-) rename app/deps/{tensor => tensorlib}/ColorInvertFilter.h (100%) rename app/deps/{tensor => tensorlib}/ColorInvertFilter.m (100%) rename app/deps/{tensor => tensorlib}/FilterBase.h (100%) rename app/deps/{tensor => tensorlib}/FilterBase.m (100%) rename app/deps/{tensor => tensorlib}/HalftoneFilter.h (100%) rename app/deps/{tensor => tensorlib}/HalftoneFilter.m (100%) rename app/deps/{tensor => tensorlib}/MissEtikateFilter.h (100%) rename app/deps/{tensor => tensorlib}/MissEtikateFilter.m (100%) rename app/deps/{tensor => tensorlib}/PolkaDotFilter.h (100%) rename app/deps/{tensor => tensorlib}/PolkaDotFilter.m (100%) rename app/deps/{tensor => tensorlib}/SepiaFilter.h (100%) rename app/deps/{tensor => tensorlib}/SepiaFilter.m (100%) rename app/deps/{tensor => tensorlib}/SoftEleganceFilter.h (100%) rename app/deps/{tensor => tensorlib}/SoftEleganceFilter.m (100%) rename app/deps/{tensor => tensorlib}/VignetteFilter.h (100%) rename app/deps/{tensor => tensorlib}/VignetteFilter.m (100%) rename app/deps/{tensor => tensorlib}/module.m (100%) rename app/deps/{tensor => tensorlib}/setup.py (100%) diff --git a/app/deps/tensor/ColorInvertFilter.h b/app/deps/tensorlib/ColorInvertFilter.h similarity index 100% rename from app/deps/tensor/ColorInvertFilter.h rename to app/deps/tensorlib/ColorInvertFilter.h diff --git a/app/deps/tensor/ColorInvertFilter.m b/app/deps/tensorlib/ColorInvertFilter.m similarity index 100% rename from app/deps/tensor/ColorInvertFilter.m rename to app/deps/tensorlib/ColorInvertFilter.m diff --git a/app/deps/tensor/FilterBase.h b/app/deps/tensorlib/FilterBase.h similarity index 100% rename from app/deps/tensor/FilterBase.h rename to app/deps/tensorlib/FilterBase.h diff --git a/app/deps/tensor/FilterBase.m b/app/deps/tensorlib/FilterBase.m similarity index 100% rename from app/deps/tensor/FilterBase.m rename to app/deps/tensorlib/FilterBase.m diff --git a/app/deps/tensor/HalftoneFilter.h b/app/deps/tensorlib/HalftoneFilter.h similarity index 100% rename from app/deps/tensor/HalftoneFilter.h rename to app/deps/tensorlib/HalftoneFilter.h diff --git a/app/deps/tensor/HalftoneFilter.m b/app/deps/tensorlib/HalftoneFilter.m similarity index 100% rename from app/deps/tensor/HalftoneFilter.m rename to app/deps/tensorlib/HalftoneFilter.m diff --git a/app/deps/tensor/MissEtikateFilter.h b/app/deps/tensorlib/MissEtikateFilter.h similarity index 100% rename from app/deps/tensor/MissEtikateFilter.h rename to app/deps/tensorlib/MissEtikateFilter.h diff --git a/app/deps/tensor/MissEtikateFilter.m b/app/deps/tensorlib/MissEtikateFilter.m similarity index 100% rename from app/deps/tensor/MissEtikateFilter.m rename to app/deps/tensorlib/MissEtikateFilter.m diff --git a/app/deps/tensor/PolkaDotFilter.h b/app/deps/tensorlib/PolkaDotFilter.h similarity index 100% rename from app/deps/tensor/PolkaDotFilter.h rename to app/deps/tensorlib/PolkaDotFilter.h diff --git a/app/deps/tensor/PolkaDotFilter.m b/app/deps/tensorlib/PolkaDotFilter.m similarity index 100% rename from app/deps/tensor/PolkaDotFilter.m rename to app/deps/tensorlib/PolkaDotFilter.m diff --git a/app/deps/tensor/SepiaFilter.h b/app/deps/tensorlib/SepiaFilter.h similarity index 100% rename from app/deps/tensor/SepiaFilter.h rename to app/deps/tensorlib/SepiaFilter.h diff --git a/app/deps/tensor/SepiaFilter.m b/app/deps/tensorlib/SepiaFilter.m similarity index 100% rename from app/deps/tensor/SepiaFilter.m rename to app/deps/tensorlib/SepiaFilter.m diff --git a/app/deps/tensor/SoftEleganceFilter.h b/app/deps/tensorlib/SoftEleganceFilter.h similarity index 100% rename from app/deps/tensor/SoftEleganceFilter.h rename to app/deps/tensorlib/SoftEleganceFilter.h diff --git a/app/deps/tensor/SoftEleganceFilter.m b/app/deps/tensorlib/SoftEleganceFilter.m similarity index 100% rename from app/deps/tensor/SoftEleganceFilter.m rename to app/deps/tensorlib/SoftEleganceFilter.m diff --git a/app/deps/tensor/VignetteFilter.h b/app/deps/tensorlib/VignetteFilter.h similarity index 100% rename from app/deps/tensor/VignetteFilter.h rename to app/deps/tensorlib/VignetteFilter.h diff --git a/app/deps/tensor/VignetteFilter.m b/app/deps/tensorlib/VignetteFilter.m similarity index 100% rename from app/deps/tensor/VignetteFilter.m rename to app/deps/tensorlib/VignetteFilter.m diff --git a/app/deps/tensor/module.m b/app/deps/tensorlib/module.m similarity index 100% rename from app/deps/tensor/module.m rename to app/deps/tensorlib/module.m diff --git a/app/deps/tensor/setup.py b/app/deps/tensorlib/setup.py similarity index 100% rename from app/deps/tensor/setup.py rename to app/deps/tensorlib/setup.py From ab7d6d45bf4f0bfaf58463302a55ee35c4063934 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Bo=CC=88hn?= Date: Wed, 9 Jul 2014 11:04:15 -0700 Subject: [PATCH 33/81] Updated dist command to get GPUImage; among other misc changes --- app/plotdevice-app.py | 13 +++--- plotdevice/__init__.py | 3 +- setup.py | 91 ++++++++++++++++++++++++++++++++++-------- 3 files changed, 82 insertions(+), 25 deletions(-) diff --git a/app/plotdevice-app.py b/app/plotdevice-app.py index 5ab623de..ad4fcc4d 100644 --- a/app/plotdevice-app.py +++ b/app/plotdevice-app.py @@ -1,9 +1,7 @@ -import sys -import objc -import Foundation -import AppKit + +import sys, objc, Foundation, AppKit from signal import signal, SIGINT -from os.path import dirname, abspath, join, isdir, exists +from os.path import abspath, isdir from PyObjCTools import AppHelper # if there's a python installed into /usr/local, it's probably homebrew -- @@ -22,9 +20,8 @@ seen = set() seen_add = seen.add clean_path = tuple(directory for directory in sys.path \ - if exists(directory) and \ - directory not in seen and \ - not seen_add(directory)) + if directory not in seen and \ + not seen_add(directory)) sys.path = list(clean_path) # install a signal handler to quit on ^c (should the app ever be launched from terminal) diff --git a/plotdevice/__init__.py b/plotdevice/__init__.py index dbae83e5..c0021863 100644 --- a/plotdevice/__init__.py +++ b/plotdevice/__init__.py @@ -34,7 +34,8 @@ try: import objc except ImportError: - extras = '/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python' + #extras = '/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python' + extras = sys.prefix sys.path.extend([extras, '%s/PyObjC'%extras]) import objc diff --git a/setup.py b/setup.py index d64eaf53..d11e697b 100644 --- a/setup.py +++ b/setup.py @@ -20,11 +20,11 @@ # - cPathMatics, cGeo, cIO, cEvent, tensorlib, & polymagic (included in the "app/deps" folder) # - Sparkle.framework (auto-downloaded only for `dist` builds) -import sys,os +import sys, os from distutils.dir_util import remove_tree from setuptools import setup, find_packages from pkg_resources import DistributionNotFound -from os.path import join, exists, dirname, basename, abspath +from os.path import join, exists, dirname, basename, abspath, relpath import plotdevice @@ -85,7 +85,11 @@ # the sparkle updater framework will be fetched as needed SPARKLE_VERSION = '1.7.0' -SPARKLE_URL = 'https://github.com/pornel/Sparkle/releases/download/%(v)s/Sparkle-%(v)s.tar.bz2'% {'v':SPARKLE_VERSION} +SPARKLE_URL = 'https://github.com/pornel/Sparkle/releases/download/%(v)s/Sparkle-%(v)s.tar.bz2'% { 'v': SPARKLE_VERSION } + +# ... as will the GPUImage framework source +GPUIMAGE_VERSION = '0.1.5' # latest stable +GPUIMAGE_URL = "https://github.com/BradLarson/GPUImage/archive/%(v)s.zip" % { 'v': GPUIMAGE_VERSION } # helpers for dealing with plists & git (spiritual cousins if ever there were) import plistlib @@ -219,13 +223,13 @@ def run(self): self.spawn([which('python'), 'app/deps/build.py', abspath(self.build_lib)]) # include some ui resources for running a script from the command line - rsrc_dir = '%s/plotdevice/rsrc'%self.build_lib + rsrc_dir = '%s/plotdevice/rsrc' % self.build_lib self.mkpath(rsrc_dir) - self.copy_file("app/Resources/colors.json", '%s/colors.json'%rsrc_dir) + self.copy_file("app/Resources/colors.json", '%s/colors.json' % rsrc_dir) self.spawn([which('ibtool'), '--compile', - '%s/viewer.nib'%rsrc_dir, + '%s/viewer.nib' % rsrc_dir, "app/Resources/English.lproj/PlotDeviceScript.xib"]) - self.copy_file("app/Resources/PlotDeviceFile.icns", '%s/viewer.icns'%rsrc_dir) + self.copy_file("app/Resources/PlotDeviceFile.icns", '%s/viewer.icns' % rsrc_dir) class BuildAppCommand(Command): description = "Build PlotDevice.app with xcode" @@ -261,20 +265,37 @@ def run(self): RSRC = self.resdir CONTENTS = dirname(RSRC) BIN = join(CONTENTS, 'SharedSupport') - GPUIMAGE = join(CONTENTS, 'Frameworks', 'GPUImage.framework') + FRAMEWORKS = join(CONTENTS, 'Frameworks') + GPUIMAGE = join(FRAMEWORKS, 'GPUImage.framework') MODULE = join(self.bdist_base, 'lib', 'plotdevice') PY = join(RSRC, 'python') + PLOTDEVICE = join(PY, 'plotdevice') + FAKEWORKS = join(PLOTDEVICE, 'Frameworks') # YOU HAVE GOT TO BE FRIGGING KIDDING ME DITTO = which('ditto') + LN = which('ln') for pth in BIN, GPUIMAGE, PY: self.mkpath(pth) # install the module in Resources/python - self.spawn([DITTO, MODULE, join(PY, 'plotdevice')]) + self.spawn([DITTO, MODULE, PLOTDEVICE]) # deposit a copy of GPUImage.framework in Frameworks self.spawn([DITTO, 'app/Frameworks/GPUImage.framework', GPUIMAGE]) + # compiling PyObjC extensions that link against GPUImage will, + # inevitably, hardcode the dynamic-link path in the output binaries + # -- HELLOOOOO?!? WHY is this a problem if it's "DYNAMIC" linking -- + # but so we need this symlink to compensate for the difference + # in the relative location of GPUImage.framework in the project tree, + # _qua_ the application bundle, vis-a-vis the extensions in question + CAMEFROM = os.getcwd() + os.chdir(CONTENTS) + self.spawn([LN, '-s', + relpath(FRAMEWORKS, start=CONTENTS), + relpath(FAKEWORKS, start=CONTENTS)]) + os.chdir(CAMEFROM) + # discard the eggery-pokery remove_tree(join(RSRC, 'lib'), dry_run=self.dry_run) os.unlink(join(RSRC, 'include')) @@ -293,7 +314,7 @@ def run(self): if 'py2app' in sys.argv: print """setup.py: py2app build failed Couldn't find the py2app module (perhaps because you've called setup.py from a virtualenv). - Make sure you're using either: + Make sure you're not in a virtualenv directory or shell, and that you're using either: * Apple's system-installed python: /usr/bin/python -- or, * A Homebrew python install: /usr/local/bin/python @@ -326,20 +347,58 @@ def run(self): CFBundleShortVersionString = VERSION, SUFeedURL = 'http://plotdevice.io/app.xml', SUEnableSystemProfiling = 'YES') + + # Deal with installable frameworks: + FRAMEWORKS = join('app', 'Frameworks') + DITTO = which('ditto') + self.mkpath(FRAMEWORKS) # Download Sparkle (if necessary) and copy it into the bundle - ORIG = 'app/deps/Sparkle-%s/Sparkle.framework'%SPARKLE_VERSION - SPARKLE = join(APP,'Contents/Frameworks/Sparkle.framework') + ORIG = join(FRAMEWORKS, 'Sparkle-%s' % SPARKLE_VERSION, 'Sparkle.framework') + SPARKLE = join(APP, 'Contents', 'Frameworks', 'Sparkle.framework') if not exists(ORIG): print "Downloading Sparkle.framework" - self.mkpath('app/deps') - os.system('%s -L %s | bunzip2 -c | tar xf - -C app/deps' % ( - which('curl'), SPARKLE_URL)) + os.system('%(curl)s -L %(url)s | %(bz)s -c | %(tar)s xf - -C %(fw)s' % dict( + curl=which('curl'), url=SPARKLE_URL, + bz=which('bunzip2'), + tar=which('tar'), fw=FRAMEWORKS)) self.mkpath(dirname(SPARKLE)) - self.spawn([which('ditto'), ORIG, SPARKLE]) + self.spawn([DITTO, ORIG, SPARKLE]) + + # Download an GPUImage release and build it, copying the build product + # into the bundle. Brad Larson (the GPUImage guy) doesn't release binaries, + # so if we're minus the bundle we have to build ourselves a new one. + # See also: https://github.com/BradLarson/GPUImage/releases + ORIG = join(FRAMEWORKS, 'GPUImage.framework') + GPUIMAGE = join(APP, 'Contents', 'Frameworks', 'GPUImage.framework') + if not exists(ORIG): + print "Downloading GPUImage source" + import tempfile + tempdir = tempfile.mkdtemp(suffix='XXXXX') + os.system('%(curl)s -L %(url)s | %(tar)s xzf - -C %(temp)s' % dict( + curl=which('curl'), url=GPUIMAGE_URL, + tar=which('tar'), temp=tempdir)) + GPUIMAGE_SOURCE = join(tempdir, 'GPUImage-%s' % GPUIMAGE_VERSION, 'framework') + GPUIMAGE_XCPROJECT = join(GPUIMAGE_SOURCE, 'GPUImageMac.xcodeproj') + GPUIMAGE_BUILT = join(GPUIMAGE_SOURCE, 'build', 'Release') + if not exists(GPUIMAGE_SOURCE): + print "ERROR: there was a problem getting the GPUImage source" + sys.exit(1) + print "Building GPUImage.framework" + self.spawn([which('xcodebuild'), + '-project', GPUIMAGE_XCPROJECT, + '-scheme', 'GPUImage', + '-arch', 'x86_64']) + if not exists(GPUIMAGE_BUILT): + print "ERROR: there was a problem building the GPUImage source" + sys.exit(1) + self.spawn([DITTO, GPUIMAGE_BUILT, ORIG]) + self.remove_tree(tempdir, dry_run=self.dry_run) + self.spawn([DITTO, ORIG, GPUIMAGE]) # code-sign the app and sparkle bundles, then verify self.spawn(['codesign', '-f', '-v', '-s', "Developer ID Application", SPARKLE]) + self.spawn(['codesign', '-f', '-v', '-s', "Developer ID Application", GPUIMAGE]) self.spawn(['codesign', '-f', '-v', '-s', "Developer ID Application", APP]) self.spawn(['spctl', '--assess', '-v', 'dist/PlotDevice.app']) From 615be6045974f9e82d0d91491f849abb4eb80c73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Bo=CC=88hn?= Date: Wed, 9 Jul 2014 11:13:04 -0700 Subject: [PATCH 34/81] Swapped the relative-ness of the framework bundle symlink (don't ask) --- setup.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/setup.py b/setup.py index d11e697b..148dedae 100644 --- a/setup.py +++ b/setup.py @@ -290,10 +290,10 @@ def run(self): # in the relative location of GPUImage.framework in the project tree, # _qua_ the application bundle, vis-a-vis the extensions in question CAMEFROM = os.getcwd() - os.chdir(CONTENTS) + os.chdir(PLOTDEVICE) self.spawn([LN, '-s', - relpath(FRAMEWORKS, start=CONTENTS), - relpath(FAKEWORKS, start=CONTENTS)]) + relpath(FRAMEWORKS, start=PLOTDEVICE), + relpath(FAKEWORKS, start=PLOTDEVICE)]) os.chdir(CAMEFROM) # discard the eggery-pokery From 012a72cbcaea5bb5f7cb977b49f9355a94acd13c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Bo=CC=88hn?= Date: Wed, 9 Jul 2014 11:19:21 -0700 Subject: [PATCH 35/81] Forgot the framework bundle name --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 148dedae..3d7f838e 100644 --- a/setup.py +++ b/setup.py @@ -380,7 +380,7 @@ def run(self): tar=which('tar'), temp=tempdir)) GPUIMAGE_SOURCE = join(tempdir, 'GPUImage-%s' % GPUIMAGE_VERSION, 'framework') GPUIMAGE_XCPROJECT = join(GPUIMAGE_SOURCE, 'GPUImageMac.xcodeproj') - GPUIMAGE_BUILT = join(GPUIMAGE_SOURCE, 'build', 'Release') + GPUIMAGE_BUILT = join(GPUIMAGE_SOURCE, 'build', 'Release', 'GPUImage.framework') if not exists(GPUIMAGE_SOURCE): print "ERROR: there was a problem getting the GPUImage source" sys.exit(1) From 92cd945c1d4b83d821069e783fb9441a7d2057b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Bo=CC=88hn?= Date: Wed, 9 Jul 2014 11:51:17 -0700 Subject: [PATCH 36/81] Enabling image filters v0.1.0 --- plotdevice/context.py | 34 ++++++++++++++++++++++++---------- plotdevice/gfx/image.py | 5 +++++ 2 files changed, 29 insertions(+), 10 deletions(-) diff --git a/plotdevice/context.py b/plotdevice/context.py index 6997f3d4..5394cd8b 100644 --- a/plotdevice/context.py +++ b/plotdevice/context.py @@ -5,7 +5,7 @@ from collections import namedtuple from .util import _copy_attr, _copy_attrs, _flatten, trim_zeroes -from .lib import geometry, pathmatics +from .lib import geometry, pathmatics, tensor from .gfx.transform import Dimension from .gfx import * from . import gfx, lib, util, Halted, DeviceError @@ -1072,13 +1072,22 @@ def textheight(self, txt, width=None, **kwargs): ### Image commands ### - def _imagefilter(self, filter_name): # DISABLED FOR NOW - import tensor - class_name = "%sFilter" % filter_name - if hasattr(tensor, class_name): - print "Loading %s" % class_name - AXFilter = getattr(tensor, class_name) + def imagefilter(self, filterName): + className = "%sFilter" % filterName + imageFilter = None + try: + imageFilter = objc.lookUpClass(className).alloc().init() + except objc.nosuchclass_error: + pass + return imageFilter + + def _imagefilter(self, filterName): + return + if hasattr(tensor, filterName): + print "Loading %s" % filterName + AXFilter = getattr(tensor, filterName) return AXFilter() + def image(self, *args, **kwargs): """Draw a bitmap or vector image @@ -1097,13 +1106,18 @@ def image(self, *args, **kwargs): draw = kwargs.pop('draw', self._autoplot) draw = kwargs.pop('plot', draw) - image_filter = kwargs.pop('filter', None) - if image_filter: - pass + imageFilter = kwargs.pop('filter', None) + imageFilterName = hasattr(imageFilter, 'className') and str(imageFilter.className()) or '' img = Image(*args, **kwargs) + + if imageFilter and imageFilterName: + print "Applying image filter: %s" % imageFilterName + img.applyFilter(imageFilter) + if draw: img.draw() + return img def imagesize(self, path, data=None): diff --git a/plotdevice/gfx/image.py b/plotdevice/gfx/image.py index b3385cbd..de1a4be6 100644 --- a/plotdevice/gfx/image.py +++ b/plotdevice/gfx/image.py @@ -128,6 +128,11 @@ def image(self): warnings.warn("The 'image' attribute is deprecated. Please use _nsImage instead.", DeprecationWarning, stacklevel=2) return self._nsImage + def applyFilter(self, gpuFilter): + filteredNSImage = gpuFilter.process_(self._nsImage) + if filteredNSImage: + self._nsImage = filteredNSImage + @property def _nsBitmap(self): for bitmap in self._nsImage.representations(): From 3236349ac6925ba58eb1dfc4207c0c64317f151a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Bo=CC=88hn?= Date: Wed, 9 Jul 2014 15:38:20 -0700 Subject: [PATCH 37/81] Bash scripts to symlink PlotDevice.app/Contents/Frameworks as PlotDevice.app/Contents/Resources/python/plotdevice/Frameworks --- etc/relpath.sh | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 etc/relpath.sh diff --git a/etc/relpath.sh b/etc/relpath.sh new file mode 100644 index 00000000..ad08dc62 --- /dev/null +++ b/etc/relpath.sh @@ -0,0 +1,7 @@ +#!/bin/sh + +# relpath.sh +# PlotDevice +# +# Created by FI$H 2000 on 7/9/14. +# From 259a973397a2319d50d60272545d032ac8fbf18e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Bo=CC=88hn?= Date: Wed, 9 Jul 2014 15:38:32 -0700 Subject: [PATCH 38/81] Bash scripts to symlink PlotDevice.app/Contents/Frameworks as PlotDevice.app/Contents/Resources/python/plotdevice/Frameworks --- PlotDevice.xcodeproj/project.pbxproj | 16 ++++++++++++++ etc/relpath.sh | 31 ++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/PlotDevice.xcodeproj/project.pbxproj b/PlotDevice.xcodeproj/project.pbxproj index 5f36614b..ce975cec 100644 --- a/PlotDevice.xcodeproj/project.pbxproj +++ b/PlotDevice.xcodeproj/project.pbxproj @@ -39,6 +39,7 @@ CF04731D196B71C200E3C358 /* GPUImage.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CF04731C196B71C200E3C358 /* GPUImage.framework */; }; CF047321196B744C00E3C358 /* GPUImage.framework in Copy Private Frameworks */ = {isa = PBXBuildFile; fileRef = CF04731C196B71C200E3C358 /* GPUImage.framework */; }; CF29B4BE196C51B70092593E /* Python.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CF29B4BC196C51410092593E /* Python.framework */; }; + CF61A9FE196DF5DC00BDFF1D /* old-python-include-link-paths.sh in Resources */ = {isa = PBXBuildFile; fileRef = CF61A9FD196DF5DC00BDFF1D /* old-python-include-link-paths.sh */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -167,6 +168,8 @@ 8D15AC370486D014006FF6A4 /* PlotDevice.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = PlotDevice.app; sourceTree = BUILT_PRODUCTS_DIR; }; CF04731C196B71C200E3C358 /* GPUImage.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GPUImage.framework; path = app/Frameworks/GPUImage.framework; sourceTree = SOURCE_ROOT; }; CF29B4BC196C51410092593E /* Python.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Python.framework; path = /usr/local/Cellar/python/2.7.8/Frameworks/Python.framework; sourceTree = ""; }; + CF61A9FD196DF5DC00BDFF1D /* old-python-include-link-paths.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = "old-python-include-link-paths.sh"; sourceTree = ""; }; + CF61A9FF196DF61600BDFF1D /* relpath.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = relpath.sh; sourceTree = ""; }; CFF92336196D31780095586A /* rtclass.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = rtclass.py; sourceTree = ""; }; CFF92337196D31780095586A /* tensor.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = tensor.py; sourceTree = ""; }; /* End PBXFileReference section */ @@ -259,6 +262,7 @@ 611CC4AE10BA8C1B00B55455 /* plotdevice */, 2A37F4AFFDCFA73011CA2CEA /* Other Sources */, 2A37F4B8FDCFA73011CA2CEA /* Resources */, + CF61A9FC196DF5DC00BDFF1D /* etc */, 2A7AF5C718D2AFAA00F8FFC2 /* examples */, 2A64AB46195F4E78001E4E69 /* deps */, 2A37F4C3FDCFA73011CA2CEA /* Frameworks */, @@ -392,6 +396,15 @@ path = util; sourceTree = ""; }; + CF61A9FC196DF5DC00BDFF1D /* etc */ = { + isa = PBXGroup; + children = ( + CF61A9FD196DF5DC00BDFF1D /* old-python-include-link-paths.sh */, + CF61A9FF196DF61600BDFF1D /* relpath.sh */, + ); + path = etc; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -461,6 +474,7 @@ 611CC68710BAA0A600B55455 /* AskString.xib in Resources */, 2A7AF5C818D2AFAA00F8FFC2 /* examples in Resources */, 6155D9F413E2B79E00675A92 /* CHANGES.md in Resources */, + CF61A9FE196DF5DC00BDFF1D /* old-python-include-link-paths.sh in Resources */, 6155D9F513E2B79E00675A92 /* README.md in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -572,6 +586,7 @@ COMBINE_HIDPI_IMAGES = YES; CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)"; COPY_PHASE_STRIP = NO; + DEPLOYMENT_POSTPROCESSING = NO; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)", @@ -607,6 +622,7 @@ COMBINE_HIDPI_IMAGES = YES; CONFIGURATION_BUILD_DIR = dist; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEPLOYMENT_POSTPROCESSING = NO; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)", diff --git a/etc/relpath.sh b/etc/relpath.sh index ad08dc62..a5eadc7d 100644 --- a/etc/relpath.sh +++ b/etc/relpath.sh @@ -5,3 +5,34 @@ # # Created by FI$H 2000 on 7/9/14. # +# Adapted from source from StackOverflow: +# http://stackoverflow.com/a/14914070/298171 +# +# + +relpath () { + [ $# -ge 1 ] && [ $# -le 2 ] || return 1 + current="${2:+"$1"}" + target="${2:-"$1"}" + [ "$target" != . ] || target=/ + target="/${target##/}" + [ "$current" != . ] || current=/ + current="${current:="/"}" + current="/${current##/}" + appendix="${target##/}" + relative='' + while appendix="${target#"$current"/}" + [ "$current" != '/' ] && [ "$appendix" = "$target" ]; do + if [ "$current" = "$appendix" ]; then + relative="${relative:-.}" + echo "${relative#/}" + return 0 + fi + current="${current%/*}" + relative="$relative${relative:+/}.." + done + relative="$relative${relative:+${appendix:+/}}${appendix#/}" + echo "$relative" +} + +#relpath "$@" \ No newline at end of file From b326567ba444d60ec6ca18b9715ec42a74565a4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Bo=CC=88hn?= Date: Wed, 9 Jul 2014 15:42:58 -0700 Subject: [PATCH 39/81] Minutiae --- etc/relpath.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/etc/relpath.sh b/etc/relpath.sh index a5eadc7d..fca90c99 100644 --- a/etc/relpath.sh +++ b/etc/relpath.sh @@ -5,7 +5,7 @@ # # Created by FI$H 2000 on 7/9/14. # -# Adapted from source from StackOverflow: +# See also: # http://stackoverflow.com/a/14914070/298171 # # From 852808df956fb81bdf8b9d4a12ed79ef5cd0def0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Bo=CC=88hn?= Date: Wed, 9 Jul 2014 18:31:53 -0700 Subject: [PATCH 40/81] Shell script build phase to perform the same post-build symlinking done by the py2app setup command --- PlotDevice.xcodeproj/project.pbxproj | 23 +++++++++++++++++++---- etc/relpath.sh | 2 -- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/PlotDevice.xcodeproj/project.pbxproj b/PlotDevice.xcodeproj/project.pbxproj index ce975cec..c170469b 100644 --- a/PlotDevice.xcodeproj/project.pbxproj +++ b/PlotDevice.xcodeproj/project.pbxproj @@ -39,7 +39,6 @@ CF04731D196B71C200E3C358 /* GPUImage.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CF04731C196B71C200E3C358 /* GPUImage.framework */; }; CF047321196B744C00E3C358 /* GPUImage.framework in Copy Private Frameworks */ = {isa = PBXBuildFile; fileRef = CF04731C196B71C200E3C358 /* GPUImage.framework */; }; CF29B4BE196C51B70092593E /* Python.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CF29B4BC196C51410092593E /* Python.framework */; }; - CF61A9FE196DF5DC00BDFF1D /* old-python-include-link-paths.sh in Resources */ = {isa = PBXBuildFile; fileRef = CF61A9FD196DF5DC00BDFF1D /* old-python-include-link-paths.sh */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -218,7 +217,7 @@ 8D15AC370486D014006FF6A4 /* PlotDevice.app */, ); name = Products; - sourceTree = ""; + sourceTree = SOURCE_ROOT; }; 2A15C44018A20971006BDFF0 /* ui */ = { isa = PBXGroup; @@ -420,6 +419,7 @@ 2ABDB76F1867D9560069EFC3 /* Copy 'plotdevice' Tool */, 8D15AC300486D014006FF6A4 /* Sources */, 8D15AC330486D014006FF6A4 /* Frameworks */, + CF093DD3196E06E200B00802 /* Symlink PlotDevice.app/Contents/Frameworks as PlotDevice.app/Contents/Resources/python/plotdevice/Frameworks */, ); buildRules = ( ); @@ -474,7 +474,6 @@ 611CC68710BAA0A600B55455 /* AskString.xib in Resources */, 2A7AF5C818D2AFAA00F8FFC2 /* examples in Resources */, 6155D9F413E2B79E00675A92 /* CHANGES.md in Resources */, - CF61A9FE196DF5DC00BDFF1D /* old-python-include-link-paths.sh in Resources */, 6155D9F513E2B79E00675A92 /* README.md in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -496,6 +495,20 @@ shellPath = /bin/sh; shellScript = "python=\"/usr/bin/python\"\nif [ -x /usr/local/bin/python ]; then\n python=\"/usr/local/bin/python\"\nfi\n\n# let the setup script handle updating\neval \"${python} setup.py build\"\n\n# copy the up-to-date module contents into the app bundle\nEXT_DIR=\"$TARGET_BUILD_DIR/$UNLOCALIZED_RESOURCES_FOLDER_PATH/python/\"\nmkdir -p $EXT_DIR\nditto build/lib/plotdevice \"$EXT_DIR/plotdevice\"\n\n# make sure everything has a .pyc (so code-signing doesn't break on first run)\neval \"${python} -m compileall ${EXT_DIR}/plotdevice\""; }; + CF093DD3196E06E200B00802 /* Symlink PlotDevice.app/Contents/Frameworks as PlotDevice.app/Contents/Resources/python/plotdevice/Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 12; + files = ( + ); + inputPaths = ( + ); + name = "Symlink PlotDevice.app/Contents/Frameworks as PlotDevice.app/Contents/Resources/python/plotdevice/Frameworks"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\n#app=\"${TARGET_BUILD_DIR}/${WRAPPER_NAME}\"\nframeworks=\"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}\"\nresources=\"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}\"\nplotdevice=\"${resources}/python/plotdevice\"\n\n/usr/local/bin/terminal-notifier -message \"Running RELEASE Post-Build Actions\"\n\nset +x\nsource ${SOURCE_ROOT}/etc/relpath.sh\n\npushd $plotdevice\n[ ! -L \"${plotdevice}/Frameworks\" ] && /bin/ln -s `relpath $plotdevice $frameworks` Frameworks\n\n"; + }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -584,8 +597,9 @@ buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; COMBINE_HIDPI_IMAGES = YES; - CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)"; + CONFIGURATION_BUILD_DIR = dist; COPY_PHASE_STRIP = NO; + DEPLOYMENT_LOCATION = NO; DEPLOYMENT_POSTPROCESSING = NO; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -622,6 +636,7 @@ COMBINE_HIDPI_IMAGES = YES; CONFIGURATION_BUILD_DIR = dist; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEPLOYMENT_LOCATION = NO; DEPLOYMENT_POSTPROCESSING = NO; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", diff --git a/etc/relpath.sh b/etc/relpath.sh index fca90c99..862fadf7 100644 --- a/etc/relpath.sh +++ b/etc/relpath.sh @@ -34,5 +34,3 @@ relpath () { relative="$relative${relative:+${appendix:+/}}${appendix#/}" echo "$relative" } - -#relpath "$@" \ No newline at end of file From f6a0ea1560700d21d395426d238fdcd3fb8d856e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Bo=CC=88hn?= Date: Mon, 14 Jul 2014 09:45:29 -0700 Subject: [PATCH 41/81] Atkinson pixel filter --- PlotDevice.xcodeproj/project.pbxproj | 4 +- app/deps/tensorlib/GrayscaleFilter.h | 18 ++++ app/deps/tensorlib/GrayscaleFilter.m | 21 ++++ app/deps/tensorlib/pixel/AtkinsonFilter.h | 29 ++++++ app/deps/tensorlib/pixel/AtkinsonFilter.m | 116 ++++++++++++++++++++++ app/deps/tensorlib/setup.py | 3 +- 6 files changed, 189 insertions(+), 2 deletions(-) create mode 100644 app/deps/tensorlib/GrayscaleFilter.h create mode 100644 app/deps/tensorlib/GrayscaleFilter.m create mode 100644 app/deps/tensorlib/pixel/AtkinsonFilter.h create mode 100644 app/deps/tensorlib/pixel/AtkinsonFilter.m diff --git a/PlotDevice.xcodeproj/project.pbxproj b/PlotDevice.xcodeproj/project.pbxproj index c170469b..c184a3a3 100644 --- a/PlotDevice.xcodeproj/project.pbxproj +++ b/PlotDevice.xcodeproj/project.pbxproj @@ -494,6 +494,7 @@ runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "python=\"/usr/bin/python\"\nif [ -x /usr/local/bin/python ]; then\n python=\"/usr/local/bin/python\"\nfi\n\n# let the setup script handle updating\neval \"${python} setup.py build\"\n\n# copy the up-to-date module contents into the app bundle\nEXT_DIR=\"$TARGET_BUILD_DIR/$UNLOCALIZED_RESOURCES_FOLDER_PATH/python/\"\nmkdir -p $EXT_DIR\nditto build/lib/plotdevice \"$EXT_DIR/plotdevice\"\n\n# make sure everything has a .pyc (so code-signing doesn't break on first run)\neval \"${python} -m compileall ${EXT_DIR}/plotdevice\""; + showEnvVarsInLog = 0; }; CF093DD3196E06E200B00802 /* Symlink PlotDevice.app/Contents/Frameworks as PlotDevice.app/Contents/Resources/python/plotdevice/Frameworks */ = { isa = PBXShellScriptBuildPhase; @@ -507,7 +508,8 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "\n#app=\"${TARGET_BUILD_DIR}/${WRAPPER_NAME}\"\nframeworks=\"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}\"\nresources=\"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}\"\nplotdevice=\"${resources}/python/plotdevice\"\n\n/usr/local/bin/terminal-notifier -message \"Running RELEASE Post-Build Actions\"\n\nset +x\nsource ${SOURCE_ROOT}/etc/relpath.sh\n\npushd $plotdevice\n[ ! -L \"${plotdevice}/Frameworks\" ] && /bin/ln -s `relpath $plotdevice $frameworks` Frameworks\n\n"; + shellScript = "\n#app=\"${TARGET_BUILD_DIR}/${WRAPPER_NAME}\"\nframeworks=\"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}\"\nresources=\"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}\"\nplotdevice=\"${resources}/python/plotdevice\"\n\n#/usr/local/bin/terminal-notifier -message \"Running RELEASE Post-Build Actions\"\n\nset +x\nsource ${SOURCE_ROOT}/etc/relpath.sh\n\npushd $plotdevice\n[ ! -L \"${plotdevice}/Frameworks\" ] && /bin/ln -s `relpath $plotdevice $frameworks` Frameworks\n\n"; + showEnvVarsInLog = 0; }; /* End PBXShellScriptBuildPhase section */ diff --git a/app/deps/tensorlib/GrayscaleFilter.h b/app/deps/tensorlib/GrayscaleFilter.h new file mode 100644 index 00000000..d054156a --- /dev/null +++ b/app/deps/tensorlib/GrayscaleFilter.h @@ -0,0 +1,18 @@ +// +// GrayscaleFilter.h +// PlotDevice +// +// Created by fish2k on 12/7/13. +// +// + +#import +#import +#import + +#import "FilterBase.h" + +@interface GrayscaleFilter : FilterBase { +} + +@end \ No newline at end of file diff --git a/app/deps/tensorlib/GrayscaleFilter.m b/app/deps/tensorlib/GrayscaleFilter.m new file mode 100644 index 00000000..c4491cdf --- /dev/null +++ b/app/deps/tensorlib/GrayscaleFilter.m @@ -0,0 +1,21 @@ +// +// GrayscaleFilter.m +// PlotDevice +// +// Created by fish2k on 12/13/13. +// +// + +#import "GrayscaleFilter.h" + +@implementation GrayscaleFilter + +- (id)init { + self = [super init]; + if (self) { + filter = (GPUImageFilter *)[[GPUImageGrayscaleFilter alloc] init]; + } + return self; +} + +@end \ No newline at end of file diff --git a/app/deps/tensorlib/pixel/AtkinsonFilter.h b/app/deps/tensorlib/pixel/AtkinsonFilter.h new file mode 100644 index 00000000..b680ca7c --- /dev/null +++ b/app/deps/tensorlib/pixel/AtkinsonFilter.h @@ -0,0 +1,29 @@ +// +// AtkinsonFilter.h +// PlotDevice +// +// Created by fish2k on 12/7/13. +// +// + +#import +#import +#import + +#import "../FilterBase.h" + +/// inline macro that adds the error so that it doesn't overflow an unsigned char +#ifndef adderror +#define adderror( b, e ) ( ((b) < -(e)) ? 0x00 : ( ((0xFF - (b)) < (e)) ? 0xFF : (b + e) ) ) +#endif + +/// threshold matrix (in leu of "if something > somethingelse" and suchlike) +static unsigned char threshold[256]; + +/// forward declaration of the bytearray-level atkinson function +unsigned char *atkinson(unsigned char *pixels, int w, int h, int len); + +/// FilterBase subclass boilerplate interface +@interface AtkinsonFilter : FilterBase {} + +@end \ No newline at end of file diff --git a/app/deps/tensorlib/pixel/AtkinsonFilter.m b/app/deps/tensorlib/pixel/AtkinsonFilter.m new file mode 100644 index 00000000..52fac983 --- /dev/null +++ b/app/deps/tensorlib/pixel/AtkinsonFilter.m @@ -0,0 +1,116 @@ +// +// AtkinsonFilter.m +// PlotDevice +// +// Created by fish2k on 12/13/13. +// +// + +#include +#include + +#import "AtkinsonFilter.h" + +/// bytearray-level atkinson pixel processing function +unsigned char *atkinson(unsigned char *inputPixels, int w, int h, int len) { + int x, y, off, err; + unsigned char *outputPixels = malloc(sizeof(unsigned char) * len); + unsigned char old, new; + + if (w * h != len) { + /// if the dimensions don't fully check out, + /// I fucking walk + return NULL; + } + + memcpy(outputPixels, inputPixels, sizeof(sizeof(unsigned char) * len)); + + for (y = 0; y < h; y++) { + for (x = 0; x < w; x++) { + /// pixel (x, y) offset within the 1D char buffer + off = (y * w) + x; + + /// calculate threshold and error value + old = outputPixels[off]; + new = threshold[ outputPixels[off] ]; + err = (old - new) >> 3; + + /// update the image + outputPixels[off] = new; + + // x+1, y + if (x+1 < w) { + outputPixels[off + 1] = adderror(outputPixels[off + 1], err); + } + + // x+2, y + if (x+2 < w) { + outputPixels[off + 2] = adderror(outputPixels[off + 2], err); + } + + // x-1, y+1 + if (x > 0 && y+1 < h) { + outputPixels[off + w - 1] = adderror(outputPixels[off + w - 1], err); + } + + // x, y+1 + if (y+1 < h) { + outputPixels[off + w] = adderror(outputPixels[off + w], err); + } + + // x+1, y+1 + if (x+1 < w && y+1 < h) { + outputPixels[off + w + 1] = adderror(outputPixels[off + w + 1], err); + } + + // x, y+2 + if (y+2 < h) { + outputPixels[off + 2 * w] = adderror(outputPixels[off + 2 * w], err); + } + } + } + + return outputPixels; +} + +/// AtkinsonFilter -- FilterBase subclass implementation +@implementation AtkinsonFilter + +- (id)init { + int i; + self = [super init]; + + if (self) { + for (i = 0; i < 128; i++) { + threshold[i] = 0x00; + } + for (i = 128; i < 256; i++) { + threshold[i] = 0xFF; + } + filter = (GPUImageFilter *)[[GPUImageGrayscaleFilter alloc] init]; + } + return self; +} + +- (NSImage *)process:(NSImage *)input { + NSBitmapImageRep *inputRep = [NSBitmapImageRep + imageRepWithData:[ + [filter imageByFilteringImage:input] + TIFFRepresentation]]; + + int w = (int)[inputRep pixelsWide]; + int h = (int)[inputRep pixelsHigh]; + NSImage *output = [[NSImage alloc] initWithSize:NSMakeSize(w, h)]; + unsigned char *inputData = [inputRep bitmapData]; + unsigned char *outputData = atkinson(inputData, w, h, w*h); + + NSData *outputWrappedData = [NSData dataWithBytes:outputData length:(w*h)]; + NSBitmapImageRep *outputRep = [NSBitmapImageRep + imageRepWithData:outputWrappedData]; + + [output addRepresentation:outputRep]; + return output; +} + +@end + diff --git a/app/deps/tensorlib/setup.py b/app/deps/tensorlib/setup.py index e4647194..09a73fa7 100644 --- a/app/deps/tensorlib/setup.py +++ b/app/deps/tensorlib/setup.py @@ -17,7 +17,8 @@ 'PolkaDotFilter.m', 'SepiaFilter.m', 'SoftEleganceFilter.m', - 'VignetteFilter.m'], + 'VignetteFilter.m', + 'pixel/AtkinsonFilter.m'], extra_compile_args=[ '-Wno-error=unused-command-line-argument-hard-error-in-future', '-Qunused-arguments', From 2fb9818543a832916d76773a81b3bcb1462257e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Bo=CC=88hn?= Date: Mon, 14 Jul 2014 09:58:51 -0700 Subject: [PATCH 42/81] Compiling GrayscaleFilter.m --- app/deps/tensorlib/setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/app/deps/tensorlib/setup.py b/app/deps/tensorlib/setup.py index 09a73fa7..486eb8eb 100644 --- a/app/deps/tensorlib/setup.py +++ b/app/deps/tensorlib/setup.py @@ -11,6 +11,7 @@ sources=[ 'module.m', 'FilterBase.m', + 'GrayscaleFilter.m', 'ColorInvertFilter.m', 'HalftoneFilter.m', 'MissEtikateFilter.m', From a927246148e1a8289d08bbe31a03246d441ef79b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Bo=CC=88hn?= Date: Mon, 14 Jul 2014 11:38:35 -0700 Subject: [PATCH 43/81] Check for errors in atkinson() return value --- app/deps/tensorlib/pixel/AtkinsonFilter.m | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/app/deps/tensorlib/pixel/AtkinsonFilter.m b/app/deps/tensorlib/pixel/AtkinsonFilter.m index 52fac983..f2ef6520 100644 --- a/app/deps/tensorlib/pixel/AtkinsonFilter.m +++ b/app/deps/tensorlib/pixel/AtkinsonFilter.m @@ -93,20 +93,29 @@ - (id)init { } - (NSImage *)process:(NSImage *)input { + NSImage *inputGrayscale = [filter imageByFilteringImage:input]; NSBitmapImageRep *inputRep = [NSBitmapImageRep imageRepWithData:[ - [filter imageByFilteringImage:input] - TIFFRepresentation]]; + inputGrayscale TIFFRepresentation]]; int w = (int)[inputRep pixelsWide]; int h = (int)[inputRep pixelsHigh]; + long length = (long)(w * h); + NSImage *output = [[NSImage alloc] initWithSize:NSMakeSize(w, h)]; unsigned char *inputData = [inputRep bitmapData]; - unsigned char *outputData = atkinson(inputData, w, h, w*h); + unsigned char *outputData = atkinson(inputData, w, h, length); + + if (outputData == NULL) { + NSLog(@"Bad dimensions passed to atkinson():"); + NSLog(@" WIDTH = %i, HEIGHT = %i, LENGTH = %li", + w, h, length); + return inputGrayscale; + } - NSData *outputWrappedData = [NSData dataWithBytes:outputData length:(w*h)]; + NSData *outputWrappedData = [NSData dataWithBytes:outputData length:length]; NSBitmapImageRep *outputRep = [NSBitmapImageRep - imageRepWithData:outputWrappedData]; + imageRepWithData:outputWrappedData]; [output addRepresentation:outputRep]; return output; From cbea974e12873292dad942525e7c02d84bab8593 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Bo=CC=88hn?= Date: Mon, 14 Jul 2014 13:30:40 -0700 Subject: [PATCH 44/81] app/deps/tensorlib/setup.py finds all filter classes for compilation --- .../{ => filters}/ColorInvertFilter.h | 0 .../{ => filters}/ColorInvertFilter.m | 0 app/deps/tensorlib/{ => filters}/FilterBase.h | 0 app/deps/tensorlib/{ => filters}/FilterBase.m | 0 .../tensorlib/{ => filters}/GrayscaleFilter.h | 0 .../tensorlib/{ => filters}/GrayscaleFilter.m | 0 .../tensorlib/{ => filters}/HalftoneFilter.h | 0 .../tensorlib/{ => filters}/HalftoneFilter.m | 0 .../{ => filters}/MissEtikateFilter.h | 0 .../{ => filters}/MissEtikateFilter.m | 0 .../tensorlib/{ => filters}/PolkaDotFilter.h | 0 .../tensorlib/{ => filters}/PolkaDotFilter.m | 0 .../tensorlib/{ => filters}/SepiaFilter.h | 0 .../tensorlib/{ => filters}/SepiaFilter.m | 0 .../{ => filters}/SoftEleganceFilter.h | 0 .../{ => filters}/SoftEleganceFilter.m | 0 .../tensorlib/{ => filters}/VignetteFilter.h | 0 .../tensorlib/{ => filters}/VignetteFilter.m | 0 .../{ => filters}/pixel/AtkinsonFilter.h | 0 .../{ => filters}/pixel/AtkinsonFilter.m | 0 app/deps/tensorlib/module.m | 16 +++++-- app/deps/tensorlib/setup.py | 44 +++++++++++++------ 22 files changed, 42 insertions(+), 18 deletions(-) rename app/deps/tensorlib/{ => filters}/ColorInvertFilter.h (100%) rename app/deps/tensorlib/{ => filters}/ColorInvertFilter.m (100%) rename app/deps/tensorlib/{ => filters}/FilterBase.h (100%) rename app/deps/tensorlib/{ => filters}/FilterBase.m (100%) rename app/deps/tensorlib/{ => filters}/GrayscaleFilter.h (100%) rename app/deps/tensorlib/{ => filters}/GrayscaleFilter.m (100%) rename app/deps/tensorlib/{ => filters}/HalftoneFilter.h (100%) rename app/deps/tensorlib/{ => filters}/HalftoneFilter.m (100%) rename app/deps/tensorlib/{ => filters}/MissEtikateFilter.h (100%) rename app/deps/tensorlib/{ => filters}/MissEtikateFilter.m (100%) rename app/deps/tensorlib/{ => filters}/PolkaDotFilter.h (100%) rename app/deps/tensorlib/{ => filters}/PolkaDotFilter.m (100%) rename app/deps/tensorlib/{ => filters}/SepiaFilter.h (100%) rename app/deps/tensorlib/{ => filters}/SepiaFilter.m (100%) rename app/deps/tensorlib/{ => filters}/SoftEleganceFilter.h (100%) rename app/deps/tensorlib/{ => filters}/SoftEleganceFilter.m (100%) rename app/deps/tensorlib/{ => filters}/VignetteFilter.h (100%) rename app/deps/tensorlib/{ => filters}/VignetteFilter.m (100%) rename app/deps/tensorlib/{ => filters}/pixel/AtkinsonFilter.h (100%) rename app/deps/tensorlib/{ => filters}/pixel/AtkinsonFilter.m (100%) diff --git a/app/deps/tensorlib/ColorInvertFilter.h b/app/deps/tensorlib/filters/ColorInvertFilter.h similarity index 100% rename from app/deps/tensorlib/ColorInvertFilter.h rename to app/deps/tensorlib/filters/ColorInvertFilter.h diff --git a/app/deps/tensorlib/ColorInvertFilter.m b/app/deps/tensorlib/filters/ColorInvertFilter.m similarity index 100% rename from app/deps/tensorlib/ColorInvertFilter.m rename to app/deps/tensorlib/filters/ColorInvertFilter.m diff --git a/app/deps/tensorlib/FilterBase.h b/app/deps/tensorlib/filters/FilterBase.h similarity index 100% rename from app/deps/tensorlib/FilterBase.h rename to app/deps/tensorlib/filters/FilterBase.h diff --git a/app/deps/tensorlib/FilterBase.m b/app/deps/tensorlib/filters/FilterBase.m similarity index 100% rename from app/deps/tensorlib/FilterBase.m rename to app/deps/tensorlib/filters/FilterBase.m diff --git a/app/deps/tensorlib/GrayscaleFilter.h b/app/deps/tensorlib/filters/GrayscaleFilter.h similarity index 100% rename from app/deps/tensorlib/GrayscaleFilter.h rename to app/deps/tensorlib/filters/GrayscaleFilter.h diff --git a/app/deps/tensorlib/GrayscaleFilter.m b/app/deps/tensorlib/filters/GrayscaleFilter.m similarity index 100% rename from app/deps/tensorlib/GrayscaleFilter.m rename to app/deps/tensorlib/filters/GrayscaleFilter.m diff --git a/app/deps/tensorlib/HalftoneFilter.h b/app/deps/tensorlib/filters/HalftoneFilter.h similarity index 100% rename from app/deps/tensorlib/HalftoneFilter.h rename to app/deps/tensorlib/filters/HalftoneFilter.h diff --git a/app/deps/tensorlib/HalftoneFilter.m b/app/deps/tensorlib/filters/HalftoneFilter.m similarity index 100% rename from app/deps/tensorlib/HalftoneFilter.m rename to app/deps/tensorlib/filters/HalftoneFilter.m diff --git a/app/deps/tensorlib/MissEtikateFilter.h b/app/deps/tensorlib/filters/MissEtikateFilter.h similarity index 100% rename from app/deps/tensorlib/MissEtikateFilter.h rename to app/deps/tensorlib/filters/MissEtikateFilter.h diff --git a/app/deps/tensorlib/MissEtikateFilter.m b/app/deps/tensorlib/filters/MissEtikateFilter.m similarity index 100% rename from app/deps/tensorlib/MissEtikateFilter.m rename to app/deps/tensorlib/filters/MissEtikateFilter.m diff --git a/app/deps/tensorlib/PolkaDotFilter.h b/app/deps/tensorlib/filters/PolkaDotFilter.h similarity index 100% rename from app/deps/tensorlib/PolkaDotFilter.h rename to app/deps/tensorlib/filters/PolkaDotFilter.h diff --git a/app/deps/tensorlib/PolkaDotFilter.m b/app/deps/tensorlib/filters/PolkaDotFilter.m similarity index 100% rename from app/deps/tensorlib/PolkaDotFilter.m rename to app/deps/tensorlib/filters/PolkaDotFilter.m diff --git a/app/deps/tensorlib/SepiaFilter.h b/app/deps/tensorlib/filters/SepiaFilter.h similarity index 100% rename from app/deps/tensorlib/SepiaFilter.h rename to app/deps/tensorlib/filters/SepiaFilter.h diff --git a/app/deps/tensorlib/SepiaFilter.m b/app/deps/tensorlib/filters/SepiaFilter.m similarity index 100% rename from app/deps/tensorlib/SepiaFilter.m rename to app/deps/tensorlib/filters/SepiaFilter.m diff --git a/app/deps/tensorlib/SoftEleganceFilter.h b/app/deps/tensorlib/filters/SoftEleganceFilter.h similarity index 100% rename from app/deps/tensorlib/SoftEleganceFilter.h rename to app/deps/tensorlib/filters/SoftEleganceFilter.h diff --git a/app/deps/tensorlib/SoftEleganceFilter.m b/app/deps/tensorlib/filters/SoftEleganceFilter.m similarity index 100% rename from app/deps/tensorlib/SoftEleganceFilter.m rename to app/deps/tensorlib/filters/SoftEleganceFilter.m diff --git a/app/deps/tensorlib/VignetteFilter.h b/app/deps/tensorlib/filters/VignetteFilter.h similarity index 100% rename from app/deps/tensorlib/VignetteFilter.h rename to app/deps/tensorlib/filters/VignetteFilter.h diff --git a/app/deps/tensorlib/VignetteFilter.m b/app/deps/tensorlib/filters/VignetteFilter.m similarity index 100% rename from app/deps/tensorlib/VignetteFilter.m rename to app/deps/tensorlib/filters/VignetteFilter.m diff --git a/app/deps/tensorlib/pixel/AtkinsonFilter.h b/app/deps/tensorlib/filters/pixel/AtkinsonFilter.h similarity index 100% rename from app/deps/tensorlib/pixel/AtkinsonFilter.h rename to app/deps/tensorlib/filters/pixel/AtkinsonFilter.h diff --git a/app/deps/tensorlib/pixel/AtkinsonFilter.m b/app/deps/tensorlib/filters/pixel/AtkinsonFilter.m similarity index 100% rename from app/deps/tensorlib/pixel/AtkinsonFilter.m rename to app/deps/tensorlib/filters/pixel/AtkinsonFilter.m diff --git a/app/deps/tensorlib/module.m b/app/deps/tensorlib/module.m index fef14763..f47cc7a3 100644 --- a/app/deps/tensorlib/module.m +++ b/app/deps/tensorlib/module.m @@ -1,3 +1,4 @@ +#import #import /* @@ -6,11 +7,18 @@ * to be found and loaded from python via `objc.lookUpClass()` */ -PyMethodDef methods[] = { - { NULL, NULL }, +static PyObject *TensorlibError; +static PyMethodDef methods[] = { + { NULL, NULL }, }; -PyMODINIT_FUNC inittensorlib() { - (void)Py_InitModule("tensorlib", methods); +PyMODINIT_FUNC +inittensorlib(void) { + PyObject *module; + + module = Py_InitModule("tensorlib", methods); + TensorlibError = PyErr_NewException("tensorlib.error", NULL, NULL); + Py_INCREF(TensorlibError); + PyModule_AddObject(module, "error", TensorlibError); } diff --git a/app/deps/tensorlib/setup.py b/app/deps/tensorlib/setup.py index 486eb8eb..f2cfecf9 100644 --- a/app/deps/tensorlib/setup.py +++ b/app/deps/tensorlib/setup.py @@ -1,5 +1,5 @@ -from os import getcwd -from os.path import dirname, join +from os import getcwd, walk +from os.path import splitext, dirname, join from setuptools import setup from setuptools.extension import Extension @@ -7,19 +7,35 @@ gpuimage_libs = join(frameworks, 'GPUImage.framework', 'Versions', 'A') gpuimage_headers = join(gpuimage_libs, 'Headers') +def find_filters(base_path="filters"): + #filters = dict(filterbase=join(base_path, "FilterBase")) + filters = dict() + for root_path, dirs, files in walk(base_path): + for file_name in files: + if file_name.lower().endswith('filter.m'): + filter_name, _ = splitext(file_name) + filters[filter_name] = join(root_path, filter_name) + return filters + +def get_sources(filter_dict, suffix="m"): + return ["%s.%s" % (filter_pth, suffix) for filter_pth in filter_dict.values()] + +def write_filter_header(filter_dict): + headers = get_sources(filter_dict, suffix="h") + with open("filters.h", 'wb') as header_fh: + header_fh.write('''#import "filters/FilterBase.h"\n''') + header_fh.writelines(['''#import "%s"\n''' % header for header in headers]) + +filters = find_filters() +sources = ['module.m', 'filters/FilterBase.m'] +sources.extend(get_sources(filters)) + +from pprint import pprint +pprint(filters) +pprint(sources) + tensorlib = Extension('tensorlib', - sources=[ - 'module.m', - 'FilterBase.m', - 'GrayscaleFilter.m', - 'ColorInvertFilter.m', - 'HalftoneFilter.m', - 'MissEtikateFilter.m', - 'PolkaDotFilter.m', - 'SepiaFilter.m', - 'SoftEleganceFilter.m', - 'VignetteFilter.m', - 'pixel/AtkinsonFilter.m'], + sources=sources, extra_compile_args=[ '-Wno-error=unused-command-line-argument-hard-error-in-future', '-Qunused-arguments', From b52dd1954b82fb8c15f1602f356a3da60325441d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Bo=CC=88hn?= Date: Mon, 14 Jul 2014 13:33:10 -0700 Subject: [PATCH 45/81] Trimmed tensorlib's linked frameworks --- app/deps/tensorlib/setup.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/app/deps/tensorlib/setup.py b/app/deps/tensorlib/setup.py index f2cfecf9..85988fd1 100644 --- a/app/deps/tensorlib/setup.py +++ b/app/deps/tensorlib/setup.py @@ -46,9 +46,6 @@ def write_filter_header(filter_dict): '-F%s' % frameworks, '-framework', 'AppKit', '-framework', 'Foundation', - '-framework', 'Quartz', - '-framework', 'Security', - '-framework', 'CoreMedia', '-framework', 'GPUImage']) setup(name="tensorlib", From 665fcc18e4919fb884a3eb96ed1f776f4938bafb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Bo=CC=88hn?= Date: Mon, 14 Jul 2014 15:36:27 -0700 Subject: [PATCH 46/81] Added STDERR/STDOUT methods to FilterBase --- app/deps/tensorlib/filters/FilterBase.h | 2 ++ app/deps/tensorlib/filters/FilterBase.m | 27 ++++++++++++++++++- .../tensorlib/filters/pixel/AtkinsonFilter.m | 15 +++++++---- app/deps/tensorlib/setup.py | 11 +++++--- 4 files changed, 45 insertions(+), 10 deletions(-) diff --git a/app/deps/tensorlib/filters/FilterBase.h b/app/deps/tensorlib/filters/FilterBase.h index 7db56aff..98d628b0 100644 --- a/app/deps/tensorlib/filters/FilterBase.h +++ b/app/deps/tensorlib/filters/FilterBase.h @@ -19,5 +19,7 @@ - (id)init; - (NSImage *)process:(NSImage *)input; +- (void)STDOUT:(NSString *)string, ...; +- (void)STDERR:(NSString *)string, ...; @end \ No newline at end of file diff --git a/app/deps/tensorlib/filters/FilterBase.m b/app/deps/tensorlib/filters/FilterBase.m index 96c01467..66742b48 100644 --- a/app/deps/tensorlib/filters/FilterBase.m +++ b/app/deps/tensorlib/filters/FilterBase.m @@ -9,7 +9,6 @@ #import "FilterBase.h" @implementation FilterBase - @synthesize filter; - (id)init { @@ -24,4 +23,30 @@ - (NSImage *)process:(NSImage *)input { return [filter imageByFilteringImage:input]; } +- (void)STDOUT:(NSString *)string, ... { + NSString *out = [NSString stringWithFormat:@"[%@] %@", [self className], string]; + va_list args; + + va_start(args, string); + NSLogv(out, args); + NSString *stdOutString = [[NSString alloc] initWithFormat:out arguments:args]; + va_end(args); + + fprintf(stdout, "%s\n", [stdOutString UTF8String]); + [stdOutString release]; +} + +- (void)STDERR:(NSString *)string, ... { + NSString *err = [NSString stringWithFormat:@"[%@] ERROR: %@", [self className], string]; + va_list args; + + va_start(args, string); + NSLogv(err, args); + NSString *stdErrString = [[NSString alloc] initWithFormat:err arguments:args]; + va_end(args); + + fprintf(stderr, "%s\n", [stdErrString UTF8String]); + [stdErrString release]; +} + @end \ No newline at end of file diff --git a/app/deps/tensorlib/filters/pixel/AtkinsonFilter.m b/app/deps/tensorlib/filters/pixel/AtkinsonFilter.m index f2ef6520..ef17c13f 100644 --- a/app/deps/tensorlib/filters/pixel/AtkinsonFilter.m +++ b/app/deps/tensorlib/filters/pixel/AtkinsonFilter.m @@ -87,12 +87,13 @@ - (id)init { for (i = 128; i < 256; i++) { threshold[i] = 0xFF; } - filter = (GPUImageFilter *)[[GPUImageGrayscaleFilter alloc] init]; + filter = (GPUImageFilter *)[[GPUImageMonochromeFilter alloc] init]; } return self; } - (NSImage *)process:(NSImage *)input { + [self STDOUT:@"Preprocessing atkinson filter image"]; NSImage *inputGrayscale = [filter imageByFilteringImage:input]; NSBitmapImageRep *inputRep = [NSBitmapImageRep imageRepWithData:[ @@ -102,14 +103,16 @@ - (NSImage *)process:(NSImage *)input { int h = (int)[inputRep pixelsHigh]; long length = (long)(w * h); - NSImage *output = [[NSImage alloc] initWithSize:NSMakeSize(w, h)]; + [self STDOUT:@"About to call atkinson():"]; + [self STDOUT:@" WIDTH = %i, HEIGHT = %i, LENGTH = %li", + w, h, length]; unsigned char *inputData = [inputRep bitmapData]; unsigned char *outputData = atkinson(inputData, w, h, length); if (outputData == NULL) { - NSLog(@"Bad dimensions passed to atkinson():"); - NSLog(@" WIDTH = %i, HEIGHT = %i, LENGTH = %li", - w, h, length); + [self STDERR:@"Bad dimensions passed to atkinson():"]; + [self STDERR:@" WIDTH = %i, HEIGHT = %i, LENGTH = %li", + w, h, length]; return inputGrayscale; } @@ -117,6 +120,8 @@ - (NSImage *)process:(NSImage *)input { NSBitmapImageRep *outputRep = [NSBitmapImageRep imageRepWithData:outputWrappedData]; + [self STDOUT:@"About to return atkinson-ized image"]; + NSImage *output = [[NSImage alloc] initWithSize:NSMakeSize(w, h)]; [output addRepresentation:outputRep]; return output; } diff --git a/app/deps/tensorlib/setup.py b/app/deps/tensorlib/setup.py index 85988fd1..c25507b1 100644 --- a/app/deps/tensorlib/setup.py +++ b/app/deps/tensorlib/setup.py @@ -1,3 +1,6 @@ +from __future__ import print_function + +from pprint import pprint from os import getcwd, walk from os.path import splitext, dirname, join from setuptools import setup @@ -8,7 +11,6 @@ gpuimage_headers = join(gpuimage_libs, 'Headers') def find_filters(base_path="filters"): - #filters = dict(filterbase=join(base_path, "FilterBase")) filters = dict() for root_path, dirs, files in walk(base_path): for file_name in files: @@ -30,14 +32,15 @@ def write_filter_header(filter_dict): sources = ['module.m', 'filters/FilterBase.m'] sources.extend(get_sources(filters)) -from pprint import pprint -pprint(filters) -pprint(sources) +#pprint(sources) +print('Building tensorlib with %d filters:' % len(filters)) +pprint(sorted(filters.keys())) tensorlib = Extension('tensorlib', sources=sources, extra_compile_args=[ '-Wno-error=unused-command-line-argument-hard-error-in-future', + '-Wno-unused-function', '-Qunused-arguments', '-F%s' % frameworks], extra_link_args=[ From be170a9fe899dcbe7edf8216d469fbf3729ecb63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Bo=CC=88hn?= Date: Mon, 14 Jul 2014 15:37:51 -0700 Subject: [PATCH 47/81] Cleanup --- app/deps/tensorlib/filters/FilterBase.h | 1 - app/deps/tensorlib/filters/FilterBase.m | 6 ++++-- app/deps/tensorlib/setup.py | 1 - 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/deps/tensorlib/filters/FilterBase.h b/app/deps/tensorlib/filters/FilterBase.h index 98d628b0..1fc1f174 100644 --- a/app/deps/tensorlib/filters/FilterBase.h +++ b/app/deps/tensorlib/filters/FilterBase.h @@ -11,7 +11,6 @@ #import @interface FilterBase : NSObject { - /// GENERIC FILTER PLACEHOLDER GPUImageFilter *filter; } diff --git a/app/deps/tensorlib/filters/FilterBase.m b/app/deps/tensorlib/filters/FilterBase.m index 66742b48..c3a059be 100644 --- a/app/deps/tensorlib/filters/FilterBase.m +++ b/app/deps/tensorlib/filters/FilterBase.m @@ -24,7 +24,8 @@ - (NSImage *)process:(NSImage *)input { } - (void)STDOUT:(NSString *)string, ... { - NSString *out = [NSString stringWithFormat:@"[%@] %@", [self className], string]; + NSString *out = [NSString stringWithFormat:@"[%@] %@", + [self className], string]; va_list args; va_start(args, string); @@ -37,7 +38,8 @@ - (void)STDOUT:(NSString *)string, ... { } - (void)STDERR:(NSString *)string, ... { - NSString *err = [NSString stringWithFormat:@"[%@] ERROR: %@", [self className], string]; + NSString *err = [NSString stringWithFormat:@"[%@] ERROR: %@", + [self className], string]; va_list args; va_start(args, string); diff --git a/app/deps/tensorlib/setup.py b/app/deps/tensorlib/setup.py index c25507b1..a8bdf408 100644 --- a/app/deps/tensorlib/setup.py +++ b/app/deps/tensorlib/setup.py @@ -32,7 +32,6 @@ def write_filter_header(filter_dict): sources = ['module.m', 'filters/FilterBase.m'] sources.extend(get_sources(filters)) -#pprint(sources) print('Building tensorlib with %d filters:' % len(filters)) pprint(sorted(filters.keys())) From 9e883aea6c7beb37ab3342dece45dc10bd393263 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Bo=CC=88hn?= Date: Mon, 14 Jul 2014 15:41:05 -0700 Subject: [PATCH 48/81] More cleanup --- app/deps/tensorlib/filters/pixel/AtkinsonFilter.m | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/app/deps/tensorlib/filters/pixel/AtkinsonFilter.m b/app/deps/tensorlib/filters/pixel/AtkinsonFilter.m index ef17c13f..3f7a17fa 100644 --- a/app/deps/tensorlib/filters/pixel/AtkinsonFilter.m +++ b/app/deps/tensorlib/filters/pixel/AtkinsonFilter.m @@ -30,7 +30,7 @@ /// pixel (x, y) offset within the 1D char buffer off = (y * w) + x; - /// calculate threshold and error value + /// threshold and error value old = outputPixels[off]; new = threshold[ outputPixels[off] ]; err = (old - new) >> 3; @@ -38,32 +38,22 @@ /// update the image outputPixels[off] = new; - // x+1, y + /// add error values if (x+1 < w) { outputPixels[off + 1] = adderror(outputPixels[off + 1], err); } - - // x+2, y if (x+2 < w) { outputPixels[off + 2] = adderror(outputPixels[off + 2], err); } - - // x-1, y+1 if (x > 0 && y+1 < h) { outputPixels[off + w - 1] = adderror(outputPixels[off + w - 1], err); } - - // x, y+1 if (y+1 < h) { outputPixels[off + w] = adderror(outputPixels[off + w], err); } - - // x+1, y+1 if (x+1 < w && y+1 < h) { outputPixels[off + w + 1] = adderror(outputPixels[off + w + 1], err); } - - // x, y+2 if (y+2 < h) { outputPixels[off + 2 * w] = adderror(outputPixels[off + 2 * w], err); } From 6bc25539d3d7a79118613ef0e96d22a9517c3a88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Bo=CC=88hn?= Date: Mon, 14 Jul 2014 15:46:08 -0700 Subject: [PATCH 49/81] Generating app/deps/tensorlib/filters.h in app/deps/tensorlib/setup.py --- app/deps/tensorlib/filters.h | 11 +++++++++++ app/deps/tensorlib/module.m | 2 ++ app/deps/tensorlib/setup.py | 3 ++- 3 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 app/deps/tensorlib/filters.h diff --git a/app/deps/tensorlib/filters.h b/app/deps/tensorlib/filters.h new file mode 100644 index 00000000..73a534d2 --- /dev/null +++ b/app/deps/tensorlib/filters.h @@ -0,0 +1,11 @@ +#import "filters/FilterBase.h" + +#import "filters/ColorInvertFilter.h" +#import "filters/HalftoneFilter.h" +#import "filters/SoftEleganceFilter.h" +#import "filters/MissEtikateFilter.h" +#import "filters/SepiaFilter.h" +#import "filters/pixel/AtkinsonFilter.h" +#import "filters/VignetteFilter.h" +#import "filters/GrayscaleFilter.h" +#import "filters/PolkaDotFilter.h" diff --git a/app/deps/tensorlib/module.m b/app/deps/tensorlib/module.m index f47cc7a3..0310e3b4 100644 --- a/app/deps/tensorlib/module.m +++ b/app/deps/tensorlib/module.m @@ -1,6 +1,8 @@ #import #import +#import "filters.h" + /* * Stub python module declaration -- * Allows Objective-C classes with which it is linked diff --git a/app/deps/tensorlib/setup.py b/app/deps/tensorlib/setup.py index a8bdf408..8897db07 100644 --- a/app/deps/tensorlib/setup.py +++ b/app/deps/tensorlib/setup.py @@ -25,12 +25,13 @@ def get_sources(filter_dict, suffix="m"): def write_filter_header(filter_dict): headers = get_sources(filter_dict, suffix="h") with open("filters.h", 'wb') as header_fh: - header_fh.write('''#import "filters/FilterBase.h"\n''') + header_fh.write('''#import "filters/FilterBase.h"\n\n''') header_fh.writelines(['''#import "%s"\n''' % header for header in headers]) filters = find_filters() sources = ['module.m', 'filters/FilterBase.m'] sources.extend(get_sources(filters)) +write_filter_header(filters) print('Building tensorlib with %d filters:' % len(filters)) pprint(sorted(filters.keys())) From ba253df45f3a51254817c54c54c36902cccfc52c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Bo=CC=88hn?= Date: Mon, 14 Jul 2014 17:32:26 -0700 Subject: [PATCH 50/81] Fixed RTClass --- plotdevice/lib/rtclass.py | 20 +++++------ plotdevice/lib/tensor.py | 74 ++++++++++++++++++++++++++++----------- 2 files changed, 64 insertions(+), 30 deletions(-) diff --git a/plotdevice/lib/rtclass.py b/plotdevice/lib/rtclass.py index 9ae8e2c4..d7e89b43 100644 --- a/plotdevice/lib/rtclass.py +++ b/plotdevice/lib/rtclass.py @@ -27,7 +27,7 @@ def __init__(cls, name, bases, attrs): class RTClass(object): __metaclass__ = ObjCAncestor - def __new__(cls, *args, **kwargs): + def __init__(self, *args, **kwargs): """ Allow PyObjC-based RTClass subclasses to initialize pythonically e.g. nsarray = NSArray() # or: @@ -38,29 +38,29 @@ def __new__(cls, *args, **kwargs): nsarray = NSArray.alloc().initWithArray_(other_nsarray) # bah """ - print("__new__ shit that's how I do shit: %s" % cls) + cls = self.__class__ if hasattr(cls, '__rtbase__'): objc_cls = cls.__rtbase__ init_method_name = kwargs.pop('init', 'init') if hasattr(objc_cls, 'alloc'): - print("ALLOC") instance = objc_cls.alloc() init_method = getattr(instance, init_method_name) - return init_method(*args) - if hasattr(objc_cls, 'init'): - print("INIT") + self.__rtinstance__ = init_method(*args) + elif hasattr(objc_cls, 'init'): init_method = getattr(objc_cls, init_method_name) - return init_method(*args) - return object.__new__(cls, *args, **kwargs) + self.__rtinstance__ = init_method(*args) + object.__init__(self, *args, **kwargs) def __getattr__(self, attr): """ For unknown attributes that don't end in underscores, look for their underscored counterpart before bailing. """ if not attr.endswith(OBJ_COLON): alt_attr = attr + OBJ_COLON - if hasattr(self, alt_attr): - return getattr(self, alt_attr) + if hasattr(self.__rtinstance__, alt_attr): + return getattr(self.__rtinstance__, alt_attr) raise AttributeError('%s (tried with underscore)' % attr) + if hasattr(self.__rtinstance__, attr): + return getattr(self.__rtinstance__, attr) raise AttributeError(attr) def __repr__(self): diff --git a/plotdevice/lib/tensor.py b/plotdevice/lib/tensor.py index 2f214224..2d2f04d4 100644 --- a/plotdevice/lib/tensor.py +++ b/plotdevice/lib/tensor.py @@ -3,7 +3,7 @@ import objc, tensorlib from .rtclass import RTClass -#from collections import defaultdict +from collections import defaultdict class ColorInvertFilter(RTClass): """ Wrapper for tensorlib/ColorInvertFilter """ @@ -13,36 +13,71 @@ class HalftoneFilter(RTClass): """ Wrapper for tensorlib/HalftoneFilter """ pass -class MissEtikateFilter(RTClass): - """ Wrapper for tensorlib/MissEtikateFilter """ +class SoftEleganceFilter(RTClass): + """ Wrapper for tensorlib/SoftElegaceFilter """ pass -class PolkaDotFilter(RTClass): - """ Wrapper for tensorlib/PolkaDotFilter """ +class MissEtikateFilter(RTClass): + """ Wrapper for tensorlib/MissEtikateFilter """ pass class SepiaFilter(RTClass): """ Wrapper for tensorlib/SepiaFilter """ pass -class SoftEleganceFilter(RTClass): - """ Wrapper for tensorlib/SoftElegaceFilter """ +class AtkinsonFilter(RTClass): + """ Wrapper for tensorlib/pixel/AtkinsonFilter """ pass class VignetteFilter(RTClass): """ Wrapper for tensorlib/VignetteFilter """ pass -# NSUnknownColorSpaceModel = -1, -NSColorSpaceModels = ( - "NSGrayColorSpaceModel", - "NSRGBColorSpaceModel", - "NSCMYKColorSpaceModel", - "NSLABColorSpaceModel", - "NSDeviceNColorSpaceModel", - "NSIndexedColorSpaceModel", - "NSPatternColorSpaceModel" -) +class GrayscaleFilter(RTClass): + """ Wrapper for tensorlib/GrayscaleFilter """ + pass + +class PolkaDotFilter(RTClass): + """ Wrapper for tensorlib/PolkaDotFilter """ + pass + +def split_abbreviations(s): + abbreviations = [] + current_token = '' + for char in s: + if current_token is '': + current_token += char + elif char.islower(): + current_token += char + else: + abbreviations.append(str(current_token)) + current_token = '' + current_token += char + if current_token is not '': + abbreviations.append(str(current_token)) + return abbreviations + +COLORSPACE_MODES = defaultdict(lambda: 'Unknown', { + 'L': "Gray", + 'Gray': "Gray", + + 'RGB': "RGB", + 'CMYK': "CMYK", + 'LAB': "LAB", + + 'NCL': "DeviceN", + 'NCL2': "DeviceN", + 'DeviceN': "DeviceN", + + 'P': "Indexed", + 'Indexed': "Indexed", + + 'PAT': "Pattern", + 'PPAT': "Pattern", + 'Pattern': "Pattern", +}) + +COLORSPACE_MODEL = lambda midx: "NS%sColorSpaceModel" % COLORSPACE_MODES[midx] class Pipe(list): """ A linear pipeline of processors to be applied en masse. """ @@ -62,7 +97,7 @@ class ChannelFork(defaultdict): - applies a channel-specific processor, or - applies a default processor. """ - default_mode = 1 # 'NSRGBColorSpaceModel' + default_mode = 'RGB' # 'NSRGBColorSpaceModel' def __init__(self, default_factory, *args, **kwargs): if default_factory is None: @@ -71,7 +106,7 @@ def __init__(self, default_factory, *args, **kwargs): raise AttributeError( "ChannelFork() requires a callable default_factory.") - self.channels = NSColorSpaceModels[int(kwargs.pop('mode', self.default_mode))] + self.channels = COLORSPACE_MODEL[kwargs.pop('mode', self.default_mode)] super(ChannelFork, self).__init__(default_factory, *args, **kwargs) @@ -163,4 +198,3 @@ def process(self, img): return super(ChannelOverprinter, clone).process(img) ''' -dir(tensorlib) \ No newline at end of file From 1372eca70c58c9a5e57c1e7ab537e86507408e18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Bo=CC=88hn?= Date: Mon, 14 Jul 2014 19:50:28 -0700 Subject: [PATCH 51/81] Script to dl/patch/build/package PyObjC as wheels --- .gitignore | 1 + etc/download.sh | 62 ++++++++++++++++++++++++ etc/pyobjc-patch-wheelhouse.sh | 88 ++++++++++++++++++++++++++++++++++ etc/requirements.txt | 3 ++ etc/urlcache.sh | 76 +++++++++++++++++++++++++++++ 5 files changed, 230 insertions(+) create mode 100644 etc/download.sh create mode 100755 etc/pyobjc-patch-wheelhouse.sh create mode 100644 etc/requirements.txt create mode 100644 etc/urlcache.sh diff --git a/.gitignore b/.gitignore index 0b8d6391..aeda64a1 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ *.pyc *.so build/ +cache/ dist/ dist-* app/deps/Sparkle* diff --git a/etc/download.sh b/etc/download.sh new file mode 100644 index 00000000..9c188521 --- /dev/null +++ b/etc/download.sh @@ -0,0 +1,62 @@ +#!/usr/bin/env bash +# download_to, expand_tarball_to, expand_zipwad_to, download_and_expand + +download_to () { + in_url="${1:?URL expected}" + out_file="${2:?pathname expected}" + success=0 + [[ -r $out_file ]] && echo "- Already exists: ${out_file}" && return 1 + echo "+ Retrieving remote file: ${in_url}" + test ! -r $out_file && test -x `which wget` && wget --tries=40 --retry-connrefused $in_url -O $out_file && success=1 + test ! -r $out_file && test -x `which curl` && curl -L $in_url -o $out_file && success=1 + test ! -r $out_file && test -x `which http` && http -d $in_url -o $out_file && success=1 + [ $success == 0 ] && test -r $out_file && rm $out_file + [ $success == 0 ] && echo "- Couldn't download. Tried: wget, curl, httpie" && return 1 + echo "+ Downloaded to: ${out_file}" +} + +expand_tarball_to () { + in_tarball="${1:?tarball expected}" + out_directory="${2:?pathname expected}" + [[ ! -r $in_tarball ]] && echo "- Can't read tarball: ${in_tarball}" && return 1 + [[ -d $out_directory ]] && rm -rf $out_directory + mkdir -p $out_directory + echo "+ Expanding tarball: $(basename ${in_tarball})" + echo "+ Expansion destination: ${out_directory}" + tar xzf $in_tarball --strip-components=1 --directory=$out_directory +} + +expand_zipwad_to () { + in_zipwad="${1:?zipwad expected}" + out_directory="${2:?pathname expected}" + tmp_directory="$(mktemp -d -t XXXXX)" + [[ ! -r $in_zipwad ]] && echo "- Can't read zipwad: ${in_zipwad}" && return 1 + [[ -d $out_directory ]] && rm -rf $out_directory + echo "+ Unzipping zipwad: $(basename ${in_zipwad})" + echo "+ Unzip destination: ${out_directory}" + unzip -q -d $tmp_directory $in_zipwad + expanded_directory=("$tmp_directory"/*) + if (( ${#tmp_directory[@]} == 1 )) && [[ -d $tmp_directory ]]; then + mv "${tmp_directory}"/* $out_directory && rm -rf $tmp_directory + else + echo "Unzip failed, deleting temporary files: ${tmp_directory}" + [[ -d $tmp_directory ]] && rm -rf $tmp_directory + return 1 + fi +} + +download_and_expand () { + url="${1:?URL expected}" + url_basename="$(basename ${url})" + url_suffix="${url_basename#*.}" + destination_directory="${2:-${url_basename%%.*}}" + tmp_directory="$(mktemp -d -t XXXXX)" + tmp_archive="${tmp_directory}/${url_basename}" + download_to $url $tmp_archive || return 1 + [[ ${url_suffix,,} == *zip ]] \ + && expand_zipwad_to $tmp_archive $destination_directory + [[ ${url_suffix,,} != *zip ]] \ + && expand_tarball_to $tmp_archive $destination_directory + rm $tmp_archive + [[ -d $tmp_directory ]] && rm -rf $tmp_directory +} \ No newline at end of file diff --git a/etc/pyobjc-patch-wheelhouse.sh b/etc/pyobjc-patch-wheelhouse.sh new file mode 100755 index 00000000..b2897688 --- /dev/null +++ b/etc/pyobjc-patch-wheelhouse.sh @@ -0,0 +1,88 @@ +#!/usr/bin/env bash + +PRAXA_DOWNLOAD_CACHE="cache/downloads" +WHEELHOUSE="${PWD}/cache/wheelhouse" +mkdir -p $PRAXA_DOWNLOAD_CACHE +mkdir -p $WHEELHOUSE + +source "etc/download.sh" +source "etc/urlcache.sh" + +PYOBJC_VERSION="2.5.1" +PYOBJC_DOWNLOAD_URL="https://bitbucket.org/ronaldoussoren/pyobjc/get/pyobjc-${PYOBJC_VERSION}.zip" +PYOBJC_BUILD_PATH="build/pyobjc-${PYOBJC_VERSION}" + +fetch_and_expand $PYOBJC_DOWNLOAD_URL $PYOBJC_BUILD_PATH + +declare -a names=("AppleScriptKit" \ +"Accounts" \ +"AddressBook" \ +"AppleScriptKit" \ +"AppleScriptObjC" \ +"Automator" \ +"CFNetwork" \ +"CalendarStore" \ +"Cocoa" \ +"Collaboration" \ +"CoreData" \ +"CoreLocation" \ +"CoreText" \ +#"CoreWLAN" \ +"DictionaryServices" \ +#"DiskArbitration" \ +"EventKit" \ +"ExceptionHandling" \ +"FSEvents" \ +"InputMethodKit" \ +"InstallerPlugins" \ +"InstantMessage" \ +#"InterfaceBuilderKit" \ +"LatentSemanticMapping" \ +"LaunchServices" \ +#"Message" \ +"OpenDirectory" \ +"PreferencePanes" \ +"PubSub" \ +"QTKit" \ +"Quartz" \ +"ScreenSaver" \ +"ScriptingBridge" \ +"SearchKit" \ +"ServerNotification" \ +"ServiceManagement" \ +"Social" \ +#"StoreKit" \ +"SyncServices" \ +"SystemConfiguration" \ +"WebKit") +#"XgridFoundation") + +PYOBJC_DIR=$PWD/$PYOBJC_BUILD_PATH +FIND="for fn in install_lib._install_lib.get_outputs(self):" +REPLACE="for fn, _ in result.items():" + +########## FIX SETUPS ########## +for name in "${names[@]}"; do + cd $PYOBJC_DIR && \ + cd "pyobjc-framework-${name}" && \ + sed -i \~ -e "s#${FIND}#${REPLACE}#" pyobjc_setup.py +done + +#cd $PYOBJC_DIR/pyobjc-core && sed -i \~ -e "s#${FIND}#${REPLACE}#" distribute_setup.py +cd $PYOBJC_DIR/pyobjc-core && sed -i \~ -e "s#${FIND}#${REPLACE}#" setup.py +#cd $PYOBJC_DIR/pyobjc && sed -i \~ -e "s#${FIND}#${REPLACE}#" distribute_setup.py +#cd $PYOBJC_DIR/pyobjc && sed -i \~ -e "s#${FIND}#${REPLACE}#" setup.py + +find $PYOBJC_DIR -name \*.py~ -print -delete + +########## WHEELHOUSE ########## +#mkdir -p $WHEELHOUSE + +for name in "${names[@]}"; do + cd $PYOBJC_DIR && \ + cd "pyobjc-framework-${name}" && \ + pip wheel --verbose --no-deps -w $WHEELHOUSE . +done + +cd $PYOBJC_DIR/pyobjc-core && pip wheel --verbose --no-deps -w $WHEELHOUSE . +cd $PYOBJC_DIR/pyobjc && pip wheel --verbose --no-deps -w $WHEELHOUSE . diff --git a/etc/requirements.txt b/etc/requirements.txt new file mode 100644 index 00000000..011468d3 --- /dev/null +++ b/etc/requirements.txt @@ -0,0 +1,3 @@ +#pyobjc==2.5.1 +pyobjc>=3.0.1 +Pillow \ No newline at end of file diff --git a/etc/urlcache.sh b/etc/urlcache.sh new file mode 100644 index 00000000..1e0727c6 --- /dev/null +++ b/etc/urlcache.sh @@ -0,0 +1,76 @@ +#!/usr/bin/env bash +# __url_hash_filename, __url_cache_filename +# __cache_has_url, __cache_clear_url, __cache_purge +# cache_url, fetch_from_cache_to, fetch_and_expand + +__url_hash_filename () { + url="${1:?URL expected}" + url_basename="$(basename ${url})" + url_suffix="${2:-${url_basename#*.}}" + hasher="${3:-$(which sha1deep)}" + url_hash=$(echo $url | $hasher) + echo "${url_hash}.${url_suffix,,}" +} + +__url_cache_filename () { + url="${1:?URL expected}" + cache_location="${2:-${PRAXA_DOWNLOAD_CACHE}}" + url_hash_filename="$(__url_hash_filename ${url})" + cache_file="${cache_location}/${url_hash_filename}" + echo $cache_file +} + +__cache_has_url () { + url="${1:?URL expected}" + cache_location="${2:-${PRAXA_DOWNLOAD_CACHE}}" + test -r $(__url_cache_filename ${url} ${cache_location}) +} + +__cache_clear_url () { + url="${1:?URL expected}" + cache_location="${2:-${PRAXA_DOWNLOAD_CACHE}}" + rm $(__url_cache_filename $url $cache_location) +} + +__cache_purge () { + cache_location="${1:-${PRAXA_DOWNLOAD_CACHE}}" + rm ${cache_location}/* +} + +cache_url () { + url="${1:?URL expected}" + cache_file="$(__url_cache_filename ${url})" + __cache_has_url $url || download_to $url $cache_file 1>&2 + if [[ ! -r $cache_file ]]; then + echo "ERROR: no cached file: ${cache_file}" 1>&2 + echo "" + return 1 + fi + echo $cache_file +} + +fetch_from_cache_to () { + in_url="${1:?URL expected}" + out_file="${2:?pathname expected}" + [[ -r $out_file ]] && echo "- Already exists: ${out_file}" && return 1 + out_cached_file="$(cache_url $in_url)" + echo "+ Fetching from cache: ${out_cached_file}" + cp $out_cached_file $out_file + [[ -r $out_file ]] && echo "+ Fetched from cache: ${out_file}" +} + +fetch_and_expand () { + url="${1:?URL expected}" + url_basename="$(basename ${url})" + url_suffix="${url_basename#*.}" + destination_directory="${2:-${url_basename%%.*}}" + tmp_directory="$(mktemp -d -t XXXXX)" + tmp_archive="${tmp_directory}/${url_basename}" + fetch_from_cache_to $url $tmp_archive || return 1 + [[ ${url_suffix,,} == *zip ]] \ + && expand_zipwad_to $tmp_archive $destination_directory + [[ ${url_suffix,,} != *zip ]] \ + && expand_tarball_to $tmp_archive $destination_directory + rm $tmp_archive + [[ -d $tmp_directory ]] && rm -rf $tmp_directory +} \ No newline at end of file From f3495fdc1834221ae03bd8758036bc74db149fcf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Bo=CC=88hn?= Date: Mon, 14 Jul 2014 20:15:08 -0700 Subject: [PATCH 52/81] Universally available URL hasher command --- etc/urlcache.sh | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) mode change 100644 => 100755 etc/urlcache.sh diff --git a/etc/urlcache.sh b/etc/urlcache.sh old mode 100644 new mode 100755 index 1e0727c6..6dd99afc --- a/etc/urlcache.sh +++ b/etc/urlcache.sh @@ -6,9 +6,8 @@ __url_hash_filename () { url="${1:?URL expected}" url_basename="$(basename ${url})" - url_suffix="${2:-${url_basename#*.}}" - hasher="${3:-$(which sha1deep)}" - url_hash=$(echo $url | $hasher) + url_suffix="${2:-${url_basename##*.}}" + url_hash=$(echo $url | openssl dgst -sha1 | awk '{ split($0, a, /\=\s/); print a[1]; }') echo "${url_hash}.${url_suffix,,}" } From 20edea917442b1ceee641aa7e6ba2fa2f7aafd88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Bo=CC=88hn?= Date: Mon, 14 Jul 2014 20:46:40 -0700 Subject: [PATCH 53/81] Removed old include/link paths --- etc/old-python-include-link-paths.sh | 4 ---- 1 file changed, 4 deletions(-) delete mode 100644 etc/old-python-include-link-paths.sh diff --git a/etc/old-python-include-link-paths.sh b/etc/old-python-include-link-paths.sh deleted file mode 100644 index 8812a82e..00000000 --- a/etc/old-python-include-link-paths.sh +++ /dev/null @@ -1,4 +0,0 @@ -/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/config -$(SYSTEM_LIBRARY_DIR)/Frameworks/Python.framework/Versions/2.7 - -/System/Library/Frameworks/Python.framework/Versions/2.7/include/python2.7 \ No newline at end of file From 7064740dc76cfae0320e4a21b61e7c0983cb17b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Bo=CC=88hn?= Date: Mon, 14 Jul 2014 23:30:54 -0700 Subject: [PATCH 54/81] Fixed Atkinson filter with bpp arg (like finally) --- .../tensorlib/filters/pixel/AtkinsonFilter.h | 2 +- .../tensorlib/filters/pixel/AtkinsonFilter.m | 35 ++++++++++++++----- 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/app/deps/tensorlib/filters/pixel/AtkinsonFilter.h b/app/deps/tensorlib/filters/pixel/AtkinsonFilter.h index b680ca7c..3d327a39 100644 --- a/app/deps/tensorlib/filters/pixel/AtkinsonFilter.h +++ b/app/deps/tensorlib/filters/pixel/AtkinsonFilter.h @@ -21,7 +21,7 @@ static unsigned char threshold[256]; /// forward declaration of the bytearray-level atkinson function -unsigned char *atkinson(unsigned char *pixels, int w, int h, int len); +unsigned char *atkinson(unsigned char *pixels, int w, int h, int bpp, int len); /// FilterBase subclass boilerplate interface @interface AtkinsonFilter : FilterBase {} diff --git a/app/deps/tensorlib/filters/pixel/AtkinsonFilter.m b/app/deps/tensorlib/filters/pixel/AtkinsonFilter.m index 3f7a17fa..5b05f9e0 100644 --- a/app/deps/tensorlib/filters/pixel/AtkinsonFilter.m +++ b/app/deps/tensorlib/filters/pixel/AtkinsonFilter.m @@ -12,7 +12,7 @@ #import "AtkinsonFilter.h" /// bytearray-level atkinson pixel processing function -unsigned char *atkinson(unsigned char *inputPixels, int w, int h, int len) { +unsigned char *atkinson(unsigned char *inputPixels, int w, int h, int bpp, int len) { int x, y, off, err; unsigned char *outputPixels = malloc(sizeof(unsigned char) * len); unsigned char old, new; @@ -23,7 +23,14 @@ return NULL; } - memcpy(outputPixels, inputPixels, sizeof(sizeof(unsigned char) * len)); + //memcpy(outputPixels, inputPixels, sizeof(unsigned char) * len * bpp); + memset(outputPixels, 0, sizeof(unsigned char) * len); + for (y = 0; y < h; y++) { + for (x = 0; x < w; x++) { + off = (y * w) + x; + outputPixels[off] = inputPixels[off * bpp]; + } + } for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { @@ -77,7 +84,7 @@ - (id)init { for (i = 128; i < 256; i++) { threshold[i] = 0xFF; } - filter = (GPUImageFilter *)[[GPUImageMonochromeFilter alloc] init]; + filter = (GPUImageFilter *)[[GPUImageGrayscaleFilter alloc] init]; } return self; } @@ -91,13 +98,15 @@ - (NSImage *)process:(NSImage *)input { int w = (int)[inputRep pixelsWide]; int h = (int)[inputRep pixelsHigh]; + int bpp = (int)[inputRep bitsPerPixel] / 8; long length = (long)(w * h); [self STDOUT:@"About to call atkinson():"]; - [self STDOUT:@" WIDTH = %i, HEIGHT = %i, LENGTH = %li", - w, h, length]; + + [self STDOUT:@" WIDTH = %i, HEIGHT = %i, LENGTH = %li, BPP = %i", + w, h, length, bpp]; unsigned char *inputData = [inputRep bitmapData]; - unsigned char *outputData = atkinson(inputData, w, h, length); + unsigned char *outputData = atkinson(inputData, w, h, bpp, length); if (outputData == NULL) { [self STDERR:@"Bad dimensions passed to atkinson():"]; @@ -106,9 +115,17 @@ - (NSImage *)process:(NSImage *)input { return inputGrayscale; } - NSData *outputWrappedData = [NSData dataWithBytes:outputData length:length]; - NSBitmapImageRep *outputRep = [NSBitmapImageRep - imageRepWithData:outputWrappedData]; + NSBitmapImageRep *outputRep = [[[NSBitmapImageRep alloc] + initWithBitmapDataPlanes:&outputData + pixelsWide:w + pixelsHigh:h + bitsPerSample:8 + samplesPerPixel:1 + hasAlpha:NO + isPlanar:NO + colorSpaceName:NSCalibratedWhiteColorSpace + bytesPerRow:w + bitsPerPixel:8] autorelease]; [self STDOUT:@"About to return atkinson-ized image"]; NSImage *output = [[NSImage alloc] initWithSize:NSMakeSize(w, h)]; From 72a898b9b7505a29a0f13653f69ce22a1543ccad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Bo=CC=88hn?= Date: Mon, 14 Jul 2014 23:37:25 -0700 Subject: [PATCH 55/81] Conditionally compile STDOUT/STDERR in FilterBase.m --- app/deps/tensorlib/filters/FilterBase.m | 4 ++++ app/deps/tensorlib/filters/pixel/AtkinsonFilter.m | 1 - app/deps/tensorlib/setup.py | 2 ++ 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/app/deps/tensorlib/filters/FilterBase.m b/app/deps/tensorlib/filters/FilterBase.m index c3a059be..dd39aa99 100644 --- a/app/deps/tensorlib/filters/FilterBase.m +++ b/app/deps/tensorlib/filters/FilterBase.m @@ -24,6 +24,7 @@ - (NSImage *)process:(NSImage *)input { } - (void)STDOUT:(NSString *)string, ... { +#ifdef TENSORLIB_STDOUT NSString *out = [NSString stringWithFormat:@"[%@] %@", [self className], string]; va_list args; @@ -35,9 +36,11 @@ - (void)STDOUT:(NSString *)string, ... { fprintf(stdout, "%s\n", [stdOutString UTF8String]); [stdOutString release]; +#endif } - (void)STDERR:(NSString *)string, ... { +#ifdef TENSORLIB_STDERR NSString *err = [NSString stringWithFormat:@"[%@] ERROR: %@", [self className], string]; va_list args; @@ -49,6 +52,7 @@ - (void)STDERR:(NSString *)string, ... { fprintf(stderr, "%s\n", [stdErrString UTF8String]); [stdErrString release]; +#endif } @end \ No newline at end of file diff --git a/app/deps/tensorlib/filters/pixel/AtkinsonFilter.m b/app/deps/tensorlib/filters/pixel/AtkinsonFilter.m index 5b05f9e0..d7e080b1 100644 --- a/app/deps/tensorlib/filters/pixel/AtkinsonFilter.m +++ b/app/deps/tensorlib/filters/pixel/AtkinsonFilter.m @@ -102,7 +102,6 @@ - (NSImage *)process:(NSImage *)input { long length = (long)(w * h); [self STDOUT:@"About to call atkinson():"]; - [self STDOUT:@" WIDTH = %i, HEIGHT = %i, LENGTH = %li, BPP = %i", w, h, length, bpp]; unsigned char *inputData = [inputRep bitmapData]; diff --git a/app/deps/tensorlib/setup.py b/app/deps/tensorlib/setup.py index 8897db07..58a06440 100644 --- a/app/deps/tensorlib/setup.py +++ b/app/deps/tensorlib/setup.py @@ -42,6 +42,8 @@ def write_filter_header(filter_dict): '-Wno-error=unused-command-line-argument-hard-error-in-future', '-Wno-unused-function', '-Qunused-arguments', + '-DTENSORLIB_STDOUT', + '-DTENSORLIB_STDERR', '-F%s' % frameworks], extra_link_args=[ '-Wno-error=unused-command-line-argument-hard-error-in-future', From b7cf132793e1cf6dc33dd84c875ab32ee7e1474d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Bo=CC=88hn?= Date: Tue, 15 Jul 2014 04:59:31 -0700 Subject: [PATCH 56/81] Runs against bundled version of PyObjC --- PlotDevice.xcodeproj/project.pbxproj | 35 +++- .../tensorlib/filters/pixel/AtkinsonFilter.m | 2 +- app/main.m | 14 ++ app/plotdevice-app.py | 20 +-- plotdevice/__init__.py | 30 ++-- setup.py | 170 +++++++++++++----- 6 files changed, 196 insertions(+), 75 deletions(-) diff --git a/PlotDevice.xcodeproj/project.pbxproj b/PlotDevice.xcodeproj/project.pbxproj index c184a3a3..596b696a 100644 --- a/PlotDevice.xcodeproj/project.pbxproj +++ b/PlotDevice.xcodeproj/project.pbxproj @@ -39,6 +39,10 @@ CF04731D196B71C200E3C358 /* GPUImage.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CF04731C196B71C200E3C358 /* GPUImage.framework */; }; CF047321196B744C00E3C358 /* GPUImage.framework in Copy Private Frameworks */ = {isa = PBXBuildFile; fileRef = CF04731C196B71C200E3C358 /* GPUImage.framework */; }; CF29B4BE196C51B70092593E /* Python.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CF29B4BC196C51410092593E /* Python.framework */; }; + CFC5106F197545210046C918 /* pyobjc-patch-wheelhouse.sh in Resources */ = {isa = PBXBuildFile; fileRef = CFC5106B197545210046C918 /* pyobjc-patch-wheelhouse.sh */; }; + CFC51070197545210046C918 /* urlcache.sh in Resources */ = {isa = PBXBuildFile; fileRef = CFC5106C197545210046C918 /* urlcache.sh */; }; + CFC51071197545210046C918 /* download.sh in Resources */ = {isa = PBXBuildFile; fileRef = CFC5106D197545210046C918 /* download.sh */; }; + CFC51072197545210046C918 /* requirements.txt in Resources */ = {isa = PBXBuildFile; fileRef = CFC5106E197545210046C918 /* requirements.txt */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -167,8 +171,11 @@ 8D15AC370486D014006FF6A4 /* PlotDevice.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = PlotDevice.app; sourceTree = BUILT_PRODUCTS_DIR; }; CF04731C196B71C200E3C358 /* GPUImage.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GPUImage.framework; path = app/Frameworks/GPUImage.framework; sourceTree = SOURCE_ROOT; }; CF29B4BC196C51410092593E /* Python.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Python.framework; path = /usr/local/Cellar/python/2.7.8/Frameworks/Python.framework; sourceTree = ""; }; - CF61A9FD196DF5DC00BDFF1D /* old-python-include-link-paths.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = "old-python-include-link-paths.sh"; sourceTree = ""; }; CF61A9FF196DF61600BDFF1D /* relpath.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = relpath.sh; sourceTree = ""; }; + CFC5106B197545210046C918 /* pyobjc-patch-wheelhouse.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = "pyobjc-patch-wheelhouse.sh"; sourceTree = ""; }; + CFC5106C197545210046C918 /* urlcache.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = urlcache.sh; sourceTree = ""; }; + CFC5106D197545210046C918 /* download.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = download.sh; sourceTree = ""; }; + CFC5106E197545210046C918 /* requirements.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = requirements.txt; sourceTree = ""; }; CFF92336196D31780095586A /* rtclass.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = rtclass.py; sourceTree = ""; }; CFF92337196D31780095586A /* tensor.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = tensor.py; sourceTree = ""; }; /* End PBXFileReference section */ @@ -398,7 +405,10 @@ CF61A9FC196DF5DC00BDFF1D /* etc */ = { isa = PBXGroup; children = ( - CF61A9FD196DF5DC00BDFF1D /* old-python-include-link-paths.sh */, + CFC5106B197545210046C918 /* pyobjc-patch-wheelhouse.sh */, + CFC5106C197545210046C918 /* urlcache.sh */, + CFC5106D197545210046C918 /* download.sh */, + CFC5106E197545210046C918 /* requirements.txt */, CF61A9FF196DF61600BDFF1D /* relpath.sh */, ); path = etc; @@ -420,6 +430,7 @@ 8D15AC300486D014006FF6A4 /* Sources */, 8D15AC330486D014006FF6A4 /* Frameworks */, CF093DD3196E06E200B00802 /* Symlink PlotDevice.app/Contents/Frameworks as PlotDevice.app/Contents/Resources/python/plotdevice/Frameworks */, + CFC51073197545B90046C918 /* Install Wheelhouse Packages to App Bundle */, ); buildRules = ( ); @@ -471,8 +482,12 @@ 611CC5A010BA908C00B55455 /* PlotDeviceDocument.xib in Resources */, 611CC5A810BA919A00B55455 /* PlotDevicePreferences.xib in Resources */, 611CC68010BAA08300B55455 /* MainMenu.xib in Resources */, + CFC51070197545210046C918 /* urlcache.sh in Resources */, 611CC68710BAA0A600B55455 /* AskString.xib in Resources */, 2A7AF5C818D2AFAA00F8FFC2 /* examples in Resources */, + CFC51071197545210046C918 /* download.sh in Resources */, + CFC51072197545210046C918 /* requirements.txt in Resources */, + CFC5106F197545210046C918 /* pyobjc-patch-wheelhouse.sh in Resources */, 6155D9F413E2B79E00675A92 /* CHANGES.md in Resources */, 6155D9F513E2B79E00675A92 /* README.md in Resources */, ); @@ -508,7 +523,21 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "\n#app=\"${TARGET_BUILD_DIR}/${WRAPPER_NAME}\"\nframeworks=\"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}\"\nresources=\"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}\"\nplotdevice=\"${resources}/python/plotdevice\"\n\n#/usr/local/bin/terminal-notifier -message \"Running RELEASE Post-Build Actions\"\n\nset +x\nsource ${SOURCE_ROOT}/etc/relpath.sh\n\npushd $plotdevice\n[ ! -L \"${plotdevice}/Frameworks\" ] && /bin/ln -s `relpath $plotdevice $frameworks` Frameworks\n\n"; + shellScript = "\n#echo \"YO DOGG\"\n\n#app=\"${TARGET_BUILD_DIR}/${WRAPPER_NAME}\"\nframeworks=\"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}\"\nresources=\"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}\"\nplotdevice=\"${resources}/python/plotdevice\"\n\n#/usr/local/bin/terminal-notifier -message \"Running RELEASE Post-Build Actions\"\n\n#echo \"SOURCIN\"\nsource ${SOURCE_ROOT}/etc/relpath.sh\n\ncd $plotdevice\necho \"LINKIN\"\nif [ ! -h ${plotdevice}/Frameworks ]; then\n /bin/ln -s `relpath $plotdevice $frameworks` Frameworks\nfi\n\n"; + }; + CFC51073197545B90046C918 /* Install Wheelhouse Packages to App Bundle */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Install Wheelhouse Packages to App Bundle"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "python=\"/usr/bin/python\"\nif [ -x /usr/local/bin/python ]; then\npython=\"/usr/local/bin/python\"\nfi\n\n# let the setup script handle wheelhousing\neval \"${python} setup.py wheelhouse\"\n"; showEnvVarsInLog = 0; }; /* End PBXShellScriptBuildPhase section */ diff --git a/app/deps/tensorlib/filters/pixel/AtkinsonFilter.m b/app/deps/tensorlib/filters/pixel/AtkinsonFilter.m index d7e080b1..b29e9cb9 100644 --- a/app/deps/tensorlib/filters/pixel/AtkinsonFilter.m +++ b/app/deps/tensorlib/filters/pixel/AtkinsonFilter.m @@ -99,7 +99,7 @@ - (NSImage *)process:(NSImage *)input { int w = (int)[inputRep pixelsWide]; int h = (int)[inputRep pixelsHigh]; int bpp = (int)[inputRep bitsPerPixel] / 8; - long length = (long)(w * h); + int length = w * h; [self STDOUT:@"About to call atkinson():"]; [self STDOUT:@" WIDTH = %i, HEIGHT = %i, LENGTH = %li, BPP = %i", diff --git a/app/main.m b/app/main.m index dc3783c9..8ec47d94 100644 --- a/app/main.m +++ b/app/main.m @@ -10,6 +10,20 @@ int main(int argc, char *argv[]) Py_SetProgramName(PLOTDEVICE_PYTHON); Py_Initialize(); PySys_SetArgv(argc, (char **)argv); + + NSString *mainBundlePath = [[NSBundle mainBundle] bundlePath]; + NSString *bundleSitePackages = [mainBundlePath stringByAppendingPathComponent:@"Contents/Resources/python"]; + NSString *bundlePyObjC = [bundleSitePackages stringByAppendingPathComponent:@"PyObjC"]; + + PyObject *sys = PyImport_ImportModule("sys"); + PyObject *path = PyObject_GetAttrString(sys, "path"); + PyList_Insert(path, (Py_ssize_t)0, + PyString_FromString( + (char *)[bundleSitePackages UTF8String])); + PyList_Insert(path, (Py_ssize_t)0, + PyString_FromString( + (char *)[bundlePyObjC UTF8String])); + NSString *mainFilePath = [[NSBundle mainBundle] pathForResource:@"plotdevice-app" ofType:@"py"]; NSString *mainFileName = [mainFilePath lastPathComponent]; return PyRun_SimpleFile(fopen([mainFilePath UTF8String], "r"), (char *)[mainFileName UTF8String]); diff --git a/app/plotdevice-app.py b/app/plotdevice-app.py index ad4fcc4d..22a3fe95 100644 --- a/app/plotdevice-app.py +++ b/app/plotdevice-app.py @@ -1,19 +1,11 @@ -import sys, objc, Foundation, AppKit -from signal import signal, SIGINT -from os.path import abspath, isdir -from PyObjCTools import AppHelper +import sys +from os.path import isdir -# if there's a python installed into /usr/local, it's probably homebrew -- -# let's use it! +# if there's a python in /usr/local, it's probably homebrew -- let's use it! local_packages = '/usr/local/lib/python2.7/site-packages' if isdir(local_packages): - sys.path.insert(0, local_packages) - -# rather than hijacking PYTHONPATH in the .m loader, add the module directory now -sys.path.insert(0, - '%s/Contents/Resources/python' % abspath( - Foundation.NSBundle.mainBundle().bundlePath())) + sys.path.append(local_packages) # remove dupes from sys.path -- for an explanation see: # http://stackoverflow.com/a/480227/298171 @@ -25,6 +17,9 @@ sys.path = list(clean_path) # install a signal handler to quit on ^c (should the app ever be launched from terminal) +import objc +import AppKit +from signal import signal, SIGINT signal(SIGINT, lambda m, n: AppKit.NSApplication.sharedApplication().terminate_(True)) # PlotDevice is a typical document-based application. We'll import the PlotDeviceDocument @@ -33,4 +28,5 @@ import plotdevice.gui # loop forever +from PyObjCTools import AppHelper AppHelper.runEventLoop() diff --git a/plotdevice/__init__.py b/plotdevice/__init__.py index c0021863..668698aa 100644 --- a/plotdevice/__init__.py +++ b/plotdevice/__init__.py @@ -19,29 +19,11 @@ MIT Licensed (see README file for details) """ -__version__ = '0.9.2' -__author__ = 'Christian Swinehart' -__email__ = "drafting@samizdat.cc" -__credits__ = 'Frederik De Bleser, Tom De Smedt, Just van Rossum, & Marcos Ojeda' -__license__ = 'MIT' - # add the shared directory (for Libraries) to the path import sys, re, os sys.path.append(os.path.join(os.getenv('HOME'), 'Library', 'Application Support', 'PlotDevice')) -# add the Extras directory to sys.path since every module depends on PyObjC and friends -try: - import objc -except ImportError: - #extras = '/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python' - extras = sys.prefix - sys.path.extend([extras, '%s/PyObjC'%extras]) - import objc - -# print python exceptions to the console rather than silently failing -objc.setVerbose(True) - # the global non-conflicting token (fingers crossed) INTERNAL = '_p_l_o_t_d_e_v_i_c_e_' @@ -64,6 +46,18 @@ class Halted(Exception): # global namespace. we'll let the Sandbox handle populating the namespace instead. __all__ = [] else: + # add the Extras directory to sys.path since every module depends on PyObjC and friends + try: + import objc + except ImportError: + #extras = '/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python' + extras = sys.prefix + sys.path.extend([extras, '%s/PyObjC'%extras]) + import objc + + # print python exceptions to the console rather than silently failing + objc.setVerbose(True) + # if imported from an external module, set up a drawing environment in __all__. # (note that since this happens at the module level, the canvas will be shared # among all the files in a given process that `import *`). diff --git a/setup.py b/setup.py index 3d7f838e..b8d78f79 100644 --- a/setup.py +++ b/setup.py @@ -20,23 +20,28 @@ # - cPathMatics, cGeo, cIO, cEvent, tensorlib, & polymagic (included in the "app/deps" folder) # - Sparkle.framework (auto-downloaded only for `dist` builds) -import sys, os +import sys, os, urllib2, plistlib from distutils.dir_util import remove_tree +from distutils.spawn import find_executable as which from setuptools import setup, find_packages from pkg_resources import DistributionNotFound -from os.path import join, exists, dirname, basename, abspath, relpath -import plotdevice - +from os import listdir +from os.path import join, exists, isdir, dirname, basename, abspath, relpath, getsize ## Metadata ## +__version__ = '0.9.2' +__author__ = 'Christian Swinehart' +__email__ = "drafting@samizdat.cc" +__credits__ = 'Frederik De Bleser, Tom De Smedt, Just van Rossum, & Marcos Ojeda' +__license__ = 'MIT' # PyPI fields APP_NAME = 'PlotDevice' MODULE = APP_NAME.lower() -VERSION = plotdevice.__version__ -AUTHOR = plotdevice.__author__ -AUTHOR_EMAIL = plotdevice.__email__ -LICENSE = plotdevice.__license__ +VERSION = __version__ +AUTHOR = __author__ +AUTHOR_EMAIL = __email__ +LICENSE = __license__ URL = "http://plotdevice.io/" CLASSIFIERS = ( "Development Status :: 5 - Production/Stable", @@ -92,7 +97,6 @@ GPUIMAGE_URL = "https://github.com/BradLarson/GPUImage/archive/%(v)s.zip" % { 'v': GPUIMAGE_VERSION } # helpers for dealing with plists & git (spiritual cousins if ever there were) -import plistlib def info_plist(pth='app/PlotDevice-Info.plist'): info = plistlib.readPlist(pth) # overwrite the xcode placeholder vars @@ -143,7 +147,6 @@ def timestamp(): now = utc.localize(datetime.utcnow()).astimezone(timezone('US/Eastern')) return now.strftime("%a, %d %b %Y %H:%M:%S %z") -import urllib2 def last_release(): from xml.etree.ElementTree import fromstring feed_xml = urllib2.urlopen('http://plotdevice.io/app.xml').read().decode('utf-8') @@ -190,11 +193,79 @@ class CleanCommand(Command): def initialize_options(self): pass def finalize_options(self): pass def run(self): + os.system('find . -iname .ds_store -print -delete') + os.system('find . -name \*.pyc -print -delete') os.system('rm -rf ./build ./dist') os.system('rm -rf ./Xcode/Build ./Xcode/Intermediates ./DerivedData') os.system('rm -rf ./app/deps/*/build') os.system('rm -rf plotdevice.egg-info MANIFEST.in PKG') +class WheelhouseToApp(Command): + description = "Install PlotDevice.app requirements from the wheelhouse" + user_options = [ + ('wheelhouse=', 'w', 'Wheelhouse directory [default: cache/wheelhouse/]'), + ('app=', 'a', 'App bundle directory [default: dist/PlotDevice.app/]')] + + def initialize_options(self): + self.wheelhouse = 'cache/wheelhouse/' + self.app = 'dist/PlotDevice.app' + + def finalize_options(self): + self.wheelhouse = abspath(self.wheelhouse) + self.app = abspath(self.app) + + def run(self): + ''' install wheels to app bundle ''' + self.install_wheels() + print "done installing wheels" + + def install_wheels(self): + ''' Install everything from the wheelhouse ''' + try: + from wheel.install import WheelFile + except ImportError: + print "ERROR: install `wheel` to enable bundle-local PyObjC" + return False + + #WHEELHOUSE = join('cache', 'wheelhouse') + WHEELHOUSE = self.wheelhouse + APP = self.app + DITTO = which('ditto') + + if not isdir(WHEELHOUSE): + print "ERROR: no wheelhouse directory at %s" % WHEELHOUSE + return False + + WHEELS = filter( + lambda wheel_file: wheel_file.lower().endswith('.whl'), + listdir(WHEELHOUSE)) + PYOBJC_WHEELS = filter( + lambda wheel_file: wheel_file.lower().startswith('pyobjc'), + WHEELS) + + CONTENTS = join(APP, 'Contents') + RESOURCES = join(CONTENTS, 'Resources') + SITE_PACKAGES = join(RESOURCES, 'python') + HEADERS = join(RESOURCES, 'Headers') # wat + SCRIPTS = join(CONTENTS, 'SharedSupport') + OVERRIDES = dict( + purelib=SITE_PACKAGES, platlib=SITE_PACKAGES, data=SITE_PACKAGES, + headers=HEADERS, scripts=SCRIPTS) + + self.mkpath(HEADERS) + for pyobjc_wheel_file in sorted(PYOBJC_WHEELS): + print "+ Installing PyObjC wheel: %s" % pyobjc_wheel_file + PYOBJC_WHEEL = WheelFile(join(WHEELHOUSE, pyobjc_wheel_file)) + PYOBJC_WHEEL.install(overrides=OVERRIDES, force=True) + + # misc. + self.spawn([DITTO, + join(SITE_PACKAGES, 'PyObjCTools'), + join(SITE_PACKAGES, 'PyObjC', 'PyObjCTools')]) + self.spawn(['touch', + join(SITE_PACKAGES, 'PyObjC', 'PyObjCTools', '__init__.py')]) + return True + from setuptools.command.sdist import sdist class BuildDistCommand(sdist): def finalize_options(self): @@ -213,7 +284,6 @@ def run(self): os.unlink('MANIFEST.in') from distutils.command.build_py import build_py -from distutils.spawn import find_executable as which class BuildCommand(build_py): def run(self): # first let the real build_py routine do its thing @@ -236,9 +306,13 @@ class BuildAppCommand(Command): user_options = [] def initialize_options(self): pass def finalize_options(self): pass + #sub_commands = Command.sub_commands[:] + #sub_commands.append(('wheelhouse', lambda arg: True)) def run(self): self.spawn(['xcodebuild']) remove_tree('dist/PlotDevice.app.dSYM') + for cmd in self.get_sub_commands(): + self.run_command(cmd) print "done building PlotDevice.app in ./dist" try: @@ -251,6 +325,10 @@ def initialize_options(self): def finalize_options(self): self.verbose=0 build_py2app.finalize_options(self) + + sub_commands = build_py2app.sub_commands[:] + sub_commands.append(('wheelhouse', lambda arg: True)) + def run(self): #assert os.getcwd() == self.cwd, 'Must be in package root: %s' % self.cwd build_py2app.run(self) @@ -304,6 +382,9 @@ def run(self): # place the command line tool in SharedSupport self.copy_file("app/plotdevice", BIN) + for cmd in self.get_sub_commands(): + self.run_command(cmd) + # success! print "done building PlotDevice.app in ./dist" @@ -330,6 +411,8 @@ class DistCommand(Command): user_options = [] def initialize_options(self): pass def finalize_options(self): pass + sub_commands = Command.sub_commands[:] + sub_commands.append(('wheelhouse', lambda arg: True)) def run(self): APP = 'dist/PlotDevice.app' ZIP = 'dist/PlotDevice_app-%s.zip' % VERSION @@ -403,14 +486,17 @@ def run(self): self.spawn(['spctl', '--assess', '-v', 'dist/PlotDevice.app']) # create versioned zipfile of the app - self.spawn([which('ditto'), '-ck', '--keepParent', APP, ZIP]) + self.spawn([DITTO, '-ck', '--keepParent', APP, ZIP]) # update the app.xml feed (pulled from the server) - release = dict(zipfile=basename(ZIP), bytes=os.path.getsize(ZIP), + release = dict(zipfile=basename(ZIP), bytes=getsize(ZIP), version=VERSION, revision=last_commit(), now=timestamp()) with file('dist/app.xml','w') as f: f.write(merged_feed(release)) + for cmd in self.get_sub_commands(): + self.run_command(cmd) + print "\nBuilt PlotDevice.app, %s, and app.xml in ./dist" % basename(ZIP) print " -" + "\n -".join(commits_since(last_release(), raw=True)) print "now edit dist/app.xml then run `python setup.py submit`." @@ -419,83 +505,85 @@ def run(self): class SubmitCommand(Command): description = "Validate contents of dist subdir then send them to the net" user_options = [] - def initialize_options(self): - pass - def finalize_options(self): - pass + def initialize_options(self): pass + def finalize_options(self): pass def run(self): print "Checking feed xml" gosub('%s -xml -utf8 -e dist/app.xml' % which('tidy'), on_err="app.xml didn't validate properly") - zipfile = 'dist/PlotDevice_app-%s.zip'%VERSION from xml.etree.ElementTree import parse + zipfile = 'dist/PlotDevice_app-%s.zip' % VERSION + SCP = which('scp') + for item in parse('dist/app.xml').getroot().iter('item'): release = item.find('enclosure').attrib - assert release['url'].endswith(basename(zipfile)), "Version mismatch: %s vs %r" % (zipfile, release['url']) + assert release['url'].endswith(basename(zipfile)), "Version mismatch: %s vs %r" % ( + zipfile, release['url']) break # print "posting dist/app.xml" - gosub('%s dist/app.xml plotdevice.io:plod' % which('scp')) + gosub('%s dist/app.xml plotdevice.io:plod' % SCP) print "posting", zipfile - gosub('%s %s plotdevice.io:plod/app' % (which('scp'), zipfile)) + gosub('%s %s plotdevice.io:plod/app' % (SCP, zipfile)) # ## Run Build ## -if __name__=='__main__': +if __name__ == '__main__': # make sure we're at the project root regardless of the cwd # (this means the various commands don't have to play path games) os.chdir(dirname(abspath(__file__))) # common config between module and app builds config = dict( - name = MODULE, - version = VERSION, - description = DESCRIPTION, - long_description = LONG_DESCRIPTION, - author = AUTHOR, - author_email = AUTHOR_EMAIL, - url = URL, - license = LICENSE, - classifiers = CLASSIFIERS, - packages = find_packages(), - scripts = ["app/plotdevice"], + name=MODULE, + version=VERSION, + description=DESCRIPTION, + long_description=LONG_DESCRIPTION, + author=AUTHOR, + author_email=AUTHOR_EMAIL, + url=URL, + license=LICENSE, + classifiers=CLASSIFIERS, + packages=find_packages(), + scripts=["app/plotdevice"], + setup_requires=['wheel>=0.24.0'], zip_safe=False, cmdclass={ 'app': BuildAppCommand, + 'wheelhouse': WheelhouseToApp, 'clean': CleanCommand, 'build_py': BuildCommand, 'dist': DistCommand, 'sdist': BuildDistCommand, 'submit': SubmitCommand, - }, - ) + }) # py2app-specific config # Note how we're not adding the GPUImage framework here, # despite what the paltry docs available, as regards # the subject of py2app and framework-addery, # seem to suggest -- we do it ourselves when executing - # the BuildPy2AppCommand stuf. + # the BuildPy2AppCommand stuff. if 'py2app' in sys.argv: config.update(dict( - app = [{ + app=[{ 'script': "app/plotdevice-app.py", "plist": info_plist(), }], - data_files = [ + data_files=[ "app/Resources/ui", "app/Resources/English.lproj", "app/Resources/PlotDevice.icns", "app/Resources/PlotDeviceFile.icns", "examples", ], - options = { + options={ "py2app": { "iconfile": "app/Resources/PlotDevice.icns", "semi_standalone": True, @@ -504,10 +592,10 @@ def run(self): } }, cmdclass={ + 'wheelhouse': WheelhouseToApp, 'build_py': BuildCommand, 'py2app': BuildPy2AppCommand, - } - )) + })) # begin the build process setup(**config) From 2fb746a27f57b752a9cf7856cdda6b014f4f68fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Bo=CC=88hn?= Date: Tue, 15 Jul 2014 05:09:55 -0700 Subject: [PATCH 57/81] Trimmed 'sub_command' nonsense in setup.py --- setup.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/setup.py b/setup.py index b8d78f79..61a89210 100644 --- a/setup.py +++ b/setup.py @@ -306,13 +306,9 @@ class BuildAppCommand(Command): user_options = [] def initialize_options(self): pass def finalize_options(self): pass - #sub_commands = Command.sub_commands[:] - #sub_commands.append(('wheelhouse', lambda arg: True)) def run(self): self.spawn(['xcodebuild']) remove_tree('dist/PlotDevice.app.dSYM') - for cmd in self.get_sub_commands(): - self.run_command(cmd) print "done building PlotDevice.app in ./dist" try: From d728ea47a26f40e1ac063b898f6493d1c06d5be4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Bo=CC=88hn?= Date: Tue, 15 Jul 2014 06:49:43 -0700 Subject: [PATCH 58/81] Wheelhousing script: ask your doctor about idempotency --- etc/pyobjc-patch-wheelhouse.sh | 37 +++++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/etc/pyobjc-patch-wheelhouse.sh b/etc/pyobjc-patch-wheelhouse.sh index b2897688..03479b2a 100755 --- a/etc/pyobjc-patch-wheelhouse.sh +++ b/etc/pyobjc-patch-wheelhouse.sh @@ -4,6 +4,7 @@ PRAXA_DOWNLOAD_CACHE="cache/downloads" WHEELHOUSE="${PWD}/cache/wheelhouse" mkdir -p $PRAXA_DOWNLOAD_CACHE mkdir -p $WHEELHOUSE +mkdir -p build source "etc/download.sh" source "etc/urlcache.sh" @@ -11,7 +12,9 @@ source "etc/urlcache.sh" PYOBJC_VERSION="2.5.1" PYOBJC_DOWNLOAD_URL="https://bitbucket.org/ronaldoussoren/pyobjc/get/pyobjc-${PYOBJC_VERSION}.zip" PYOBJC_BUILD_PATH="build/pyobjc-${PYOBJC_VERSION}" +PYOBJC_VIRTUALENV="build/pyobjc-virtualenv-${PYOBJC_VERSION}" +rm -rf $PYOBJC_BUILD_PATH $PYOBJC_VIRTUALENV fetch_and_expand $PYOBJC_DOWNLOAD_URL $PYOBJC_BUILD_PATH declare -a names=("AppleScriptKit" \ @@ -61,28 +64,38 @@ PYOBJC_DIR=$PWD/$PYOBJC_BUILD_PATH FIND="for fn in install_lib._install_lib.get_outputs(self):" REPLACE="for fn, _ in result.items():" -########## FIX SETUPS ########## +########## FIX SETUPS ###################################################################### + +cd $PYOBJC_DIR/pyobjc-core && sed -i \~ -e "s#${FIND}#${REPLACE}#" distribute_setup.py +cd $PYOBJC_DIR/pyobjc-core && sed -i \~ -e "s#${FIND}#${REPLACE}#" setup.py +cd $PYOBJC_DIR/pyobjc && sed -i \~ -e "s#${FIND}#${REPLACE}#" distribute_setup.py +cd $PYOBJC_DIR/pyobjc && sed -i \~ -e "s#${FIND}#${REPLACE}#" setup.py + for name in "${names[@]}"; do cd $PYOBJC_DIR && \ cd "pyobjc-framework-${name}" && \ - sed -i \~ -e "s#${FIND}#${REPLACE}#" pyobjc_setup.py + sed -i \~ -e "s#${FIND}#${REPLACE}#" *setup.py done -#cd $PYOBJC_DIR/pyobjc-core && sed -i \~ -e "s#${FIND}#${REPLACE}#" distribute_setup.py -cd $PYOBJC_DIR/pyobjc-core && sed -i \~ -e "s#${FIND}#${REPLACE}#" setup.py -#cd $PYOBJC_DIR/pyobjc && sed -i \~ -e "s#${FIND}#${REPLACE}#" distribute_setup.py -#cd $PYOBJC_DIR/pyobjc && sed -i \~ -e "s#${FIND}#${REPLACE}#" setup.py - find $PYOBJC_DIR -name \*.py~ -print -delete -########## WHEELHOUSE ########## -#mkdir -p $WHEELHOUSE +########## LOCAL INSTALL ################################################################### + +virtualenv -v -p `which python` $PYOBJC_VIRTUALENV +source $PYOBJC_VIRTUALENV/bin/activate + +cd $PYOBJC_DIR/pyobjc-core && pip install --verbose --no-deps . +cd $PYOBJC_DIR/pyobjc && pip install --verbose . + +########## WHEELHOUSE ###################################################################### + +pip install -U wheel + +cd $PYOBJC_DIR/pyobjc-core && pip wheel --verbose --no-deps -w $WHEELHOUSE . +cd $PYOBJC_DIR/pyobjc && pip wheel --verbose --no-deps -w $WHEELHOUSE . for name in "${names[@]}"; do cd $PYOBJC_DIR && \ cd "pyobjc-framework-${name}" && \ pip wheel --verbose --no-deps -w $WHEELHOUSE . done - -cd $PYOBJC_DIR/pyobjc-core && pip wheel --verbose --no-deps -w $WHEELHOUSE . -cd $PYOBJC_DIR/pyobjc && pip wheel --verbose --no-deps -w $WHEELHOUSE . From 0eab89a1148b039a5753bb72d11766f68d1ce4bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Bo=CC=88hn?= Date: Tue, 15 Jul 2014 07:08:07 -0700 Subject: [PATCH 59/81] Shush --- PlotDevice.xcodeproj/project.pbxproj | 1 + 1 file changed, 1 insertion(+) diff --git a/PlotDevice.xcodeproj/project.pbxproj b/PlotDevice.xcodeproj/project.pbxproj index 596b696a..3cf65ecf 100644 --- a/PlotDevice.xcodeproj/project.pbxproj +++ b/PlotDevice.xcodeproj/project.pbxproj @@ -524,6 +524,7 @@ runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\n#echo \"YO DOGG\"\n\n#app=\"${TARGET_BUILD_DIR}/${WRAPPER_NAME}\"\nframeworks=\"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}\"\nresources=\"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}\"\nplotdevice=\"${resources}/python/plotdevice\"\n\n#/usr/local/bin/terminal-notifier -message \"Running RELEASE Post-Build Actions\"\n\n#echo \"SOURCIN\"\nsource ${SOURCE_ROOT}/etc/relpath.sh\n\ncd $plotdevice\necho \"LINKIN\"\nif [ ! -h ${plotdevice}/Frameworks ]; then\n /bin/ln -s `relpath $plotdevice $frameworks` Frameworks\nfi\n\n"; + showEnvVarsInLog = 0; }; CFC51073197545B90046C918 /* Install Wheelhouse Packages to App Bundle */ = { isa = PBXShellScriptBuildPhase; From 6dba15fed4f0aa2195b87a8b69e6ab08f90c72e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Bo=CC=88hn?= Date: Tue, 15 Jul 2014 13:01:17 -0700 Subject: [PATCH 60/81] Apple-T opens embedded bpython with PlotDevice.app env loaded --- PlotDevice.xcodeproj/project.pbxproj | 4 +++ app/Resources/English.lproj/MainMenu.xib | 8 +++++- app/plotdevice-term.py | 16 ++++++++++++ plotdevice/gfx/atoms.py | 16 ++++++++++++ plotdevice/gui/app.py | 16 ++++++++++++ setup.py | 32 +++++++++++++++++++++--- 6 files changed, 88 insertions(+), 4 deletions(-) create mode 100755 app/plotdevice-term.py diff --git a/PlotDevice.xcodeproj/project.pbxproj b/PlotDevice.xcodeproj/project.pbxproj index 3cf65ecf..b2471d11 100644 --- a/PlotDevice.xcodeproj/project.pbxproj +++ b/PlotDevice.xcodeproj/project.pbxproj @@ -38,6 +38,7 @@ 8D15AC340486D014006FF6A4 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A7FEA54F5311CA2CBB /* Cocoa.framework */; }; CF04731D196B71C200E3C358 /* GPUImage.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CF04731C196B71C200E3C358 /* GPUImage.framework */; }; CF047321196B744C00E3C358 /* GPUImage.framework in Copy Private Frameworks */ = {isa = PBXBuildFile; fileRef = CF04731C196B71C200E3C358 /* GPUImage.framework */; }; + CF0CB1E21975B76A00511DC8 /* plotdevice-term.py in Resources */ = {isa = PBXBuildFile; fileRef = CF0CB1E11975B76A00511DC8 /* plotdevice-term.py */; }; CF29B4BE196C51B70092593E /* Python.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CF29B4BC196C51410092593E /* Python.framework */; }; CFC5106F197545210046C918 /* pyobjc-patch-wheelhouse.sh in Resources */ = {isa = PBXBuildFile; fileRef = CFC5106B197545210046C918 /* pyobjc-patch-wheelhouse.sh */; }; CFC51070197545210046C918 /* urlcache.sh in Resources */ = {isa = PBXBuildFile; fileRef = CFC5106C197545210046C918 /* urlcache.sh */; }; @@ -170,6 +171,7 @@ 6155D9F313E2B79E00675A92 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = README.md; sourceTree = ""; }; 8D15AC370486D014006FF6A4 /* PlotDevice.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = PlotDevice.app; sourceTree = BUILT_PRODUCTS_DIR; }; CF04731C196B71C200E3C358 /* GPUImage.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GPUImage.framework; path = app/Frameworks/GPUImage.framework; sourceTree = SOURCE_ROOT; }; + CF0CB1E11975B76A00511DC8 /* plotdevice-term.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; name = "plotdevice-term.py"; path = "app/plotdevice-term.py"; sourceTree = ""; }; CF29B4BC196C51410092593E /* Python.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Python.framework; path = /usr/local/Cellar/python/2.7.8/Frameworks/Python.framework; sourceTree = ""; }; CF61A9FF196DF61600BDFF1D /* relpath.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = relpath.sh; sourceTree = ""; }; CFC5106B197545210046C918 /* pyobjc-patch-wheelhouse.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = "pyobjc-patch-wheelhouse.sh"; sourceTree = ""; }; @@ -280,6 +282,7 @@ 2A37F4AFFDCFA73011CA2CEA /* Other Sources */ = { isa = PBXGroup; children = ( + CF0CB1E11975B76A00511DC8 /* plotdevice-term.py */, 2ABDB7671867D8160069EFC3 /* plotdevice-app.py */, 2ABDB7681867D8160069EFC3 /* main.m */, 2ABDB7691867D8160069EFC3 /* PlotDevice_Prefix.pch */, @@ -476,6 +479,7 @@ 2ABDB76E1867D8BB0069EFC3 /* plotdevice-app.py in Resources */, 611CC49810BA8B9E00B55455 /* Credits.rtf in Resources */, 611CC49C10BA8B9E00B55455 /* InfoPlist.strings in Resources */, + CF0CB1E21975B76A00511DC8 /* plotdevice-term.py in Resources */, 611CC4A110BA8B9E00B55455 /* PlotDevice.icns in Resources */, 2A93AE751903326E00C6144D /* placeholder.pdf in Resources */, 611CC4A210BA8B9E00B55455 /* PlotDeviceFile.icns in Resources */, diff --git a/app/Resources/English.lproj/MainMenu.xib b/app/Resources/English.lproj/MainMenu.xib index 91e0ae34..39d6fd11 100644 --- a/app/Resources/English.lproj/MainMenu.xib +++ b/app/Resources/English.lproj/MainMenu.xib @@ -1,5 +1,5 @@ - + @@ -441,6 +441,12 @@ CQ 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]v3a9!oS?7so; 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

b-fWUKjtnDV4)bZJf zS*;(yw_~KbS!npa+_mEG`7hrwZhJ4)e7S)i+0cYzuAb%ryqhm~X$3fer+L71ZIKQX zA^jF>-n1I#CT4hs*)0w83z(%Xf9w!oZUi#w1;!n%D;7YuET*;PiAV9orZc z^8&{k74ZT;6zf;r3!E^`_X2-GJYISK12W{GH+G?Xe+SzM`w``^^ew&{FnaG?#A-^eQ99E@~c3U-B+nLi~fw+ zSYF4=IwQ!+s*?V{(LJ6N&r6!9ez%V017^TnbuXzApw+yjhDuMpq^dK7&_?%Henl8t z^}WVeei5;GVe%ugjme{6(jUuD_Hq{lxxFO!UybFL(fd4AuWDOE)yF7B9m|IrXF8Vu zUwow}St1bD4+xlB_lGCn$GxnKAWObuDdPD4^gzBX@T)y9^c%CI>Auo)fL4?5Jd!+L z=|Ls5(Y;Hd*10$9dky(E@Hn|bF+~YRz@#tVUx=4W6;26qPm|n#CEvX<<(_;WJfwzv z>nKH)@6V&8%8?1BTB23-XAk|1n&=hacs|jK)zNo9A6={Nf?A?^SE;sEy5m4q38q=1 zX)-iB$yR`n3AZGS#mzscpO2@fI z#VpacBbAC+qJaSwo%7m!^!v%aCAtXddgUDoWW*A^1`V@BO^ifniJXvpRzO}l-vq@` zOLQ)ee{YF?dzbpDB^nJZmS{Z*QA>0@$)V5uEj-Km+%DNVdPkcYn(+H+K~rw#F-;S^ zohQC)+gxKI>e}9}REccP1t;hQ@zU)XyryC!7fIv!KJ6f5p*O)PTC@>7nA_P6#zUX> zP=lKExhLc7oV4scEPL$_es=w|?9HlFiTif?*+0Ic#A(XGj345@c0MTLzB+ViNh~=~ z6N8ZZSNJcIep?i{&J;fm&ruRij(O@u%e{7LAibw~M0yrUkR35LJw3*1UD4~2?XyLt|inm0#%8rQbu?J3YYb@x6&QYn|L>uwe%H; z1kP?JT7~)@0|CE&>UhrZ@I%M*K*KY~vx<_bTRqTF7Rmuaed@OY%qP<@PcqDNLd@qBQ(HaFwY|kp4_w=u zYott1PYLEMx}3g3CmpH3{v^bc>2s-T-alWd@XNkafzHnn z%OY#u%_z^-ydOc&r9a=>B<$z9@|^`~ZwT8y%PuE5bxc)@{<>BwaqrJsw>9p{lOv+H>wyq|DMg2d{R+c5_Y+CX?GCeM z*q^D48uq~kbtaT8`>wR?E|y(;i=RE!vXR1_7>FDU38-9{Q!FTYn%ms&IV--HK-1h+@|MjFB2>f4;1kMz}6P4F!bjFIXL$ z8Ng=?ernSlTX4TWg)C;Om!Z#$b2$=BIR1kk=(xPq8M2E2f<-ruSJ=6{4U@K6<}SJt zAeXtvqG-NzIUc?M7^nsoB=&|AtaJGc^v%1>JppVxn;nnh%}?X(O@&z$wdQ8Wz0~nc zb++F~ZuM<`DyRSE0imMK<$zM5bNMpOT<$XWlW{|)wiNS&sqZJi^f;Gc&`{^{M@qtV zE+@O>zu}NaCE52#8F4O;0$A9&H0BQS0>PI#>@@H$G6YF}2Vk?=@deO^>@>f}m7N3I zoZM@X3%NL?&5qqDW-Iu%OJcTG@WQ*@3jWQ_olvv_u(@0)dc!fj{uH~IpF@J;LZ7q{ zQZn+y(~;nHp^rwg4XYTBLJkkrirX&s@?#=sW&g1cqz1-rlRxl>zi_^Y9Zy|f0&Qyj z9=ppr!gI9D6F`RajYbpIAU=G**Iot{Yd5eo`v;oM!JG&35P%ns!3E0wK;X@xTe6QV zV5KS94hXWmrFLD_7W*>Hv z#7th9V_HyP(aCforcrkc%aQKXtlHI%w>%Pzru@d3GRiTQlxSnpS+@}@7bv&V=oxD(b_h9JAt)cYJ(AMl>p(7<} z>)xAL22$t=Vy*BX@;{%x%){ZmV8$g_nNU;nlF4MQ3UchhfE_x7|U7 z!2e|`zbGae^X}t}b5e3(Ye@jFw30a(kw@s+<9$HVv2Yi188x{Bf0>9H ze%vSRxc5H1c$MALETVAYJC4TSI2Zf8iBx@!`(;2F=$~zofrg-zOu(d`{bq}fzb515 z)6IZH4BpRY^ZQ3<*AZo)r0lz+tcoQ0hS(@@>wv+?@T8B7V^#$|dFnao1(10{7k$^mxVoyGG$p_Ixma zSA)la`*T;%oH*2!ehP0CjsRCX?#I5?P~B$0?0{!ctT8?H2P-9W0#0Ex|e;eB`?vmZ40vMRd0r23S}|IH}ak%ZS-YiC!K9c z|E(p1#q_xYqt5CKmG*7H2kpn+T{;pMAuoldl#ksa@Fjq+*^>Pt8YPm}*;LxMqb2T2pMjE>zwMo6_FgUwRiF%J znJ>T7&NA!o@y;@LDb_?_=`54>Wq(1lCpp=1U-mVceY%tVLCuCJeiu$Ndaoos)?IPI zTdMwdlfE)1{gX(i>PIzQn5kZaMDY;C{K-|mi#VkE>i=wj`STn`?&nxML*CMlh%2FB^x%7D;TFKANfcU5nq)DoU6+J2?_5 zx;XgP+d;rt96TBoMxQ*!W%Opu9m41k*TQC=a~Zvo*<^HYPIeBXTbZ59=dxTxOpe%e@|)2BnvY`&|2 zf+PJlq(c-vr@C$}g86Brmu_|tN7i1A1ip8@dv0OR@jbF|5YO>KGCNRqOqPG(GIpbg zV=zkB+)WV~D0%m{ygEHb%iM$Gn$YQoORY|iN40JU_1R9L{KRusr~iiKx|_X2v-ddJ z&uTV0@JS2}l`wmxXHk6w98t^%dyxj4ZZt7deE_(n=K+%^jZ5FDXOvHIO8$9+x8!Cm`JZmd6LL!a zd6TX4E?>ztS~BI9d<2+&S=cElALfDQ4}14^Hx)|vPZuXkj7Fx5iy`3{{lv5UgAmu{ zjh@j@o{5nUTF%6&IacxSe})tM&&Oi5oEbY0H8Q*fm%kRpja8fkFmGy+@N*C-+y6g>!uWN1P;|?|%_E@%a8r8a%%L)hL2a%kljqCe`EnfBN@DeE%ar4w~45 zC`3`;{|ohwCN~4`AXD{sC4?b;|C@H{`!i9w^!>{q2>KR*vVV)z@D*`BaJ(mbClq@7D31M!mjiCRapnmi-UW~z|E53IVJJrt+(NKn)M(_M z?-nX)0o=3$1a$hD!z|}#?R@ynsD1?)gxin%z)uJyPl4G!Q`5V_)==5S;0kwcBE96f z?*oyyhNtEN>lnqFEm%_(>kOp72A336f7vEfY3;u`mQj@>&^g3hlraQn*wL>h{xcDm@(NCr2JFa@sfAqMVg0> ztG)qchstg|N^dEP!3#$rW;{Tm17&wYJJv=VIUJU~dBU;|}(LSq}DVIy|I(v4gz<*gGBUhYU7` z`UDPj_IM&@YH#Y1p?KvoXDE&%7rf}GcB$t53VCSx$Y*$aG6Li~vVS45^aJRX9g#8^nMHJQa5aVS&nh{>W5?|t2XLOfNu9)EFv=!WdSDX=MflLA|^YXO)Jm@Fz$ zHW!3hX=dy_{{;wRXY${XoBuU`{(cAxn0Ct#n0ziu-_Huu_Y*u;Kwbujm(>d$^3{mQ z2T&RdwW z*{j$CXR`pxo`;m|9)pX|qnwp}z%BT!2$Xz05IvRc<}f}sdpmjtlfa3`{S_B9JFEWD zwOsW>?6L=D0@}6)&?Z2r^%bn**|DJURZwh6{~pWKpDMn%NSew7@SpdP!D|0og+ zhxc8IAxh)rN8T-KWyu`qw(B_GbcMh44N=X~Q4z-$Qk!cedUza_eu8E4}l`txu0Tayd;g-6V` zP&|Nu;%gGc$&P0uaeWG?KJgv)8ysnTrwHJxnIi+q!_Uo}Q1wD9lKy=p=005QyQ6Uz zBn>j zyUrBF;|+a?z9-~T&}8&fEeWpPc45v?p^no~mJ;HG{HhPY?ShRO@#aWTbPi{^^nJ;Gi2%$TS+PG` z!lvPCvn?Reh3~6kFn8@}+=HnCGslzo!GGi~m-(fukFiX+-*J?@Lhhf;2z2o-3 z;ey3$_hn0%x_Vpr2VIM$tJv#ayl?~y@Jq*ISQR2Nq7pJ$ECjbOYKxG8DFQ87%Nr%} zcYxPI(y2MMG3Q>@`XF{ZFfJecEJf+aP=cS;1KJ`GYuO~w2tXSJ zf?Kq9gFtge16&WV;#WdAGa$I;7EW@P-3&J$dF!y7hmF(E@Mcb2ixtGpm$oqwjK7>O z6K7LqJ~BR|wamoF4XURu1fS{qq#--9Uj{9xH5N+9`d4Hj9XowoIK`0FocT7%YxZnp z!&T-th5i!l>0?9Yo%M#dX;QO@88r* z=}nT}Lu&T|mH0G_kJcR;x<7Q*7qj59^!kVJbnf{yBRLanct&!l?EQbG%sOMZ_7)Th zW$ux#y}Agy;+!6=pPF8TQDDu4FsT1uuzr?Q_%(Zb(zn8X~3&+xN;mkz!Q zza?5DUePQS@6UWqs-uE^75P*!+>yrX$x9An&A2sgN8=_{vb&9vVT+3yTSE9w0QOV> z?xd34T_MT4nlf`Be~sCu%;8O$d5|k?Xp1vf3;B%dvS`$Ak>_gE0+168dJY=(Gh~TILBsI=C$gF|UsH`@_C93iYt-{ni|W06 zWZGP)Y(6t>)Zx(eg*6?%fciqpE$Kfu4ee+?>mF5^XT2(;W}^B?Hpn%8c>nuVN}$vC zYrmr^Bi$D|gWV@y`R*^X_n|URN?OT9EQZmrDnoJds!SKqI`hAm`^IFyzC4TH>UWkb zM-AvO{|YRGc?jvw)jjxq0e(B{H~gNTlYfpk-|KFaLy#MBtuDT9gh=RT4#QXuTr**W zF7fXNBXBDq2iV9hUGo6c56rae#3JoM03|D5;zAAIIWIkb3x1ca9OUoIuwpxAF%m8W z(lIUAjDE1^91dCmACZvD zwxWKh{gzQpLl383Xio3NFg(^-Lxq?PiNB~01KsS zzJ^Q~_Ry=lL#tmq5ZbYYpT-K6&fOY%b(h?o8Cv@w_#1b^C-`js#HiBp`@!N?y{u_B z-VIJa6x#hfLXV-<&*HwO$9Z4VW!n*&<=5B{x8hFm2Q+o#9n>O8ga5st>D9;3TL+qU>|hVH zl+Jyl>D4EG1R>|!PKum4AWI8{Rk2r3tAKAs?MA>s$q4wZD&V^?$TryfXACM;zbm%v8T5vsl?}$l5ppBgnFQpoLT% z1mH{8tYXcX+6Rc2!IiMDBHVQVvb0S;G*>!zFQn^7us@Kc>J^}ZRyBO?4fMpQ )v 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 Cr3R+} diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GLProgram.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GLProgram.h deleted file mode 100755 index 572d8ae9..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GLProgram.h +++ /dev/null @@ -1,42 +0,0 @@ -// This is Jeff LaMarche's GLProgram OpenGL shader wrapper class from his OpenGL ES 2.0 book. -// A description of this can be found at his page on the topic: -// http://iphonedevelopment.blogspot.com/2010/11/opengl-es-20-for-ios-chapter-4.html -// I've extended this to be able to take programs as NSStrings in addition to files, for baked-in shaders - -#import - -#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE -#import -#import -#else -#import -#import -#endif - -@interface GLProgram : NSObject -{ - NSMutableArray *attributes; - NSMutableArray *uniforms; - GLuint program, - vertShader, - fragShader; -} - -@property(readwrite, nonatomic) BOOL initialized; - -- (id)initWithVertexShaderString:(NSString *)vShaderString - fragmentShaderString:(NSString *)fShaderString; -- (id)initWithVertexShaderString:(NSString *)vShaderString - fragmentShaderFilename:(NSString *)fShaderFilename; -- (id)initWithVertexShaderFilename:(NSString *)vShaderFilename - fragmentShaderFilename:(NSString *)fShaderFilename; -- (void)addAttribute:(NSString *)attributeName; -- (GLuint)attributeIndex:(NSString *)attributeName; -- (GLuint)uniformIndex:(NSString *)uniformName; -- (BOOL)link; -- (void)use; -- (NSString *)vertexShaderLog; -- (NSString *)fragmentShaderLog; -- (NSString *)programLog; -- (void)validate; -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImage.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImage.h deleted file mode 100755 index 5a2374aa..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImage.h +++ /dev/null @@ -1,155 +0,0 @@ -#import - -// Base classes -#import -#import - -// Sources -#import -#import -#import -#import -#import - -// Filters -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import - -// Outputs -#import -#import diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImage3x3ConvolutionFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImage3x3ConvolutionFilter.h deleted file mode 100755 index 67e68def..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImage3x3ConvolutionFilter.h +++ /dev/null @@ -1,18 +0,0 @@ -#import "GPUImage3x3TextureSamplingFilter.h" - -/** Runs a 3x3 convolution kernel against the image - */ -@interface GPUImage3x3ConvolutionFilter : GPUImage3x3TextureSamplingFilter -{ - GLint convolutionMatrixUniform; -} - -/** Convolution kernel to run against the image - - The convolution kernel is a 3x3 matrix of values to apply to the pixel and its 8 surrounding pixels. - The matrix is specified in row-major order, with the top left pixel being one.one and the bottom right three.three - If the values in the matrix don't add up to 1.0, the image could be brightened or darkened. - */ -@property(readwrite, nonatomic) GPUMatrix3x3 convolutionKernel; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImage3x3TextureSamplingFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImage3x3TextureSamplingFilter.h deleted file mode 100644 index 5599e156..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImage3x3TextureSamplingFilter.h +++ /dev/null @@ -1,18 +0,0 @@ -#import "GPUImageFilter.h" - -extern NSString *const kGPUImageNearbyTexelSamplingVertexShaderString; - -@interface GPUImage3x3TextureSamplingFilter : GPUImageFilter -{ - GLint texelWidthUniform, texelHeightUniform; - - CGFloat texelWidth, texelHeight; - BOOL hasOverriddenImageSizeFactor; -} - -// The texel width and height determines how far out to sample from this texel. By default, this is the normalized width of a pixel, but this can be overridden for different effects. -@property(readwrite, nonatomic) CGFloat texelWidth; -@property(readwrite, nonatomic) CGFloat texelHeight; - - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageAVCamera.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageAVCamera.h deleted file mode 100755 index 54c1a2f7..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageAVCamera.h +++ /dev/null @@ -1,132 +0,0 @@ -#import -#import -#import -#import "GPUImageContext.h" -#import "GPUImageOutput.h" - -//Delegate Protocal for Face Detection. -@protocol GPUImageVideoCameraDelegate - -@optional -- (void)willOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer; -@end - - -/** - A GPUImageOutput that provides frames from either camera -*/ -@interface GPUImageAVCamera : GPUImageOutput -{ - NSUInteger numberOfFramesCaptured; - CGFloat totalFrameTimeDuringCapture; - - AVCaptureSession *_captureSession; - AVCaptureDevice *_inputCamera; - AVCaptureDevice *_microphone; - AVCaptureDeviceInput *videoInput; - AVCaptureVideoDataOutput *videoOutput; - - BOOL capturePaused; - GPUImageRotationMode outputRotation; - dispatch_semaphore_t frameRenderingSemaphore; - - BOOL captureAsYUV; - GLuint luminanceTexture, chrominanceTexture; - - __unsafe_unretained id _delegate; -} - -/// The AVCaptureSession used to capture from the camera -@property(readonly, retain, nonatomic) AVCaptureSession *captureSession; - -/// This enables the capture session preset to be changed on the fly -@property (readwrite, nonatomic, copy) NSString *captureSessionPreset; - -/// This sets the frame rate of the camera (iOS 5 and above only) -/** - Setting this to 0 or below will set the frame rate back to the default setting for a particular preset. - */ -@property (readwrite) NSInteger frameRate; - -/// Easy way to tell if front-facing camera is present on device -@property (readonly, getter = isFrontFacingCameraPresent) BOOL frontFacingCameraPresent; - -/// This enables the benchmarking mode, which logs out instantaneous and average frame times to the console -@property(readwrite, nonatomic) BOOL runBenchmark; - -/// Use this property to manage camera settings. Focus point, exposure point, etc. -@property(readonly) AVCaptureDevice *inputCamera; - -/// These properties determine whether or not the two camera orientations should be mirrored. By default, both are NO. -@property(readwrite, nonatomic) BOOL horizontallyMirrorFrontFacingCamera, horizontallyMirrorRearFacingCamera; - -@property(nonatomic, assign) id delegate; - -/// @name Initialization and teardown - -+ (NSArray *)connectedCameraDevices; - -/** Begin a capture session - - See AVCaptureSession for acceptable values - - @param sessionPreset Session preset to use - @param cameraPosition Camera to capture from - */ -- (id)initWithDeviceUniqueID:(NSString *)deviceUniqueID; -- (id)initWithSessionPreset:(NSString *)sessionPreset deviceUniqueID:(NSString *)deviceUniqueID; -- (id)initWithSessionPreset:(NSString *)sessionPreset cameraDevice:(AVCaptureDevice *)cameraDevice; - -/** Tear down the capture session - */ -- (void)removeInputsAndOutputs; - -/// @name Manage the camera video stream - -/** Start camera capturing - */ -- (void)startCameraCapture; - -/** Stop camera capturing - */ -- (void)stopCameraCapture; - -/** Pause camera capturing - */ -- (void)pauseCameraCapture; - -/** Resume camera capturing - */ -- (void)resumeCameraCapture; - -/** Process a video sample - @param sampleBuffer Buffer to process - */ -- (void)processVideoSampleBuffer:(CMSampleBufferRef)sampleBuffer; - -/** Process an audio sample - @param sampleBuffer Buffer to process - */ -- (void)processAudioSampleBuffer:(CMSampleBufferRef)sampleBuffer; - -/** Get the position (front, rear) of the source camera - */ -- (AVCaptureDevicePosition)cameraPosition; - -/** Get the AVCaptureConnection of the source camera - */ -- (AVCaptureConnection *)videoCaptureConnection; - -/** This flips between the front and rear cameras - */ -- (void)rotateCamera; - -/// @name Benchmarking - -/** When benchmarking is enabled, this will keep a running average of the time from uploading, processing, and final recording or display - */ -- (CGFloat)averageFrameDurationDuringCapture; - -- (void)printSupportedPixelFormats; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageAdaptiveThresholdFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageAdaptiveThresholdFilter.h deleted file mode 100755 index 32785560..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageAdaptiveThresholdFilter.h +++ /dev/null @@ -1,9 +0,0 @@ -#import "GPUImageFilterGroup.h" - -@interface GPUImageAdaptiveThresholdFilter : GPUImageFilterGroup - -/** A multiplier for the background averaging blur radius in pixels, with a default of 4 - */ -@property(readwrite, nonatomic) CGFloat blurRadiusInPixels; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageAddBlendFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageAddBlendFilter.h deleted file mode 100644 index b14c60c6..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageAddBlendFilter.h +++ /dev/null @@ -1,5 +0,0 @@ -#import "GPUImageTwoInputFilter.h" - -@interface GPUImageAddBlendFilter : GPUImageTwoInputFilter - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageAlphaBlendFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageAlphaBlendFilter.h deleted file mode 100755 index c4d75759..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageAlphaBlendFilter.h +++ /dev/null @@ -1,11 +0,0 @@ -#import "GPUImageTwoInputFilter.h" - -@interface GPUImageAlphaBlendFilter : GPUImageTwoInputFilter -{ - GLint mixUniform; -} - -// Mix ranges from 0.0 (only image 1) to 1.0 (only image 2), with 1.0 as the normal level -@property(readwrite, nonatomic) CGFloat mix; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageAmatorkaFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageAmatorkaFilter.h deleted file mode 100755 index 1dbe096d..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageAmatorkaFilter.h +++ /dev/null @@ -1,17 +0,0 @@ -#import "GPUImageFilterGroup.h" - -@class GPUImagePicture; - -/** A photo filter based on Photoshop action by Amatorka - http://amatorka.deviantart.com/art/Amatorka-Action-2-121069631 - */ - -// Note: If you want to use this effect you have to add lookup_amatorka.png -// from Resources folder to your application bundle. - -@interface GPUImageAmatorkaFilter : GPUImageFilterGroup -{ - GPUImagePicture *lookupImageSource; -} - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageAverageColor.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageAverageColor.h deleted file mode 100644 index e3d957d0..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageAverageColor.h +++ /dev/null @@ -1,20 +0,0 @@ -#import "GPUImageFilter.h" - -extern NSString *const kGPUImageColorAveragingVertexShaderString; - -@interface GPUImageAverageColor : GPUImageFilter -{ - GLint texelWidthUniform, texelHeightUniform; - - NSUInteger numberOfStages; - - GLubyte *rawImagePixels; - CGSize finalStageSize; -} - -// This block is called on the completion of color averaging for a frame -@property(nonatomic, copy) void(^colorAverageProcessingFinishedBlock)(CGFloat redComponent, CGFloat greenComponent, CGFloat blueComponent, CGFloat alphaComponent, CMTime frameTime); - -- (void)extractAverageColorAtFrameTime:(CMTime)frameTime; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageAverageLuminanceThresholdFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageAverageLuminanceThresholdFilter.h deleted file mode 100644 index 7f1ae464..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageAverageLuminanceThresholdFilter.h +++ /dev/null @@ -1,8 +0,0 @@ -#import "GPUImageFilterGroup.h" - -@interface GPUImageAverageLuminanceThresholdFilter : GPUImageFilterGroup - -// This is multiplied by the continually calculated average image luminosity to arrive at the final threshold. Default is 1.0. -@property(readwrite, nonatomic) CGFloat thresholdMultiplier; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageBilateralFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageBilateralFilter.h deleted file mode 100644 index 6b736ccf..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageBilateralFilter.h +++ /dev/null @@ -1,10 +0,0 @@ -#import "GPUImageGaussianBlurFilter.h" - -@interface GPUImageBilateralFilter : GPUImageGaussianBlurFilter -{ - CGFloat firstDistanceNormalizationFactorUniform; - CGFloat secondDistanceNormalizationFactorUniform; -} -// A normalization factor for the distance between central color and sample color. -@property(nonatomic, readwrite) CGFloat distanceNormalizationFactor; -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageBoxBlurFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageBoxBlurFilter.h deleted file mode 100755 index 3fd880bf..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageBoxBlurFilter.h +++ /dev/null @@ -1,7 +0,0 @@ -#import "GPUImageGaussianBlurFilter.h" - -/** A hardware-accelerated box blur of an image - */ -@interface GPUImageBoxBlurFilter : GPUImageGaussianBlurFilter - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageBrightnessFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageBrightnessFilter.h deleted file mode 100755 index 046473b9..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageBrightnessFilter.h +++ /dev/null @@ -1,11 +0,0 @@ -#import "GPUImageFilter.h" - -@interface GPUImageBrightnessFilter : GPUImageFilter -{ - GLint brightnessUniform; -} - -// Brightness ranges from -1.0 to 1.0, with 0.0 as the normal level -@property(readwrite, nonatomic) CGFloat brightness; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageBuffer.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageBuffer.h deleted file mode 100644 index caf09c8d..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageBuffer.h +++ /dev/null @@ -1,10 +0,0 @@ -#import "GPUImageFilter.h" - -@interface GPUImageBuffer : GPUImageFilter -{ - NSMutableArray *bufferedFramebuffers; -} - -@property(readwrite, nonatomic) NSUInteger bufferSize; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageBulgeDistortionFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageBulgeDistortionFilter.h deleted file mode 100755 index d416e536..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageBulgeDistortionFilter.h +++ /dev/null @@ -1,16 +0,0 @@ -#import "GPUImageFilter.h" - -/// Creates a bulge distortion on the image -@interface GPUImageBulgeDistortionFilter : GPUImageFilter -{ - GLint aspectRatioUniform, radiusUniform, centerUniform, scaleUniform; -} - -/// The center about which to apply the distortion, with a default of (0.5, 0.5) -@property(readwrite, nonatomic) CGPoint center; -/// The radius of the distortion, ranging from 0.0 to 1.0, with a default of 0.25 -@property(readwrite, nonatomic) CGFloat radius; -/// The amount of distortion to apply, from -1.0 to 1.0, with a default of 0.5 -@property(readwrite, nonatomic) CGFloat scale; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageCGAColorspaceFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageCGAColorspaceFilter.h deleted file mode 100755 index 4f97804b..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageCGAColorspaceFilter.h +++ /dev/null @@ -1,5 +0,0 @@ -#import "GPUImageFilter.h" - -@interface GPUImageCGAColorspaceFilter : GPUImageFilter - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageCannyEdgeDetectionFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageCannyEdgeDetectionFilter.h deleted file mode 100755 index e01a6433..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageCannyEdgeDetectionFilter.h +++ /dev/null @@ -1,62 +0,0 @@ -#import "GPUImageFilterGroup.h" - -@class GPUImageGrayscaleFilter; -@class GPUImageSingleComponentGaussianBlurFilter; -@class GPUimageDirectionalSobelEdgeDetectionFilter; -@class GPUImageDirectionalNonMaximumSuppressionFilter; -@class GPUImageWeakPixelInclusionFilter; - -/** This applies the edge detection process described by John Canny in - - Canny, J., A Computational Approach To Edge Detection, IEEE Trans. Pattern Analysis and Machine Intelligence, 8(6):679–698, 1986. - - and implemented in OpenGL ES by - - A. Ensor, S. Hall. GPU-based Image Analysis on Mobile Devices. Proceedings of Image and Vision Computing New Zealand 2011. - - It starts with a conversion to luminance, followed by an accelerated 9-hit Gaussian blur. A Sobel operator is applied to obtain the overall - gradient strength in the blurred image, as well as the direction (in texture sampling steps) of the gradient. A non-maximum suppression filter - acts along the direction of the gradient, highlighting strong edges that pass the threshold and completely removing those that fail the lower - threshold. Finally, pixels from in-between these thresholds are either included in edges or rejected based on neighboring pixels. - */ -@interface GPUImageCannyEdgeDetectionFilter : GPUImageFilterGroup -{ - GPUImageGrayscaleFilter *luminanceFilter; - GPUImageSingleComponentGaussianBlurFilter *blurFilter; - GPUimageDirectionalSobelEdgeDetectionFilter *edgeDetectionFilter; - GPUImageDirectionalNonMaximumSuppressionFilter *nonMaximumSuppressionFilter; - GPUImageWeakPixelInclusionFilter *weakPixelInclusionFilter; -} - -/** The image width and height factors tweak the appearance of the edges. - - These parameters affect the visibility of the detected edges - - By default, they match the inverse of the filter size in pixels - */ -@property(readwrite, nonatomic) CGFloat texelWidth; -/** The image width and height factors tweak the appearance of the edges. - - These parameters affect the visibility of the detected edges - - By default, they match the inverse of the filter size in pixels - */ -@property(readwrite, nonatomic) CGFloat texelHeight; - -/** The underlying blur radius for the Gaussian blur. Default is 2.0. - */ -@property (readwrite, nonatomic) CGFloat blurRadiusInPixels; - -/** The underlying blur texel spacing multiplier. Default is 1.0. - */ -@property (readwrite, nonatomic) CGFloat blurTexelSpacingMultiplier; - -/** Any edge with a gradient magnitude above this threshold will pass and show up in the final result. - */ -@property(readwrite, nonatomic) CGFloat upperThreshold; - -/** Any edge with a gradient magnitude below this threshold will fail and be removed from the final result. - */ -@property(readwrite, nonatomic) CGFloat lowerThreshold; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageChromaKeyBlendFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageChromaKeyBlendFilter.h deleted file mode 100755 index 47f5acbc..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageChromaKeyBlendFilter.h +++ /dev/null @@ -1,32 +0,0 @@ -#import "GPUImageTwoInputFilter.h" - -/** Selectively replaces a color in the first image with the second image - */ -@interface GPUImageChromaKeyBlendFilter : GPUImageTwoInputFilter -{ - GLint colorToReplaceUniform, thresholdSensitivityUniform, smoothingUniform; -} - -/** The threshold sensitivity controls how similar pixels need to be colored to be replaced - - The default value is 0.3 - */ -@property(readwrite, nonatomic) GLfloat thresholdSensitivity; - -/** The degree of smoothing controls how gradually similar colors are replaced in the image - - The default value is 0.1 - */ -@property(readwrite, nonatomic) GLfloat smoothing; - -/** The color to be replaced is specified using individual red, green, and blue components (normalized to 1.0). - - The default is green: (0.0, 1.0, 0.0). - - @param redComponent Red component of color to be replaced - @param greenComponent Green component of color to be replaced - @param blueComponent Blue component of color to be replaced - */ -- (void)setColorToReplaceRed:(GLfloat)redComponent green:(GLfloat)greenComponent blue:(GLfloat)blueComponent; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageChromaKeyFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageChromaKeyFilter.h deleted file mode 100644 index a3d073c8..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageChromaKeyFilter.h +++ /dev/null @@ -1,30 +0,0 @@ -#import "GPUImageFilter.h" - -@interface GPUImageChromaKeyFilter : GPUImageFilter -{ - GLint colorToReplaceUniform, thresholdSensitivityUniform, smoothingUniform; -} - -/** The threshold sensitivity controls how similar pixels need to be colored to be replaced - - The default value is 0.3 - */ -@property(readwrite, nonatomic) GLfloat thresholdSensitivity; - -/** The degree of smoothing controls how gradually similar colors are replaced in the image - - The default value is 0.1 - */ -@property(readwrite, nonatomic) GLfloat smoothing; - -/** The color to be replaced is specified using individual red, green, and blue components (normalized to 1.0). - - The default is green: (0.0, 1.0, 0.0). - - @param redComponent Red component of color to be replaced - @param greenComponent Green component of color to be replaced - @param blueComponent Blue component of color to be replaced - */ -- (void)setColorToReplaceRed:(GLfloat)redComponent green:(GLfloat)greenComponent blue:(GLfloat)blueComponent; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageClosingFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageClosingFilter.h deleted file mode 100644 index 61e34c41..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageClosingFilter.h +++ /dev/null @@ -1,19 +0,0 @@ -#import "GPUImageFilterGroup.h" - -@class GPUImageErosionFilter; -@class GPUImageDilationFilter; - -// A filter that first performs a dilation on the red channel of an image, followed by an erosion of the same radius. -// This helps to filter out smaller dark elements. - -@interface GPUImageClosingFilter : GPUImageFilterGroup -{ - GPUImageErosionFilter *erosionFilter; - GPUImageDilationFilter *dilationFilter; -} - -@property(readwrite, nonatomic) CGFloat verticalTexelSpacing, horizontalTexelSpacing; - -- (id)initWithRadius:(NSUInteger)radius; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageColorBlendFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageColorBlendFilter.h deleted file mode 100644 index 302a16c6..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageColorBlendFilter.h +++ /dev/null @@ -1,5 +0,0 @@ -#import "GPUImageTwoInputFilter.h" - -@interface GPUImageColorBlendFilter : GPUImageTwoInputFilter - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageColorBurnBlendFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageColorBurnBlendFilter.h deleted file mode 100755 index 50ebb3f4..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageColorBurnBlendFilter.h +++ /dev/null @@ -1,9 +0,0 @@ -#import "GPUImageTwoInputFilter.h" - -/** Applies a color burn blend of two images - */ -@interface GPUImageColorBurnBlendFilter : GPUImageTwoInputFilter -{ -} - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageColorDodgeBlendFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageColorDodgeBlendFilter.h deleted file mode 100755 index 0f541c42..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageColorDodgeBlendFilter.h +++ /dev/null @@ -1,9 +0,0 @@ -#import "GPUImageTwoInputFilter.h" - -/** Applies a color dodge blend of two images - */ -@interface GPUImageColorDodgeBlendFilter : GPUImageTwoInputFilter -{ -} - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageColorInvertFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageColorInvertFilter.h deleted file mode 100755 index aaeec438..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageColorInvertFilter.h +++ /dev/null @@ -1,7 +0,0 @@ -#import "GPUImageFilter.h" - -@interface GPUImageColorInvertFilter : GPUImageFilter -{ -} - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageColorMatrixFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageColorMatrixFilter.h deleted file mode 100755 index 75887276..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageColorMatrixFilter.h +++ /dev/null @@ -1,19 +0,0 @@ -#import "GPUImageFilter.h" - -/** Transforms the colors of an image by applying a matrix to them - */ -@interface GPUImageColorMatrixFilter : GPUImageFilter -{ - GLint colorMatrixUniform; - GLint intensityUniform; -} - -/** A 4x4 matrix used to transform each color in an image - */ -@property(readwrite, nonatomic) GPUMatrix4x4 colorMatrix; - -/** The degree to which the new transformed color replaces the original color for each pixel - */ -@property(readwrite, nonatomic) CGFloat intensity; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageColorPackingFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageColorPackingFilter.h deleted file mode 100644 index c2edca51..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageColorPackingFilter.h +++ /dev/null @@ -1,10 +0,0 @@ -#import "GPUImageFilter.h" - -@interface GPUImageColorPackingFilter : GPUImageFilter -{ - GLint texelWidthUniform, texelHeightUniform; - - CGFloat texelWidth, texelHeight; -} - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageContext.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageContext.h deleted file mode 100755 index 356b288a..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageContext.h +++ /dev/null @@ -1,54 +0,0 @@ -#import -#import -#import -#import "GLProgram.h" -#import "GPUImageFramebuffer.h" -#import "GPUImageFramebufferCache.h" - -#define GPUImageRotationSwapsWidthAndHeight(rotation) (((rotation) == kGPUImageRotateLeft) || ((rotation) == kGPUImageRotateRight) || ((rotation) == kGPUImageRotateRightFlipVertical) ) - -typedef enum { kGPUImageNoRotation, kGPUImageRotateLeft, kGPUImageRotateRight, kGPUImageFlipVertical, kGPUImageFlipHorizonal, kGPUImageRotateRightFlipVertical, kGPUImageRotateRightFlipHorizontal, kGPUImageRotate180 } GPUImageRotationMode; - -@interface GPUImageContext : NSObject - -@property(readonly, nonatomic) dispatch_queue_t contextQueue; -@property(readwrite, retain, nonatomic) GLProgram *currentShaderProgram; -@property(readonly, retain, nonatomic) NSOpenGLContext *context; -@property(readonly) GPUImageFramebufferCache *framebufferCache; - -+ (void *)contextKey; -+ (GPUImageContext *)sharedImageProcessingContext; -+ (dispatch_queue_t)sharedContextQueue; -+ (GPUImageFramebufferCache *)sharedFramebufferCache; -+ (void)useImageProcessingContext; -+ (void)setActiveShaderProgram:(GLProgram *)shaderProgram; -+ (GLint)maximumTextureSizeForThisDevice; -+ (GLint)maximumTextureUnitsForThisDevice; -+ (BOOL)deviceSupportsOpenGLESExtension:(NSString *)extension; -+ (BOOL)deviceSupportsRedTextures; -+ (BOOL)deviceSupportsFramebufferReads; -+ (CGSize)sizeThatFitsWithinATextureForSize:(CGSize)inputSize; - -- (void)presentBufferForDisplay; -- (GLProgram *)programForVertexShaderString:(NSString *)vertexShaderString fragmentShaderString:(NSString *)fragmentShaderString; - -- (void)useSharegroup:(CGLShareGroupObj *)sharegroup; - -// Manage fast texture upload -+ (BOOL)supportsFastTextureUpload; - -@end - -@protocol GPUImageInput -- (void)newFrameReadyAtTime:(CMTime)frameTime atIndex:(NSInteger)textureIndex; -- (void)setInputFramebuffer:(GPUImageFramebuffer *)newInputFramebuffer atIndex:(NSInteger)textureIndex; -- (NSInteger)nextAvailableTextureIndex; -- (void)setInputSize:(CGSize)newSize atIndex:(NSInteger)textureIndex; -- (void)setInputRotation:(GPUImageRotationMode)newInputRotation atIndex:(NSInteger)textureIndex; -- (CGSize)maximumOutputSize; -- (void)endProcessing; -- (BOOL)shouldIgnoreUpdatesToThisTarget; -- (BOOL)enabled; -- (BOOL)wantsMonochromeInput; -- (void)setCurrentlyReceivingMonochromeInput:(BOOL)newValue; -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageContrastFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageContrastFilter.h deleted file mode 100755 index e09e6dc4..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageContrastFilter.h +++ /dev/null @@ -1,14 +0,0 @@ -#import "GPUImageFilter.h" - -/** Adjusts the contrast of the image - */ -@interface GPUImageContrastFilter : GPUImageFilter -{ - GLint contrastUniform; -} - -/** Contrast ranges from 0.0 to 4.0 (max contrast), with 1.0 as the normal level - */ -@property(readwrite, nonatomic) CGFloat contrast; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageCropFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageCropFilter.h deleted file mode 100755 index 641fb7bf..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageCropFilter.h +++ /dev/null @@ -1,14 +0,0 @@ -#import "GPUImageFilter.h" - -@interface GPUImageCropFilter : GPUImageFilter -{ - GLfloat cropTextureCoordinates[8]; -} - -// The crop region is the rectangle within the image to crop. It is normalized to a coordinate space from 0.0 to 1.0, with 0.0, 0.0 being the upper left corner of the image -@property(readwrite, nonatomic) CGRect cropRegion; - -// Initialization and teardown -- (id)initWithCropRegion:(CGRect)newCropRegion; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageCrosshairGenerator.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageCrosshairGenerator.h deleted file mode 100644 index 569774f5..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageCrosshairGenerator.h +++ /dev/null @@ -1,17 +0,0 @@ -#import "GPUImageFilter.h" - -@interface GPUImageCrosshairGenerator : GPUImageFilter -{ - GLint crosshairWidthUniform, crosshairColorUniform; -} - -// The width of the displayed crosshairs, in pixels. Currently this only works well for odd widths. The default is 5. -@property(readwrite, nonatomic) CGFloat crosshairWidth; - -// The color of the crosshairs is specified using individual red, green, and blue components (normalized to 1.0). The default is green: (0.0, 1.0, 0.0). -- (void)setCrosshairColorRed:(GLfloat)redComponent green:(GLfloat)greenComponent blue:(GLfloat)blueComponent; - -// Rendering -- (void)renderCrosshairsFromArray:(GLfloat *)crosshairCoordinates count:(NSUInteger)numberOfCrosshairs frameTime:(CMTime)frameTime; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageCrosshatchFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageCrosshatchFilter.h deleted file mode 100755 index dab18967..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageCrosshatchFilter.h +++ /dev/null @@ -1,13 +0,0 @@ -#import "GPUImageFilter.h" - -@interface GPUImageCrosshatchFilter : GPUImageFilter -{ - GLint crossHatchSpacingUniform, lineWidthUniform; -} -// The fractional width of the image to use as the spacing for the crosshatch. The default is 0.03. -@property(readwrite, nonatomic) CGFloat crossHatchSpacing; - -// A relative width for the crosshatch lines. The default is 0.003. -@property(readwrite, nonatomic) CGFloat lineWidth; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageDarkenBlendFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageDarkenBlendFilter.h deleted file mode 100755 index 5dfe3405..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageDarkenBlendFilter.h +++ /dev/null @@ -1,7 +0,0 @@ -#import "GPUImageTwoInputFilter.h" - -@interface GPUImageDarkenBlendFilter : GPUImageTwoInputFilter -{ -} - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageDifferenceBlendFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageDifferenceBlendFilter.h deleted file mode 100755 index 7c7dfc23..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageDifferenceBlendFilter.h +++ /dev/null @@ -1,7 +0,0 @@ -#import "GPUImageTwoInputFilter.h" - -@interface GPUImageDifferenceBlendFilter : GPUImageTwoInputFilter -{ -} - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageDilationFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageDilationFilter.h deleted file mode 100644 index 59423a37..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageDilationFilter.h +++ /dev/null @@ -1,16 +0,0 @@ -#import "GPUImageTwoPassTextureSamplingFilter.h" - -// For each pixel, this sets it to the maximum value of the red channel in a rectangular neighborhood extending out dilationRadius pixels from the center. -// This extends out bright features, and is most commonly used with black-and-white thresholded images. - -extern NSString *const kGPUImageDilationRadiusOneVertexShaderString; -extern NSString *const kGPUImageDilationRadiusTwoVertexShaderString; -extern NSString *const kGPUImageDilationRadiusThreeVertexShaderString; -extern NSString *const kGPUImageDilationRadiusFourVertexShaderString; - -@interface GPUImageDilationFilter : GPUImageTwoPassTextureSamplingFilter - -// Acceptable values for dilationRadius, which sets the distance in pixels to sample out from the center, are 1, 2, 3, and 4. -- (id)initWithRadius:(NSUInteger)dilationRadius; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageDirectionalNonMaximumSuppressionFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageDirectionalNonMaximumSuppressionFilter.h deleted file mode 100644 index fdffb9fb..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageDirectionalNonMaximumSuppressionFilter.h +++ /dev/null @@ -1,19 +0,0 @@ -#import "GPUImageFilter.h" - -@interface GPUImageDirectionalNonMaximumSuppressionFilter : GPUImageFilter -{ - GLint texelWidthUniform, texelHeightUniform; - GLint upperThresholdUniform, lowerThresholdUniform; - - BOOL hasOverriddenImageSizeFactor; -} - -// The texel width and height determines how far out to sample from this texel. By default, this is the normalized width of a pixel, but this can be overridden for different effects. -@property(readwrite, nonatomic) CGFloat texelWidth; -@property(readwrite, nonatomic) CGFloat texelHeight; - -// These thresholds set cutoffs for the intensities that definitely get registered (upper threshold) and those that definitely don't (lower threshold) -@property(readwrite, nonatomic) CGFloat upperThreshold; -@property(readwrite, nonatomic) CGFloat lowerThreshold; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageDissolveBlendFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageDissolveBlendFilter.h deleted file mode 100755 index b4e5720a..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageDissolveBlendFilter.h +++ /dev/null @@ -1,11 +0,0 @@ -#import "GPUImageTwoInputFilter.h" - -@interface GPUImageDissolveBlendFilter : GPUImageTwoInputFilter -{ - GLint mixUniform; -} - -// Mix ranges from 0.0 (only image 1) to 1.0 (only image 2), with 0.5 (half of either) as the normal level -@property(readwrite, nonatomic) CGFloat mix; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageDivideBlendFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageDivideBlendFilter.h deleted file mode 100644 index ad798e29..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageDivideBlendFilter.h +++ /dev/null @@ -1,5 +0,0 @@ -#import "GPUImageTwoInputFilter.h" - -@interface GPUImageDivideBlendFilter : GPUImageTwoInputFilter - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageEmbossFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageEmbossFilter.h deleted file mode 100755 index dbd21e82..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageEmbossFilter.h +++ /dev/null @@ -1,8 +0,0 @@ -#import "GPUImage3x3ConvolutionFilter.h" - -@interface GPUImageEmbossFilter : GPUImage3x3ConvolutionFilter - -// The strength of the embossing, from 0.0 to 4.0, with 1.0 as the normal level -@property(readwrite, nonatomic) CGFloat intensity; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageErosionFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageErosionFilter.h deleted file mode 100644 index b311a265..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageErosionFilter.h +++ /dev/null @@ -1,11 +0,0 @@ -#import "GPUImageTwoPassTextureSamplingFilter.h" - -// For each pixel, this sets it to the minimum value of the red channel in a rectangular neighborhood extending out dilationRadius pixels from the center. -// This extends out dark features, and is most commonly used with black-and-white thresholded images. - -@interface GPUImageErosionFilter : GPUImageTwoPassTextureSamplingFilter - -// Acceptable values for erosionRadius, which sets the distance in pixels to sample out from the center, are 1, 2, 3, and 4. -- (id)initWithRadius:(NSUInteger)erosionRadius; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageExclusionBlendFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageExclusionBlendFilter.h deleted file mode 100755 index f7c83f57..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageExclusionBlendFilter.h +++ /dev/null @@ -1,7 +0,0 @@ -#import "GPUImageTwoInputFilter.h" - -@interface GPUImageExclusionBlendFilter : GPUImageTwoInputFilter -{ -} - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageExposureFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageExposureFilter.h deleted file mode 100755 index 886a052f..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageExposureFilter.h +++ /dev/null @@ -1,11 +0,0 @@ -#import "GPUImageFilter.h" - -@interface GPUImageExposureFilter : GPUImageFilter -{ - GLint exposureUniform; -} - -// Exposure ranges from -10.0 to 10.0, with 0.0 as the normal level -@property(readwrite, nonatomic) CGFloat exposure; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageFalseColorFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageFalseColorFilter.h deleted file mode 100644 index cb0b82f7..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageFalseColorFilter.h +++ /dev/null @@ -1,15 +0,0 @@ -#import "GPUImageFilter.h" - -@interface GPUImageFalseColorFilter : GPUImageFilter -{ - GLint firstColorUniform, secondColorUniform; -} - -// The first and second colors specify what colors replace the dark and light areas of the image, respectively. The defaults are (0.0, 0.0, 0.5) amd (1.0, 0.0, 0.0). -@property(readwrite, nonatomic) GPUVector4 firstColor; -@property(readwrite, nonatomic) GPUVector4 secondColor; - -- (void)setFirstColorRed:(GLfloat)redComponent green:(GLfloat)greenComponent blue:(GLfloat)blueComponent; -- (void)setSecondColorRed:(GLfloat)redComponent green:(GLfloat)greenComponent blue:(GLfloat)blueComponent; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageFilter.h deleted file mode 100755 index 0171aa80..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageFilter.h +++ /dev/null @@ -1,134 +0,0 @@ -#import "GPUImageOutput.h" - -#define STRINGIZE(x) #x -#define STRINGIZE2(x) STRINGIZE(x) -#define SHADER_STRING(text) @ STRINGIZE2(text) - -#define GPUImageHashIdentifier # -#define GPUImageWrappedLabel(x) x -#define GPUImageEscapedHashIdentifier(a) GPUImageWrappedLabel(GPUImageHashIdentifier)a - -extern NSString *const kGPUImageVertexShaderString; -extern NSString *const kGPUImagePassthroughFragmentShaderString; - -struct GPUVector4 { - GLfloat one; - GLfloat two; - GLfloat three; - GLfloat four; -}; -typedef struct GPUVector4 GPUVector4; - -struct GPUVector3 { - GLfloat one; - GLfloat two; - GLfloat three; -}; -typedef struct GPUVector3 GPUVector3; - -struct GPUMatrix4x4 { - GPUVector4 one; - GPUVector4 two; - GPUVector4 three; - GPUVector4 four; -}; -typedef struct GPUMatrix4x4 GPUMatrix4x4; - -struct GPUMatrix3x3 { - GPUVector3 one; - GPUVector3 two; - GPUVector3 three; -}; -typedef struct GPUMatrix3x3 GPUMatrix3x3; - -/** GPUImage's base filter class - - Filters and other subsequent elements in the chain conform to the GPUImageInput protocol, which lets them take in the supplied or processed texture from the previous link in the chain and do something with it. Objects one step further down the chain are considered targets, and processing can be branched by adding multiple targets to a single output or filter. - */ -@interface GPUImageFilter : GPUImageOutput -{ - GPUImageFramebuffer *firstInputFramebuffer; - - GLProgram *filterProgram; - GLint filterPositionAttribute, filterTextureCoordinateAttribute; - GLint filterInputTextureUniform; - GLfloat backgroundColorRed, backgroundColorGreen, backgroundColorBlue, backgroundColorAlpha; - - BOOL isEndProcessing; - - CGSize currentFilterSize; - GPUImageRotationMode inputRotation; - - BOOL currentlyReceivingMonochromeInput; - - NSMutableDictionary *uniformStateRestorationBlocks; - dispatch_semaphore_t imageCaptureSemaphore; -} - -@property(readonly) CVPixelBufferRef renderTarget; -@property(readwrite, nonatomic) BOOL preventRendering; -@property(readwrite, nonatomic) BOOL currentlyReceivingMonochromeInput; - -/// @name Initialization and teardown - -/** - Initialize with vertex and fragment shaders - - You make take advantage of the SHADER_STRING macro to write your shaders in-line. - @param vertexShaderString Source code of the vertex shader to use - @param fragmentShaderString Source code of the fragment shader to use - */ -- (id)initWithVertexShaderFromString:(NSString *)vertexShaderString fragmentShaderFromString:(NSString *)fragmentShaderString; - -/** - Initialize with a fragment shader - - You may take advantage of the SHADER_STRING macro to write your shader in-line. - @param fragmentShaderString Source code of fragment shader to use - */ -- (id)initWithFragmentShaderFromString:(NSString *)fragmentShaderString; -/** - Initialize with a fragment shader - @param fragmentShaderFilename Filename of fragment shader to load - */ -- (id)initWithFragmentShaderFromFile:(NSString *)fragmentShaderFilename; -- (void)initializeAttributes; -- (void)setupFilterForSize:(CGSize)filterFrameSize; -- (CGSize)rotatedSize:(CGSize)sizeToRotate forIndex:(NSInteger)textureIndex; -- (CGPoint)rotatedPoint:(CGPoint)pointToRotate forRotation:(GPUImageRotationMode)rotation; - -/// @name Managing the display FBOs -/** Size of the frame buffer object - */ -- (CGSize)sizeOfFBO; - -/// @name Rendering -+ (const GLfloat *)textureCoordinatesForRotation:(GPUImageRotationMode)rotationMode; -- (void)renderToTextureWithVertices:(const GLfloat *)vertices textureCoordinates:(const GLfloat *)textureCoordinates; -- (void)informTargetsAboutNewFrameAtTime:(CMTime)frameTime; -- (CGSize)outputFrameSize; - -/// @name Input parameters -- (void)setBackgroundColorRed:(GLfloat)redComponent green:(GLfloat)greenComponent blue:(GLfloat)blueComponent alpha:(GLfloat)alphaComponent; -- (void)setInteger:(GLint)newInteger forUniformName:(NSString *)uniformName; -- (void)setFloat:(GLfloat)newFloat forUniformName:(NSString *)uniformName; -- (void)setSize:(CGSize)newSize forUniformName:(NSString *)uniformName; -- (void)setPoint:(CGPoint)newPoint forUniformName:(NSString *)uniformName; -- (void)setFloatVec3:(GPUVector3)newVec3 forUniformName:(NSString *)uniformName; -- (void)setFloatVec4:(GPUVector4)newVec4 forUniform:(NSString *)uniformName; -- (void)setFloatArray:(GLfloat *)array length:(GLsizei)count forUniform:(NSString*)uniformName; - -- (void)setMatrix3f:(GPUMatrix3x3)matrix forUniform:(GLint)uniform program:(GLProgram *)shaderProgram; -- (void)setMatrix4f:(GPUMatrix4x4)matrix forUniform:(GLint)uniform program:(GLProgram *)shaderProgram; -- (void)setFloat:(GLfloat)floatValue forUniform:(GLint)uniform program:(GLProgram *)shaderProgram; -- (void)setPoint:(CGPoint)pointValue forUniform:(GLint)uniform program:(GLProgram *)shaderProgram; -- (void)setSize:(CGSize)sizeValue forUniform:(GLint)uniform program:(GLProgram *)shaderProgram; -- (void)setVec3:(GPUVector3)vectorValue forUniform:(GLint)uniform program:(GLProgram *)shaderProgram; -- (void)setVec4:(GPUVector4)vectorValue forUniform:(GLint)uniform program:(GLProgram *)shaderProgram; -- (void)setFloatArray:(GLfloat *)arrayValue length:(GLsizei)arrayLength forUniform:(GLint)uniform program:(GLProgram *)shaderProgram; -- (void)setInteger:(GLint)intValue forUniform:(GLint)uniform program:(GLProgram *)shaderProgram; - -- (void)setAndExecuteUniformStateCallbackAtIndex:(GLint)uniform forProgram:(GLProgram *)shaderProgram toBlock:(dispatch_block_t)uniformStateBlock; -- (void)setUniformsForProgramAtIndex:(NSUInteger)programIndex; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageFilterGroup.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageFilterGroup.h deleted file mode 100755 index 6817cdf0..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageFilterGroup.h +++ /dev/null @@ -1,19 +0,0 @@ -#import "GPUImageOutput.h" -#import "GPUImageFilter.h" - -@interface GPUImageFilterGroup : GPUImageOutput -{ - NSMutableArray *filters; - BOOL isEndProcessing; -} - -@property(readwrite, nonatomic, strong) GPUImageOutput *terminalFilter; -@property(readwrite, nonatomic, strong) NSArray *initialFilters; -@property(readwrite, nonatomic, strong) GPUImageOutput *inputFilterToIgnoreForUpdates; - -// Filter management -- (void)addFilter:(GPUImageOutput *)newFilter; -- (GPUImageOutput *)filterAtIndex:(NSUInteger)filterIndex; -- (NSUInteger)filterCount; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageFramebuffer.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageFramebuffer.h deleted file mode 100644 index 5cf20dd3..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageFramebuffer.h +++ /dev/null @@ -1,58 +0,0 @@ -#import - -#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE -#import -#import -#import -#else -#import -#import -#endif - -#import -#import - - -typedef struct GPUTextureOptions { - GLenum minFilter; - GLenum magFilter; - GLenum wrapS; - GLenum wrapT; - GLenum internalFormat; - GLenum format; - GLenum type; -} GPUTextureOptions; - -@interface GPUImageFramebuffer : NSObject - -@property(readonly) CGSize size; -@property(readonly) GPUTextureOptions textureOptions; -@property(readonly) GLuint texture; -@property(readonly) BOOL missingFramebuffer; - -// Initialization and teardown -- (id)initWithSize:(CGSize)framebufferSize; -- (id)initWithSize:(CGSize)framebufferSize textureOptions:(GPUTextureOptions)fboTextureOptions onlyTexture:(BOOL)onlyGenerateTexture; -- (id)initWithSize:(CGSize)framebufferSize overriddenTexture:(GLuint)inputTexture; - -// Usage -- (void)activateFramebuffer; - -// Reference counting -- (void)lock; -- (void)unlock; -- (void)clearAllLocks; -- (void)disableReferenceCounting; -- (void)enableReferenceCounting; - -// Image capture -- (CGImageRef)newCGImageFromFramebufferContents; -- (void)restoreRenderTarget; - -// Raw data bytes -- (void)lockForReading; -- (void)unlockAfterReading; -- (NSUInteger)bytesPerRow; -- (GLubyte *)byteBuffer; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageFramebufferCache.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageFramebufferCache.h deleted file mode 100644 index e56a3456..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageFramebufferCache.h +++ /dev/null @@ -1,15 +0,0 @@ -#import -#import -#import "GPUImageFramebuffer.h" - -@interface GPUImageFramebufferCache : NSObject - -// Framebuffer management -- (GPUImageFramebuffer *)fetchFramebufferForSize:(CGSize)framebufferSize textureOptions:(GPUTextureOptions)textureOptions onlyTexture:(BOOL)onlyTexture; -- (GPUImageFramebuffer *)fetchFramebufferForSize:(CGSize)framebufferSize onlyTexture:(BOOL)onlyTexture; -- (void)returnFramebufferToCache:(GPUImageFramebuffer *)framebuffer; -- (void)purgeAllUnassignedFramebuffers; -- (void)addFramebufferToActiveImageCaptureList:(GPUImageFramebuffer *)framebuffer; -- (void)removeFramebufferFromActiveImageCaptureList:(GPUImageFramebuffer *)framebuffer; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageGammaFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageGammaFilter.h deleted file mode 100755 index 0521d089..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageGammaFilter.h +++ /dev/null @@ -1,11 +0,0 @@ -#import "GPUImageFilter.h" - -@interface GPUImageGammaFilter : GPUImageFilter -{ - GLint gammaUniform; -} - -// Gamma ranges from 0.0 to 3.0, with 1.0 as the normal level -@property(readwrite, nonatomic) CGFloat gamma; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageGaussianBlurFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageGaussianBlurFilter.h deleted file mode 100755 index dc2bb785..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageGaussianBlurFilter.h +++ /dev/null @@ -1,36 +0,0 @@ -#import "GPUImageTwoPassTextureSamplingFilter.h" - -/** A Gaussian blur filter - Interpolated optimization based on Daniel Rákos' work at http://rastergrid.com/blog/2010/09/efficient-gaussian-blur-with-linear-sampling/ - */ - -@interface GPUImageGaussianBlurFilter : GPUImageTwoPassTextureSamplingFilter -{ - BOOL shouldResizeBlurRadiusWithImageSize; - CGFloat _blurRadiusInPixels; -} - -/** A multiplier for the spacing between texels, ranging from 0.0 on up, with a default of 1.0. Adjusting this may slightly increase the blur strength, but will introduce artifacts in the result. - */ -@property (readwrite, nonatomic) CGFloat texelSpacingMultiplier; - -/** A radius in pixels to use for the blur, with a default of 2.0. This adjusts the sigma variable in the Gaussian distribution function. - */ -@property (readwrite, nonatomic) CGFloat blurRadiusInPixels; - -/** Setting these properties will allow the blur radius to scale with the size of the image - */ -@property (readwrite, nonatomic) CGFloat blurRadiusAsFractionOfImageWidth; -@property (readwrite, nonatomic) CGFloat blurRadiusAsFractionOfImageHeight; - -/// The number of times to sequentially blur the incoming image. The more passes, the slower the filter. -@property(readwrite, nonatomic) NSUInteger blurPasses; - -+ (NSString *)vertexShaderForStandardBlurOfRadius:(NSUInteger)blurRadius sigma:(CGFloat)sigma; -+ (NSString *)fragmentShaderForStandardBlurOfRadius:(NSUInteger)blurRadius sigma:(CGFloat)sigma; -+ (NSString *)vertexShaderForOptimizedBlurOfRadius:(NSUInteger)blurRadius sigma:(CGFloat)sigma; -+ (NSString *)fragmentShaderForOptimizedBlurOfRadius:(NSUInteger)blurRadius sigma:(CGFloat)sigma; - -- (void)switchToVertexShader:(NSString *)newVertexShader fragmentShader:(NSString *)newFragmentShader; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageGaussianBlurPositionFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageGaussianBlurPositionFilter.h deleted file mode 100755 index dc88a563..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageGaussianBlurPositionFilter.h +++ /dev/null @@ -1,22 +0,0 @@ -#import "GPUImageTwoPassTextureSamplingFilter.h" - -/** A more generalized 9x9 Gaussian blur filter - */ -@interface GPUImageGaussianBlurPositionFilter : GPUImageTwoPassTextureSamplingFilter -{ - GLint blurCenterUniform, blurRadiusUniform, aspectRatioUniform; -} - -/** A multiplier for the blur size, ranging from 0.0 on up, with a default of 1.0 - */ -@property (readwrite, nonatomic) CGFloat blurSize; - -/** Center for the blur, defaults to 0.5, 0.5 - */ -@property (readwrite, nonatomic) CGPoint blurCenter; - -/** Radius for the blur, defaults to 1.0 - */ -@property (readwrite, nonatomic) CGFloat blurRadius; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageGaussianSelectiveBlurFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageGaussianSelectiveBlurFilter.h deleted file mode 100755 index 02324566..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageGaussianSelectiveBlurFilter.h +++ /dev/null @@ -1,30 +0,0 @@ -#import "GPUImageFilterGroup.h" - -@class GPUImageGaussianBlurFilter; - -/** A Gaussian blur that preserves focus within a circular region - */ -@interface GPUImageGaussianSelectiveBlurFilter : GPUImageFilterGroup -{ - GPUImageGaussianBlurFilter *blurFilter; - GPUImageFilter *selectiveFocusFilter; - BOOL hasOverriddenAspectRatio; -} - -/** The radius of the circular area being excluded from the blur - */ -@property (readwrite, nonatomic) CGFloat excludeCircleRadius; -/** The center of the circular area being excluded from the blur - */ -@property (readwrite, nonatomic) CGPoint excludeCirclePoint; -/** The size of the area between the blurred portion and the clear circle - */ -@property (readwrite, nonatomic) CGFloat excludeBlurSize; -/** A radius in pixels to use for the blur, with a default of 5.0. This adjusts the sigma variable in the Gaussian distribution function. - */ -@property (readwrite, nonatomic) CGFloat blurRadiusInPixels; -/** The aspect ratio of the image, used to adjust the circularity of the in-focus region. By default, this matches the image aspect ratio, but you can override this value. - */ -@property (readwrite, nonatomic) CGFloat aspectRatio; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageGlassSphereFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageGlassSphereFilter.h deleted file mode 100644 index 809a4ee8..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageGlassSphereFilter.h +++ /dev/null @@ -1,5 +0,0 @@ -#import "GPUImageSphereRefractionFilter.h" - -@interface GPUImageGlassSphereFilter : GPUImageSphereRefractionFilter - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageGrayscaleFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageGrayscaleFilter.h deleted file mode 100755 index 2d97f8c3..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageGrayscaleFilter.h +++ /dev/null @@ -1,9 +0,0 @@ -#import "GPUImageFilter.h" - -extern NSString *const kGPUImageLuminanceFragmentShaderString; - -/** Converts an image to grayscale (a slightly faster implementation of the saturation filter, without the ability to vary the color contribution) - */ -@interface GPUImageGrayscaleFilter : GPUImageFilter - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageHalftoneFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageHalftoneFilter.h deleted file mode 100644 index 1860bc97..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageHalftoneFilter.h +++ /dev/null @@ -1,5 +0,0 @@ -#import "GPUImagePixellateFilter.h" - -@interface GPUImageHalftoneFilter : GPUImagePixellateFilter - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageHardLightBlendFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageHardLightBlendFilter.h deleted file mode 100755 index 47d62609..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageHardLightBlendFilter.h +++ /dev/null @@ -1,7 +0,0 @@ -#import "GPUImageTwoInputFilter.h" - -@interface GPUImageHardLightBlendFilter : GPUImageTwoInputFilter -{ -} - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageHarrisCornerDetectionFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageHarrisCornerDetectionFilter.h deleted file mode 100755 index 1492b8b8..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageHarrisCornerDetectionFilter.h +++ /dev/null @@ -1,53 +0,0 @@ -#import "GPUImageFilterGroup.h" - -@class GPUImageGaussianBlurFilter; -@class GPUImageXYDerivativeFilter; -@class GPUImageGrayscaleFilter; -@class GPUImageGaussianBlurFilter; -@class GPUImageThresholdedNonMaximumSuppressionFilter; -@class GPUImageColorPackingFilter; - -//#define DEBUGFEATUREDETECTION - -/** Harris corner detector - - First pass: reduce to luminance and take the derivative of the luminance texture (GPUImageXYDerivativeFilter) - - Second pass: blur the derivative (GPUImageGaussianBlurFilter) - - Third pass: apply the Harris corner detection calculation - - This is the Harris corner detector, as described in - C. Harris and M. Stephens. A Combined Corner and Edge Detector. Proc. Alvey Vision Conf., Univ. Manchester, pp. 147-151, 1988. - */ -@interface GPUImageHarrisCornerDetectionFilter : GPUImageFilterGroup -{ - GPUImageXYDerivativeFilter *derivativeFilter; - GPUImageGaussianBlurFilter *blurFilter; - GPUImageFilter *harrisCornerDetectionFilter; - GPUImageThresholdedNonMaximumSuppressionFilter *nonMaximumSuppressionFilter; - GPUImageColorPackingFilter *colorPackingFilter; - GLfloat *cornersArray; - GLubyte *rawImagePixels; -} - -/** The radius of the underlying Gaussian blur. The default is 2.0. - */ -@property(readwrite, nonatomic) CGFloat blurRadiusInPixels; - -// This changes the dynamic range of the Harris corner detector by amplifying small cornerness values. Default is 5.0. -@property(readwrite, nonatomic) CGFloat sensitivity; - -// A threshold value at which a point is recognized as being a corner after the non-maximum suppression. Default is 0.20. -@property(readwrite, nonatomic) CGFloat threshold; - -// This block is called on the detection of new corner points, usually on every processed frame. A C array containing normalized coordinates in X, Y pairs is passed in, along with a count of the number of corners detected and the current timestamp of the video frame -@property(nonatomic, copy) void(^cornersDetectedBlock)(GLfloat* cornerArray, NSUInteger cornersDetected, CMTime frameTime); - -// These images are only enabled when built with DEBUGFEATUREDETECTION defined, and are used to examine the intermediate states of the feature detector -@property(nonatomic, readonly, strong) NSMutableArray *intermediateImages; - -// Initialization and teardown -- (id)initWithCornerDetectionFragmentShader:(NSString *)cornerDetectionFragmentShader; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageHazeFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageHazeFilter.h deleted file mode 100755 index eb3fbca6..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageHazeFilter.h +++ /dev/null @@ -1,29 +0,0 @@ -#import "GPUImageFilter.h" - -/* - * The haze filter can be used to add or remove haze (similar to a UV filter) - * - * @author Alaric Cole - * @creationDate 03/10/12 - * - */ - -/** The haze filter can be used to add or remove haze - - This is similar to a UV filter - */ -@interface GPUImageHazeFilter : GPUImageFilter -{ - GLint distanceUniform; - GLint slopeUniform; -} - -/** Strength of the color applied. Default 0. Values between -.3 and .3 are best - */ -@property(readwrite, nonatomic) CGFloat distance; - -/** Amount of color change. Default 0. Values between -.3 and .3 are best - */ -@property(readwrite, nonatomic) CGFloat slope; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageHighPassFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageHighPassFilter.h deleted file mode 100644 index 263d8df1..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageHighPassFilter.h +++ /dev/null @@ -1,14 +0,0 @@ -#import "GPUImageFilterGroup.h" -#import "GPUImageLowPassFilter.h" -#import "GPUImageDifferenceBlendFilter.h" - -@interface GPUImageHighPassFilter : GPUImageFilterGroup -{ - GPUImageLowPassFilter *lowPassFilter; - GPUImageDifferenceBlendFilter *differenceBlendFilter; -} - -// This controls the degree by which the previous accumulated frames are blended and then subtracted from the current one. This ranges from 0.0 to 1.0, with a default of 0.5. -@property(readwrite, nonatomic) CGFloat filterStrength; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageHighlightShadowFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageHighlightShadowFilter.h deleted file mode 100644 index 35791298..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageHighlightShadowFilter.h +++ /dev/null @@ -1,20 +0,0 @@ -#import "GPUImageFilter.h" - -@interface GPUImageHighlightShadowFilter : GPUImageFilter -{ - GLint shadowsUniform, highlightsUniform; -} - -/** - * 0 - 1, increase to lighten shadows. - * @default 0 - */ -@property(readwrite, nonatomic) CGFloat shadows; - -/** - * 0 - 1, decrease to darken highlights. - * @default 1 - */ -@property(readwrite, nonatomic) CGFloat highlights; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageHistogramFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageHistogramFilter.h deleted file mode 100755 index 6016d5e6..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageHistogramFilter.h +++ /dev/null @@ -1,25 +0,0 @@ -#import "GPUImageFilter.h" - -typedef enum { kGPUImageHistogramRed, kGPUImageHistogramGreen, kGPUImageHistogramBlue, kGPUImageHistogramRGB, kGPUImageHistogramLuminance} GPUImageHistogramType; - -@interface GPUImageHistogramFilter : GPUImageFilter -{ - GPUImageHistogramType histogramType; - - GLubyte *vertexSamplingCoordinates; - - GLProgram *secondFilterProgram, *thirdFilterProgram; - GLint secondFilterPositionAttribute, thirdFilterPositionAttribute; -} - -// Rather than sampling every pixel, this dictates what fraction of the image is sampled. By default, this is 16 with a minimum of 1. -@property(readwrite, nonatomic) NSUInteger downsamplingFactor; - -// Initialization and teardown -- (id)initWithHistogramType:(GPUImageHistogramType)newHistogramType; -- (void)initializeSecondaryAttributes; - -// Rendering -- (void)generatePointCoordinates; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageHistogramGenerator.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageHistogramGenerator.h deleted file mode 100755 index f80c50f3..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageHistogramGenerator.h +++ /dev/null @@ -1,8 +0,0 @@ -#import "GPUImageFilter.h" - -@interface GPUImageHistogramGenerator : GPUImageFilter -{ - GLint backgroundColorUniform; -} - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageHoughTransformLineDetector.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageHoughTransformLineDetector.h deleted file mode 100644 index 3ab6977f..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageHoughTransformLineDetector.h +++ /dev/null @@ -1,49 +0,0 @@ -#import "GPUImageFilterGroup.h" -#import "GPUImageThresholdEdgeDetectionFilter.h" -#import "GPUImageParallelCoordinateLineTransformFilter.h" -#import "GPUImageThresholdedNonMaximumSuppressionFilter.h" -#import "GPUImageCannyEdgeDetectionFilter.h" - -// This applies a Hough transform to detect lines in a scene. It starts with a thresholded Sobel edge detection pass, -// then takes those edge points in and applies a Hough transform to convert them to lines. The intersection of these lines -// is then determined via blending and accumulation, and a non-maximum suppression filter is applied to find local maxima. -// These local maxima are then converted back into lines in normal space and returned via a callback block. -// -// Rather than using one of the standard Hough transform types, this filter uses parallel coordinate space which is far more efficient -// to rasterize on a GPU. -// -// This approach is based entirely on the PC lines process developed by the Graph@FIT research group at the Brno University of Technology -// and described in their publications: -// -// M. Dubská, J. Havel, and A. Herout. Real-Time Detection of Lines using Parallel Coordinates and OpenGL. Proceedings of SCCG 2011, Bratislava, SK, p. 7. -// http://medusa.fit.vutbr.cz/public/data/papers/2011-SCCG-Dubska-Real-Time-Line-Detection-Using-PC-and-OpenGL.pdf -// M. Dubská, J. Havel, and A. Herout. PClines — Line detection using parallel coordinates. 2011 IEEE Conference on Computer Vision and Pattern Recognition (CVPR), p. 1489- 1494. -// http://medusa.fit.vutbr.cz/public/data/papers/2011-CVPR-Dubska-PClines.pdf - -//#define DEBUGLINEDETECTION - -@interface GPUImageHoughTransformLineDetector : GPUImageFilterGroup -{ - GPUImageOutput *thresholdEdgeDetectionFilter; - -// GPUImageThresholdEdgeDetectionFilter *thresholdEdgeDetectionFilter; - GPUImageParallelCoordinateLineTransformFilter *parallelCoordinateLineTransformFilter; - GPUImageThresholdedNonMaximumSuppressionFilter *nonMaximumSuppressionFilter; - - GLfloat *linesArray; - GLubyte *rawImagePixels; -} - -// A threshold value for which a point is detected as belonging to an edge for determining lines. Default is 0.9. -@property(readwrite, nonatomic) CGFloat edgeThreshold; - -// A threshold value for which a local maximum is detected as belonging to a line in parallel coordinate space. Default is 0.20. -@property(readwrite, nonatomic) CGFloat lineDetectionThreshold; - -// This block is called on the detection of lines, usually on every processed frame. A C array containing normalized slopes and intercepts in m, b pairs (y=mx+b) is passed in, along with a count of the number of lines detected and the current timestamp of the video frame -@property(nonatomic, copy) void(^linesDetectedBlock)(GLfloat* lineArray, NSUInteger linesDetected, CMTime frameTime); - -// These images are only enabled when built with DEBUGLINEDETECTION defined, and are used to examine the intermediate states of the Hough transform -@property(nonatomic, readonly, strong) NSMutableArray *intermediateImages; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageHueBlendFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageHueBlendFilter.h deleted file mode 100644 index 4399ffcf..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageHueBlendFilter.h +++ /dev/null @@ -1,5 +0,0 @@ -#import "GPUImageTwoInputFilter.h" - -@interface GPUImageHueBlendFilter : GPUImageTwoInputFilter - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageHueFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageHueFilter.h deleted file mode 100644 index eef24651..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageHueFilter.h +++ /dev/null @@ -1,11 +0,0 @@ - -#import "GPUImageFilter.h" - -@interface GPUImageHueFilter : GPUImageFilter -{ - GLint hueAdjustUniform; - -} -@property (nonatomic, readwrite) CGFloat hue; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageJFAVoronoiFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageJFAVoronoiFilter.h deleted file mode 100644 index 4c50cc37..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageJFAVoronoiFilter.h +++ /dev/null @@ -1,17 +0,0 @@ -#import "GPUImageFilter.h" - -@interface GPUImageJFAVoronoiFilter : GPUImageFilter -{ - GLuint secondFilterOutputTexture; - GLuint secondFilterFramebuffer; - - - GLint sampleStepUniform; - GLint sizeUniform; - NSUInteger numPasses; - -} - -@property (nonatomic, readwrite) CGSize sizeInPixels; - -@end \ No newline at end of file diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageKuwaharaFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageKuwaharaFilter.h deleted file mode 100755 index ef4ff479..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageKuwaharaFilter.h +++ /dev/null @@ -1,13 +0,0 @@ -#import "GPUImageFilter.h" - -/** Kuwahara image abstraction, drawn from the work of Kyprianidis, et. al. in their publication "Anisotropic Kuwahara Filtering on the GPU" within the GPU Pro collection. This produces an oil-painting-like image, but it is extremely computationally expensive, so it can take seconds to render a frame on an iPad 2. This might be best used for still images. - */ -@interface GPUImageKuwaharaFilter : GPUImageFilter -{ - GLint radiusUniform; -} - -/// The radius to sample from when creating the brush-stroke effect, with a default of 3. The larger the radius, the slower the filter. -@property(readwrite, nonatomic) GLuint radius; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageKuwaharaRadius3Filter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageKuwaharaRadius3Filter.h deleted file mode 100644 index c4591b81..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageKuwaharaRadius3Filter.h +++ /dev/null @@ -1,8 +0,0 @@ -// -// GPUImageKuwaharaRadius3Filter.h - -#import "GPUImageFilter.h" - -@interface GPUImageKuwaharaRadius3Filter : GPUImageFilter - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageLanczosResamplingFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageLanczosResamplingFilter.h deleted file mode 100644 index 5d7409f5..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageLanczosResamplingFilter.h +++ /dev/null @@ -1,7 +0,0 @@ -#import "GPUImageTwoPassTextureSamplingFilter.h" - -@interface GPUImageLanczosResamplingFilter : GPUImageTwoPassTextureSamplingFilter - -@property(readwrite, nonatomic) CGSize originalImageSize; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageLaplacianFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageLaplacianFilter.h deleted file mode 100644 index 267c1bab..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageLaplacianFilter.h +++ /dev/null @@ -1,5 +0,0 @@ -#import "GPUImage3x3ConvolutionFilter.h" - -@interface GPUImageLaplacianFilter : GPUImage3x3ConvolutionFilter - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageLevelsFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageLevelsFilter.h deleted file mode 100644 index d0948fbf..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageLevelsFilter.h +++ /dev/null @@ -1,45 +0,0 @@ -#import "GPUImageFilter.h" - -/** - * Levels like Photoshop. - * - * The min, max, minOut and maxOut parameters are floats in the range [0, 1]. - * If you have parameters from Photoshop in the range [0, 255] you must first - * convert them to be [0, 1]. - * The gamma/mid parameter is a float >= 0. This matches the value from Photoshop. - * - * If you want to apply levels to RGB as well as individual channels you need to use - * this filter twice - first for the individual channels and then for all channels. - */ -@interface GPUImageLevelsFilter : GPUImageFilter -{ - GLint minUniform; - GLint midUniform; - GLint maxUniform; - GLint minOutputUniform; - GLint maxOutputUniform; - - GPUVector3 minVector, midVector, maxVector, minOutputVector, maxOutputVector; -} - -/** Set levels for the red channel */ -- (void)setRedMin:(CGFloat)min gamma:(CGFloat)mid max:(CGFloat)max minOut:(CGFloat)minOut maxOut:(CGFloat)maxOut; - -- (void)setRedMin:(CGFloat)min gamma:(CGFloat)mid max:(CGFloat)max; - -/** Set levels for the green channel */ -- (void)setGreenMin:(CGFloat)min gamma:(CGFloat)mid max:(CGFloat)max minOut:(CGFloat)minOut maxOut:(CGFloat)maxOut; - -- (void)setGreenMin:(CGFloat)min gamma:(CGFloat)mid max:(CGFloat)max; - -/** Set levels for the blue channel */ -- (void)setBlueMin:(CGFloat)min gamma:(CGFloat)mid max:(CGFloat)max minOut:(CGFloat)minOut maxOut:(CGFloat)maxOut; - -- (void)setBlueMin:(CGFloat)min gamma:(CGFloat)mid max:(CGFloat)max; - -/** Set levels for all channels at once */ -- (void)setMin:(CGFloat)min gamma:(CGFloat)mid max:(CGFloat)max minOut:(CGFloat)minOut maxOut:(CGFloat)maxOut; -- (void)setMin:(CGFloat)min gamma:(CGFloat)mid max:(CGFloat)max; - -@end - diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageLightenBlendFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageLightenBlendFilter.h deleted file mode 100755 index b0287c13..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageLightenBlendFilter.h +++ /dev/null @@ -1,8 +0,0 @@ -#import "GPUImageTwoInputFilter.h" - -/// Blends two images by taking the maximum value of each color component between the images -@interface GPUImageLightenBlendFilter : GPUImageTwoInputFilter -{ -} - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageLineGenerator.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageLineGenerator.h deleted file mode 100644 index 4c467366..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageLineGenerator.h +++ /dev/null @@ -1,18 +0,0 @@ -#import "GPUImageFilter.h" - -@interface GPUImageLineGenerator : GPUImageFilter -{ - GLint lineWidthUniform, lineColorUniform; - GLfloat *lineCoordinates; -} - -// The width of the displayed lines, in pixels. The default is 1. -@property(readwrite, nonatomic) CGFloat lineWidth; - -// The color of the lines is specified using individual red, green, and blue components (normalized to 1.0). The default is green: (0.0, 1.0, 0.0). -- (void)setLineColorRed:(GLfloat)redComponent green:(GLfloat)greenComponent blue:(GLfloat)blueComponent; - -// Rendering -- (void)renderLinesFromArray:(GLfloat *)lineSlopeAndIntercepts count:(NSUInteger)numberOfLines frameTime:(CMTime)frameTime; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageLinearBurnBlendFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageLinearBurnBlendFilter.h deleted file mode 100644 index 7e5e415c..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageLinearBurnBlendFilter.h +++ /dev/null @@ -1,5 +0,0 @@ -#import "GPUImageTwoInputFilter.h" - -@interface GPUImageLinearBurnBlendFilter : GPUImageTwoInputFilter - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageLocalBinaryPatternFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageLocalBinaryPatternFilter.h deleted file mode 100644 index 431dbbd4..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageLocalBinaryPatternFilter.h +++ /dev/null @@ -1,5 +0,0 @@ -#import "GPUImage3x3TextureSamplingFilter.h" - -@interface GPUImageLocalBinaryPatternFilter : GPUImage3x3TextureSamplingFilter - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageLookupFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageLookupFilter.h deleted file mode 100644 index f1487048..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageLookupFilter.h +++ /dev/null @@ -1,28 +0,0 @@ -#import "GPUImageTwoInputFilter.h" - -@interface GPUImageLookupFilter : GPUImageTwoInputFilter - -// How To Use: -// 1) Use your favourite photo editing application to apply a filter to lookup.png from GPUImage/framework/Resources. -// For this to work properly each pixel color must not depend on other pixels (e.g. blur will not work). -// If you need more complex filter you can create as many lookup tables as required. -// E.g. color_balance_lookup_1.png -> GPUImageGaussianBlurFilter -> color_balance_lookup_2.png -// 2) Use you new lookup.png file as a second input for GPUImageLookupFilter. - -// See GPUImageAmatorkaFilter, GPUImageMissEtikateFilter, and GPUImageSoftEleganceFilter for example. - -// Additional Info: -// Lookup texture is organised as 8x8 quads of 64x64 pixels representing all possible RGB colors: -//for (int by = 0; by < 8; by++) { -// for (int bx = 0; bx < 8; bx++) { -// for (int g = 0; g < 64; g++) { -// for (int r = 0; r < 64; r++) { -// image.setPixel(r + bx * 64, g + by * 64, qRgb((int)(r * 255.0 / 63.0 + 0.5), -// (int)(g * 255.0 / 63.0 + 0.5), -// (int)((bx + by * 8.0) * 255.0 / 63.0 + 0.5))); -// } -// } -// } -//} - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageLowPassFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageLowPassFilter.h deleted file mode 100644 index be5c397e..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageLowPassFilter.h +++ /dev/null @@ -1,14 +0,0 @@ -#import "GPUImageFilterGroup.h" -#import "GPUImageBuffer.h" -#import "GPUImageDissolveBlendFilter.h" - -@interface GPUImageLowPassFilter : GPUImageFilterGroup -{ - GPUImageBuffer *bufferFilter; - GPUImageDissolveBlendFilter *dissolveBlendFilter; -} - -// This controls the degree by which the previous accumulated frames are blended with the current one. This ranges from 0.0 to 1.0, with a default of 0.5. -@property(readwrite, nonatomic) CGFloat filterStrength; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageLuminanceThresholdFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageLuminanceThresholdFilter.h deleted file mode 100755 index 0abb9a1e..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageLuminanceThresholdFilter.h +++ /dev/null @@ -1,14 +0,0 @@ -#import "GPUImageFilter.h" - -/** Pixels with a luminance above the threshold will appear white, and those below will be black - */ -@interface GPUImageLuminanceThresholdFilter : GPUImageFilter -{ - GLint thresholdUniform; -} - -/** Anything above this luminance will be white, and anything below black. Ranges from 0.0 to 1.0, with 0.5 as the default - */ -@property(readwrite, nonatomic) CGFloat threshold; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageLuminosity.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageLuminosity.h deleted file mode 100644 index b2d2458f..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageLuminosity.h +++ /dev/null @@ -1,17 +0,0 @@ -#import "GPUImageAverageColor.h" - -@interface GPUImageLuminosity : GPUImageAverageColor -{ - GLProgram *secondFilterProgram; - GLint secondFilterPositionAttribute, secondFilterTextureCoordinateAttribute; - GLint secondFilterInputTextureUniform, secondFilterInputTextureUniform2; - GLint secondFilterTexelWidthUniform, secondFilterTexelHeightUniform; -} - -// This block is called on the completion of color averaging for a frame -@property(nonatomic, copy) void(^luminosityProcessingFinishedBlock)(CGFloat luminosity, CMTime frameTime); - -- (void)extractLuminosityAtFrameTime:(CMTime)frameTime; -- (void)initializeSecondaryAttributes; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageLuminosityBlendFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageLuminosityBlendFilter.h deleted file mode 100644 index 03b5e4c9..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageLuminosityBlendFilter.h +++ /dev/null @@ -1,5 +0,0 @@ -#import "GPUImageTwoInputFilter.h" - -@interface GPUImageLuminosityBlendFilter : GPUImageTwoInputFilter - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageMaskFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageMaskFilter.h deleted file mode 100755 index 94cf0648..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageMaskFilter.h +++ /dev/null @@ -1,5 +0,0 @@ -#import "GPUImageTwoInputFilter.h" - -@interface GPUImageMaskFilter : GPUImageTwoInputFilter - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageMedianFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageMedianFilter.h deleted file mode 100644 index 80225789..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageMedianFilter.h +++ /dev/null @@ -1,5 +0,0 @@ -#import "GPUImage3x3TextureSamplingFilter.h" - -@interface GPUImageMedianFilter : GPUImage3x3TextureSamplingFilter - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageMissEtikateFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageMissEtikateFilter.h deleted file mode 100755 index de170647..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageMissEtikateFilter.h +++ /dev/null @@ -1,17 +0,0 @@ -#import "GPUImageFilterGroup.h" - -@class GPUImagePicture; - -/** A photo filter based on Photoshop action by Miss Etikate: - http://miss-etikate.deviantart.com/art/Photoshop-Action-15-120151961 - */ - -// Note: If you want to use this effect you have to add lookup_miss_etikate.png -// from Resources folder to your application bundle. - -@interface GPUImageMissEtikateFilter : GPUImageFilterGroup -{ - GPUImagePicture *lookupImageSource; -} - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageMonochromeFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageMonochromeFilter.h deleted file mode 100644 index 66a0e773..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageMonochromeFilter.h +++ /dev/null @@ -1,13 +0,0 @@ -#import "GPUImageFilter.h" - -@interface GPUImageMonochromeFilter : GPUImageFilter -{ - GLint intensityUniform, filterColorUniform; -} - -@property(readwrite, nonatomic) CGFloat intensity; -@property(readwrite, nonatomic) GPUVector4 color; - -- (void)setColorRed:(GLfloat)redComponent green:(GLfloat)greenComponent blue:(GLfloat)blueComponent; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageMosaicFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageMosaicFilter.h deleted file mode 100644 index ae829ec4..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageMosaicFilter.h +++ /dev/null @@ -1,27 +0,0 @@ - -// This needs a little more work, it's rotating the input tileset and there are some artifacts (I think from GL_LINEAR interpolation), but it's working - -#import "GPUImageTwoInputFilter.h" -#import "GPUImagePicture.h" - -@interface GPUImageMosaicFilter : GPUImageTwoInputFilter { - GLint inputTileSizeUniform, numTilesUniform, displayTileSizeUniform, colorOnUniform; - GPUImagePicture *pic; -} - -// This filter takes an input tileset, the tiles must ascend in luminance -// It looks at the input image and replaces each display tile with an input tile -// according to the luminance of that tile. The idea was to replicate the ASCII -// video filters seen in other apps, but the tileset can be anything. -@property(readwrite, nonatomic) CGSize inputTileSize; -@property(readwrite, nonatomic) float numTiles; -@property(readwrite, nonatomic) CGSize displayTileSize; -@property(readwrite, nonatomic) BOOL colorOn; - -- (void)setNumTiles:(float)numTiles; -- (void)setDisplayTileSize:(CGSize)displayTileSize; -- (void)setInputTileSize:(CGSize)inputTileSize; -- (void)setTileSet:(NSString *)tileSet; -- (void)setColorOn:(BOOL)yes; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageMotionBlurFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageMotionBlurFilter.h deleted file mode 100644 index dcca712f..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageMotionBlurFilter.h +++ /dev/null @@ -1,13 +0,0 @@ -#import "GPUImageFilter.h" - -@interface GPUImageMotionBlurFilter : GPUImageFilter - -/** A multiplier for the blur size, ranging from 0.0 on up, with a default of 1.0 - */ -@property (readwrite, nonatomic) CGFloat blurSize; - -/** The angular direction of the blur, in degrees. 0 degrees by default - */ -@property (readwrite, nonatomic) CGFloat blurAngle; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageMotionDetector.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageMotionDetector.h deleted file mode 100644 index 01329145..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageMotionDetector.h +++ /dev/null @@ -1,18 +0,0 @@ -#import "GPUImageFilterGroup.h" -#import "GPUImageLowPassFilter.h" -#import "GPUImageAverageColor.h" - -@interface GPUImageMotionDetector : GPUImageFilterGroup -{ - GPUImageLowPassFilter *lowPassFilter; - GPUImageTwoInputFilter *frameComparisonFilter; - GPUImageAverageColor *averageColor; -} - -// This controls the low pass filter strength used to compare the current frame with previous ones to detect motion. This ranges from 0.0 to 1.0, with a default of 0.5. -@property(readwrite, nonatomic) CGFloat lowPassFilterStrength; - -// For every frame, this will feed back the calculated centroid of the motion, as well as a relative intensity. -@property(nonatomic, copy) void(^motionDetectionBlock)(CGPoint motionCentroid, CGFloat motionIntensity, CMTime frameTime); - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageMovieWriter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageMovieWriter.h deleted file mode 100755 index 530e5a61..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageMovieWriter.h +++ /dev/null @@ -1,57 +0,0 @@ -#import -#import -#import "GPUImageContext.h" - -extern NSString *const kGPUImageColorSwizzlingFragmentShaderString; - -@protocol GPUImageMovieWriterDelegate - -@optional -- (void)movieRecordingCompleted; -- (void)movieRecordingFailedWithError:(NSError*)error; - -@end - -@interface GPUImageMovieWriter : NSObject -{ - CMVideoDimensions videoDimensions; - CMVideoCodecType videoType; - - NSURL *movieURL; - NSString *fileType; - AVAssetWriter *assetWriter; - AVAssetWriterInput *assetWriterAudioInput; - AVAssetWriterInput *assetWriterVideoInput; - AVAssetWriterInputPixelBufferAdaptor *assetWriterPixelBufferInput; - dispatch_queue_t movieWritingQueue; - - CGSize videoSize; - GPUImageRotationMode inputRotation; -} - -@property(readwrite, nonatomic) BOOL hasAudioTrack; -@property(readwrite, nonatomic) BOOL shouldPassthroughAudio; -@property(nonatomic, copy) void(^completionBlock)(void); -@property(nonatomic, copy) void(^failureBlock)(NSError*); -@property(nonatomic, assign) id delegate; -@property(readwrite, nonatomic) BOOL encodingLiveVideo; -@property(nonatomic, copy) void(^videoInputReadyCallback)(void); -@property(nonatomic, copy) void(^audioInputReadyCallback)(void); -@property(nonatomic) BOOL enabled; - -// Initialization and teardown -- (id)initWithMovieURL:(NSURL *)newMovieURL size:(CGSize)newSize; -- (id)initWithMovieURL:(NSURL *)newMovieURL size:(CGSize)newSize fileType:(NSString *)newFileType outputSettings:(NSMutableDictionary *)outputSettings; - -- (void)setHasAudioTrack:(BOOL)hasAudioTrack audioSettings:(NSDictionary *)audioOutputSettings; - -// Movie recording -- (void)startRecording; -- (void)startRecordingInOrientation:(CGAffineTransform)orientationTransform; -- (void)finishRecording; -- (void)finishRecordingWithCompletionHandler:(void (^)(void))handler; -- (void)cancelRecording; -- (void)processAudioBuffer:(CMSampleBufferRef)audioBuffer; -- (void)enableSynchronizationCallbacks; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageMultiplyBlendFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageMultiplyBlendFilter.h deleted file mode 100755 index 5ebc28bb..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageMultiplyBlendFilter.h +++ /dev/null @@ -1,7 +0,0 @@ -#import "GPUImageTwoInputFilter.h" - -@interface GPUImageMultiplyBlendFilter : GPUImageTwoInputFilter -{ -} - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageNobleCornerDetectionFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageNobleCornerDetectionFilter.h deleted file mode 100644 index 963fd66a..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageNobleCornerDetectionFilter.h +++ /dev/null @@ -1,12 +0,0 @@ -#import "GPUImageHarrisCornerDetectionFilter.h" - -/** Noble corner detector - - This is the Noble variant on the Harris detector, from - Alison Noble, "Descriptions of Image Surfaces", PhD thesis, Department of Engineering Science, Oxford University 1989, p45. -*/ - - -@interface GPUImageNobleCornerDetectionFilter : GPUImageHarrisCornerDetectionFilter - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageNonMaximumSuppressionFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageNonMaximumSuppressionFilter.h deleted file mode 100644 index fd8fe6d6..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageNonMaximumSuppressionFilter.h +++ /dev/null @@ -1,5 +0,0 @@ -#import "GPUImage3x3TextureSamplingFilter.h" - -@interface GPUImageNonMaximumSuppressionFilter : GPUImage3x3TextureSamplingFilter - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageNormalBlendFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageNormalBlendFilter.h deleted file mode 100644 index ce5e22b4..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageNormalBlendFilter.h +++ /dev/null @@ -1,8 +0,0 @@ -// Created by Jorge Garcia on 9/5/12. -// - -#import "GPUImageTwoInputFilter.h" - -@interface GPUImageNormalBlendFilter : GPUImageTwoInputFilter - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageOpacityFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageOpacityFilter.h deleted file mode 100644 index 826749fb..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageOpacityFilter.h +++ /dev/null @@ -1,11 +0,0 @@ -#import "GPUImageFilter.h" - -@interface GPUImageOpacityFilter : GPUImageFilter -{ - GLint opacityUniform; -} - -// Opacity ranges from 0.0 to 1.0, with 1.0 as the normal setting -@property(readwrite, nonatomic) CGFloat opacity; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageOpeningFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageOpeningFilter.h deleted file mode 100644 index 3e4f7545..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageOpeningFilter.h +++ /dev/null @@ -1,19 +0,0 @@ -#import "GPUImageFilterGroup.h" - -@class GPUImageErosionFilter; -@class GPUImageDilationFilter; - -// A filter that first performs an erosion on the red channel of an image, followed by a dilation of the same radius. -// This helps to filter out smaller bright elements. - -@interface GPUImageOpeningFilter : GPUImageFilterGroup -{ - GPUImageErosionFilter *erosionFilter; - GPUImageDilationFilter *dilationFilter; -} - -@property(readwrite, nonatomic) CGFloat verticalTexelSpacing, horizontalTexelSpacing; - -- (id)initWithRadius:(NSUInteger)radius; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageOutput.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageOutput.h deleted file mode 100755 index a1af54d7..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageOutput.h +++ /dev/null @@ -1,127 +0,0 @@ -#import "GPUImageContext.h" -#import "GPUImageFramebuffer.h" - -#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE -#import -#else -// For now, just redefine this on the Mac -typedef NS_ENUM(NSInteger, UIImageOrientation) { - UIImageOrientationUp, // default orientation - UIImageOrientationDown, // 180 deg rotation - UIImageOrientationLeft, // 90 deg CCW - UIImageOrientationRight, // 90 deg CW - UIImageOrientationUpMirrored, // as above but image mirrored along other axis. horizontal flip - UIImageOrientationDownMirrored, // horizontal flip - UIImageOrientationLeftMirrored, // vertical flip - UIImageOrientationRightMirrored, // vertical flip -}; -#endif - -void runOnMainQueueWithoutDeadlocking(void (^block)(void)); -void runSynchronouslyOnVideoProcessingQueue(void (^block)(void)); -void runAsynchronouslyOnVideoProcessingQueue(void (^block)(void)); -void runSynchronouslyOnContextQueue(GPUImageContext *context, void (^block)(void)); -void runAsynchronouslyOnContextQueue(GPUImageContext *context, void (^block)(void)); -void reportAvailableMemoryForGPUImage(NSString *tag); - -@class GPUImageMovieWriter; - -/** GPUImage's base source object - - Images or frames of video are uploaded from source objects, which are subclasses of GPUImageOutput. These include: - - - GPUImageVideoCamera (for live video from an iOS camera) - - GPUImageStillCamera (for taking photos with the camera) - - GPUImagePicture (for still images) - - GPUImageMovie (for movies) - - Source objects upload still image frames to OpenGL ES as textures, then hand those textures off to the next objects in the processing chain. - */ -@interface GPUImageOutput : NSObject -{ - GPUImageFramebuffer *outputFramebuffer; - - NSMutableArray *targets, *targetTextureIndices; - - CGSize inputTextureSize, cachedMaximumOutputSize, forcedMaximumSize; - - BOOL overrideInputSize; - - BOOL allTargetsWantMonochromeData; - BOOL usingNextFrameForImageCapture; -} - -@property(readwrite, nonatomic) BOOL shouldSmoothlyScaleOutput; -@property(readwrite, nonatomic) BOOL shouldIgnoreUpdatesToThisTarget; -@property(readwrite, nonatomic, retain) GPUImageMovieWriter *audioEncodingTarget; -@property(readwrite, nonatomic, unsafe_unretained) id targetToIgnoreForUpdates; -@property(nonatomic, copy) void(^frameProcessingCompletionBlock)(GPUImageOutput*, CMTime); -@property(nonatomic) BOOL enabled; -@property(readwrite, nonatomic) GPUTextureOptions outputTextureOptions; - -/// @name Managing targets -- (void)setInputFramebufferForTarget:(id)target atIndex:(NSInteger)inputTextureIndex; -- (GPUImageFramebuffer *)framebufferForOutput; -- (void)removeOutputFramebuffer; -- (void)notifyTargetsAboutNewOutputTexture; - -/** Returns an array of the current targets. - */ -- (NSArray*)targets; - -/** Adds a target to receive notifications when new frames are available. - - The target will be asked for its next available texture. - - See [GPUImageInput newFrameReadyAtTime:] - - @param newTarget Target to be added - */ -- (void)addTarget:(id)newTarget; - -/** Adds a target to receive notifications when new frames are available. - - See [GPUImageInput newFrameReadyAtTime:] - - @param newTarget Target to be added - */ -- (void)addTarget:(id)newTarget atTextureLocation:(NSInteger)textureLocation; - -/** Removes a target. The target will no longer receive notifications when new frames are available. - - @param targetToRemove Target to be removed - */ -- (void)removeTarget:(id)targetToRemove; - -/** Removes all targets. - */ -- (void)removeAllTargets; - -/// @name Manage the output texture - -- (void)forceProcessingAtSize:(CGSize)frameSize; -- (void)forceProcessingAtSizeRespectingAspectRatio:(CGSize)frameSize; - -/// @name Still image processing - -- (void)useNextFrameForImageCapture; -- (CGImageRef)newCGImageFromCurrentlyProcessedOutput; -- (CGImageRef)newCGImageByFilteringCGImage:(CGImageRef)imageToFilter; - -// Platform-specific image output methods -// If you're trying to use these methods, remember that you need to set -useNextFrameForImageCapture before running -processImage or running video and calling any of these methods, or you will get a nil image -#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE -- (UIImage *)imageFromCurrentFramebuffer; -- (UIImage *)imageFromCurrentFramebufferWithOrientation:(UIImageOrientation)imageOrientation; -- (UIImage *)imageByFilteringImage:(UIImage *)imageToFilter; -- (CGImageRef)newCGImageByFilteringImage:(UIImage *)imageToFilter; -#else -- (NSImage *)imageFromCurrentFramebuffer; -- (NSImage *)imageFromCurrentFramebufferWithOrientation:(UIImageOrientation)imageOrientation; -- (NSImage *)imageByFilteringImage:(NSImage *)imageToFilter; -- (CGImageRef)newCGImageByFilteringImage:(NSImage *)imageToFilter; -#endif - -- (BOOL)providesMonochromeOutput; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageOverlayBlendFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageOverlayBlendFilter.h deleted file mode 100755 index 57eb8402..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageOverlayBlendFilter.h +++ /dev/null @@ -1,5 +0,0 @@ -#import "GPUImageTwoInputFilter.h" - -@interface GPUImageOverlayBlendFilter : GPUImageTwoInputFilter - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageParallelCoordinateLineTransformFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageParallelCoordinateLineTransformFilter.h deleted file mode 100644 index aa8f3f47..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageParallelCoordinateLineTransformFilter.h +++ /dev/null @@ -1,16 +0,0 @@ -#import "GPUImageFilter.h" - -// This is an accumulator that uses a Hough transform in parallel coordinate space to identify probable lines in a scene. -// -// It is entirely based on the work of the Graph@FIT research group at the Brno University of Technology and their publications: -// M. Dubská, J. Havel, and A. Herout. Real-Time Detection of Lines using Parallel Coordinates and OpenGL. Proceedings of SCCG 2011, Bratislava, SK, p. 7. -// M. Dubská, J. Havel, and A. Herout. PClines — Line detection using parallel coordinates. 2011 IEEE Conference on Computer Vision and Pattern Recognition (CVPR), p. 1489- 1494. - -@interface GPUImageParallelCoordinateLineTransformFilter : GPUImageFilter -{ - GLubyte *rawImagePixels; - GLfloat *lineCoordinates; - unsigned int maxLinePairsToRender, linePairsToRender; -} - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImagePerlinNoiseFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImagePerlinNoiseFilter.h deleted file mode 100644 index 922f4d30..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImagePerlinNoiseFilter.h +++ /dev/null @@ -1,13 +0,0 @@ -#import "GPUImageFilter.h" - -@interface GPUImagePerlinNoiseFilter : GPUImageFilter -{ - GLint scaleUniform, colorStartUniform, colorFinishUniform; -} - -@property (readwrite, nonatomic) GPUVector4 colorStart; -@property (readwrite, nonatomic) GPUVector4 colorFinish; - -@property (readwrite, nonatomic) float scale; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImagePicture.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImagePicture.h deleted file mode 100755 index 65970535..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImagePicture.h +++ /dev/null @@ -1,25 +0,0 @@ -#import -#import "GPUImageOutput.h" - -@interface GPUImagePicture : GPUImageOutput -{ - CGSize pixelSizeOfImage; - BOOL hasProcessedImage; - - dispatch_semaphore_t imageUpdateSemaphore; -} - -// Initialization and teardown -- (id)initWithURL:(NSURL *)url; -- (id)initWithImage:(NSImage *)newImageSource; -- (id)initWithCGImage:(CGImageRef)newImageSource; -- (id)initWithImage:(NSImage *)newImageSource smoothlyScaleOutput:(BOOL)smoothlyScaleOutput; -- (id)initWithCGImage:(CGImageRef)newImageSource smoothlyScaleOutput:(BOOL)smoothlyScaleOutput; - -// Image rendering -- (void)processImage; -- (BOOL)processImageWithCompletionHandler:(void (^)(void))completion; -- (void)processImageUpToFilter:(GPUImageOutput *)finalFilterInChain withCompletionHandler:(void (^)(NSImage *processedImage))block; -- (CGSize)outputImageSize; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImagePinchDistortionFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImagePinchDistortionFilter.h deleted file mode 100755 index 994774fd..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImagePinchDistortionFilter.h +++ /dev/null @@ -1,20 +0,0 @@ -#import "GPUImageFilter.h" - -/** Creates a pinch distortion of the image - */ -@interface GPUImagePinchDistortionFilter : GPUImageFilter -{ - GLint aspectRatioUniform, radiusUniform, centerUniform, scaleUniform; -} - -/** The center about which to apply the distortion, with a default of (0.5, 0.5) - */ -@property(readwrite, nonatomic) CGPoint center; -/** The radius of the distortion, ranging from 0.0 to 2.0, with a default of 1.0 - */ -@property(readwrite, nonatomic) CGFloat radius; -/** The amount of distortion to apply, from -2.0 to 2.0, with a default of 0.5 - */ -@property(readwrite, nonatomic) CGFloat scale; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImagePixellateFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImagePixellateFilter.h deleted file mode 100755 index d0f6ae04..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImagePixellateFilter.h +++ /dev/null @@ -1,12 +0,0 @@ -#import "GPUImageFilter.h" - -@interface GPUImagePixellateFilter : GPUImageFilter -{ - GLint fractionalWidthOfAPixelUniform, aspectRatioUniform; -} - -// The fractional width of the image to use as a size for the pixels in the resulting image. Values below one pixel width in the source image are ignored. -@property(readwrite, nonatomic) CGFloat fractionalWidthOfAPixel; - - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImagePixellatePositionFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImagePixellatePositionFilter.h deleted file mode 100755 index 9d304c93..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImagePixellatePositionFilter.h +++ /dev/null @@ -1,17 +0,0 @@ -#import "GPUImageFilter.h" - -@interface GPUImagePixellatePositionFilter : GPUImageFilter -{ - GLint fractionalWidthOfAPixelUniform, aspectRatioUniform, centerUniform, radiusUniform; -} - -// The fractional width of the image to use as a size for the pixels in the resulting image. Values below one pixel width in the source image are ignored. -@property(readwrite, nonatomic) CGFloat fractionalWidthOfAPixel; - -// the center point to start pixelation in texture coordinates, default 0.5, 0.5 -@property(readwrite, nonatomic) CGPoint center; - -// the radius (0.0 - 1.0) in which to pixelate, default 1.0 -@property(readwrite, nonatomic) CGFloat radius; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImagePoissonBlendFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImagePoissonBlendFilter.h deleted file mode 100644 index 58eff225..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImagePoissonBlendFilter.h +++ /dev/null @@ -1,18 +0,0 @@ -#import "GPUImageTwoInputCrossTextureSamplingFilter.h" -#import "GPUImageFilterGroup.h" - -@interface GPUImagePoissonBlendFilter : GPUImageTwoInputCrossTextureSamplingFilter -{ - GLint mixUniform; - - GPUImageFramebuffer *secondOutputFramebuffer; -} - -// Mix ranges from 0.0 (only image 1) to 1.0 (only image 2 gradients), with 1.0 as the normal level -@property(readwrite, nonatomic) CGFloat mix; - -// The number of times to propagate the gradients. -// Crank this up to 100 or even 1000 if you want to get anywhere near convergence. Yes, this will be slow. -@property(readwrite, nonatomic) NSUInteger numIterations; - -@end \ No newline at end of file diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImagePolarPixellateFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImagePolarPixellateFilter.h deleted file mode 100755 index 3de6a4d3..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImagePolarPixellateFilter.h +++ /dev/null @@ -1,13 +0,0 @@ -#import "GPUImageFilter.h" - -@interface GPUImagePolarPixellateFilter : GPUImageFilter { - GLint centerUniform, pixelSizeUniform; -} - -// The center about which to apply the distortion, with a default of (0.5, 0.5) -@property(readwrite, nonatomic) CGPoint center; -// The amount of distortion to apply, from (-2.0, -2.0) to (2.0, 2.0), with a default of (0.05, 0.05) -@property(readwrite, nonatomic) CGSize pixelSize; - - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImagePolkaDotFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImagePolkaDotFilter.h deleted file mode 100644 index 369b7737..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImagePolkaDotFilter.h +++ /dev/null @@ -1,10 +0,0 @@ -#import "GPUImagePixellateFilter.h" - -@interface GPUImagePolkaDotFilter : GPUImagePixellateFilter -{ - GLint dotScalingUniform; -} - -@property(readwrite, nonatomic) CGFloat dotScaling; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImagePosterizeFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImagePosterizeFilter.h deleted file mode 100755 index 6f655b3e..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImagePosterizeFilter.h +++ /dev/null @@ -1,14 +0,0 @@ -#import "GPUImageFilter.h" - -/** This reduces the color dynamic range into the number of steps specified, leading to a cartoon-like simple shading of the image. - */ -@interface GPUImagePosterizeFilter : GPUImageFilter -{ - GLint colorLevelsUniform; -} - -/** The number of color levels to reduce the image space to. This ranges from 1 to 256, with a default of 10. - */ -@property(readwrite, nonatomic) NSUInteger colorLevels; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImagePrewittEdgeDetectionFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImagePrewittEdgeDetectionFilter.h deleted file mode 100755 index 141f8c5f..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImagePrewittEdgeDetectionFilter.h +++ /dev/null @@ -1,5 +0,0 @@ -#import "GPUImageSobelEdgeDetectionFilter.h" - -@interface GPUImagePrewittEdgeDetectionFilter : GPUImageSobelEdgeDetectionFilter - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageRGBClosingFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageRGBClosingFilter.h deleted file mode 100644 index 08d13f88..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageRGBClosingFilter.h +++ /dev/null @@ -1,18 +0,0 @@ -#import "GPUImageFilterGroup.h" - -@class GPUImageRGBErosionFilter; -@class GPUImageRGBDilationFilter; - -// A filter that first performs a dilation on each color channel of an image, followed by an erosion of the same radius. -// This helps to filter out smaller dark elements. - -@interface GPUImageRGBClosingFilter : GPUImageFilterGroup -{ - GPUImageRGBErosionFilter *erosionFilter; - GPUImageRGBDilationFilter *dilationFilter; -} - -- (id)initWithRadius:(NSUInteger)radius; - - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageRGBDilationFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageRGBDilationFilter.h deleted file mode 100644 index 68276f84..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageRGBDilationFilter.h +++ /dev/null @@ -1,11 +0,0 @@ -#import "GPUImageTwoPassTextureSamplingFilter.h" - -// For each pixel, this sets it to the maximum value of each color channel in a rectangular neighborhood extending out dilationRadius pixels from the center. -// This extends out brighter colors, and can be used for abstraction of color images. - -@interface GPUImageRGBDilationFilter : GPUImageTwoPassTextureSamplingFilter - -// Acceptable values for dilationRadius, which sets the distance in pixels to sample out from the center, are 1, 2, 3, and 4. -- (id)initWithRadius:(NSUInteger)dilationRadius; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageRGBErosionFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageRGBErosionFilter.h deleted file mode 100644 index 5979cb7e..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageRGBErosionFilter.h +++ /dev/null @@ -1,11 +0,0 @@ -#import "GPUImageTwoPassTextureSamplingFilter.h" - -// For each pixel, this sets it to the minimum value of each color channel in a rectangular neighborhood extending out dilationRadius pixels from the center. -// This extends out dark features, and can be used for abstraction of color images. - -@interface GPUImageRGBErosionFilter : GPUImageTwoPassTextureSamplingFilter - -// Acceptable values for erosionRadius, which sets the distance in pixels to sample out from the center, are 1, 2, 3, and 4. -- (id)initWithRadius:(NSUInteger)erosionRadius; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageRGBFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageRGBFilter.h deleted file mode 100755 index 18966b1b..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageRGBFilter.h +++ /dev/null @@ -1,15 +0,0 @@ -#import "GPUImageFilter.h" - -@interface GPUImageRGBFilter : GPUImageFilter -{ - GLint redUniform; - GLint greenUniform; - GLint blueUniform; -} - -// Normalized values by which each color channel is multiplied. The range is from 0.0 up, with 1.0 as the default. -@property (readwrite, nonatomic) CGFloat red; -@property (readwrite, nonatomic) CGFloat green; -@property (readwrite, nonatomic) CGFloat blue; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageRGBOpeningFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageRGBOpeningFilter.h deleted file mode 100644 index dbec75fb..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageRGBOpeningFilter.h +++ /dev/null @@ -1,17 +0,0 @@ -#import "GPUImageFilterGroup.h" - -@class GPUImageRGBErosionFilter; -@class GPUImageRGBDilationFilter; - -// A filter that first performs an erosion on each color channel of an image, followed by a dilation of the same radius. -// This helps to filter out smaller bright elements. - -@interface GPUImageRGBOpeningFilter : GPUImageFilterGroup -{ - GPUImageRGBErosionFilter *erosionFilter; - GPUImageRGBDilationFilter *dilationFilter; -} - -- (id)initWithRadius:(NSUInteger)radius; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageRawDataInput.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageRawDataInput.h deleted file mode 100644 index 64858180..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageRawDataInput.h +++ /dev/null @@ -1,42 +0,0 @@ -#import "GPUImageOutput.h" - -// The bytes passed into this input are not copied or retained, but you are free to deallocate them after they are used by this filter. -// The bytes are uploaded and stored within a texture, so nothing is kept locally. -// The default format for input bytes is GPUPixelFormatBGRA, unless specified with pixelFormat: -// The default type for input bytes is GPUPixelTypeUByte, unless specified with pixelType: - -typedef enum { - GPUPixelFormatBGRA = GL_BGRA, - GPUPixelFormatRGBA = GL_RGBA, - GPUPixelFormatRGB = GL_RGB -} GPUPixelFormat; - -typedef enum { - GPUPixelTypeUByte = GL_UNSIGNED_BYTE, - GPUPixelTypeFloat = GL_FLOAT -} GPUPixelType; - -@interface GPUImageRawDataInput : GPUImageOutput -{ - CGSize uploadedImageSize; - - dispatch_semaphore_t dataUpdateSemaphore; -} - -// Initialization and teardown -- (id)initWithBytes:(GLubyte *)bytesToUpload size:(CGSize)imageSize; -- (id)initWithBytes:(GLubyte *)bytesToUpload size:(CGSize)imageSize pixelFormat:(GPUPixelFormat)pixelFormat; -- (id)initWithBytes:(GLubyte *)bytesToUpload size:(CGSize)imageSize pixelFormat:(GPUPixelFormat)pixelFormat type:(GPUPixelType)pixelType; - -/** Input data pixel format - */ -@property (readwrite, nonatomic) GPUPixelFormat pixelFormat; -@property (readwrite, nonatomic) GPUPixelType pixelType; - -// Image rendering -- (void)updateDataFromBytes:(GLubyte *)bytesToUpload size:(CGSize)imageSize; -- (void)processData; -- (void)processDataForTimestamp:(CMTime)frameTime; -- (CGSize)outputImageSize; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageRawDataOutput.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageRawDataOutput.h deleted file mode 100755 index 5a4538c1..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageRawDataOutput.h +++ /dev/null @@ -1,44 +0,0 @@ -#import -#import "GPUImageContext.h" - -struct GPUByteColorVector { - GLubyte red; - GLubyte green; - GLubyte blue; - GLubyte alpha; -}; -typedef struct GPUByteColorVector GPUByteColorVector; - -@protocol GPUImageRawDataProcessor; - -#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE -@interface GPUImageRawDataOutput : NSObject { - CGSize imageSize; - GPUImageRotationMode inputRotation; - BOOL outputBGRA; -} -#else -@interface GPUImageRawDataOutput : NSObject { - CGSize imageSize; - GPUImageRotationMode inputRotation; - BOOL outputBGRA; -} -#endif - -@property(readonly) GLubyte *rawBytesForImage; -@property(nonatomic, copy) void(^newFrameAvailableBlock)(void); -@property(nonatomic) BOOL enabled; - -// Initialization and teardown -- (id)initWithImageSize:(CGSize)newImageSize resultsInBGRAFormat:(BOOL)resultsInBGRAFormat; - -// Data access -- (GPUByteColorVector)colorAtLocation:(CGPoint)locationInImage; -- (NSUInteger)bytesPerRowInOutput; - -- (void)setImageSize:(CGSize)newImageSize; - -- (void)lockFramebufferForReading; -- (void)unlockFramebufferAfterReading; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSaturationBlendFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSaturationBlendFilter.h deleted file mode 100644 index 767892a5..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSaturationBlendFilter.h +++ /dev/null @@ -1,5 +0,0 @@ -#import "GPUImageTwoInputFilter.h" - -@interface GPUImageSaturationBlendFilter : GPUImageTwoInputFilter - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSaturationFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSaturationFilter.h deleted file mode 100755 index 1c6ff5bd..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSaturationFilter.h +++ /dev/null @@ -1,14 +0,0 @@ -#import "GPUImageFilter.h" - -/** Adjusts the saturation of an image - */ -@interface GPUImageSaturationFilter : GPUImageFilter -{ - GLint saturationUniform; -} - -/** Saturation ranges from 0.0 (fully desaturated) to 2.0 (max saturation), with 1.0 as the normal level - */ -@property(readwrite, nonatomic) CGFloat saturation; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageScreenBlendFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageScreenBlendFilter.h deleted file mode 100755 index 2df3abf3..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageScreenBlendFilter.h +++ /dev/null @@ -1,7 +0,0 @@ -#import "GPUImageTwoInputFilter.h" - -@interface GPUImageScreenBlendFilter : GPUImageTwoInputFilter -{ -} - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSepiaFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSepiaFilter.h deleted file mode 100755 index a45164fe..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSepiaFilter.h +++ /dev/null @@ -1,6 +0,0 @@ -#import "GPUImageColorMatrixFilter.h" - -/// Simple sepia tone filter -@interface GPUImageSepiaFilter : GPUImageColorMatrixFilter - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSharpenFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSharpenFilter.h deleted file mode 100755 index 739df503..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSharpenFilter.h +++ /dev/null @@ -1,12 +0,0 @@ -#import "GPUImageFilter.h" - -@interface GPUImageSharpenFilter : GPUImageFilter -{ - GLint sharpnessUniform; - GLint imageWidthFactorUniform, imageHeightFactorUniform; -} - -// Sharpness ranges from -4.0 to 4.0, with 0.0 as the normal level -@property(readwrite, nonatomic) CGFloat sharpness; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageShiTomasiFeatureDetectionFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageShiTomasiFeatureDetectionFilter.h deleted file mode 100644 index b16ebc01..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageShiTomasiFeatureDetectionFilter.h +++ /dev/null @@ -1,13 +0,0 @@ -#import "GPUImageHarrisCornerDetectionFilter.h" - -/** Shi-Tomasi feature detector - - This is the Shi-Tomasi feature detector, as described in - J. Shi and C. Tomasi. Good features to track. Proceedings of the IEEE Conference on Computer Vision and Pattern Recognition, pages 593-600, June 1994. - */ - -@interface GPUImageShiTomasiFeatureDetectionFilter : GPUImageHarrisCornerDetectionFilter - -// Compared to the Harris corner detector, the default sensitivity value for this detector is set to 1.5 - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSingleComponentGaussianBlurFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSingleComponentGaussianBlurFilter.h deleted file mode 100644 index 934b1e3a..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSingleComponentGaussianBlurFilter.h +++ /dev/null @@ -1,7 +0,0 @@ -#import "GPUImageGaussianBlurFilter.h" - -// This filter merely performs the standard Gaussian blur on the red color channel (assuming a luminance image) - -@interface GPUImageSingleComponentGaussianBlurFilter : GPUImageGaussianBlurFilter - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSketchFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSketchFilter.h deleted file mode 100755 index 598145ae..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSketchFilter.h +++ /dev/null @@ -1,11 +0,0 @@ -#import "GPUImageSobelEdgeDetectionFilter.h" - -/** Converts video to look like a sketch. - - This is just the Sobel edge detection filter with the colors inverted. - */ -@interface GPUImageSketchFilter : GPUImageSobelEdgeDetectionFilter -{ -} - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSmoothToonFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSmoothToonFilter.h deleted file mode 100755 index f89caac5..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSmoothToonFilter.h +++ /dev/null @@ -1,28 +0,0 @@ -#import "GPUImageFilterGroup.h" - -@class GPUImageGaussianBlurFilter; -@class GPUImageToonFilter; - -/** This uses a similar process as the GPUImageToonFilter, only it precedes the toon effect with a Gaussian blur to smooth out noise. - */ -@interface GPUImageSmoothToonFilter : GPUImageFilterGroup -{ - GPUImageGaussianBlurFilter *blurFilter; - GPUImageToonFilter *toonFilter; -} - -/// The image width and height factors tweak the appearance of the edges. By default, they match the filter size in pixels -@property(readwrite, nonatomic) CGFloat texelWidth; -/// The image width and height factors tweak the appearance of the edges. By default, they match the filter size in pixels -@property(readwrite, nonatomic) CGFloat texelHeight; - -/// The radius of the underlying Gaussian blur. The default is 2.0. -@property (readwrite, nonatomic) CGFloat blurRadiusInPixels; - -/// The threshold at which to apply the edges, default of 0.2 -@property(readwrite, nonatomic) CGFloat threshold; - -/// The levels of quantization for the posterization of colors within the scene, with a default of 10.0 -@property(readwrite, nonatomic) CGFloat quantizationLevels; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSobelEdgeDetectionFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSobelEdgeDetectionFilter.h deleted file mode 100755 index d6b2c13a..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSobelEdgeDetectionFilter.h +++ /dev/null @@ -1,16 +0,0 @@ -#import "GPUImageTwoPassFilter.h" - -@interface GPUImageSobelEdgeDetectionFilter : GPUImageTwoPassFilter -{ - GLint texelWidthUniform, texelHeightUniform, edgeStrengthUniform; - BOOL hasOverriddenImageSizeFactor; -} - -// The texel width and height factors tweak the appearance of the edges. By default, they match the inverse of the filter size in pixels -@property(readwrite, nonatomic) CGFloat texelWidth; -@property(readwrite, nonatomic) CGFloat texelHeight; - -// The filter strength property affects the dynamic range of the filter. High values can make edges more visible, but can lead to saturation. Default of 1.0. -@property(readwrite, nonatomic) CGFloat edgeStrength; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSoftEleganceFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSoftEleganceFilter.h deleted file mode 100755 index 596e1567..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSoftEleganceFilter.h +++ /dev/null @@ -1,19 +0,0 @@ -#import "GPUImageFilterGroup.h" - -@class GPUImagePicture; - -/** A photo filter based on Soft Elegance Photoshop action - http://h-d-stock.deviantart.com/art/H-D-A-soft-elegance-70107603 - */ - -// Note: If you want to use this effect you have to add -// lookup_soft_elegance_1.png and lookup_soft_elegance_2.png -// from Resources folder to your application bundle. - -@interface GPUImageSoftEleganceFilter : GPUImageFilterGroup -{ - GPUImagePicture *lookupImageSource1; - GPUImagePicture *lookupImageSource2; -} - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSoftLightBlendFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSoftLightBlendFilter.h deleted file mode 100755 index 13fc877c..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSoftLightBlendFilter.h +++ /dev/null @@ -1,7 +0,0 @@ -#import "GPUImageTwoInputFilter.h" - -@interface GPUImageSoftLightBlendFilter : GPUImageTwoInputFilter -{ -} - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSolidColorGenerator.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSolidColorGenerator.h deleted file mode 100644 index 8d7a5ed1..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSolidColorGenerator.h +++ /dev/null @@ -1,19 +0,0 @@ -#import "GPUImageFilter.h" - -// This outputs an image with a constant color. You need to use -forceProcessingAtSize: in order to set the output image -// dimensions, or this won't work correctly - - -@interface GPUImageSolidColorGenerator : GPUImageFilter -{ - GLint colorUniform; - GLint useExistingAlphaUniform; -} - -// This color dictates what the output image will be filled with -@property(readwrite, nonatomic) GPUVector4 color; -@property(readwrite, nonatomic, assign) BOOL useExistingAlpha; // whether to use the alpha of the existing image or not, default is NO - -- (void)setColorRed:(GLfloat)redComponent green:(GLfloat)greenComponent blue:(GLfloat)blueComponent alpha:(GLfloat)alphaComponent; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSourceOverBlendFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSourceOverBlendFilter.h deleted file mode 100644 index 29e30635..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSourceOverBlendFilter.h +++ /dev/null @@ -1,5 +0,0 @@ -#import "GPUImageTwoInputFilter.h" - -@interface GPUImageSourceOverBlendFilter : GPUImageTwoInputFilter - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSphereRefractionFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSphereRefractionFilter.h deleted file mode 100644 index cbbd2afa..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSphereRefractionFilter.h +++ /dev/null @@ -1,15 +0,0 @@ -#import "GPUImageFilter.h" - -@interface GPUImageSphereRefractionFilter : GPUImageFilter -{ - GLint radiusUniform, centerUniform, aspectRatioUniform, refractiveIndexUniform; -} - -/// The center about which to apply the distortion, with a default of (0.5, 0.5) -@property(readwrite, nonatomic) CGPoint center; -/// The radius of the distortion, ranging from 0.0 to 1.0, with a default of 0.25 -@property(readwrite, nonatomic) CGFloat radius; -/// The index of refraction for the sphere, with a default of 0.71 -@property(readwrite, nonatomic) CGFloat refractiveIndex; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageStretchDistortionFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageStretchDistortionFilter.h deleted file mode 100755 index 07803095..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageStretchDistortionFilter.h +++ /dev/null @@ -1,13 +0,0 @@ -#import "GPUImageFilter.h" - -/** Creates a stretch distortion of the image - */ -@interface GPUImageStretchDistortionFilter : GPUImageFilter { - GLint centerUniform; -} - -/** The center about which to apply the distortion, with a default of (0.5, 0.5) - */ -@property(readwrite, nonatomic) CGPoint center; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSubtractBlendFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSubtractBlendFilter.h deleted file mode 100755 index 8dee8215..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSubtractBlendFilter.h +++ /dev/null @@ -1,5 +0,0 @@ -#import "GPUImageTwoInputFilter.h" - -@interface GPUImageSubtractBlendFilter : GPUImageTwoInputFilter - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSwirlFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSwirlFilter.h deleted file mode 100755 index ed7d0122..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageSwirlFilter.h +++ /dev/null @@ -1,17 +0,0 @@ -#import "GPUImageFilter.h" - -/** Creates a swirl distortion on the image - */ -@interface GPUImageSwirlFilter : GPUImageFilter -{ - GLint radiusUniform, centerUniform, angleUniform; -} - -/// The center about which to apply the distortion, with a default of (0.5, 0.5) -@property(readwrite, nonatomic) CGPoint center; -/// The radius of the distortion, ranging from 0.0 to 1.0, with a default of 0.5 -@property(readwrite, nonatomic) CGFloat radius; -/// The amount of distortion to apply, with a minimum of 0.0 and a default of 1.0 -@property(readwrite, nonatomic) CGFloat angle; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageThreeInputFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageThreeInputFilter.h deleted file mode 100644 index 5ecd53e0..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageThreeInputFilter.h +++ /dev/null @@ -1,21 +0,0 @@ -#import "GPUImageTwoInputFilter.h" - -extern NSString *const kGPUImageThreeInputTextureVertexShaderString; - -@interface GPUImageThreeInputFilter : GPUImageTwoInputFilter -{ - GPUImageFramebuffer *thirdInputFramebuffer; - - GLint filterThirdTextureCoordinateAttribute; - GLint filterInputTextureUniform3; - GPUImageRotationMode inputRotation3; - GLuint filterSourceTexture3; - CMTime thirdFrameTime; - - BOOL hasSetSecondTexture, hasReceivedThirdFrame, thirdFrameWasVideo; - BOOL thirdFrameCheckDisabled; -} - -- (void)disableThirdFrameCheck; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageThresholdEdgeDetectionFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageThresholdEdgeDetectionFilter.h deleted file mode 100755 index 2036030c..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageThresholdEdgeDetectionFilter.h +++ /dev/null @@ -1,12 +0,0 @@ -#import "GPUImageSobelEdgeDetectionFilter.h" - -@interface GPUImageThresholdEdgeDetectionFilter : GPUImageSobelEdgeDetectionFilter -{ - GLint thresholdUniform; -} - -/** Any edge above this threshold will be black, and anything below white. Ranges from 0.0 to 1.0, with 0.8 as the default - */ -@property(readwrite, nonatomic) CGFloat threshold; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageThresholdSketchFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageThresholdSketchFilter.h deleted file mode 100644 index fda58979..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageThresholdSketchFilter.h +++ /dev/null @@ -1,5 +0,0 @@ -#import "GPUImageThresholdEdgeDetectionFilter.h" - -@interface GPUImageThresholdSketchFilter : GPUImageThresholdEdgeDetectionFilter - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageThresholdedNonMaximumSuppressionFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageThresholdedNonMaximumSuppressionFilter.h deleted file mode 100644 index 9c6e5d72..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageThresholdedNonMaximumSuppressionFilter.h +++ /dev/null @@ -1,14 +0,0 @@ -#import "GPUImage3x3TextureSamplingFilter.h" - -@interface GPUImageThresholdedNonMaximumSuppressionFilter : GPUImage3x3TextureSamplingFilter -{ - GLint thresholdUniform; -} - -/** Any local maximum above this threshold will be white, and anything below black. Ranges from 0.0 to 1.0, with 0.8 as the default - */ -@property(readwrite, nonatomic) CGFloat threshold; - -- (id)initWithPackedColorspace:(BOOL)inputUsesPackedColorspace; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageTiltShiftFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageTiltShiftFilter.h deleted file mode 100755 index e41adee7..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageTiltShiftFilter.h +++ /dev/null @@ -1,24 +0,0 @@ -#import "GPUImageFilterGroup.h" - -@class GPUImageGaussianBlurFilter; - -/// A simulated tilt shift lens effect -@interface GPUImageTiltShiftFilter : GPUImageFilterGroup -{ - GPUImageGaussianBlurFilter *blurFilter; - GPUImageFilter *tiltShiftFilter; -} - -/// The radius of the underlying blur, in pixels. This is 7.0 by default. -@property(readwrite, nonatomic) CGFloat blurRadiusInPixels; - -/// The normalized location of the top of the in-focus area in the image, this value should be lower than bottomFocusLevel, default 0.4 -@property(readwrite, nonatomic) CGFloat topFocusLevel; - -/// The normalized location of the bottom of the in-focus area in the image, this value should be higher than topFocusLevel, default 0.6 -@property(readwrite, nonatomic) CGFloat bottomFocusLevel; - -/// The rate at which the image gets blurry away from the in-focus region, default 0.2 -@property(readwrite, nonatomic) CGFloat focusFallOffRate; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageToneCurveFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageToneCurveFilter.h deleted file mode 100755 index ff4ae92e..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageToneCurveFilter.h +++ /dev/null @@ -1,30 +0,0 @@ -#import "GPUImageFilter.h" - -@interface GPUImageToneCurveFilter : GPUImageFilter - -@property(readwrite, nonatomic, copy) NSArray *redControlPoints; -@property(readwrite, nonatomic, copy) NSArray *greenControlPoints; -@property(readwrite, nonatomic, copy) NSArray *blueControlPoints; -@property(readwrite, nonatomic, copy) NSArray *rgbCompositeControlPoints; - -// Initialization and teardown -- (id)initWithACVData:(NSData*)data; - -- (id)initWithACV:(NSString*)curveFilename; -- (id)initWithACVURL:(NSURL*)curveFileURL; - -// This lets you set all three red, green, and blue tone curves at once. -// NOTE: Deprecated this function because this effect can be accomplished -// using the rgbComposite channel rather then setting all 3 R, G, and B channels. -- (void)setRGBControlPoints:(NSArray *)points DEPRECATED_ATTRIBUTE; - -- (void)setPointsWithACV:(NSString*)curveFilename; -- (void)setPointsWithACVURL:(NSURL*)curveFileURL; - -// Curve calculation -- (NSMutableArray *)getPreparedSplineCurve:(NSArray *)points; -- (NSMutableArray *)splineCurve:(NSArray *)points; -- (NSMutableArray *)secondDerivative:(NSArray *)cgPoints; -- (void)updateToneCurveTexture; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageToonFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageToonFilter.h deleted file mode 100755 index ef8e17c3..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageToonFilter.h +++ /dev/null @@ -1,19 +0,0 @@ -#import "GPUImage3x3TextureSamplingFilter.h" - -/** This uses Sobel edge detection to place a black border around objects, - and then it quantizes the colors present in the image to give a cartoon-like quality to the image. - */ -@interface GPUImageToonFilter : GPUImage3x3TextureSamplingFilter -{ - GLint thresholdUniform, quantizationLevelsUniform; -} - -/** The threshold at which to apply the edges, default of 0.2 - */ -@property(readwrite, nonatomic) CGFloat threshold; - -/** The levels of quantization for the posterization of colors within the scene, with a default of 10.0 - */ -@property(readwrite, nonatomic) CGFloat quantizationLevels; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageTransformFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageTransformFilter.h deleted file mode 100755 index 9865b853..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageTransformFilter.h +++ /dev/null @@ -1,19 +0,0 @@ -#import "GPUImageFilter.h" - -@interface GPUImageTransformFilter : GPUImageFilter -{ - GLint transformMatrixUniform, orthographicMatrixUniform; - GPUMatrix4x4 orthographicMatrix; -} - -// You can either set the transform to apply to be a 2-D affine transform or a 3-D transform. The default is the identity transform (the output image is identical to the input). -@property(readwrite, nonatomic) CGAffineTransform affineTransform; -@property(readwrite, nonatomic) CATransform3D transform3D; - -// This applies the transform to the raw frame data if set to YES, the default of NO takes the aspect ratio of the image input into account when rotating -@property(readwrite, nonatomic) BOOL ignoreAspectRatio; - -// sets the anchor point to top left corner -@property(readwrite, nonatomic) BOOL anchorTopLeft; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageTwoInputCrossTextureSamplingFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageTwoInputCrossTextureSamplingFilter.h deleted file mode 100644 index 64eac9dc..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageTwoInputCrossTextureSamplingFilter.h +++ /dev/null @@ -1,15 +0,0 @@ -#import "GPUImageTwoInputFilter.h" - -@interface GPUImageTwoInputCrossTextureSamplingFilter : GPUImageTwoInputFilter -{ - GLint texelWidthUniform, texelHeightUniform; - - CGFloat texelWidth, texelHeight; - BOOL hasOverriddenImageSizeFactor; -} - -// The texel width and height determines how far out to sample from this texel. By default, this is the normalized width of a pixel, but this can be overridden for different effects. -@property(readwrite, nonatomic) CGFloat texelWidth; -@property(readwrite, nonatomic) CGFloat texelHeight; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageTwoInputFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageTwoInputFilter.h deleted file mode 100644 index da3a1345..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageTwoInputFilter.h +++ /dev/null @@ -1,21 +0,0 @@ -#import "GPUImageFilter.h" - -extern NSString *const kGPUImageTwoInputTextureVertexShaderString; - -@interface GPUImageTwoInputFilter : GPUImageFilter -{ - GPUImageFramebuffer *secondInputFramebuffer; - - GLint filterSecondTextureCoordinateAttribute; - GLint filterInputTextureUniform2; - GPUImageRotationMode inputRotation2; - CMTime firstFrameTime, secondFrameTime; - - BOOL hasSetFirstTexture, hasReceivedFirstFrame, hasReceivedSecondFrame, firstFrameWasVideo, secondFrameWasVideo; - BOOL firstFrameCheckDisabled, secondFrameCheckDisabled; -} - -- (void)disableFirstFrameCheck; -- (void)disableSecondFrameCheck; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageTwoPassFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageTwoPassFilter.h deleted file mode 100755 index 23087f35..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageTwoPassFilter.h +++ /dev/null @@ -1,19 +0,0 @@ -#import "GPUImageFilter.h" - -@interface GPUImageTwoPassFilter : GPUImageFilter -{ - GPUImageFramebuffer *secondOutputFramebuffer; - - GLProgram *secondFilterProgram; - GLint secondFilterPositionAttribute, secondFilterTextureCoordinateAttribute; - GLint secondFilterInputTextureUniform, secondFilterInputTextureUniform2; - - NSMutableDictionary *secondProgramUniformStateRestorationBlocks; -} - -// Initialization and teardown -- (id)initWithFirstStageVertexShaderFromString:(NSString *)firstStageVertexShaderString firstStageFragmentShaderFromString:(NSString *)firstStageFragmentShaderString secondStageVertexShaderFromString:(NSString *)secondStageVertexShaderString secondStageFragmentShaderFromString:(NSString *)secondStageFragmentShaderString; -- (id)initWithFirstStageFragmentShaderFromString:(NSString *)firstStageFragmentShaderString secondStageFragmentShaderFromString:(NSString *)secondStageFragmentShaderString; -- (void)initializeSecondaryAttributes; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageTwoPassTextureSamplingFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageTwoPassTextureSamplingFilter.h deleted file mode 100644 index 73ab79d3..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageTwoPassTextureSamplingFilter.h +++ /dev/null @@ -1,13 +0,0 @@ -#import "GPUImageTwoPassFilter.h" - -@interface GPUImageTwoPassTextureSamplingFilter : GPUImageTwoPassFilter -{ - GLint verticalPassTexelWidthOffsetUniform, verticalPassTexelHeightOffsetUniform, horizontalPassTexelWidthOffsetUniform, horizontalPassTexelHeightOffsetUniform; - GLfloat verticalPassTexelWidthOffset, verticalPassTexelHeightOffset, horizontalPassTexelWidthOffset, horizontalPassTexelHeightOffset; - CGFloat _verticalTexelSpacing, _horizontalTexelSpacing; -} - -// This sets the spacing between texels (in pixels) when sampling for the first. By default, this is 1.0 -@property(readwrite, nonatomic) CGFloat verticalTexelSpacing, horizontalTexelSpacing; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageUnsharpMaskFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageUnsharpMaskFilter.h deleted file mode 100755 index 9d8aff01..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageUnsharpMaskFilter.h +++ /dev/null @@ -1,16 +0,0 @@ -#import "GPUImageFilterGroup.h" - -@class GPUImageGaussianBlurFilter; - -@interface GPUImageUnsharpMaskFilter : GPUImageFilterGroup -{ - GPUImageGaussianBlurFilter *blurFilter; - GPUImageFilter *unsharpMaskFilter; -} -// The blur radius of the underlying Gaussian blur. The default is 4.0. -@property (readwrite, nonatomic) CGFloat blurRadiusInPixels; - -// The strength of the sharpening, from 0.0 on up, with a default of 1.0 -@property(readwrite, nonatomic) CGFloat intensity; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageView.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageView.h deleted file mode 100755 index 029883a1..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageView.h +++ /dev/null @@ -1,39 +0,0 @@ -#import -#import "GPUImageContext.h" - -typedef enum { - kGPUImageFillModeStretch, // Stretch to fill the full view, which may distort the image outside of its normal aspect ratio - kGPUImageFillModePreserveAspectRatio, // Maintains the aspect ratio of the source image, adding bars of the specified background color - kGPUImageFillModePreserveAspectRatioAndFill // Maintains the aspect ratio of the source image, zooming in on its center to fill the view -} GPUImageFillModeType; - -/** - UIView subclass to use as an endpoint for displaying GPUImage outputs - */ -@interface GPUImageView : NSOpenGLView -{ - GPUImageRotationMode inputRotation; -} - -/** The fill mode dictates how images are fit in the view, with the default being kGPUImageFillModePreserveAspectRatio - */ -@property(readwrite, nonatomic) GPUImageFillModeType fillMode; - -/** This calculates the current display size, in pixels, taking into account Retina scaling factors - */ -@property(readonly, nonatomic) CGSize sizeInPixels; - -@property(nonatomic) BOOL enabled; - -/** Handling fill mode - - @param redComponent Red component for background color - @param greenComponent Green component for background color - @param blueComponent Blue component for background color - @param alphaComponent Alpha component for background color - */ -- (void)setBackgroundColorRed:(GLfloat)redComponent green:(GLfloat)greenComponent blue:(GLfloat)blueComponent alpha:(GLfloat)alphaComponent; - -- (void)setCurrentlyReceivingMonochromeInput:(BOOL)newValue; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageVignetteFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageVignetteFilter.h deleted file mode 100755 index 37be9449..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageVignetteFilter.h +++ /dev/null @@ -1,22 +0,0 @@ -#import "GPUImageFilter.h" - -/** Performs a vignetting effect, fading out the image at the edges - */ -@interface GPUImageVignetteFilter : GPUImageFilter -{ - GLint vignetteCenterUniform, vignetteColorUniform, vignetteStartUniform, vignetteEndUniform; -} - -// the center for the vignette in tex coords (defaults to 0.5, 0.5) -@property (nonatomic, readwrite) CGPoint vignetteCenter; - -// The color to use for the Vignette (defaults to black) -@property (nonatomic, readwrite) GPUVector3 vignetteColor; - -// The normalized distance from the center where the vignette effect starts. Default of 0.5. -@property (nonatomic, readwrite) CGFloat vignetteStart; - -// The normalized distance from the center where the vignette effect ends. Default of 0.75. -@property (nonatomic, readwrite) CGFloat vignetteEnd; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageVoronoiConsumerFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageVoronoiConsumerFilter.h deleted file mode 100644 index 659e39d5..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageVoronoiConsumerFilter.h +++ /dev/null @@ -1,10 +0,0 @@ -#import "GPUImageTwoInputFilter.h" - -@interface GPUImageVoronoiConsumerFilter : GPUImageTwoInputFilter -{ - GLint sizeUniform; -} - -@property (nonatomic, readwrite) CGSize sizeInPixels; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageWeakPixelInclusionFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageWeakPixelInclusionFilter.h deleted file mode 100644 index 44b76c6a..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageWeakPixelInclusionFilter.h +++ /dev/null @@ -1,5 +0,0 @@ -#import "GPUImage3x3TextureSamplingFilter.h" - -@interface GPUImageWeakPixelInclusionFilter : GPUImage3x3TextureSamplingFilter - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageWhiteBalanceFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageWhiteBalanceFilter.h deleted file mode 100644 index eafd65a0..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageWhiteBalanceFilter.h +++ /dev/null @@ -1,17 +0,0 @@ -#import "GPUImageFilter.h" -/** - * Created by Alaric Cole - * Allows adjustment of color temperature in terms of what an image was effectively shot in. This means higher Kelvin values will warm the image, while lower values will cool it. - - */ -@interface GPUImageWhiteBalanceFilter : GPUImageFilter -{ - GLint temperatureUniform, tintUniform; -} -//choose color temperature, in degrees Kelvin -@property(readwrite, nonatomic) int temperature; - -//adjust tint to compensate -@property(readwrite, nonatomic) int tint; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageXYDerivativeFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageXYDerivativeFilter.h deleted file mode 100755 index 8db57457..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageXYDerivativeFilter.h +++ /dev/null @@ -1,5 +0,0 @@ -#import "GPUImageSobelEdgeDetectionFilter.h" - -@interface GPUImageXYDerivativeFilter : GPUImageSobelEdgeDetectionFilter - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageZoomBlurFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageZoomBlurFilter.h deleted file mode 100644 index 744a72cb..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUImageZoomBlurFilter.h +++ /dev/null @@ -1,13 +0,0 @@ -#import "GPUImageFilter.h" - -@interface GPUImageZoomBlurFilter : GPUImageFilter - -/** A multiplier for the blur size, ranging from 0.0 on up, with a default of 1.0 - */ -@property (readwrite, nonatomic) CGFloat blurSize; - -/** The normalized center of the blur. (0.5, 0.5) by default - */ -@property (readwrite, nonatomic) CGPoint blurCenter; - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUimageDirectionalSobelEdgeDetectionFilter.h b/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUimageDirectionalSobelEdgeDetectionFilter.h deleted file mode 100644 index 3aca7463..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Headers/GPUimageDirectionalSobelEdgeDetectionFilter.h +++ /dev/null @@ -1,5 +0,0 @@ -#import "GPUImage3x3TextureSamplingFilter.h" - -@interface GPUimageDirectionalSobelEdgeDetectionFilter : GPUImage3x3TextureSamplingFilter - -@end diff --git a/app/Frameworks/GPUImage.framework/Versions/A/Resources/Info.plist b/app/Frameworks/GPUImage.framework/Versions/A/Resources/Info.plist deleted file mode 100644 index 66b42e21..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/A/Resources/Info.plist +++ /dev/null @@ -1,42 +0,0 @@ - - - - - BuildMachineOSBuild - 13A603 - CFBundleDevelopmentRegion - English - CFBundleExecutable - GPUImage - CFBundleIdentifier - com.sunsetlakesoftware.GPUImage - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - GPUImage - CFBundlePackageType - FMWK - CFBundleShortVersionString - 1.0 - CFBundleSignature - ???? - CFBundleVersion - 1 - DTCompiler - com.apple.compilers.llvm.clang.1_0 - DTPlatformBuild - 5B1008 - DTPlatformVersion - GM - DTSDKBuild - 13C64 - DTSDKName - macosx10.9 - DTXcode - 0511 - DTXcodeBuild - 5B1008 - NSHumanReadableCopyright - Copyright © 2013 Sunset Lake Software LLC. All rights reserved. - - diff --git a/app/Frameworks/GPUImage.framework/Versions/Current b/app/Frameworks/GPUImage.framework/Versions/Current deleted file mode 120000 index 8c7e5a66..00000000 --- a/app/Frameworks/GPUImage.framework/Versions/Current +++ /dev/null @@ -1 +0,0 @@ -A \ No newline at end of file diff --git a/app/deps/tensorlib/filters.h b/app/deps/tensorlib/filters.h deleted file mode 100644 index 73a534d2..00000000 --- a/app/deps/tensorlib/filters.h +++ /dev/null @@ -1,11 +0,0 @@ -#import "filters/FilterBase.h" - -#import "filters/ColorInvertFilter.h" -#import "filters/HalftoneFilter.h" -#import "filters/SoftEleganceFilter.h" -#import "filters/MissEtikateFilter.h" -#import "filters/SepiaFilter.h" -#import "filters/pixel/AtkinsonFilter.h" -#import "filters/VignetteFilter.h" -#import "filters/GrayscaleFilter.h" -#import "filters/PolkaDotFilter.h" diff --git a/app/deps/tensorlib/filters/ColorInvertFilter.h b/app/deps/tensorlib/filters/ColorInvertFilter.h deleted file mode 100644 index 0fd548ba..00000000 --- a/app/deps/tensorlib/filters/ColorInvertFilter.h +++ /dev/null @@ -1,18 +0,0 @@ -// -// ColorInvertFilter.h -// PlotDevice -// -// Created by fish2k on 12/7/13. -// -// - -#import -#import -#import - -#import "FilterBase.h" - -@interface ColorInvertFilter : FilterBase { -} - -@end \ No newline at end of file diff --git a/app/deps/tensorlib/filters/ColorInvertFilter.m b/app/deps/tensorlib/filters/ColorInvertFilter.m deleted file mode 100644 index 5a5a4add..00000000 --- a/app/deps/tensorlib/filters/ColorInvertFilter.m +++ /dev/null @@ -1,21 +0,0 @@ -// -// ColorInvertFilter.m -// PlotDevice -// -// Created by fish2k on 12/13/13. -// -// - -#import "ColorInvertFilter.h" - -@implementation ColorInvertFilter - -- (id)init { - self = [super init]; - if (self) { - filter = (GPUImageFilter *)[[GPUImageColorInvertFilter alloc] init]; - } - return self; -} - -@end \ No newline at end of file diff --git a/app/deps/tensorlib/filters/FilterBase.h b/app/deps/tensorlib/filters/FilterBase.h deleted file mode 100644 index 1fc1f174..00000000 --- a/app/deps/tensorlib/filters/FilterBase.h +++ /dev/null @@ -1,24 +0,0 @@ -// -// FilterBase.h -// PlotDevice -// -// Created by fish2k on 12/7/13. -// -// - -#import -#import -#import - -@interface FilterBase : NSObject { - GPUImageFilter *filter; -} - -@property(nonatomic, retain) GPUImageFilter *filter; - -- (id)init; -- (NSImage *)process:(NSImage *)input; -- (void)STDOUT:(NSString *)string, ...; -- (void)STDERR:(NSString *)string, ...; - -@end \ No newline at end of file diff --git a/app/deps/tensorlib/filters/FilterBase.m b/app/deps/tensorlib/filters/FilterBase.m deleted file mode 100644 index dd39aa99..00000000 --- a/app/deps/tensorlib/filters/FilterBase.m +++ /dev/null @@ -1,58 +0,0 @@ -// -// FilterBase.m -// PlotDevice -// -// Created by fish2k on 12/13/13. -// -// - -#import "FilterBase.h" - -@implementation FilterBase -@synthesize filter; - -- (id)init { - self = [super init]; - if (!self) { - return nil; - } - return self; -} - -- (NSImage *)process:(NSImage *)input { - return [filter imageByFilteringImage:input]; -} - -- (void)STDOUT:(NSString *)string, ... { -#ifdef TENSORLIB_STDOUT - NSString *out = [NSString stringWithFormat:@"[%@] %@", - [self className], string]; - va_list args; - - va_start(args, string); - NSLogv(out, args); - NSString *stdOutString = [[NSString alloc] initWithFormat:out arguments:args]; - va_end(args); - - fprintf(stdout, "%s\n", [stdOutString UTF8String]); - [stdOutString release]; -#endif -} - -- (void)STDERR:(NSString *)string, ... { -#ifdef TENSORLIB_STDERR - NSString *err = [NSString stringWithFormat:@"[%@] ERROR: %@", - [self className], string]; - va_list args; - - va_start(args, string); - NSLogv(err, args); - NSString *stdErrString = [[NSString alloc] initWithFormat:err arguments:args]; - va_end(args); - - fprintf(stderr, "%s\n", [stdErrString UTF8String]); - [stdErrString release]; -#endif -} - -@end \ No newline at end of file diff --git a/app/deps/tensorlib/filters/GrayscaleFilter.h b/app/deps/tensorlib/filters/GrayscaleFilter.h deleted file mode 100644 index d054156a..00000000 --- a/app/deps/tensorlib/filters/GrayscaleFilter.h +++ /dev/null @@ -1,18 +0,0 @@ -// -// GrayscaleFilter.h -// PlotDevice -// -// Created by fish2k on 12/7/13. -// -// - -#import -#import -#import - -#import "FilterBase.h" - -@interface GrayscaleFilter : FilterBase { -} - -@end \ No newline at end of file diff --git a/app/deps/tensorlib/filters/GrayscaleFilter.m b/app/deps/tensorlib/filters/GrayscaleFilter.m deleted file mode 100644 index c4491cdf..00000000 --- a/app/deps/tensorlib/filters/GrayscaleFilter.m +++ /dev/null @@ -1,21 +0,0 @@ -// -// GrayscaleFilter.m -// PlotDevice -// -// Created by fish2k on 12/13/13. -// -// - -#import "GrayscaleFilter.h" - -@implementation GrayscaleFilter - -- (id)init { - self = [super init]; - if (self) { - filter = (GPUImageFilter *)[[GPUImageGrayscaleFilter alloc] init]; - } - return self; -} - -@end \ No newline at end of file diff --git a/app/deps/tensorlib/filters/HalftoneFilter.h b/app/deps/tensorlib/filters/HalftoneFilter.h deleted file mode 100644 index 995d1696..00000000 --- a/app/deps/tensorlib/filters/HalftoneFilter.h +++ /dev/null @@ -1,18 +0,0 @@ -// -// HalftoneFilter.h -// PlotDevice -// -// Created by fish2k on 12/7/13. -// -// - -#import -#import -#import - -#import "FilterBase.h" - -@interface HalftoneFilter : FilterBase { -} - -@end \ No newline at end of file diff --git a/app/deps/tensorlib/filters/HalftoneFilter.m b/app/deps/tensorlib/filters/HalftoneFilter.m deleted file mode 100644 index bfa8282c..00000000 --- a/app/deps/tensorlib/filters/HalftoneFilter.m +++ /dev/null @@ -1,21 +0,0 @@ -// -// HalftoneFilter.m -// PlotDevice -// -// Created by fish2k on 12/13/13. -// -// - -#import "HalftoneFilter.h" - -@implementation HalftoneFilter - -- (id)init { - self = [super init]; - if (self) { - filter = (GPUImageFilter *)[[GPUImageHalftoneFilter alloc] init]; - } - return self; -} - -@end \ No newline at end of file diff --git a/app/deps/tensorlib/filters/MissEtikateFilter.h b/app/deps/tensorlib/filters/MissEtikateFilter.h deleted file mode 100644 index b6d910e0..00000000 --- a/app/deps/tensorlib/filters/MissEtikateFilter.h +++ /dev/null @@ -1,18 +0,0 @@ -// -// MissEtikateFilter.h -// PlotDevice -// -// Created by fish2k on 12/7/13. -// -// - -#import -#import -#import - -#import "FilterBase.h" - -@interface MissEtikateFilter : FilterBase { -} - -@end \ No newline at end of file diff --git a/app/deps/tensorlib/filters/MissEtikateFilter.m b/app/deps/tensorlib/filters/MissEtikateFilter.m deleted file mode 100644 index c1391003..00000000 --- a/app/deps/tensorlib/filters/MissEtikateFilter.m +++ /dev/null @@ -1,21 +0,0 @@ -// -// MissEtikateFilter.m -// PlotDevice -// -// Created by fish2k on 12/13/13. -// -// - -#import "MissEtikateFilter.h" - -@implementation MissEtikateFilter - -- (id)init { - self = [super init]; - if (self) { - filter = (GPUImageFilter *)[[GPUImageMissEtikateFilter alloc] init]; - } - return self; -} - -@end \ No newline at end of file diff --git a/app/deps/tensorlib/filters/PolkaDotFilter.h b/app/deps/tensorlib/filters/PolkaDotFilter.h deleted file mode 100644 index 9f013a63..00000000 --- a/app/deps/tensorlib/filters/PolkaDotFilter.h +++ /dev/null @@ -1,18 +0,0 @@ -// -// PolkaDotFilter.h -// PlotDevice -// -// Created by fish2k on 12/7/13. -// -// - -#import -#import -#import - -#import "FilterBase.h" - -@interface PolkaDotFilter : FilterBase { -} - -@end \ No newline at end of file diff --git a/app/deps/tensorlib/filters/PolkaDotFilter.m b/app/deps/tensorlib/filters/PolkaDotFilter.m deleted file mode 100644 index ef08834f..00000000 --- a/app/deps/tensorlib/filters/PolkaDotFilter.m +++ /dev/null @@ -1,21 +0,0 @@ -// -// PolkaDotFilter.m -// PlotDevice -// -// Created by fish2k on 12/13/13. -// -// - -#import "PolkaDotFilter.h" - -@implementation PolkaDotFilter - -- (id)init { - self = [super init]; - if (self) { - filter = (GPUImageFilter *)[[GPUImagePolkaDotFilter alloc] init]; - } - return self; -} - -@end \ No newline at end of file diff --git a/app/deps/tensorlib/filters/SepiaFilter.h b/app/deps/tensorlib/filters/SepiaFilter.h deleted file mode 100644 index 3da4a1df..00000000 --- a/app/deps/tensorlib/filters/SepiaFilter.h +++ /dev/null @@ -1,18 +0,0 @@ -// -// SepiaFilter.h -// PlotDevice -// -// Created by fish2k on 12/7/13. -// -// - -#import -#import -#import - -#import "FilterBase.h" - -@interface SepiaFilter : FilterBase { -} - -@end \ No newline at end of file diff --git a/app/deps/tensorlib/filters/SepiaFilter.m b/app/deps/tensorlib/filters/SepiaFilter.m deleted file mode 100644 index fe77eeba..00000000 --- a/app/deps/tensorlib/filters/SepiaFilter.m +++ /dev/null @@ -1,21 +0,0 @@ -// -// SepiaFilter.m -// PlotDevice -// -// Created by fish2k on 12/13/13. -// -// - -#import "SepiaFilter.h" - -@implementation SepiaFilter - -- (id)init { - self = [super init]; - if (self) { - filter = (GPUImageFilter *)[[GPUImageSepiaFilter alloc] init]; - } - return self; -} - -@end \ No newline at end of file diff --git a/app/deps/tensorlib/filters/SoftEleganceFilter.h b/app/deps/tensorlib/filters/SoftEleganceFilter.h deleted file mode 100644 index ed3d0997..00000000 --- a/app/deps/tensorlib/filters/SoftEleganceFilter.h +++ /dev/null @@ -1,18 +0,0 @@ -// -// SoftEleganceFilter.h -// PlotDevice -// -// Created by fish2k on 12/7/13. -// -// - -#import -#import -#import - -#import "FilterBase.h" - -@interface SoftEleganceFilter : FilterBase { -} - -@end \ No newline at end of file diff --git a/app/deps/tensorlib/filters/SoftEleganceFilter.m b/app/deps/tensorlib/filters/SoftEleganceFilter.m deleted file mode 100644 index f9a347af..00000000 --- a/app/deps/tensorlib/filters/SoftEleganceFilter.m +++ /dev/null @@ -1,21 +0,0 @@ -// -// SoftEleganceFilter.m -// PlotDevice -// -// Created by fish2k on 12/13/13. -// -// - -#import "SoftEleganceFilter.h" - -@implementation SoftEleganceFilter - -- (id)init { - self = [super init]; - if (self) { - filter = (GPUImageFilter *)[[GPUImageSoftEleganceFilter alloc] init]; - } - return self; -} - -@end \ No newline at end of file diff --git a/app/deps/tensorlib/filters/VignetteFilter.h b/app/deps/tensorlib/filters/VignetteFilter.h deleted file mode 100644 index d55de866..00000000 --- a/app/deps/tensorlib/filters/VignetteFilter.h +++ /dev/null @@ -1,18 +0,0 @@ -// -// VignetteFilter.h -// PlotDevice -// -// Created by fish2k on 12/7/13. -// -// - -#import -#import -#import - -#import "FilterBase.h" - -@interface VignetteFilter : FilterBase { -} - -@end \ No newline at end of file diff --git a/app/deps/tensorlib/filters/VignetteFilter.m b/app/deps/tensorlib/filters/VignetteFilter.m deleted file mode 100644 index a0749121..00000000 --- a/app/deps/tensorlib/filters/VignetteFilter.m +++ /dev/null @@ -1,21 +0,0 @@ -// -// VignetteFilter.m -// PlotDevice -// -// Created by fish2k on 12/13/13. -// -// - -#import "VignetteFilter.h" - -@implementation VignetteFilter - -- (id)init { - self = [super init]; - if (self) { - filter = (GPUImageFilter *)[[GPUImageVignetteFilter alloc] init]; - } - return self; -} - -@end \ No newline at end of file diff --git a/app/deps/tensorlib/filters/pixel/AtkinsonFilter.h b/app/deps/tensorlib/filters/pixel/AtkinsonFilter.h deleted file mode 100644 index 3d327a39..00000000 --- a/app/deps/tensorlib/filters/pixel/AtkinsonFilter.h +++ /dev/null @@ -1,29 +0,0 @@ -// -// AtkinsonFilter.h -// PlotDevice -// -// Created by fish2k on 12/7/13. -// -// - -#import -#import -#import - -#import "../FilterBase.h" - -/// inline macro that adds the error so that it doesn't overflow an unsigned char -#ifndef adderror -#define adderror( b, e ) ( ((b) < -(e)) ? 0x00 : ( ((0xFF - (b)) < (e)) ? 0xFF : (b + e) ) ) -#endif - -/// threshold matrix (in leu of "if something > somethingelse" and suchlike) -static unsigned char threshold[256]; - -/// forward declaration of the bytearray-level atkinson function -unsigned char *atkinson(unsigned char *pixels, int w, int h, int bpp, int len); - -/// FilterBase subclass boilerplate interface -@interface AtkinsonFilter : FilterBase {} - -@end \ No newline at end of file diff --git a/app/deps/tensorlib/filters/pixel/AtkinsonFilter.m b/app/deps/tensorlib/filters/pixel/AtkinsonFilter.m deleted file mode 100644 index b29e9cb9..00000000 --- a/app/deps/tensorlib/filters/pixel/AtkinsonFilter.m +++ /dev/null @@ -1,136 +0,0 @@ -// -// AtkinsonFilter.m -// PlotDevice -// -// Created by fish2k on 12/13/13. -// -// - -#include -#include - -#import "AtkinsonFilter.h" - -/// bytearray-level atkinson pixel processing function -unsigned char *atkinson(unsigned char *inputPixels, int w, int h, int bpp, int len) { - int x, y, off, err; - unsigned char *outputPixels = malloc(sizeof(unsigned char) * len); - unsigned char old, new; - - if (w * h != len) { - /// if the dimensions don't fully check out, - /// I fucking walk - return NULL; - } - - //memcpy(outputPixels, inputPixels, sizeof(unsigned char) * len * bpp); - memset(outputPixels, 0, sizeof(unsigned char) * len); - for (y = 0; y < h; y++) { - for (x = 0; x < w; x++) { - off = (y * w) + x; - outputPixels[off] = inputPixels[off * bpp]; - } - } - - for (y = 0; y < h; y++) { - for (x = 0; x < w; x++) { - /// pixel (x, y) offset within the 1D char buffer - off = (y * w) + x; - - /// threshold and error value - old = outputPixels[off]; - new = threshold[ outputPixels[off] ]; - err = (old - new) >> 3; - - /// update the image - outputPixels[off] = new; - - /// add error values - if (x+1 < w) { - outputPixels[off + 1] = adderror(outputPixels[off + 1], err); - } - if (x+2 < w) { - outputPixels[off + 2] = adderror(outputPixels[off + 2], err); - } - if (x > 0 && y+1 < h) { - outputPixels[off + w - 1] = adderror(outputPixels[off + w - 1], err); - } - if (y+1 < h) { - outputPixels[off + w] = adderror(outputPixels[off + w], err); - } - if (x+1 < w && y+1 < h) { - outputPixels[off + w + 1] = adderror(outputPixels[off + w + 1], err); - } - if (y+2 < h) { - outputPixels[off + 2 * w] = adderror(outputPixels[off + 2 * w], err); - } - } - } - - return outputPixels; -} - -/// AtkinsonFilter -- FilterBase subclass implementation -@implementation AtkinsonFilter - -- (id)init { - int i; - self = [super init]; - - if (self) { - for (i = 0; i < 128; i++) { - threshold[i] = 0x00; - } - for (i = 128; i < 256; i++) { - threshold[i] = 0xFF; - } - filter = (GPUImageFilter *)[[GPUImageGrayscaleFilter alloc] init]; - } - return self; -} - -- (NSImage *)process:(NSImage *)input { - [self STDOUT:@"Preprocessing atkinson filter image"]; - NSImage *inputGrayscale = [filter imageByFilteringImage:input]; - NSBitmapImageRep *inputRep = [NSBitmapImageRep - imageRepWithData:[ - inputGrayscale TIFFRepresentation]]; - - int w = (int)[inputRep pixelsWide]; - int h = (int)[inputRep pixelsHigh]; - int bpp = (int)[inputRep bitsPerPixel] / 8; - int length = w * h; - - [self STDOUT:@"About to call atkinson():"]; - [self STDOUT:@" WIDTH = %i, HEIGHT = %i, LENGTH = %li, BPP = %i", - w, h, length, bpp]; - unsigned char *inputData = [inputRep bitmapData]; - unsigned char *outputData = atkinson(inputData, w, h, bpp, length); - - if (outputData == NULL) { - [self STDERR:@"Bad dimensions passed to atkinson():"]; - [self STDERR:@" WIDTH = %i, HEIGHT = %i, LENGTH = %li", - w, h, length]; - return inputGrayscale; - } - - NSBitmapImageRep *outputRep = [[[NSBitmapImageRep alloc] - initWithBitmapDataPlanes:&outputData - pixelsWide:w - pixelsHigh:h - bitsPerSample:8 - samplesPerPixel:1 - hasAlpha:NO - isPlanar:NO - colorSpaceName:NSCalibratedWhiteColorSpace - bytesPerRow:w - bitsPerPixel:8] autorelease]; - - [self STDOUT:@"About to return atkinson-ized image"]; - NSImage *output = [[NSImage alloc] initWithSize:NSMakeSize(w, h)]; - [output addRepresentation:outputRep]; - return output; -} - -@end - diff --git a/app/deps/tensorlib/module.m b/app/deps/tensorlib/module.m deleted file mode 100644 index 0310e3b4..00000000 --- a/app/deps/tensorlib/module.m +++ /dev/null @@ -1,26 +0,0 @@ -#import -#import - -#import "filters.h" - -/* - * Stub python module declaration -- - * Allows Objective-C classes with which it is linked - * to be found and loaded from python via `objc.lookUpClass()` - */ - -static PyObject *TensorlibError; -static PyMethodDef methods[] = { - { NULL, NULL }, -}; - -PyMODINIT_FUNC -inittensorlib(void) { - PyObject *module; - - module = Py_InitModule("tensorlib", methods); - TensorlibError = PyErr_NewException("tensorlib.error", NULL, NULL); - Py_INCREF(TensorlibError); - PyModule_AddObject(module, "error", TensorlibError); -} - diff --git a/app/deps/tensorlib/setup.py b/app/deps/tensorlib/setup.py deleted file mode 100644 index 58a06440..00000000 --- a/app/deps/tensorlib/setup.py +++ /dev/null @@ -1,61 +0,0 @@ -from __future__ import print_function - -from pprint import pprint -from os import getcwd, walk -from os.path import splitext, dirname, join -from setuptools import setup -from setuptools.extension import Extension - -frameworks = join(dirname(dirname(getcwd())), 'Frameworks') -gpuimage_libs = join(frameworks, 'GPUImage.framework', 'Versions', 'A') -gpuimage_headers = join(gpuimage_libs, 'Headers') - -def find_filters(base_path="filters"): - filters = dict() - for root_path, dirs, files in walk(base_path): - for file_name in files: - if file_name.lower().endswith('filter.m'): - filter_name, _ = splitext(file_name) - filters[filter_name] = join(root_path, filter_name) - return filters - -def get_sources(filter_dict, suffix="m"): - return ["%s.%s" % (filter_pth, suffix) for filter_pth in filter_dict.values()] - -def write_filter_header(filter_dict): - headers = get_sources(filter_dict, suffix="h") - with open("filters.h", 'wb') as header_fh: - header_fh.write('''#import "filters/FilterBase.h"\n\n''') - header_fh.writelines(['''#import "%s"\n''' % header for header in headers]) - -filters = find_filters() -sources = ['module.m', 'filters/FilterBase.m'] -sources.extend(get_sources(filters)) -write_filter_header(filters) - -print('Building tensorlib with %d filters:' % len(filters)) -pprint(sorted(filters.keys())) - -tensorlib = Extension('tensorlib', - sources=sources, - extra_compile_args=[ - '-Wno-error=unused-command-line-argument-hard-error-in-future', - '-Wno-unused-function', - '-Qunused-arguments', - '-DTENSORLIB_STDOUT', - '-DTENSORLIB_STDERR', - '-F%s' % frameworks], - extra_link_args=[ - '-Wno-error=unused-command-line-argument-hard-error-in-future', - '-L%s' % gpuimage_libs, - '-F%s' % frameworks, - '-framework', 'AppKit', - '-framework', 'Foundation', - '-framework', 'GPUImage']) - -setup(name="tensorlib", - version="1.0", - author="fish2k", - description="GPU-based image processing", - ext_modules=[tensorlib], - include_dirs=[gpuimage_headers]) \ No newline at end of file diff --git a/plotdevice/context.py b/plotdevice/context.py index 5394cd8b..329e4500 100644 --- a/plotdevice/context.py +++ b/plotdevice/context.py @@ -5,7 +5,7 @@ from collections import namedtuple from .util import _copy_attr, _copy_attrs, _flatten, trim_zeroes -from .lib import geometry, pathmatics, tensor +from .lib import geometry, pathmatics from .gfx.transform import Dimension from .gfx import * from . import gfx, lib, util, Halted, DeviceError @@ -1072,23 +1072,6 @@ def textheight(self, txt, width=None, **kwargs): ### Image commands ### - def imagefilter(self, filterName): - className = "%sFilter" % filterName - imageFilter = None - try: - imageFilter = objc.lookUpClass(className).alloc().init() - except objc.nosuchclass_error: - pass - return imageFilter - - def _imagefilter(self, filterName): - return - if hasattr(tensor, filterName): - print "Loading %s" % filterName - AXFilter = getattr(tensor, filterName) - return AXFilter() - - def image(self, *args, **kwargs): """Draw a bitmap or vector image @@ -1107,13 +1090,14 @@ def image(self, *args, **kwargs): draw = kwargs.pop('plot', draw) imageFilter = kwargs.pop('filter', None) - imageFilterName = hasattr(imageFilter, 'className') and str(imageFilter.className()) or '' + #imageFilterName = hasattr(imageFilter, 'className') and str(imageFilter.className()) or '' img = Image(*args, **kwargs) if imageFilter and imageFilterName: - print "Applying image filter: %s" % imageFilterName - img.applyFilter(imageFilter) + pass + #print "Applying image filter: %s" % imageFilterName + #img.applyFilter(imageFilter) if draw: img.draw() diff --git a/plotdevice/gfx/image.py b/plotdevice/gfx/image.py index de1a4be6..b3385cbd 100644 --- a/plotdevice/gfx/image.py +++ b/plotdevice/gfx/image.py @@ -128,11 +128,6 @@ def image(self): warnings.warn("The 'image' attribute is deprecated. Please use _nsImage instead.", DeprecationWarning, stacklevel=2) return self._nsImage - def applyFilter(self, gpuFilter): - filteredNSImage = gpuFilter.process_(self._nsImage) - if filteredNSImage: - self._nsImage = filteredNSImage - @property def _nsBitmap(self): for bitmap in self._nsImage.representations(): diff --git a/plotdevice/lib/__init__.py b/plotdevice/lib/__init__.py index 94b870fe..5c15e3f1 100644 --- a/plotdevice/lib/__init__.py +++ b/plotdevice/lib/__init__.py @@ -1,4 +1,4 @@ -import sys, warnings +import sys from os.path import join, abspath, dirname, exists from pprint import pformat @@ -14,7 +14,7 @@ raise RuntimeError(unbuilt) # test the sys.path by attempting to load the c-extensions -# io, geometry, pathmatics, tensorlib -- (cIO.so, cGeometry.so, cPathmatics.so, & tensorlib.so) +# io, geometry, pathmatics, -- (cIO.so, cGeometry.so & cPathmatics.so) notfound_tmpl = "Couldn't load extension: %s.so\nSearched in:\n%s\nto no avail..." notfound = lambda lib_name: notfound_tmpl % ( lib_name, pformat(sys.path)) @@ -34,14 +34,8 @@ except ImportError: raise RuntimeError(notfound('cPathmatics')) -try: - import tensorlib -except ImportError: - #raise RuntimeError(notfound('tensorlib')) - warnings.warn(notfound('tensorlib')) - # FUCKING FLAKE-EIGHT ENOUGH ALREADY FOR FUCK'S SAKE -io = geometry = pathmatics = tensorlib = None +io = geometry = pathmatics = None # allow Libraries to request a _ctx reference def register(module): diff --git a/plotdevice/lib/rtclass.py b/plotdevice/lib/rtclass.py deleted file mode 100644 index d7e89b43..00000000 --- a/plotdevice/lib/rtclass.py +++ /dev/null @@ -1,94 +0,0 @@ - -from __future__ import print_function -# from functools import partial -import sys, objc, warnings - -OBJ_COLON = '_' - -class ObjCAncestor(type): - """ Subclass RTClass using the name of an Objective-C class - to generate a pythonic wrapper (if you like your syntax sweet) - """ - def __init__(cls, name, bases, attrs): - # print("%s, (%s) {%s}" % (name, bases, attrs.keys())) - # creator = partial(cls.__new__, cls) - if name == 'RTClass': - # Don't search for something named RTClass - super(ObjCAncestor, cls).__init__(name, bases, attrs) - return - try: - cls.__rtbase__ = objc.lookUpClass(name) - except objc.nosuchclass_error: - warnings.warn("Objective-C class '%s' not found" % name) - super(ObjCAncestor, cls).__init__(name, bases, attrs) - return - super(ObjCAncestor, cls).__init__(name, tuple([cls.__rtbase__] + list(bases) + [object]), attrs) - -class RTClass(object): - __metaclass__ = ObjCAncestor - - def __init__(self, *args, **kwargs): - """ Allow PyObjC-based RTClass subclasses to initialize pythonically e.g. - - nsarray = NSArray() # or: - nsarray = NSArray(other_nsarray, - init='initWithArray') - - rather than having to do the ObjC allocation/initialization dance: - - nsarray = NSArray.alloc().initWithArray_(other_nsarray) # bah - """ - cls = self.__class__ - if hasattr(cls, '__rtbase__'): - objc_cls = cls.__rtbase__ - init_method_name = kwargs.pop('init', 'init') - if hasattr(objc_cls, 'alloc'): - instance = objc_cls.alloc() - init_method = getattr(instance, init_method_name) - self.__rtinstance__ = init_method(*args) - elif hasattr(objc_cls, 'init'): - init_method = getattr(objc_cls, init_method_name) - self.__rtinstance__ = init_method(*args) - object.__init__(self, *args, **kwargs) - - def __getattr__(self, attr): - """ For unknown attributes that don't end in underscores, - look for their underscored counterpart before bailing. """ - if not attr.endswith(OBJ_COLON): - alt_attr = attr + OBJ_COLON - if hasattr(self.__rtinstance__, alt_attr): - return getattr(self.__rtinstance__, alt_attr) - raise AttributeError('%s (tried with underscore)' % attr) - if hasattr(self.__rtinstance__, attr): - return getattr(self.__rtinstance__, attr) - raise AttributeError(attr) - - def __repr__(self): - # This may be a bad idea, let's find out - return "(%s) <<- %s" % ( - self.__class__.__name__, - super(RTClass, self).__repr__()) - - - -if __name__ == '__main__': - try: - import tensorlib - except ImportError: - sys.exit(1) - - class NSImage(RTClass): - pass - - class PolkaDotFilter(RTClass): - pass - - polkadotter = PolkaDotFilter() - - print(polkadotter) - print(polkadotter.__class__) - print(polkadotter.__class__.__bases__) - #print(polkadotter.process) - print(polkadotter) - - print(dir(tensorlib)) diff --git a/plotdevice/lib/tensor.py b/plotdevice/lib/tensor.py deleted file mode 100644 index 2d2f04d4..00000000 --- a/plotdevice/lib/tensor.py +++ /dev/null @@ -1,200 +0,0 @@ - -from __future__ import print_function - -import objc, tensorlib -from .rtclass import RTClass -from collections import defaultdict - -class ColorInvertFilter(RTClass): - """ Wrapper for tensorlib/ColorInvertFilter """ - pass - -class HalftoneFilter(RTClass): - """ Wrapper for tensorlib/HalftoneFilter """ - pass - -class SoftEleganceFilter(RTClass): - """ Wrapper for tensorlib/SoftElegaceFilter """ - pass - -class MissEtikateFilter(RTClass): - """ Wrapper for tensorlib/MissEtikateFilter """ - pass - -class SepiaFilter(RTClass): - """ Wrapper for tensorlib/SepiaFilter """ - pass - -class AtkinsonFilter(RTClass): - """ Wrapper for tensorlib/pixel/AtkinsonFilter """ - pass - -class VignetteFilter(RTClass): - """ Wrapper for tensorlib/VignetteFilter """ - pass - -class GrayscaleFilter(RTClass): - """ Wrapper for tensorlib/GrayscaleFilter """ - pass - -class PolkaDotFilter(RTClass): - """ Wrapper for tensorlib/PolkaDotFilter """ - pass - -def split_abbreviations(s): - abbreviations = [] - current_token = '' - for char in s: - if current_token is '': - current_token += char - elif char.islower(): - current_token += char - else: - abbreviations.append(str(current_token)) - current_token = '' - current_token += char - if current_token is not '': - abbreviations.append(str(current_token)) - return abbreviations - -COLORSPACE_MODES = defaultdict(lambda: 'Unknown', { - 'L': "Gray", - 'Gray': "Gray", - - 'RGB': "RGB", - 'CMYK': "CMYK", - 'LAB': "LAB", - - 'NCL': "DeviceN", - 'NCL2': "DeviceN", - 'DeviceN': "DeviceN", - - 'P': "Indexed", - 'Indexed': "Indexed", - - 'PAT': "Pattern", - 'PPAT': "Pattern", - 'Pattern': "Pattern", -}) - -COLORSPACE_MODEL = lambda midx: "NS%sColorSpaceModel" % COLORSPACE_MODES[midx] - -class Pipe(list): - """ A linear pipeline of processors to be applied en masse. """ - def process(self, img): - for p in self: - img = p.process(img) - return img - -class NOOp(object): - """ A no-op processor. """ - def process(self, img): - return img - -''' -class ChannelFork(defaultdict): - """ A processor wrapper that, for each image channel: - - applies a channel-specific processor, or - - applies a default processor. """ - - default_mode = 'RGB' # 'NSRGBColorSpaceModel' - - def __init__(self, default_factory, *args, **kwargs): - if default_factory is None: - default_factory = NOOp - if not callable(default_factory): - raise AttributeError( - "ChannelFork() requires a callable default_factory.") - - self.channels = COLORSPACE_MODEL[kwargs.pop('mode', self.default_mode)] - - super(ChannelFork, self).__init__(default_factory, *args, **kwargs) - - def __setitem__(self, idx, value): - if value in (None, NOOp): - value = NOOp() - super(ChannelFork, self).__setitem__(idx, value) - - @property - def mode(self): - return self.channels.mode - - @mode.setter - def mode(self, mode_string): - self._set_mode(mode_string) - - def _set_mode(self, mode_string): - self.channels = ImageMode.getmode(mode_string) - - def compose(self, *channels): - return Image.merge( - self.channels.mode, - channels) - - def process(self, img): - if img.mode != self.channels.mode: - img = img.convert(self.channels.mode) - - processed_channels = [] - for idx, channel in enumerate(img.split()): - processed_channels.append( - self[self.channels.bands[idx]].process(channel)) - - return self.compose(*processed_channels) - -class CMYKInk(object): - """ Renders an input L-mode image, - by simulating a CMYK primary ink color. - """ - - WHITE = (255, 255, 255) - CYAN = (0, 250, 250) - MAGENTA = (250, 0, 250) - YELLOW = (250, 250, 0) - KEY = (0, 0, 0) - CMYK = (CYAN, MAGENTA, YELLOW, KEY) - - def __init__(self, ink_value=None): - if ink_value is None: - ink_value = self.KEY - self.ink_value = ink_value - - def process(self, img): - from PIL import ImageOps - return ImageOps.colorize( - img.convert('L'), - self.WHITE, - self.ink_value) - - -class ChannelOverprinter(ChannelFork): - """ A ChannelFork subclass that rebuilds its output image using - multiply-mode to simulate CMYK overprinting effects. - """ - default_mode = 'CMYK' - - def _set_mode(self, mode_string): - if mode_string != self.default_mode: - raise AttributeError( - "ChannelOverprinter can operate in %s mode only" % - self.default_mode) - - def compose(self, *channels): - from PIL import ImageChops - return reduce(ImageChops.multiply, channels) - - def process(self, img): - inks = zip(self.default_mode, - [CMYKInk(ink_label) \ - for ink_label in CMYKInk.CMYK]) - - clone = ChannelOverprinter( - self.default_factory, - mode=self.channels.mode) - - for channel_name, ink in inks: - clone[channel_name] = Pipe([ - self[channel_name], ink]) - - return super(ChannelOverprinter, clone).process(img) -''' diff --git a/setup.py b/setup.py index ab638143..c6d58a26 100644 --- a/setup.py +++ b/setup.py @@ -17,7 +17,7 @@ # - Mac OS X 10.9+ # - py2app or xcode or just pip # - PyObjC (should be in /System/Library/Frameworks/Python.framework/Versions/2.7/Extras) -# - cPathMatics, cGeo, cIO, cEvent, tensorlib, & polymagic (included in the "app/deps" folder) +# - cPathMatics, cGeo, cIO, cEvent, & polymagic (included in the "app/deps" folder) # - Sparkle.framework (auto-downloaded only for `dist` builds) import sys, os, urllib2, plistlib @@ -26,8 +26,8 @@ from distutils.file_util import write_file as write from setuptools import setup, find_packages from pkg_resources import DistributionNotFound -from os import listdir, chdir, getcwd -from os.path import join, exists, isdir, dirname, basename, abspath, relpath, getsize +from os import listdir, getcwd +from os.path import join, exists, isdir, dirname, basename, abspath, getsize ## Metadata ## __version__ = '0.9.2' @@ -93,10 +93,6 @@ SPARKLE_VERSION = '1.7.0' SPARKLE_URL = 'https://github.com/pornel/Sparkle/releases/download/%(v)s/Sparkle-%(v)s.tar.bz2'% { 'v': SPARKLE_VERSION } -# ... as will the GPUImage framework source -GPUIMAGE_VERSION = '0.1.5' # latest stable -GPUIMAGE_URL = "https://github.com/BradLarson/GPUImage/archive/%(v)s.zip" % { 'v': GPUIMAGE_VERSION } - # helpers for dealing with plists & git (spiritual cousins if ever there were) def info_plist(pth='app/PlotDevice-Info.plist'): info = plistlib.readPlist(pth) @@ -357,7 +353,6 @@ def run(self): print "done building PlotDevice.app in ./dist" try: - #import py2app from py2app.build_app import py2app as build_py2app class BuildPy2AppCommand(build_py2app): description = """Build PlotDevice.app with py2app (then undo some of its questionable layout defaults)""" @@ -384,37 +379,17 @@ def run(self): RSRC = self.resdir CONTENTS = dirname(RSRC) BIN = join(CONTENTS, 'SharedSupport') - FRAMEWORKS = join(CONTENTS, 'Frameworks') - GPUIMAGE = join(FRAMEWORKS, 'GPUImage.framework') MODULE = join(self.bdist_base, 'lib', 'plotdevice') PY = join(RSRC, 'python') PLOTDEVICE = join(PY, 'plotdevice') - FAKEWORKS = join(PLOTDEVICE, 'Frameworks') # YOU HAVE GOT TO BE FRIGGING KIDDING ME DITTO = which('ditto') - LN = which('ln') - for pth in BIN, GPUIMAGE, PY: + for pth in BIN, PY: self.mkpath(pth) # install the module in Resources/python self.spawn([DITTO, MODULE, PLOTDEVICE]) - # deposit a copy of GPUImage.framework in Frameworks - self.spawn([DITTO, 'app/Frameworks/GPUImage.framework', GPUIMAGE]) - - # compiling PyObjC extensions that link against GPUImage will, - # inevitably, hardcode the dynamic-link path in the output binaries - # -- HELLOOOOO?!? WHY is this a problem if it's "DYNAMIC" linking -- - # but so we need this symlink to compensate for the difference - # in the relative location of GPUImage.framework in the project tree, - # _qua_ the application bundle, vis-a-vis the extensions in question - CAMEFROM = getcwd() - chdir(PLOTDEVICE) - self.spawn([LN, '-s', - relpath(FRAMEWORKS, start=PLOTDEVICE), - relpath(FAKEWORKS, start=PLOTDEVICE)]) - chdir(CAMEFROM) - # discard the eggery-pokery remove_tree(join(RSRC, 'lib'), dry_run=self.dry_run) os.unlink(join(RSRC, 'include')) @@ -488,41 +463,9 @@ def run(self): tar=which('tar'), fw=FRAMEWORKS)) self.mkpath(dirname(SPARKLE)) self.spawn([DITTO, ORIG, SPARKLE]) - - # Download an GPUImage release and build it, copying the build product - # into the bundle. Brad Larson (the GPUImage guy) doesn't release binaries, - # so if we're minus the bundle we have to build ourselves a new one. - # See also: https://github.com/BradLarson/GPUImage/releases - ORIG = join(FRAMEWORKS, 'GPUImage.framework') - GPUIMAGE = join(APP, 'Contents', 'Frameworks', 'GPUImage.framework') - if not exists(ORIG): - print "Downloading GPUImage source" - import tempfile - tempdir = tempfile.mkdtemp(suffix='XXXXX') - os.system('%(curl)s -L %(url)s | %(tar)s xzf - -C %(temp)s' % dict( - curl=which('curl'), url=GPUIMAGE_URL, - tar=which('tar'), temp=tempdir)) - GPUIMAGE_SOURCE = join(tempdir, 'GPUImage-%s' % GPUIMAGE_VERSION, 'framework') - GPUIMAGE_XCPROJECT = join(GPUIMAGE_SOURCE, 'GPUImageMac.xcodeproj') - GPUIMAGE_BUILT = join(GPUIMAGE_SOURCE, 'build', 'Release', 'GPUImage.framework') - if not exists(GPUIMAGE_SOURCE): - print "ERROR: there was a problem getting the GPUImage source" - sys.exit(1) - print "Building GPUImage.framework" - self.spawn([which('xcodebuild'), - '-project', GPUIMAGE_XCPROJECT, - '-scheme', 'GPUImage', - '-arch', 'x86_64']) - if not exists(GPUIMAGE_BUILT): - print "ERROR: there was a problem building the GPUImage source" - sys.exit(1) - self.spawn([DITTO, GPUIMAGE_BUILT, ORIG]) - self.remove_tree(tempdir, dry_run=self.dry_run) - self.spawn([DITTO, ORIG, GPUIMAGE]) # code-sign the app and sparkle bundles, then verify self.spawn(['codesign', '-f', '-v', '-s', "Developer ID Application", SPARKLE]) - self.spawn(['codesign', '-f', '-v', '-s', "Developer ID Application", GPUIMAGE]) self.spawn(['codesign', '-f', '-v', '-s', "Developer ID Application", APP]) self.spawn(['spctl', '--assess', '-v', 'dist/PlotDevice.app']) From 5927ea0767b0df507e7e3ba6dff9b3ffe53121c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Bo=CC=88hn?= Date: Wed, 16 Jul 2014 17:05:08 -0700 Subject: [PATCH 66/81] Less absurdly grotesque REPL terminal script installation --- PlotDevice.xcodeproj/project.pbxproj | 16 +++++++++++----- app/bplotdevice | 14 ++++++++++++++ app/plotdevice-term.py | 5 ----- plotdevice/gui/app.py | 2 +- setup.py | 24 +++++------------------- 5 files changed, 31 insertions(+), 30 deletions(-) create mode 100755 app/bplotdevice diff --git a/PlotDevice.xcodeproj/project.pbxproj b/PlotDevice.xcodeproj/project.pbxproj index 5ce9bca9..18dd8172 100644 --- a/PlotDevice.xcodeproj/project.pbxproj +++ b/PlotDevice.xcodeproj/project.pbxproj @@ -24,7 +24,7 @@ 2ABBB2FE185402AC001C4E0A /* CoreMedia.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2ABBB2FD185402AC001C4E0A /* CoreMedia.framework */; }; 2ABDB76B1867D8160069EFC3 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 2ABDB7681867D8160069EFC3 /* main.m */; }; 2ABDB76E1867D8BB0069EFC3 /* plotdevice-app.py in Resources */ = {isa = PBXBuildFile; fileRef = 2ABDB7671867D8160069EFC3 /* plotdevice-app.py */; }; - 2ABDB7741867D9970069EFC3 /* plotdevice in Copy 'plotdevice' Tool */ = {isa = PBXBuildFile; fileRef = 2ABDB7721867D9920069EFC3 /* plotdevice */; }; + 2ABDB7741867D9970069EFC3 /* plotdevice in Copy 'plotdevice' and 'bplotdevice' Tools */ = {isa = PBXBuildFile; fileRef = 2ABDB7721867D9920069EFC3 /* plotdevice */; }; 611CC49810BA8B9E00B55455 /* Credits.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 611CC48110BA8B9E00B55455 /* Credits.rtf */; }; 611CC49C10BA8B9E00B55455 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 611CC48910BA8B9E00B55455 /* InfoPlist.strings */; }; 611CC4A110BA8B9E00B55455 /* PlotDevice.icns in Resources */ = {isa = PBXBuildFile; fileRef = 611CC49310BA8B9E00B55455 /* PlotDevice.icns */; }; @@ -38,6 +38,8 @@ 8D15AC340486D014006FF6A4 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A7FEA54F5311CA2CBB /* Cocoa.framework */; }; CF0CB1E21975B76A00511DC8 /* plotdevice-term.py in Resources */ = {isa = PBXBuildFile; fileRef = CF0CB1E11975B76A00511DC8 /* plotdevice-term.py */; }; CF29B4BE196C51B70092593E /* Python.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CF29B4BC196C51410092593E /* Python.framework */; }; + CFA6011D1977493700D8E07B /* bplotdevice in Resources */ = {isa = PBXBuildFile; fileRef = CFA6011C1977493700D8E07B /* bplotdevice */; }; + CFA6011E1977494500D8E07B /* bplotdevice in Copy 'plotdevice' and 'bplotdevice' Tools */ = {isa = PBXBuildFile; fileRef = CFA6011C1977493700D8E07B /* bplotdevice */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -69,15 +71,16 @@ name = "Copy Editor Scripts"; runOnlyForDeploymentPostprocessing = 0; }; - 2ABDB76F1867D9560069EFC3 /* Copy 'plotdevice' Tool */ = { + 2ABDB76F1867D9560069EFC3 /* Copy 'plotdevice' and 'bplotdevice' Tools */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; dstPath = ""; dstSubfolderSpec = 12; files = ( - 2ABDB7741867D9970069EFC3 /* plotdevice in Copy 'plotdevice' Tool */, + CFA6011E1977494500D8E07B /* bplotdevice in Copy 'plotdevice' and 'bplotdevice' Tools */, + 2ABDB7741867D9970069EFC3 /* plotdevice in Copy 'plotdevice' and 'bplotdevice' Tools */, ); - name = "Copy 'plotdevice' Tool"; + name = "Copy 'plotdevice' and 'bplotdevice' Tools"; runOnlyForDeploymentPostprocessing = 0; }; /* End PBXCopyFilesBuildPhase section */ @@ -156,6 +159,7 @@ CF1C6CCF1975E87800C6C330 /* required-wheels.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "required-wheels.txt"; sourceTree = ""; }; CF29B4BC196C51410092593E /* Python.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Python.framework; path = /usr/local/Cellar/python/2.7.8/Frameworks/Python.framework; sourceTree = ""; }; CF61A9FF196DF61600BDFF1D /* relpath.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = relpath.sh; sourceTree = ""; }; + CFA6011C1977493700D8E07B /* bplotdevice */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = bplotdevice; path = app/bplotdevice; sourceTree = ""; }; CFC5106C197545210046C918 /* urlcache.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = urlcache.sh; sourceTree = ""; }; CFC5106D197545210046C918 /* download.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = download.sh; sourceTree = ""; }; /* End PBXFileReference section */ @@ -257,6 +261,7 @@ 2A37F4AFFDCFA73011CA2CEA /* Other Sources */ = { isa = PBXGroup; children = ( + CFA6011C1977493700D8E07B /* bplotdevice */, CF0CB1E11975B76A00511DC8 /* plotdevice-term.py */, 2ABDB7671867D8160069EFC3 /* plotdevice-app.py */, 2ABDB7681867D8160069EFC3 /* main.m */, @@ -392,7 +397,7 @@ 2A15C43718A20929006BDFF0 /* Copy Editor Assets */, 2A66ECEA18A99303002903DE /* Copy Editor Scripts */, 2A758E411957B7CE003ECF9D /* Copy PlotDevice Module */, - 2ABDB76F1867D9560069EFC3 /* Copy 'plotdevice' Tool */, + 2ABDB76F1867D9560069EFC3 /* Copy 'plotdevice' and 'bplotdevice' Tools */, 8D15AC300486D014006FF6A4 /* Sources */, 8D15AC330486D014006FF6A4 /* Frameworks */, CFC51073197545B90046C918 /* Install Wheelhouse Packages to App Bundle */, @@ -449,6 +454,7 @@ 611CC5A810BA919A00B55455 /* PlotDevicePreferences.xib in Resources */, 611CC68010BAA08300B55455 /* MainMenu.xib in Resources */, 611CC68710BAA0A600B55455 /* AskString.xib in Resources */, + CFA6011D1977493700D8E07B /* bplotdevice in Resources */, 2A7AF5C818D2AFAA00F8FFC2 /* examples in Resources */, 6155D9F413E2B79E00675A92 /* CHANGES.md in Resources */, 6155D9F513E2B79E00675A92 /* README.md in Resources */, diff --git a/app/bplotdevice b/app/bplotdevice new file mode 100755 index 00000000..7310db2e --- /dev/null +++ b/app/bplotdevice @@ -0,0 +1,14 @@ +#!/usr/bin/env python +# EASY-INSTALL-ENTRY-SCRIPT: 'bpython==0.13','console_scripts','bpython' +__requires__ = 'bpython==0.13' +import sys +from pkg_resources import load_entry_point + +if __name__ == '__main__': + sys.exit( + load_entry_point('bpython==0.13', 'console_scripts', 'bpython')() + ) + +#if __name__ == '__main__': +# from bpython.cli import main +# sys.exit(main()) \ No newline at end of file diff --git a/app/plotdevice-term.py b/app/plotdevice-term.py index c82f3bfd..5e8e5813 100755 --- a/app/plotdevice-term.py +++ b/app/plotdevice-term.py @@ -9,8 +9,3 @@ from plotdevice.gui import ScriptController from plotdevice.util import rsrc_path from plotdevice.run import encoding - - -#if __name__ == '__main__': -# from bpython.cli import main -# sys.exit(main()) \ No newline at end of file diff --git a/plotdevice/gui/app.py b/plotdevice/gui/app.py index 7b4e48fc..81e704e2 100644 --- a/plotdevice/gui/app.py +++ b/plotdevice/gui/app.py @@ -123,7 +123,7 @@ def openTerminal_(self, sender): TerminalApp = SBApplication.applicationWithBundleIdentifier_("com.apple.Terminal") bundlePath = NSBundle.mainBundle().bundlePath() scriptPythonPath = ":".join(sys.path) - scriptBPythonExecutable = "%s/Contents/SharedSupport/bpython" % bundlePath + scriptBPythonExecutable = "%s/Contents/SharedSupport/bplotdevice" % bundlePath scriptBPythonSetup = "%s/Contents/Resources/plotdevice-term.py" % bundlePath scriptCommand = '''cd %s && PYTHONPATH="%s" %s -i %s && exit''' % ( bundlePath, scriptPythonPath, scriptBPythonExecutable, scriptBPythonSetup) diff --git a/setup.py b/setup.py index c6d58a26..b5a96ac2 100644 --- a/setup.py +++ b/setup.py @@ -23,7 +23,6 @@ import sys, os, urllib2, plistlib from distutils.dir_util import remove_tree from distutils.spawn import find_executable as which -from distutils.file_util import write_file as write from setuptools import setup, find_packages from pkg_resources import DistributionNotFound from os import listdir, getcwd @@ -243,11 +242,9 @@ def install_wheels(self): print "ERROR: install `wheel` to enable bundle-local PyObjC" return False - #WHEELHOUSE = join('cache', 'wheelhouse') WHEELHOUSE = self.wheelhouse APP = self.app DITTO = which('ditto') - PYTHON = which('python') if not isdir(WHEELHOUSE): print "ERROR: no wheelhouse directory at %s" % WHEELHOUSE @@ -291,20 +288,6 @@ def install_wheels(self): self.spawn(['touch', join(SITE_PACKAGES, 'PyObjC', 'PyObjCTools', '__init__.py')]) - bpython_script_src = """#!%(python)s -# EASY-INSTALL-ENTRY-SCRIPT: 'bpython==0.13','console_scripts','bpython' -__requires__ = 'bpython==0.13' -import sys -from pkg_resources import load_entry_point - -if __name__ == '__main__': - sys.exit( - load_entry_point('bpython==0.13', 'console_scripts', 'bpython')() - ) -""" % dict(python=PYTHON) - bpython_script = join(SCRIPTS, 'bpython') - write(bpython_script, bpython_script_src.split('\n')) - self.spawn(['chmod', '+x', bpython_script]) return True from setuptools.command.sdist import sdist @@ -395,8 +378,9 @@ def run(self): os.unlink(join(RSRC, 'include')) os.unlink(join(RSRC, 'site.pyc')) - # place the command line tool in SharedSupport + # place the command line tools in SharedSupport self.copy_file("app/plotdevice", BIN) + self.copy_file("app/bplotdevice", BIN) for cmd in self.get_sub_commands(): self.run_command(cmd) @@ -535,7 +519,9 @@ def run(self): license=LICENSE, classifiers=CLASSIFIERS, packages=find_packages(), - scripts=["app/plotdevice"], + scripts=[ + "app/plotdevice", + "app/bplotdevice"], setup_requires=['wheel>=0.24.0'], zip_safe=False, cmdclass={ From 47c5d078781ad6957f20be067117428dcf37a33d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Bo=CC=88hn?= Date: Wed, 16 Jul 2014 17:29:22 -0700 Subject: [PATCH 67/81] Fixed py2app BOOOOOOOM THATS DOGG RIGHT I FUCKING DID THAT --- app/plotdevice-app.py | 12 +++++++++++- plotdevice/__init__.py | 24 ++++++++++++++++++++---- 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/app/plotdevice-app.py b/app/plotdevice-app.py index 22a3fe95..e98bbe44 100644 --- a/app/plotdevice-app.py +++ b/app/plotdevice-app.py @@ -1,12 +1,22 @@ import sys -from os.path import isdir +from os import environ as env +from os.path import isdir, join # if there's a python in /usr/local, it's probably homebrew -- let's use it! local_packages = '/usr/local/lib/python2.7/site-packages' if isdir(local_packages): sys.path.append(local_packages) +# If running from a py2app build, update sys.path +# with the bundle-local python package directory +RESOURCEPATH = env.get('RESOURCEPATH') +if RESOURCEPATH: + sys.path.insert(0, + join(RESOURCEPATH, 'python')) + sys.path.insert(0, + join(RESOURCEPATH, 'python', 'PyObjC')) + # remove dupes from sys.path -- for an explanation see: # http://stackoverflow.com/a/480227/298171 seen = set() diff --git a/plotdevice/__init__.py b/plotdevice/__init__.py index 668698aa..2651c742 100644 --- a/plotdevice/__init__.py +++ b/plotdevice/__init__.py @@ -19,10 +19,21 @@ MIT Licensed (see README file for details) """ - -# add the shared directory (for Libraries) to the path -import sys, re, os -sys.path.append(os.path.join(os.getenv('HOME'), 'Library', 'Application Support', 'PlotDevice')) +# Add the shared directory (for Libraries) to the path +import sys, re +from os import getenv, environ as env +from os.path import join +sys.path.append( + join(getenv('HOME'), 'Library', 'Application Support', 'PlotDevice')) + +# If running from a py2app build, update sys.path +# with the bundle-local python package directory +RESOURCEPATH = env.get('RESOURCEPATH') +if RESOURCEPATH: + sys.path.insert(0, + join(RESOURCEPATH, 'python')) + sys.path.insert(0, + join(RESOURCEPATH, 'python', 'PyObjC')) # the global non-conflicting token (fingers crossed) INTERNAL = '_p_l_o_t_d_e_v_i_c_e_' @@ -50,6 +61,11 @@ class Halted(Exception): try: import objc except ImportError: + from pprint import pformat + with open("/tmp/plotdevice-panic.log", "w+b") as log: + log.write("ENV:\n") + log.writelines(pformat(dict(env)).split('\n')) + log.flush() #extras = '/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python' extras = sys.prefix sys.path.extend([extras, '%s/PyObjC'%extras]) From affaa145a7f19d75aebab5755f1c6d469909f713 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Bo=CC=88hn?= Date: Wed, 16 Jul 2014 21:10:05 -0700 Subject: [PATCH 68/81] Couple of string macros --- app/macros.h | 10 ++++++++++ app/main.m | 11 ++++------- 2 files changed, 14 insertions(+), 7 deletions(-) create mode 100644 app/macros.h diff --git a/app/macros.h b/app/macros.h new file mode 100644 index 00000000..3258feb3 --- /dev/null +++ b/app/macros.h @@ -0,0 +1,10 @@ + +/// NSString to (char *) +#ifndef CSTRING + #define CSTRING(NSStringRef) (char *)[NSStringRef UTF8String] +#endif + +/// NSString to (PyString *) +#ifndef PYSTRING + #define PYSTRING(NSStringRef) PyString_FromString((char *)[NSStringRef UTF8String]) +#endif diff --git a/app/main.m b/app/main.m index 8ec47d94..8bad951e 100644 --- a/app/main.m +++ b/app/main.m @@ -1,4 +1,5 @@ #import +#include "macros.h" #ifndef PLOTDEVICE_PYTHON #define PLOTDEVICE_PYTHON "/usr/bin/python" @@ -17,15 +18,11 @@ int main(int argc, char *argv[]) PyObject *sys = PyImport_ImportModule("sys"); PyObject *path = PyObject_GetAttrString(sys, "path"); - PyList_Insert(path, (Py_ssize_t)0, - PyString_FromString( - (char *)[bundleSitePackages UTF8String])); - PyList_Insert(path, (Py_ssize_t)0, - PyString_FromString( - (char *)[bundlePyObjC UTF8String])); + PyList_Insert(path, (Py_ssize_t)0, PYSTRING(bundleSitePackages)); + PyList_Insert(path, (Py_ssize_t)0, PYSTRING(bundlePyObjC)); NSString *mainFilePath = [[NSBundle mainBundle] pathForResource:@"plotdevice-app" ofType:@"py"]; NSString *mainFileName = [mainFilePath lastPathComponent]; - return PyRun_SimpleFile(fopen([mainFilePath UTF8String], "r"), (char *)[mainFileName UTF8String]); + return PyRun_SimpleFile(fopen([mainFilePath UTF8String], "r"), CSTRING(mainFileName)); } } From f2452dd3e455192b9541b3c745380557c64266f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Bo=CC=88hn?= Date: Fri, 18 Jul 2014 13:37:56 -0700 Subject: [PATCH 69/81] Build against the system python (non-framework) library --- PlotDevice.xcodeproj/project.pbxproj | 38 ++++++++++------------------ app/PlotDevice_Prefix.pch | 2 +- app/bplotdevice | 2 +- app/deps/IO/setup.py | 31 +++++++++++++++++------ app/deps/geometry/setup.py | 17 +++++++------ app/deps/pathmatics/setup.py | 21 +++++++++------ app/plotdevice | 5 ++-- app/plotdevice-app.py | 6 ++--- app/plotdevice-term.py | 2 +- plotdevice/run/console.py | 2 +- setup.py | 2 +- 11 files changed, 70 insertions(+), 58 deletions(-) diff --git a/PlotDevice.xcodeproj/project.pbxproj b/PlotDevice.xcodeproj/project.pbxproj index 18dd8172..947e77c2 100644 --- a/PlotDevice.xcodeproj/project.pbxproj +++ b/PlotDevice.xcodeproj/project.pbxproj @@ -37,9 +37,9 @@ 6155D9F513E2B79E00675A92 /* README.md in Resources */ = {isa = PBXBuildFile; fileRef = 6155D9F313E2B79E00675A92 /* README.md */; }; 8D15AC340486D014006FF6A4 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A7FEA54F5311CA2CBB /* Cocoa.framework */; }; CF0CB1E21975B76A00511DC8 /* plotdevice-term.py in Resources */ = {isa = PBXBuildFile; fileRef = CF0CB1E11975B76A00511DC8 /* plotdevice-term.py */; }; - CF29B4BE196C51B70092593E /* Python.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CF29B4BC196C51410092593E /* Python.framework */; }; CFA6011D1977493700D8E07B /* bplotdevice in Resources */ = {isa = PBXBuildFile; fileRef = CFA6011C1977493700D8E07B /* bplotdevice */; }; CFA6011E1977494500D8E07B /* bplotdevice in Copy 'plotdevice' and 'bplotdevice' Tools */ = {isa = PBXBuildFile; fileRef = CFA6011C1977493700D8E07B /* bplotdevice */; }; + CFF01E861979B49F00907EEA /* Python in Frameworks */ = {isa = PBXBuildFile; fileRef = CFF01E851979B49F00907EEA /* Python */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -157,11 +157,11 @@ CF0CB1E11975B76A00511DC8 /* plotdevice-term.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; name = "plotdevice-term.py"; path = "app/plotdevice-term.py"; sourceTree = ""; }; CF1C6CCE1975E87800C6C330 /* load-cache.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = "load-cache.sh"; sourceTree = ""; }; CF1C6CCF1975E87800C6C330 /* required-wheels.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "required-wheels.txt"; sourceTree = ""; }; - CF29B4BC196C51410092593E /* Python.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Python.framework; path = /usr/local/Cellar/python/2.7.8/Frameworks/Python.framework; sourceTree = ""; }; CF61A9FF196DF61600BDFF1D /* relpath.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = relpath.sh; sourceTree = ""; }; CFA6011C1977493700D8E07B /* bplotdevice */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = bplotdevice; path = app/bplotdevice; sourceTree = ""; }; CFC5106C197545210046C918 /* urlcache.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = urlcache.sh; sourceTree = ""; }; CFC5106D197545210046C918 /* download.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = download.sh; sourceTree = ""; }; + CFF01E851979B49F00907EEA /* Python */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = Python; path = /System/Library/Frameworks/Python.framework/Versions/2.7/Python; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -169,7 +169,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - CF29B4BE196C51B70092593E /* Python.framework in Frameworks */, + CFF01E861979B49F00907EEA /* Python in Frameworks */, 2ABBB2FC18540246001C4E0A /* CoreVideo.framework in Frameworks */, 2ABBB2FE185402AC001C4E0A /* CoreMedia.framework in Frameworks */, 2ABBB2FA1854018B001C4E0A /* AVFoundation.framework in Frameworks */, @@ -185,7 +185,6 @@ 1058C7A6FEA54F5311CA2CBB /* Linked Frameworks */ = { isa = PBXGroup; children = ( - CF29B4BC196C51410092593E /* Python.framework */, 1058C7A7FEA54F5311CA2CBB /* Cocoa.framework */, ); name = "Linked Frameworks"; @@ -294,6 +293,7 @@ 2A37F4C3FDCFA73011CA2CEA /* Frameworks */ = { isa = PBXGroup; children = ( + CFF01E851979B49F00907EEA /* Python */, 2AEE843D18B5603900CF91D4 /* CoreText.framework */, 2A15C42C18A1FA14006BDFF0 /* WebKit.framework */, 2A591FEF185C17D200D1833D /* Security.framework */, @@ -580,18 +580,13 @@ C05733C808A9546B00998B17 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; + ALWAYS_SEARCH_USER_PATHS = YES; COMBINE_HIDPI_IMAGES = YES; CONFIGURATION_BUILD_DIR = dist; COPY_PHASE_STRIP = NO; DEPLOYMENT_LOCATION = NO; DEPLOYMENT_POSTPROCESSING = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)", - "$(PROJECT_DIR)/app/Frameworks", - /usr/local/Cellar/python/2.7.8/Frameworks, - ); + FRAMEWORK_SEARCH_PATHS = "$(inherited)"; GCC_DYNAMIC_NO_PIC = NO; GCC_MODEL_TUNING = G5; GCC_OPTIMIZATION_LEVEL = 0; @@ -599,12 +594,12 @@ GCC_PREFIX_HEADER = app/PlotDevice_Prefix.pch; HEADER_SEARCH_PATHS = ( "$(inherited)", - /usr/local/opt/python/Frameworks/Python.framework/Headers, /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + /usr/include/python2.7, ); INFOPLIST_FILE = "app/PlotDevice-Info.plist"; INSTALL_PATH = /Applications; - LIBRARY_SEARCH_PATHS = /usr/local/Cellar/python/2.7.8/Frameworks/Python.framework/Versions/2.7; + LIBRARY_SEARCH_PATHS = "$(SYSTEM_LIBRARY_DIR)/Frameworks/Python.framework/Versions/2.7"; MACOSX_DEPLOYMENT_TARGET = 10.9; ONLY_ACTIVE_ARCH = YES; OTHER_LDFLAGS = ""; @@ -617,29 +612,24 @@ C05733C908A9546B00998B17 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; + ALWAYS_SEARCH_USER_PATHS = YES; COMBINE_HIDPI_IMAGES = YES; CONFIGURATION_BUILD_DIR = dist; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEPLOYMENT_LOCATION = NO; DEPLOYMENT_POSTPROCESSING = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)", - "$(PROJECT_DIR)/app/Frameworks", - /usr/local/Cellar/python/2.7.8/Frameworks, - ); + FRAMEWORK_SEARCH_PATHS = "$(inherited)"; GCC_MODEL_TUNING = G5; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = app/PlotDevice_Prefix.pch; HEADER_SEARCH_PATHS = ( "$(inherited)", - /usr/local/opt/python/Frameworks/Python.framework/Headers, /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + /usr/include/python2.7, ); INFOPLIST_FILE = "app/PlotDevice-Info.plist"; INSTALL_PATH = /Applications; - LIBRARY_SEARCH_PATHS = /usr/local/Cellar/python/2.7.8/Frameworks/Python.framework/Versions/2.7; + LIBRARY_SEARCH_PATHS = "$(SYSTEM_LIBRARY_DIR)/Frameworks/Python.framework/Versions/2.7"; MACOSX_DEPLOYMENT_TARGET = 10.9; ONLY_ACTIVE_ARCH = YES; OTHER_LDFLAGS = ""; @@ -654,7 +644,7 @@ buildSettings = { COPY_PHASE_STRIP = NO; "DEBUG_INFORMATION_FORMAT[sdk=*]" = ""; - FRAMEWORK_SEARCH_PATHS = /Users/fish/Dropbox/plotdevice/app/Frameworks; + FRAMEWORK_SEARCH_PATHS = ""; MACOSX_DEPLOYMENT_TARGET = 10.9; ONLY_ACTIVE_ARCH = YES; PRODUCT_NAME = PlotDevice; @@ -669,7 +659,7 @@ isa = XCBuildConfiguration; buildSettings = { "DEBUG_INFORMATION_FORMAT[sdk=*]" = ""; - FRAMEWORK_SEARCH_PATHS = /Users/fish/Dropbox/plotdevice/app/Frameworks; + FRAMEWORK_SEARCH_PATHS = ""; MACOSX_DEPLOYMENT_TARGET = 10.9; ONLY_ACTIVE_ARCH = YES; PRODUCT_NAME = PlotDevice; diff --git a/app/PlotDevice_Prefix.pch b/app/PlotDevice_Prefix.pch index eeefc690..bdbe44d5 100644 --- a/app/PlotDevice_Prefix.pch +++ b/app/PlotDevice_Prefix.pch @@ -7,5 +7,5 @@ #endif #ifndef PLOTDEVICE_PYTHON - #define PLOTDEVICE_PYTHON "/usr/local/bin/python" + #define PLOTDEVICE_PYTHON "/usr/bin/python" #endif diff --git a/app/bplotdevice b/app/bplotdevice index 7310db2e..26f7f4e6 100755 --- a/app/bplotdevice +++ b/app/bplotdevice @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/python # EASY-INSTALL-ENTRY-SCRIPT: 'bpython==0.13','console_scripts','bpython' __requires__ = 'bpython==0.13' import sys diff --git a/app/deps/IO/setup.py b/app/deps/IO/setup.py index 333c678c..5190fa77 100644 --- a/app/deps/IO/setup.py +++ b/app/deps/IO/setup.py @@ -1,12 +1,27 @@ -# from distutils.core import setup, Extension from setuptools import setup, find_packages from setuptools.extension import Extension -quiet = {"extra_compile_args":['-Qunused-arguments']} -cIO = Extension('cIO', sources=['module.m', 'SysAdmin.m', 'Pages.m', 'AnimatedGif.m', 'Video.m'], extra_link_args=['-framework', 'AppKit', '-framework', 'Foundation', '-framework', 'Quartz', '-framework', 'Security', '-framework', 'AVFoundation', '-framework', 'CoreMedia', '-framework', 'CoreVideo'], **quiet) +quiet = { "extra_compile_args": ['-Qunused-arguments'] } -setup (name = "cIO", - version = "1.0", - author = "Christian Swinehart", - description = "Image and video export routines.", - ext_modules = [cIO]) \ No newline at end of file +cIO = Extension('cIO', + sources=[ + 'module.m', + 'SysAdmin.m', + 'Pages.m', + 'AnimatedGif.m', + 'Video.m'], + extra_link_args=[ + '-framework', 'AppKit', + '-framework', 'Foundation', + '-framework', 'Quartz', + '-framework', 'Security', + '-framework', 'AVFoundation', + '-framework', 'CoreMedia', + '-framework', 'CoreVideo'], + **quiet) + +setup(name="cIO", + version="1.0", + author="Christian Swinehart", + description="Image and video export routines.", + ext_modules=[cIO]) \ No newline at end of file diff --git a/app/deps/geometry/setup.py b/app/deps/geometry/setup.py index 279131cf..b057f823 100644 --- a/app/deps/geometry/setup.py +++ b/app/deps/geometry/setup.py @@ -1,12 +1,13 @@ -# from distutils.core import setup, Extension from setuptools import setup, find_packages from setuptools.extension import Extension -quiet = {"extra_compile_args":['-Qunused-arguments']} -cGeometry = Extension("cGeometry", ["cGeometry.c"], **quiet) +quiet = { "extra_compile_args": ['-Qunused-arguments'] } +cGeometry = Extension("cGeometry", + sources=["cGeometry.c"], + **quiet) -setup (name = "cGeometry", - version = "0.1", - author = "Tom De Smedt", - description = "Fast geometric functionality.", - ext_modules = [cGeometry]) \ No newline at end of file +setup(name="cGeometry", + version="0.1", + author="Tom De Smedt", + description="Fast geometric functionality.", + ext_modules=[cGeometry]) \ No newline at end of file diff --git a/app/deps/pathmatics/setup.py b/app/deps/pathmatics/setup.py index 3f2f1ea0..45cc1e90 100644 --- a/app/deps/pathmatics/setup.py +++ b/app/deps/pathmatics/setup.py @@ -2,12 +2,17 @@ from setuptools.extension import Extension cPathmatics = Extension("cPathmatics", - sources = ["pathmatics.m", "gpc.c",], - extra_link_args=['-framework', 'AppKit', '-framework', 'Foundation'], - extra_compile_args=['-Qunused-arguments']) + sources=[ + "pathmatics.m", + "gpc.c"], + extra_link_args=[ + '-framework', 'AppKit', + '-framework', 'Foundation'], + extra_compile_args=[ + '-Qunused-arguments']) -setup (name = "pathmatics", - version = "1.0", - author = "Written for NodeBox by Tom De Smedt and Frederik De Bleser", - description = "Fast bezier math routines.", - ext_modules = [cPathmatics]) \ No newline at end of file +setup(name="pathmatics", + version="1.0", + author="Written for NodeBox by Tom De Smedt and Frederik De Bleser", + description="Fast bezier math routines.", + ext_modules=[cPathmatics]) \ No newline at end of file diff --git a/app/plotdevice b/app/plotdevice index 3c180ba3..52210b04 100755 --- a/app/plotdevice +++ b/app/plotdevice @@ -58,7 +58,7 @@ import argparse import json import signal from subprocess import Popen, PIPE -from distutils.spawn import find_executable as which +#from distutils.spawn import find_executable as which from os.path import exists, islink, dirname, abspath, realpath, join def parse_args(): @@ -163,6 +163,7 @@ def main(): opts = parse_args() root = module_root() env = dict(os.environ) + PYTHON = "/usr/bin/python" # run the backend with the system python # install a signal handler to catch ^c def cancel(*args): @@ -175,7 +176,7 @@ def main(): py_path.insert(0, root) env['PYTHONPATH'] = ":".join(py_path) script = join(root, 'plotdevice/run/console.py') - p = Popen([which('python'), script], env=env, stdin=PIPE) + p = Popen([PYTHON, script], env=env, stdin=PIPE) p.stdin.write(json.dumps(vars(opts))+"\n") p.wait() diff --git a/app/plotdevice-app.py b/app/plotdevice-app.py index e98bbe44..013bcfb4 100644 --- a/app/plotdevice-app.py +++ b/app/plotdevice-app.py @@ -4,9 +4,9 @@ from os.path import isdir, join # if there's a python in /usr/local, it's probably homebrew -- let's use it! -local_packages = '/usr/local/lib/python2.7/site-packages' -if isdir(local_packages): - sys.path.append(local_packages) +#local_packages = '/usr/local/lib/python2.7/site-packages' +#if isdir(local_packages): +# sys.path.append(local_packages) # If running from a py2app build, update sys.path # with the bundle-local python package directory diff --git a/app/plotdevice-term.py b/app/plotdevice-term.py index 5e8e5813..6a289d00 100755 --- a/app/plotdevice-term.py +++ b/app/plotdevice-term.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/python # encoding: utf-8 import plotdevice # adds pyobjc to sys.path as a side effect... diff --git a/plotdevice/run/console.py b/plotdevice/run/console.py index 041b3c4d..f1b0ba11 100755 --- a/plotdevice/run/console.py +++ b/plotdevice/run/console.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/python # encoding: utf-8 """ console.py diff --git a/setup.py b/setup.py index b5a96ac2..2c14f464 100644 --- a/setup.py +++ b/setup.py @@ -262,7 +262,7 @@ def install_wheels(self): CONTENTS = join(APP, 'Contents') RESOURCES = join(CONTENTS, 'Resources') SITE_PACKAGES = join(RESOURCES, 'python') - HEADERS = join(RESOURCES, 'Headers') # wat + HEADERS = join(CONTENTS, 'PrivateHeaders') SCRIPTS = join(CONTENTS, 'SharedSupport') OVERRIDES = dict( purelib=SITE_PACKAGES, platlib=SITE_PACKAGES, data=SITE_PACKAGES, From a4d95eaa3105da3b66d5a3389c1ab9c4ebae5ca9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Bo=CC=88hn?= Date: Fri, 18 Jul 2014 14:08:42 -0700 Subject: [PATCH 70/81] Warn when wheelhouse installation can't proceed --- setup.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/setup.py b/setup.py index 2c14f464..9454d393 100644 --- a/setup.py +++ b/setup.py @@ -230,16 +230,16 @@ def finalize_options(self): self.app = abspath(self.app) def run(self): - ''' install wheels to app bundle ''' - self.install_wheels() - print "done installing wheels" + ''' try to install wheels to app bundle ''' + if self.install_wheels(): + print "Done installing wheels" def install_wheels(self): ''' Install everything from the wheelhouse ''' try: from wheel.install import WheelFile except ImportError: - print "ERROR: install `wheel` to enable bundle-local PyObjC" + print "ERROR: install the `wheel` Python package to enable bundle-local PyObjC" return False WHEELHOUSE = self.wheelhouse From 6698ba2bcac86d1006db964b8f177493552bec01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Bo=CC=88hn?= Date: Fri, 18 Jul 2014 14:28:34 -0700 Subject: [PATCH 71/81] Stop including gratuitous pyobjc-framework-* packages in wheelhouse installation --- etc/load-cache.sh | 57 ++++++++++++++++++++++------------------------- setup.py | 17 ++++---------- 2 files changed, 31 insertions(+), 43 deletions(-) diff --git a/etc/load-cache.sh b/etc/load-cache.sh index 05d1d57d..43995301 100755 --- a/etc/load-cache.sh +++ b/etc/load-cache.sh @@ -21,48 +21,45 @@ PYOBJC_VIRTUALENV="build/pyobjc-virtualenv-${PYOBJC_VERSION}" rm -rf $PYOBJC_BUILD_PATH $PYOBJC_VIRTUALENV fetch_and_expand $PYOBJC_DOWNLOAD_URL $PYOBJC_BUILD_PATH -declare -a names=("AppleScriptKit" \ -"Accounts" \ -"AddressBook" \ -"AppleScriptKit" \ -"AppleScriptObjC" \ -"Automator" \ +declare -a names=( \ +#"AppleScriptKit" \ +#"Accounts" \ +#"AddressBook" \ +#"AppleScriptKit" \ +#"AppleScriptObjC" \ +#"Automator" \ "CFNetwork" \ -"CalendarStore" \ +#"CalendarStore" \ "Cocoa" \ -"Collaboration" \ +#"Collaboration" \ "CoreData" \ -"CoreLocation" \ +#"CoreLocation" \ "CoreText" \ -#"CoreWLAN" \ "DictionaryServices" \ -#"DiskArbitration" \ -"EventKit" \ +#"EventKit" \ "ExceptionHandling" \ "FSEvents" \ -"InputMethodKit" \ -"InstallerPlugins" \ -"InstantMessage" \ +#"InputMethodKit" \ +#"InstallerPlugins" \ +#"InstantMessage" \ #"InterfaceBuilderKit" \ -"LatentSemanticMapping" \ -"LaunchServices" \ -#"Message" \ -"OpenDirectory" \ -"PreferencePanes" \ -"PubSub" \ -"QTKit" \ +#"LatentSemanticMapping" \ +#"LaunchServices" \ +#"OpenDirectory" \ +#"PreferencePanes" \ +#"PubSub" \ +#"QTKit" \ "Quartz" \ -"ScreenSaver" \ +#"ScreenSaver" \ "ScriptingBridge" \ -"SearchKit" \ -"ServerNotification" \ -"ServiceManagement" \ -"Social" \ -#"StoreKit" \ +#"SearchKit" \ +#"ServerNotification" \ +#"ServiceManagement" \ +#"Social" \ "SyncServices" \ "SystemConfiguration" \ -"WebKit") -#"XgridFoundation") +"WebKit" \ +) PYOBJC_DIR=${PLOTDEVICE}/$PYOBJC_BUILD_PATH FIND="for fn in install_lib._install_lib.get_outputs(self):" diff --git a/setup.py b/setup.py index 9454d393..77df7823 100644 --- a/setup.py +++ b/setup.py @@ -23,6 +23,9 @@ import sys, os, urllib2, plistlib from distutils.dir_util import remove_tree from distutils.spawn import find_executable as which +from distutils.core import Command +from setuptools.command.sdist import sdist +from distutils.command.build_py import build_py from setuptools import setup, find_packages from pkg_resources import DistributionNotFound from os import listdir, getcwd @@ -178,11 +181,8 @@ def merged_feed(new_release): spliced.append(line) return (u"\n".join(spliced)).encode('utf-8') - - ## Build Commands ## -from distutils.core import Command class CleanCommand(Command): description = "wipe out the ./build ./dist and app/deps/.../build dirs" user_options = [] @@ -280,8 +280,7 @@ def install_wheels(self): wheel = WheelFile(join(WHEELHOUSE, wheel_file)) wheel.install(overrides=OVERRIDES, force=True) - # misc. patching (this should obvi be in pyobjc-patch-wheelhouse.sh - # ... or better yet fixed in the fucking upstream repository) + # misc. PyObjC patching (ideally should obvi be fixed in the upstream repository) self.spawn([DITTO, join(SITE_PACKAGES, 'PyObjCTools'), join(SITE_PACKAGES, 'PyObjC', 'PyObjCTools')]) @@ -290,7 +289,6 @@ def install_wheels(self): return True -from setuptools.command.sdist import sdist class BuildDistCommand(sdist): def finalize_options(self): with file('MANIFEST.in','w') as f: @@ -307,7 +305,6 @@ def run(self): remove_tree('plotdevice.egg-info') os.unlink('MANIFEST.in') -from distutils.command.build_py import build_py class BuildCommand(build_py): def run(self): # first let the real build_py routine do its thing @@ -349,7 +346,6 @@ def finalize_options(self): sub_commands.append(('wheelhouse', lambda arg: True)) def run(self): - #assert os.getcwd() == self.cwd, 'Must be in package root: %s' % self.cwd build_py2app.run(self) if self.dry_run: return @@ -536,11 +532,6 @@ def run(self): }) # py2app-specific config - # Note how we're not adding the GPUImage framework here, - # despite what the paltry docs available, as regards - # the subject of py2app and framework-addery, - # seem to suggest -- we do it ourselves when executing - # the BuildPy2AppCommand stuff. if 'py2app' in sys.argv: config.update(dict( app=[{ From 18d53882a423924358ffc5f79b8ec538f47be12d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Bo=CC=88hn?= Date: Fri, 18 Jul 2014 17:47:02 -0700 Subject: [PATCH 72/81] Less fragile bplotdevice script --- app/bplotdevice | 14 ++------------ app/plotdevice-term.py | 2 ++ etc/required-wheels.txt | 2 +- plotdevice/gui/app.py | 1 + 4 files changed, 6 insertions(+), 13 deletions(-) diff --git a/app/bplotdevice b/app/bplotdevice index 26f7f4e6..93e5646f 100755 --- a/app/bplotdevice +++ b/app/bplotdevice @@ -1,14 +1,4 @@ #!/usr/bin/python -# EASY-INSTALL-ENTRY-SCRIPT: 'bpython==0.13','console_scripts','bpython' -__requires__ = 'bpython==0.13' import sys -from pkg_resources import load_entry_point - -if __name__ == '__main__': - sys.exit( - load_entry_point('bpython==0.13', 'console_scripts', 'bpython')() - ) - -#if __name__ == '__main__': -# from bpython.cli import main -# sys.exit(main()) \ No newline at end of file +from bpython.cli import main +sys.exit(main()) \ No newline at end of file diff --git a/app/plotdevice-term.py b/app/plotdevice-term.py index 6a289d00..d71f1809 100755 --- a/app/plotdevice-term.py +++ b/app/plotdevice-term.py @@ -1,6 +1,8 @@ #!/usr/bin/python # encoding: utf-8 +print "Loading PlotDevice.app environment..." + import plotdevice # adds pyobjc to sys.path as a side effect... import objc # ...otherwise this would fail from Foundation import * diff --git a/etc/required-wheels.txt b/etc/required-wheels.txt index d05cff00..0baf8278 100644 --- a/etc/required-wheels.txt +++ b/etc/required-wheels.txt @@ -1,2 +1,2 @@ #Pillow>=2.1.0 -bpython>=0.13.0 \ No newline at end of file +bpython==0.13.1 \ No newline at end of file diff --git a/plotdevice/gui/app.py b/plotdevice/gui/app.py index 81e704e2..77b23025 100644 --- a/plotdevice/gui/app.py +++ b/plotdevice/gui/app.py @@ -127,6 +127,7 @@ def openTerminal_(self, sender): scriptBPythonSetup = "%s/Contents/Resources/plotdevice-term.py" % bundlePath scriptCommand = '''cd %s && PYTHONPATH="%s" %s -i %s && exit''' % ( bundlePath, scriptPythonPath, scriptBPythonExecutable, scriptBPythonSetup) + TerminalApp.activate() TerminalApp.doScript_in_(scriptCommand, None) def applicationWillTerminate_(self, note): From 5ff308f75364348b070ca497f90cb49284a9ddca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Bo=CC=88hn?= Date: Fri, 18 Jul 2014 18:07:08 -0700 Subject: [PATCH 73/81] Use bundle_path() when launching terminal script --- plotdevice/gui/__init__.py | 4 +++- plotdevice/gui/app.py | 29 ++++++++++++++--------------- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/plotdevice/gui/__init__.py b/plotdevice/gui/__init__.py index 31d1646f..373893d5 100644 --- a/plotdevice/gui/__init__.py +++ b/plotdevice/gui/__init__.py @@ -1,8 +1,10 @@ -def bundle_path(subpath=None, rsrc=None, fmwk=None): +def bundle_path(subpath=None, rsrc=None, fmwk=None, shared=None): """Find the path to the main NSBundle (or an optional subpath within it)""" from os.path import join from Foundation import NSBundle bundle = NSBundle.mainBundle().bundlePath() + if shared: + return join(bundle, "Contents", "SharedSupport", shared) if rsrc: return join(bundle, "Contents", "Resources", rsrc) if fmwk: diff --git a/plotdevice/gui/app.py b/plotdevice/gui/app.py index 77b23025..09e1f73e 100644 --- a/plotdevice/gui/app.py +++ b/plotdevice/gui/app.py @@ -1,7 +1,8 @@ # encoding: utf-8 import sys -import os import objc +from os import mkdir, getenv +from os.path import join, exists, basename, dirname from glob import glob from Foundation import * from AppKit import * @@ -20,18 +21,18 @@ class PlotDeviceAppDelegate(NSObject): def awakeFromNib(self): self._prefsController = None self._docsController = NSDocumentController.sharedDocumentController() - libDir = os.path.join(os.getenv("HOME"), "Library", "Application Support", "PlotDevice") + libDir = join(getenv("HOME"), "Library", "Application Support", "PlotDevice") try: - if not os.path.exists(libDir): - os.mkdir(libDir) - f = open(os.path.join(libDir, "README.txt"), "w") + if not exists(libDir): + mkdir(libDir) + f = open(join(libDir, "README.txt"), "w") f.write(LIB_DIR_README) f.close() except OSError: pass except IOError: pass def applicationDidFinishLaunching_(self, note): - mm=NSApp().mainMenu() + mm = NSApp().mainMenu() # disable the start-dictation item in the edit menu edmenu = mm.itemAtIndex_(2).submenu() @@ -50,7 +51,7 @@ def applicationDidFinishLaunching_(self, note): # If the sparkle framework was installed in our bundle, init an updater self.sparkle = None sparkle_path = bundle_path(fmwk='Sparkle') - if os.path.exists(sparkle_path): + if exists(sparkle_path): objc.loadBundle('Sparkle', globals(), bundle_path=sparkle_path) self.sparkle = objc.lookUpClass('SUUpdater').sharedUpdater() self.updatesMenu.setTarget_(self.sparkle) @@ -64,15 +65,15 @@ def applicationWillBecomeActive_(self, note): def updateExamples(self): examples_folder = bundle_path(rsrc="examples") - pyfiles = glob('%s/*/*.pv'%examples_folder) + pyfiles = glob('%s/*/*.pv' % examples_folder) categories = self.examplesMenu.submenu() folders = {} for item in categories.itemArray(): item.submenu().removeAllItems() folders[item.title()] = item.submenu() for fn in sorted(pyfiles): - cat = os.path.basename(os.path.dirname(fn)) - example = os.path.basename(fn) + cat = basename(dirname(fn)) + example = basename(fn) item = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(example[:-3], "openExample:", "") item.setRepresentedObject_(fn) folders[cat].addItem_(item) @@ -119,14 +120,12 @@ def showSite_(self, sender): def openTerminal_(self, sender): """ Open a Terminal.app window running bpython, with the PlotDevice.app environment pre-loaded """ - # TODO: Bring new Terminal.app window to the fore TerminalApp = SBApplication.applicationWithBundleIdentifier_("com.apple.Terminal") - bundlePath = NSBundle.mainBundle().bundlePath() scriptPythonPath = ":".join(sys.path) - scriptBPythonExecutable = "%s/Contents/SharedSupport/bplotdevice" % bundlePath - scriptBPythonSetup = "%s/Contents/Resources/plotdevice-term.py" % bundlePath + scriptBPythonExecutable = bundle_path(shared='bplotdevice') + scriptBPythonSetup = bundle_path(rsrc='plotdevice-term.py') scriptCommand = '''cd %s && PYTHONPATH="%s" %s -i %s && exit''' % ( - bundlePath, scriptPythonPath, scriptBPythonExecutable, scriptBPythonSetup) + bundle_path(), scriptPythonPath, scriptBPythonExecutable, scriptBPythonSetup) TerminalApp.activate() TerminalApp.doScript_in_(scriptCommand, None) From 17b7e715b1bcc500af09fe24a1363d8759a36e80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Bo=CC=88hn?= Date: Fri, 18 Jul 2014 18:48:45 -0700 Subject: [PATCH 74/81] Context manager for CoreImage CIContext --- plotdevice/gfx/__init__.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/plotdevice/gfx/__init__.py b/plotdevice/gfx/__init__.py index b911dfa0..4ca6d62b 100644 --- a/plotdevice/gfx/__init__.py +++ b/plotdevice/gfx/__init__.py @@ -36,6 +36,14 @@ def _cg_layer(): def _cg_port(): return NSGraphicsContext.currentContext().graphicsPort() +@contextmanager +def _ci_context(): + ctx = NSGraphicsContext.currentContext() + ctx.saveGraphicsState() + #yield CIContext.contextWithCGContext_options_(_cg_port(), None) + yield ctx.CIContext() + ctx.restoreGraphicsState() + ### submodule init ### # pool the submodules' __all__ namespaces into our own From a8972e6cea23106c82267982d1fff81dc1fba39b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Bo=CC=88hn?= Date: Tue, 22 Jul 2014 18:25:17 -0700 Subject: [PATCH 75/81] Way faster and less verbose wheelhouse construction --- etc/load-cache.sh | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/etc/load-cache.sh b/etc/load-cache.sh index 43995301..d35de2c5 100755 --- a/etc/load-cache.sh +++ b/etc/load-cache.sh @@ -4,7 +4,7 @@ SCRIPT_DIR="$(cd `dirname "${BASH_SOURCE[0]}"` && pwd)" # http://stackoverflow.c PLOTDEVICE=`dirname $SCRIPT_DIR` cd $PLOTDEVICE -PRAXA_DOWNLOAD_CACHE="cache/downloads" +PRAXA_DOWNLOAD_CACHE="${PLOTDEVICE}/cache/downloads" WHEELHOUSE="${PLOTDEVICE}/cache/wheelhouse" mkdir -p $PRAXA_DOWNLOAD_CACHE mkdir -p $WHEELHOUSE @@ -56,8 +56,8 @@ declare -a names=( \ #"ServerNotification" \ #"ServiceManagement" \ #"Social" \ -"SyncServices" \ -"SystemConfiguration" \ +#"SyncServices" \ +#"SystemConfiguration" \ "WebKit" \ ) @@ -80,29 +80,26 @@ done find $PYOBJC_DIR -name \*.py~ -print -delete -########## LOCAL INSTALL ################################################################### +########## VIRTUALENV INSTALLATION (NECESSARY FOR EXTENSION BUILDING) ###################### virtualenv -v -p `which python` $PYOBJC_VIRTUALENV source $PYOBJC_VIRTUALENV/bin/activate - -cd $PYOBJC_DIR/pyobjc-core && pip install --verbose --no-deps . -cd $PYOBJC_DIR/pyobjc && pip install --verbose . +cd $PYOBJC_DIR/pyobjc-core && pip install --no-deps . ########## WHEELHOUSE: PYOBJC ############################################################## -pip install -U wheel - -cd $PYOBJC_DIR/pyobjc-core && pip wheel --verbose --no-deps -w $WHEELHOUSE . -cd $PYOBJC_DIR/pyobjc && pip wheel --verbose --no-deps -w $WHEELHOUSE . +#pip install -U wheel +cd $PYOBJC_DIR/pyobjc-core && pip wheel --no-deps -w $WHEELHOUSE . +cd $PYOBJC_DIR/pyobjc && pip wheel --no-deps -w $WHEELHOUSE . for name in "${names[@]}"; do cd $PYOBJC_DIR && \ cd "pyobjc-framework-${name}" && \ - pip wheel --verbose --no-deps -w $WHEELHOUSE . + pip wheel --no-deps -w $WHEELHOUSE . done ########## WHEELHOUSE: OTHER ############################################################### cd $PLOTDEVICE -pip wheel --verbose -w $WHEELHOUSE -r "${SCRIPT_DIR}/required-wheels.txt" +pip wheel -w $WHEELHOUSE -r "${SCRIPT_DIR}/required-wheels.txt" From 6c7e205fe754ad101d69e947e929c2650753a84a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Bo=CC=88hn?= Date: Tue, 22 Jul 2014 18:26:24 -0700 Subject: [PATCH 76/81] Even less verboser --- etc/load-cache.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/etc/load-cache.sh b/etc/load-cache.sh index d35de2c5..378e3c44 100755 --- a/etc/load-cache.sh +++ b/etc/load-cache.sh @@ -82,13 +82,12 @@ find $PYOBJC_DIR -name \*.py~ -print -delete ########## VIRTUALENV INSTALLATION (NECESSARY FOR EXTENSION BUILDING) ###################### -virtualenv -v -p `which python` $PYOBJC_VIRTUALENV +virtualenv -p `which python` $PYOBJC_VIRTUALENV source $PYOBJC_VIRTUALENV/bin/activate cd $PYOBJC_DIR/pyobjc-core && pip install --no-deps . ########## WHEELHOUSE: PYOBJC ############################################################## -#pip install -U wheel cd $PYOBJC_DIR/pyobjc-core && pip wheel --no-deps -w $WHEELHOUSE . cd $PYOBJC_DIR/pyobjc && pip wheel --no-deps -w $WHEELHOUSE . From 4abf0fc19f5f4f40e1439f6f93fb611a24db2889 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Bo=CC=88hn?= Date: Tue, 22 Jul 2014 19:26:58 -0700 Subject: [PATCH 77/81] Added aodict --- plotdevice/util/__init__.py | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/plotdevice/util/__init__.py b/plotdevice/util/__init__.py index 7be702f7..bbb09d60 100644 --- a/plotdevice/util/__init__.py +++ b/plotdevice/util/__init__.py @@ -191,7 +191,7 @@ def __repr__(self, indent=2): result += '}' return result -class odict(BetterRepr,OrderedDict): +class odict(BetterRepr, OrderedDict): """Dictionary that remembers insertion order Normal dict objects return keys in an arbitrary order. An odict will return them in @@ -207,7 +207,7 @@ class odict(BetterRepr,OrderedDict): """ pass -class ddict(BetterRepr,defaultdict): +class ddict(BetterRepr, defaultdict): """Dictionary with default factory Any time you access a key that was previously undefined, the factory function @@ -257,6 +257,23 @@ def __delattr__(self, key): except KeyError, k: raise AttributeError, k +class aodict(BetterRepr, adict, OrderedDict): + """ + aodict -- an OrderedDict subclass that works like adict. + + The 'O' in 'AODict' is for 'Ordered' -- see the stdlib OrderedDict for deets, or refer to + the reimplementation in ordereddict.py, if your python install is lacking. + + """ + def __init__(self, *args, **kwargs): + OrderedDict.__init__(self, *args, **kwargs) + + def __setattr__(self, key, value): + if key == "_keys": + adict.__setattr__(self, key, value) + else: + self[key] = value + ### datafile unpackers ### From aabecd6578228ac48cb50399cde5ef117bc93f28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Bo=CC=88hn?= Date: Tue, 22 Jul 2014 19:34:51 -0700 Subject: [PATCH 78/81] Fixed aodict --- plotdevice/util/__init__.py | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/plotdevice/util/__init__.py b/plotdevice/util/__init__.py index bbb09d60..c7c22b1f 100644 --- a/plotdevice/util/__init__.py +++ b/plotdevice/util/__init__.py @@ -249,7 +249,10 @@ def __setattr__(self, key, value): # this test allows attributes to be set in the __init__ method if not self.__dict__.has_key('_adict__initialised'): return dict.__setattr__(self, key, value) - self[key] = value + if key == "_keys": + adict.__setattr__(self, key, value) + else: + self[key] = value def __delattr__(self, key): try: @@ -257,7 +260,7 @@ def __delattr__(self, key): except KeyError, k: raise AttributeError, k -class aodict(BetterRepr, adict, OrderedDict): +class aodict(adict, odict): """ aodict -- an OrderedDict subclass that works like adict. @@ -265,14 +268,7 @@ class aodict(BetterRepr, adict, OrderedDict): the reimplementation in ordereddict.py, if your python install is lacking. """ - def __init__(self, *args, **kwargs): - OrderedDict.__init__(self, *args, **kwargs) - - def __setattr__(self, key, value): - if key == "_keys": - adict.__setattr__(self, key, value) - else: - self[key] = value + pass ### datafile unpackers ### From 3b7026f01b6ebbf2219a224e60301870290b9c34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Bo=CC=88hn?= Date: Tue, 22 Jul 2014 23:27:12 -0700 Subject: [PATCH 79/81] Util func for getting the display ICC profile --- plotdevice/util/__init__.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/plotdevice/util/__init__.py b/plotdevice/util/__init__.py index c7c22b1f..1b52908f 100644 --- a/plotdevice/util/__init__.py +++ b/plotdevice/util/__init__.py @@ -357,3 +357,18 @@ def rsrc_path(resource=None): if resource: return join(rsrc_root, resource) return rsrc_root + +### display color profile ### + +def get_display_profile_path(): + if not hasattr(get_display_profile_path, 'profile_path'): + import objc + from ScriptingBridge import SBApplication + ImageEvents = SBApplication.applicationWithBundleIdentifier_('com.apple.ImageEvents') + #ImageEvents.activate() + displays = ImageEvents.displays() + if len(displays) < 1: + get_display_profile_path.profile_path = None + get_display_profile_path.profile_path = displays[0].displayProfile().location().properties()['POSIXPath'] + ImageEvents.quitSaving_(objc.NO) + return get_display_profile_path.profile_path From f605b019af06dcd5ab621552f8434e5d43cd8160 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Bo=CC=88hn?= Date: Wed, 17 Sep 2014 17:56:22 -0700 Subject: [PATCH 80/81] Whitespace --- setup.py | 1 - 1 file changed, 1 deletion(-) diff --git a/setup.py b/setup.py index 77df7823..e4b8a7ff 100644 --- a/setup.py +++ b/setup.py @@ -135,7 +135,6 @@ def gosub(cmd, on_err=True): if on_err: msg = '%s:\n' % on_err if isinstance(on_err, basestring) else '' assert ret==0, msg + (err or out) - return out, err, ret ## Distribution Build Utils ## From bebb58c8e4ee858faff2ab9f9c08fb8c79f518d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Bo=CC=88hn?= Date: Wed, 12 Nov 2014 20:03:29 -0800 Subject: [PATCH 81/81] Build all PyObjC modules --- etc/load-cache.sh | 54 +++++++++++++++++++++++------------------------ 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/etc/load-cache.sh b/etc/load-cache.sh index 378e3c44..4144371b 100755 --- a/etc/load-cache.sh +++ b/etc/load-cache.sh @@ -22,42 +22,42 @@ rm -rf $PYOBJC_BUILD_PATH $PYOBJC_VIRTUALENV fetch_and_expand $PYOBJC_DOWNLOAD_URL $PYOBJC_BUILD_PATH declare -a names=( \ -#"AppleScriptKit" \ -#"Accounts" \ -#"AddressBook" \ -#"AppleScriptKit" \ -#"AppleScriptObjC" \ -#"Automator" \ +"AppleScriptKit" \ +"Accounts" \ +"AddressBook" \ +"AppleScriptKit" \ +"AppleScriptObjC" \ +"Automator" \ "CFNetwork" \ -#"CalendarStore" \ +"CalendarStore" \ "Cocoa" \ -#"Collaboration" \ +"Collaboration" \ "CoreData" \ -#"CoreLocation" \ +"CoreLocation" \ "CoreText" \ "DictionaryServices" \ -#"EventKit" \ +"EventKit" \ "ExceptionHandling" \ "FSEvents" \ -#"InputMethodKit" \ -#"InstallerPlugins" \ -#"InstantMessage" \ -#"InterfaceBuilderKit" \ -#"LatentSemanticMapping" \ -#"LaunchServices" \ -#"OpenDirectory" \ -#"PreferencePanes" \ -#"PubSub" \ -#"QTKit" \ +"InputMethodKit" \ +"InstallerPlugins" \ +"InstantMessage" \ +"InterfaceBuilderKit" \ +"LatentSemanticMapping" \ +"LaunchServices" \ +"OpenDirectory" \ +"PreferencePanes" \ +"PubSub" \ +"QTKit" \ "Quartz" \ -#"ScreenSaver" \ +"ScreenSaver" \ "ScriptingBridge" \ -#"SearchKit" \ -#"ServerNotification" \ -#"ServiceManagement" \ -#"Social" \ -#"SyncServices" \ -#"SystemConfiguration" \ +"SearchKit" \ +"ServerNotification" \ +"ServiceManagement" \ +"Social" \ +"SyncServices" \ +"SystemConfiguration" \ "WebKit" \ )

b-fWUKjtnDV4)bZJf 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 )v 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