Git Product home page Git Product logo

pictureselector's Introduction

PictureSelector 2.0

一款针对android平台下的图片选择器,支持从相册或拍照选择图片或视频、音频,支持动态权限获取、裁剪(单图or多图裁剪)、压缩、主题自定义配置等功能、适配android 6.0+系统的开源图片选择框架。
 
项目会一直维护(有bug修复完成,一般周末会更新(不好意思,最近比较忙有时间会解决~有问题先提issue)),有bug请描述清楚,并请Issues会第一时间修复,个人QQ [email protected] 希望用得着的朋友点个star。
Android开发交流 群一 619458861 (已满)
Android开发交流 群二 679824206 (已满)
Android开发交流 群三 854136996

 我的博客地址

PRs Welcome CSDN I Star

目录

-功能特点
-集成方式
-常见错误
-功能配置
-缓存清除
-主题配置
-常用功能
-结果回调
-更新日志
-混淆配置
-兼容性测试
-演示效果
-打赏

功能特点

  • 1.适配android6.0+系统
  • 2.解决部分机型裁剪闪退问题
  • 3.解决图片过大oom闪退问题
  • 4.动态获取系统权限,避免闪退
  • 5.支持相片or视频的单选和多选
  • 6.支持裁剪比例设置,如常用的 1:1、3:4、3:2、16:9 默认为图片大小
  • 7.支持视频预览
  • 8.支持gif图片
  • 9.支持.webp格式图片
  • 10.支持一些常用场景设置:如:是否裁剪、是否预览图片、是否显示相机等
  • 11.新增自定义主题设置
  • 12.新增图片勾选样式设置
  • 13.新增图片裁剪宽高设置
  • 14.新增图片压缩处理
  • 15.新增录视频最大时间设置
  • 16.新增视频清晰度设置
  • 17.新增QQ选择风格,带数字效果
  • 18.新增自定义 文字颜色 背景色让风格和项目更搭配
  • 19.新增多图裁剪功能
  • 20.新增LuBan多图压缩
  • 21.新增单独拍照功能
  • 22.新增压缩大小设置
  • 23.新增Luban压缩档次设置
  • 24.新增圆形头像裁剪
  • 25.新增音频功能查询
  • 26.新增可自定义启动相册动画 forResult(int requestCode, int enterAnim, int exitAnim);
  • 27.新增指定精确查询 querySpecifiedFormatSuffix(PictureMimeType.ofPNG())// 查询指定后缀格式资源
  • 28.新增单选模式可设置点击选择后直接返回控制 isSingleDirectReturn(false)// 单选模式下是否直接返回
  • 29.多图裁剪下可自由选择某图不裁剪不在强制一张张裁剪,但最后一张除外

重要的事情说三遍记得添加权限

  <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
  <uses-permission android:name="android.permission.CAMERA" />
    

集成方式

方式一 compile引入

dependencies {
    implementation 'com.github.LuckSiege.PictureSelector:picture_library:v2.2.9'
}

项目根目录build.gradle加入

allprojects {
   repositories {
      jcenter()
      maven { url 'https://jitpack.io' }
   }
}

方式二 maven引入

step 1.

<repositories>
       <repository>
       <id>jitpack.io</id>
	<url>https://jitpack.io</url>
       </repository>
 </repositories>

step 2.


<dependency>
      <groupId>com.github.LuckSiege.PictureSelector</groupId>
      <artifactId>picture_library</artifactId>
      <version>v2.2.9</version> 
</dependency>

常见错误

 重要:PictureSelector.create();调用此方法时,在activity中传activity.this,在fragment中请传fragment.this,
 影响回调到哪个地方的onActivityResult()。
 
 问题一:
 rxjava冲突:在app build.gradle下添加
 packagingOptions {
   exclude 'META-INF/rxjava.properties'
 }  
 
 问题二:
 java.lang.NullPointerException: 
 Attempt to invoke virtual method 'android.content.res.XmlResourceParser 
 android.content.pm.ProviderInfo.loadXmlMetaData(android.content.pm.PackageManager, java.lang.String)'
 on a null object reference
 
 * 注意 从v2.1.3版本中,将不需要配制以下内容
 
 application下添加如下节点:
 
 <provider
      android:name="android.support.v4.content.FileProvider"
      android:authorities="${applicationId}.provider"
      android:exported="false"
      android:grantUriPermissions="true">
       <meta-data
         android:name="android.support.FILE_PROVIDER_PATHS"
         android:resource="@xml/file_paths" />
</provider>

注意:如已添加其他sdk或项目中已使用过provider节点,
[请参考我的博客](http://blog.csdn.net/luck_mw/article/details/54970105)的解决方案

问题三:
经测试在小米部分低端机中,Fragment调用PictureSelector 2.0 拍照有时内存不足会暂时回收activity,
导致其fragment会重新创建 建议在fragment所依赖的activity加上如下代码:
if (savedInstanceState == null) {
      // 添加显示第一个fragment
      	fragment = new PhotoFragment();
      		getSupportFragmentManager().beginTransaction().add(R.id.tab_content, fragment,
                    PictureConfig.FC_TAG).show(fragment)
                    .commit();
     } else { 
      	fragment = (PhotoFragment) getSupportFragmentManager()
          .findFragmentByTag(PictureConfig.FC_TAG);
}
这里就是如果是被回收时,则不重新创建 通过tag取出fragment的实例。

问题四:
glide冲突
由于PictureSelector 2.0引入的是最新的glide 4.5.0,所以将项目中老版本的glide删除,并且将报错代码换成如下写法:
RequestOptions options = new RequestOptions();
options.placeholder(R.drawable.image);
Glide.with(context).load(url).apply(options).into(imageView);

问题五:
拍照出现损坏问题
如果出现拍照返回后图片加载不出来出现已损坏现象,建议提前获取一下存储权限,也就是通过RxPermissions.request  
WRITE_EXTERNAL_STORAGE 
READ_EXTERNAL_STORAGE

问题六:
如果出现如下Invoke-customs are only supported starting with Android O (--min-api 26) 错误
请在app目录下的build.gradle android{ }末尾添加    
compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
    
 问题七:
 bug:UCropActivity继承AppCompatActivity没有添加Theme会出现一个下面的bug
java.lang.IllegalStateException: This Activity already has an action bar supplied by the window decor. Do not request       Window.FEATURE_SUPPORT_ACTION_BAR and set windowActionBar to false in your theme to use a Toolbar instead.
 解决:1.在styles文件中添加去掉ActionBar的theme

    <style name="AppTheme.NoActionBar">
        <item name="windowActionBar">false</item>
        <item name="windowNoTitle">true</item>
    </style>
在Manifest.xml中,修改UCropActivity的theme
<activity
        android:name="com.yalantis.ucrop.UCropActivity"
         android:theme="@style/AppTheme.NoActionBar" />
 

功能配置

// 进入相册 以下是例子:用不到的api可以不写
 PictureSelector.create(MainActivity.this)
 	.openGallery()//全部.PictureMimeType.ofAll()、图片.ofImage()、视频.ofVideo()、音频.ofAudio()
 	.theme()//主题样式(不设置为默认样式) 也可参考demo values/styles下 例如:R.style.picture.white.style
 	.maxSelectNum()// 最大图片选择数量 int
 	.minSelectNum()// 最小选择数量 int
	.imageSpanCount(4)// 每行显示个数 int
	.querySpecifiedFormatSuffix(PictureMimeType.ofPNG())// 查询指定后缀格式资源
	.cameraFileName("")// 使用相机时保存至本地的文件名称,注意这个只在拍照时可以使用,选图时不要用
	.isSingleDirectReturn(false)// 单选模式下是否直接返回
	.isChangeStatusBarFontColor(isChangeStatusBarFontColor)// 是否关闭白色状态栏字体颜色
        .setStatusBarColorPrimaryDark(statusBarColorPrimaryDark)// 状态栏背景色
        .setUpArrowDrawable(upResId)// 设置标题栏右侧箭头图标
        .setDownArrowDrawable(downResId)// 设置标题栏右侧箭头图标
        .isOpenStyleCheckNumMode(isOpenStyleCheckNumMode)// 是否开启数字选择模式 类似QQ相册
 	.selectionMode()// 多选 or 单选 PictureConfig.MULTIPLE or PictureConfig.SINGLE
 	.previewImage()// 是否可预览图片 true or false
 	.previewVideo()// 是否可预览视频 true or false
	.enablePreviewAudio() // 是否可播放音频 true or false
 	.isCamera()// 是否显示拍照按钮 true or false
	.imageFormat(PictureMimeType.PNG)// 拍照保存图片格式后缀,默认jpeg
	.isZoomAnim(true)// 图片列表点击 缩放效果 默认true
	.sizeMultiplier(0.5f)// glide 加载图片大小 0~1之间 如设置 .glideOverride()无效
	.setOutputCameraPath("/CustomPath")// 自定义拍照保存路径,可不填
 	.enableCrop()// 是否裁剪 true or false
 	.compress()// 是否压缩 true or false
 	.glideOverride()// int glide 加载宽高,越小图片列表越流畅,但会影响列表图片浏览的清晰度
 	.withAspectRatio()// int 裁剪比例 如16:9 3:2 3:4 1:1 可自定义
 	.hideBottomControls()// 是否显示uCrop工具栏,默认不显示 true or false
 	.isGif()// 是否显示gif图片 true or false
	.compressSavePath(getPath())//压缩图片保存地址
 	.freeStyleCropEnabled()// 裁剪框是否可拖拽 true or false
 	.circleDimmedLayer()// 是否圆形裁剪 true or false
 	.showCropFrame()// 是否显示裁剪矩形边框 圆形裁剪时建议设为false   true or false
 	.showCropGrid()// 是否显示裁剪矩形网格 圆形裁剪时建议设为false    true or false
 	.openClickSound()// 是否开启点击声音 true or false
 	.selectionMedia()// 是否传入已选图片 List<LocalMedia> list
 	.previewEggs()// 预览图片时 是否增强左右滑动图片体验(图片滑动一半即可看到上一张是否选中) true or false
 	.cropCompressQuality(90)// 废弃 改用cutOutQuality()
        .cutOutQuality(90)// 裁剪输出质量 默认100
 	.minimumCompressSize(100)// 小于100kb的图片不压缩 
 	.synOrAsy(true)//同步true或异步false 压缩 默认同步
 	.cropWH()// 裁剪宽高比,设置如果大于图片本身宽高则无效 int 
 	.rotateEnabled() // 裁剪是否可旋转图片 true or false
 	.scaleEnabled()// 裁剪是否可放大缩小图片 true or false
 	.videoQuality()// 视频录制质量 0 or 1 int
	.videoMaxSecond(15)// 显示多少秒以内的视频or音频也可适用 int 
        .videoMinSecond(10)// 显示多少秒以内的视频or音频也可适用 int 
	.recordVideoSecond()//视频秒数录制 默认60s int
	.isDragFrame(false)// 是否可拖动裁剪框(固定)
 	.forResult(PictureConfig.CHOOSE_REQUEST);//结果回调onActivityResult code     

缓存清除

 //包括裁剪和压缩后的缓存,要在上传成功后调用,type 指的是图片or视频缓存取决于你设置的ofImage或ofVideo 注意:需要系统sd卡权限  
 PictureFileUtils.deleteCacheDirFile(MainActivity.this,type);
 

主题配置

<!--默认样式 注意* 样式只可修改,不能删除任何一项 否则报错-->
    <style name="picture.default.style" parent="Theme.AppCompat.Light.DarkActionBar">
        <!-- Customize your theme here. -->
        <!--标题栏背景色-->
        <item name="colorPrimary">@color/bar_grey</item>
        <!--状态栏背景色-->
        <item name="colorPrimaryDark">@color/bar_grey</item>
        <!--是否改变图片列表界面状态栏字体颜色为黑色-->
        <item name="picture.statusFontColor">false</item>
        <!--返回键图标-->
        <item name="picture.leftBack.icon">@drawable/picture_back</item>
        <!--标题下拉箭头-->
        <item name="picture.arrow_down.icon">@drawable/arrow_down</item>
        <!--标题上拉箭头-->
        <item name="picture.arrow_up.icon">@drawable/arrow_up</item>
        <!--标题文字颜色-->
        <item name="picture.title.textColor">@color/white</item>
        <!--标题栏右边文字-->
        <item name="picture.right.textColor">@color/white</item>
        <!--图片列表勾选样式-->
        <item name="picture.checked.style">@drawable/checkbox_selector</item>
        <!--开启图片列表勾选数字模式-->
        <item name="picture.style.checkNumMode">false</item>
        <!--选择图片样式0/9-->
        <item name="picture.style.numComplete">false</item>
        <!--图片列表底部背景色-->
        <item name="picture.bottom.bg">@color/color_fa</item>
        <!--图片列表预览文字颜色-->
        <item name="picture.preview.textColor">@color/tab_color_true</item>
        <!--图片列表已完成文字颜色-->
        <item name="picture.complete.textColor">@color/tab_color_true</item>
        <!--图片已选数量圆点背景色-->
        <item name="picture.num.style">@drawable/num_oval</item>
        <!--预览界面标题文字颜色-->
        <item name="picture.ac_preview.title.textColor">@color/white</item>
        <!--预览界面已完成文字颜色-->
        <item name="picture.ac_preview.complete.textColor">@color/tab_color_true</item>
        <!--预览界面标题栏背景色-->
        <item name="picture.ac_preview.title.bg">@color/bar_grey</item>
        <!--预览界面底部背景色-->
        <item name="picture.ac_preview.bottom.bg">@color/bar_grey_90</item>
        <!--预览界面返回箭头-->
        <item name="picture.preview.leftBack.icon">@drawable/picture_back</item>
        <!--是否改变预览界面状态栏字体颜色为黑色-->
        <item name="picture.preview.statusFontColor">false</item>
        <!--裁剪页面标题背景色-->
        <item name="picture.crop.toolbar.bg">@color/bar_grey</item>
        <!--裁剪页面状态栏颜色-->
        <item name="picture.crop.status.color">@color/bar_grey</item>
        <!--裁剪页面标题文字颜色-->
        <item name="picture.crop.title.color">@color/white</item>
        <!--相册文件夹列表选中图标-->
        <item name="picture.folder_checked_dot">@drawable/orange_oval</item>
    </style>

常用功能

启动相册并拍照      

 PictureSelector.create(MainActivity.this)
       .openGallery(PictureMimeType.ofImage())
       .forResult(PictureConfig.CHOOSE_REQUEST);
       

单独启动拍照或视频 根据PictureMimeType自动识别      

  PictureSelector.create(MainActivity.this)
       .openCamera(PictureMimeType.ofImage())
       .forResult(PictureConfig.CHOOSE_REQUEST);

预览图片      

// 预览图片 可自定长按保存路径
*注意 .themeStyle(themeId);不可少,否则闪退...

PictureSelector.create(MainActivity.this).themeStyle(themeId).openExternalPreview(position, "/custom_file", selectList);
PictureSelector.create(MainActivity.this).themeStyle(themeId).openExternalPreview(position, selectList);

预览视频

PictureSelector.create(MainActivity.this).externalPictureVideo(video_path);

结果回调

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (resultCode == RESULT_OK) {
            switch (requestCode) {
                case PictureConfig.CHOOSE_REQUEST:
                    // 图片、视频、音频选择结果回调
                    List<LocalMedia> selectList = PictureSelector.obtainMultipleResult(data);
                    // 例如 LocalMedia 里面返回四种path
                    // 1.media.getPath(); 为原图path
                    // 2.media.getCutPath();为裁剪后path,需判断media.isCut();是否为true  注意:音视频除外
                    // 3.media.getCompressPath();为压缩后path,需判断media.isCompressed();是否为true  注意:音视频除外
                    // 如果裁剪并压缩了,以取压缩路径为准,因为是先裁剪后压缩的
		    // 4.media.getAndroidQToPath();为Android Q版本特有返回的字段,此字段有值就用来做上传使用
                    adapter.setList(selectList);
                    adapter.notifyDataSetChanged();
                    break;
            }
        }
    }
    

更新日志

当前版本:

  • v2.2.9
  • 1.新增 querySpecifiedFormatSuffix(PictureMimeType.ofPNG());// 查询指定后缀格式资源
  • 2.新增启动相册支持自定义启动动画设置 forResult(int requestCode, int enterAnim, int exitAnim);
  • 3.优化多图裁剪时可选择性裁剪图片
  • 4.修复部分issues

历史版本:

  • v2.2.8

  • 1.PictureConfig.SINGLE模式下新增isSingleDirectReturn(true); api选择

  • 图片可立即返回不需要点击确认.

  • 新增几个动态配制样式api,移除了原有动态获取TypedValue导致内存不足闪退问题

  • 1.isChangeStatusBarFontColor(); 是否改变状态栏字段颜色(黑白转换)

  • 2.isOpenStyleNumComplete(); 选择图片样式0/9

  • 3.isOpenStyleCheckNumMode(); 是否开启数字选择模式

  • 4.setTitleBarBackgroundColor(); 设置标题栏背景色

  • 5.setStatusBarColorPrimaryDark(); 设置状态栏背景色

  • 6.setCropTitleBarBackgroundColor(); 设置裁剪页标题栏背景色

  • 7.setCropStatusBarColorPrimaryDark(); 设置裁剪状态栏颜色 8.setCropTitleColor(); 设置裁剪页标题字体颜色

  • 9.setUpArrowDrawable(); 设置相册右侧箭头图标

  • 10.setDownArrowDrawable(); 设置相册右侧箭头图标

  • 以上api具体参考demo使用场景

  • fix

  • 1.修复多选裁剪时框不能拖动问题

  • 2.修复Android Q压缩时会在DIRECTORY_PICTURES目录重复生成文件问题

  • 3.返回视频或图片文件大小

  • 4.适配Android X

  • 5.修复gif压缩和裁剪会变成静态图问题

  • 6.LocalMedia对象新增AndroidQToPath路径,适用于 Android Q版本

  • 7.修复异步压缩失败问题

  • 8.修复部分手机拍照后图片生成不出来问题&权限问题

  • 9.修复minSdkVersion设置过大问题

  • 10.修复多图裁剪下setHideBottomControls无效问题

  • 11.新增拍照自定义生成文件名 .cameraFileName("") * 使用相机时保存至本地的文件

  • 名称,注意这个只在拍照时可以使用,选图时不要用

  • 修复一些已知bug

  • ...

  • v2.2.4

  • 1.适配Android Q 版本

  • 2.修复Android Q多图裁剪失败问题

  • 3.升级glide、Luan 最新版本

  • 4.修复了部分已知问题

  • v2.2.3

  • 1.修复沉浸式在部分机型标题栏遮挡情况

  • v2.2.2

  • 1.优化外部预览界面样式不同步问题

  • 2.优化沉浸式方案,适配更多机型

  • 3.新增isDragFrame(false) API 是否可拖动裁剪框(固定)

  • 4.修复录音会生成重复文件问题

  • v2.2.0

  • 1.修复单独拍照+裁剪图片不返回问题

  • v2.1.9

  • 1.修改单选策略,也支持预览模式

  • 2.修复8.0部分手机闪退问题

  • 3.修复图片到了最大可选数量,在拍照返回图片不出现问题

  • 4.修改单选模式在拍照返回图片不存在问题

  • 5.升级glide为最新版本4.5.0

  • 6.修复parUri() sdk判断错误问题

  • 7.修复预览图片变形问题

  • 8.修复Toast内存泄漏问题

  • 9.修复若干已知bug

  • v2.1.7

  • 1.修复.bmp格式图片,同步压缩会出现闪退问题

  • 2.修复部分机型在使用裁剪或压缩路径时报FileNotfoundException异常问题

  • v2.1.6

  • 1.增加拍照自定义相片后缀名(.imageFormat(PictureMimeType.PNG)// 拍照保存图片格式后缀,默认jpeg)

  • 2.修复设置数字选择风格,不显示数量问题

  • 3.修复预览界面文字设置无效问题

  • 4.修复已知bug

  • v2.1.5

  • 简化压缩代码,只保留luban最新版本压缩

  • 增加压缩自定义保存路径

  • 增加过滤多少kb范围内的图片不压缩处理

  • 修复压缩透明图片出现黑色背景问题

  • 修复开启点击音效第一次不响bug

  • v2.1.3

  • 支持长图预览功能

  • 修复部分图片或视频查询不出来bug

  • 去除使用者主动添加适配android 6.0以上系统拍照适配配置

  • 升级PhotoView版本为最新版本

  • 解决部分图片预览时没有填充满屏幕问题

  • 优化相册启动时间,去除一些耗时操作

  • 优化代码结构

  • 修复已知问题

  • v2.1.1

  • 升级glide 4.0为正式版

  • 修复7.1.1系统PopupWindow弹出位置错误bug

  • v2.1.0

  • 修复裁剪速度慢的问题

  • v2.0.9

  • 修复直接播放视频闪退bug

  • 升级glide为4.0.0 rc1

  • 新增图片列表点击缩放效果api

  • v2.0.7

  • 修复已知bug

  • v2.0.6

  • 新增自定拍照保存路径

  • 修复录音不显示时长问题

项目使用第三方库:

  • glide:4.5.0
  • rxjava:2.0.5
  • rxandroid:2.0.1
  • PhotoView:2.1.3
  • luban
  • 裁剪使用ucrop

混淆配置

#PictureSelector 2.0
-keep class com.luck.picture.lib.** { *; }

-dontwarn com.yalantis.ucrop**
-keep class com.yalantis.ucrop** { *; }
-keep interface com.yalantis.ucrop** { *; }
   
 #rxjava
-dontwarn sun.misc.**
-keepclassmembers class rx.internal.util.unsafe.*ArrayQueue*Field* {
 long producerIndex;
 long consumerIndex;
}
-keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueProducerNodeRef {
 rx.internal.util.atomic.LinkedQueueNode producerNode;
}
-keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueConsumerNodeRef {
 rx.internal.util.atomic.LinkedQueueNode consumerNode;
}

#rxandroid
-dontwarn sun.misc.**
-keepclassmembers class rx.internal.util.unsafe.*ArrayQueue*Field* {
   long producerIndex;
   long consumerIndex;
}
-keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueProducerNodeRef {
    rx.internal.util.atomic.LinkedQueueNode producerNode;
}
-keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueConsumerNodeRef {
    rx.internal.util.atomic.LinkedQueueNode consumerNode;
}

#glide
-keep public class * implements com.bumptech.glide.module.GlideModule
-keep public class * extends com.bumptech.glide.AppGlideModule
-keep public enum com.bumptech.glide.load.resource.bitmap.ImageHeaderParser$** {
  **[] $VALUES;
  public *;
}

# for DexGuard only
-keepresourcexmlelements manifest/application/meta-data@value=GlideModule

打赏

~如果您觉得好,对你有帮助,可以给我一点打赏当做鼓励,蚊子再小也是肉呀(^__^) 嘻嘻……

image

兼容性测试

腾讯优测-深度测试-通过率达到100%

image

演示效果

image image image image image image image image image image image image image image

pictureselector's People

Contributors

luck1991 avatar lucksiege avatar

Watchers

James Cloos avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.