




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)
文檔簡介
1、 Photoshop提供了豐富的圖象圖層混合模式,其中的顏色混合模式是用下圖層圖象的亮度與上圖層填充顏色或者圖象色彩進(jìn)行混合,形成的結(jié)果既有著上圖層的色彩,又保留了下層圖象的灰度,基于這種混合特性,顏色混合模式常用來對灰度圖象進(jìn)行著色。 如何用程序代碼準(zhǔn)確地實現(xiàn)Photoshop的圖層顏色混合模式,一直是程序員們熱衷的話題。本文采用BCB2007和GDI+等工具,較好地實現(xiàn)了其主要功能(不考慮不透明度和填充選項)。 按照Photoshop的解釋,顏色混合模式是用上圖層圖象顏色的色相、飽和度與下圖層圖象像素的明度進(jìn)行的混合。如此,我們在程序代碼中,就需要首先將
2、上層圖象顏色的色相、飽和度和下圖層圖象顏色的明度(亮度)提取出來,色相、飽和度的提取是按照HSV的方式進(jìn)行的,然后按照下圖層顏色明度按照0.3R +0.59G + 0.11B 的比例逐像素進(jìn)行運算合成,可事實上,我在顏色合成過程中,無論是采用HSV還是HSL甚或其它HSB方式,均沒法達(dá)到應(yīng)有的效果。例如取上層顏色R=225,G=211,B=179,提取的H,S分別為42,20%,下層灰度為179,采用HSV或者SHL合成顏色的G,B均為0,而實際合成的R,G,B應(yīng)分別為192,178,146。 通過在Photoshop中反復(fù)試驗,發(fā)現(xiàn)上層顏色中的飽和度在合成過程中似乎沒起
3、什么作用,最終合成結(jié)果只要保證上層顏色色相和下層灰度的比例不變就行了,這也是顏色混合模式的2個必要條件,其中灰度比例是必須保證的,如果二者發(fā)生沖突,可不考慮色相比例(如圖象某像素的灰度為0或者255)。按照這個思路,我放棄了用HSB進(jìn)行合成的方法,而按照上面2個條件采用解方程的方法來實現(xiàn)顏色混合。為此,可列出下列等式關(guān)系:1:Max - Min = a2:Mid - Min = b3:0.3R + 0.59G + 0.11B = c其中,Max,Mid,Min分別為上層顏色R、G、B分量中的最大、中間、最小值。等式1和2代表了上層顏色色相的比例關(guān)系,等式3則代表著下層顏色的灰度比例。如果只考慮
4、60度以內(nèi)的色相和假定R>G>B,那么用上面的3個等式可列為下面的三元一次方程組:1) R - B = a2) G - B = b3) 0.3R + 0.59G + 0.11B = c 可以將滿足色相在0 - 60范圍,R>G>B的任何顏色的常數(shù)代入上面的方程組進(jìn)行驗算,其結(jié)果是正確的。但是實際的顏色混合是用2個顏色不同的灰度和色相,采用上面的方程組解出的RGB值有可能會超出0 - 255的范圍,而我們又無法在方程組中加入這種范圍限制,因此對于超出范圍的RGB值,還必須在程序代碼中進(jìn)行調(diào)整。下面是我寫的一個單像素
5、合成代碼。view plaincopy to clipboardprint?1. /- 2. typedef union / 顏色分量交換結(jié)構(gòu) 3. 4. int tmp; /&
6、#160;交換時用的臨時變量 5. struct 6. 7. short value; / 顏色分量值 8. short index;
7、0; / 顏色分量索引:blue=0,green=1,red=2 9. 10. RgbSwap, *PRgbSwap; 11. 12. typedef struct 13. 14. unsigned char v4; 15. ArgbArray;
8、 16. /- 17. inline void SwapRgb(RgbSwap &a, RgbSwap &b) 18. 19. a.tmp += b.tmp; 20. b.tmp = a.tmp - b.tmp; 21.
9、0; a.tmp -= b.tmp; 22. 23. /- 24. Color ColorMix(Color color, int gray) 25. 26. const double ys = 0.11, 0.59, 0.30; 27. 28.
10、 int e14, e24, e34, e44, e54, e64; 29. RgbSwap max, mid, min; 30. int newMax, newMid, newMin; 31. int max_min,
11、60;mid_min; 32. double hueCoef; 33. Color result; 34. 35. max.tmp = color.GetRed() + 0x20000; 36. mid.tmp =
12、color.GetGreen() + 0x10000; 37. min.tmp = color.GetBlue(); 38. 39. if (max.value < mid.value) 40. SwapRgb(max, mid);
13、 41. if (max.value < min.value) 42. SwapRgb(max, min); 43. if (min.value > mid.value) 44.
14、; SwapRgb(min, mid); 45. 46. max_min = max.value - min.value; 47. / 飽和度為0,返回灰度 48. if (max_min = 0) return Col
15、or(gray, gray, gray); 49. 50. mid_min = mid.value - min.value; 51. hueCoef = (double)mid_min / (double)max_min; 52. 53. /
16、 假設(shè)最大值=R,中間值=G,最小值=B,設(shè)置方程組: 54. / 1): -B + R = max - min 55. / 2): -B + G = mid - min 56.
17、; / 3): 11B + 59G + 30R = Gray * 100 57. e1max.index = 1; 58. e1mid.index = 0; 59. e1min.index =
18、-1; 60. e13 = max_min; 61. e2max.index = 0; 62. e2mid.index = 1; 63. e2min.index = -1; 64.
19、 e23 = mid_min; 65. e30 = 11; 66. e31 = 59; 67. e32 = 30; 68. e33 = gray * 100; 69.
20、 70. / 解方程組: 71. / 4): (1) - 2) * 30 72. / 5): 2) * 11 73. / 6): 3) -
21、 4) + 5) 74. for (int i = 0; i < 4; i +) 75. 76. e4i = (e1i - e2i) * e
22、3max.index; 77. e5i = e2i * e3min.index; 78. e6i = e3i - e4i + e5i; 79. 80.
23、60;81. / 求G解:6) / 100 (因灰度公式緣故,等式右邊恒等于100) 82. newMid = (e63 + 50) / 100; 83. / 求B解:G代入 2) 84. newMin
24、160;= newMid - e23; 85. / 如果B < 0,B = 0,同時按灰度比例和色相比例解二元一次方程求R、G 86. / 方程式:1-1): 0.3R + 0.59G = Gray 87. /
25、60; 1-2): HueCoef * R - G = 0 88. if (newMin < 0 | newMid <= 0) 89. 90.
26、0; newMax = (int)(gray / (ysmax.index + ysmid.index * hueCoef) + 0.5); 91. newMid = (int)(newMax * hueCoef + 0.5); 92.
27、160; newMin = 0; 93. 94. / 否則求R解:G、B代入 1) 95. else 96. 97.
28、160;newMax = newMin + e13; 98. / 如果R > 255,R = 255,同時按灰度比例和色相比例解二元一次方程求G、B 99. / 方程式:2-1): 0.59G + 0.11B =
29、160;gray - 0.3 * 255 100. / 2-2): G + (hueCoef - 1)B = 255 * hueCoef 101.
30、 if (newMax > 255) 102. 103. newMin = (int)(gray - (ysmax.index + ysmid.index * hueCoef)
31、 * 255) / 104. (ysmin.index - ysmid.index * (hueCoef - 1) + 1.0); 105.
32、160; newMid = (int)(newMin + (255 - newMin) * hueCoef + 0.5); 106. newMax = 255; 107. &
33、#160; 108. 109. 110. (ArgbArray*)&result)->vmax.index = newMax; 111. (ArgbArray*)&result)->vmid.index = ne
34、wMid; 112. (ArgbArray*)&result)->vmin.index = newMin; 113. return result; 114. /-typedefunion/ 顏色分量交換結(jié)構(gòu)int tmp;/ 交換時用的臨時變量structshort value;/ 顏色分量值short index;/ 顏色分量索引:blue=0,green=1,re
35、d=2 ;RgbSwap, *PRgbSwap;typedef structunsigned char v4;ArgbArray;/-inline void SwapRgb(RgbSwap &a, RgbSwap &b)a.tmp += b.tmp;b.tmp = a.tmp - b.tmp;a.tmp -= b.tmp;/-Color ColorMix(Color color, int gray)const double ys = 0.11, 0.59, 0.30;int e14, e24, e34, e44, e54, e64;RgbSwap max, mid, min;i
36、nt newMax, newMid, newMin;int max_min, mid_min;double hueCoef;Color result;max.tmp = color.GetRed() + 0x20000;mid.tmp = color.GetGreen() + 0x10000;min.tmp = color.GetBlue();if (max.value < mid.value)SwapRgb(max, mid);if (max.value < min.value)SwapRgb(max, min);if (min.value > mid.value)Swap
37、Rgb(min, mid);max_min = max.value - min.value;/ 飽和度為0,返回灰度if (max_min = 0) return Color(gray, gray, gray);mid_min = mid.value - min.value;hueCoef = (double)mid_min / (double)max_min;/ 假設(shè)最大值=R,中間值=G,最小值=B,設(shè)置方程組:/ 1): -B + R = max - min/ 2): -B + G = mid - min/ 3): 11B + 59G + 30R = Gray * 100e1max.in
38、dex = 1;e1mid.index = 0;e1min.index = -1;e13 = max_min;e2max.index = 0;e2mid.index = 1;e2min.index = -1;e23 = mid_min;e30 = 11;e31 = 59;e32 = 30;e33 = gray * 100;/ 解方程組:/ 4): (1) - 2) * 30/ 5): 2) * 11/ 6): 3) - 4) + 5) for (int i = 0; i < 4; i +)e4i = (e1i - e2i) * e3max.index;e5i = e2i * e3min.
39、index;e6i = e3i - e4i + e5i;/ 求G解:6) / 100 (因灰度公式緣故,等式右邊恒等于100)newMid = (e63 + 50) / 100;/ 求B解:G代入 2)newMin = newMid - e23;/ 如果B < 0,B = 0,同時按灰度比例和色相比例解二元一次方程求R、G/ 方程式:1-1): 0.3R + 0.59G = Gray/ 1-2): HueCoef * R - G = 0if (newMin < 0 | newMid <= 0)newMax = (int)(gray / (ysmax.index + ysmid
40、.index * hueCoef) + 0.5);newMid = (int)(newMax * hueCoef + 0.5);newMin = 0;/ 否則求R解:G、B代入 1)elsenewMax = newMin + e13;/ 如果R > 255,R = 255,同時按灰度比例和色相比例解二元一次方程求G、B/ 方程式:2-1): 0.59G + 0.11B = gray - 0.3 * 255/ 2-2): G + (hueCoef - 1)B = 255 * hueCoefif (newMax > 255)newMin = (int)(gray - (ysmax.in
41、dex + ysmid.index * hueCoef) * 255) /(ysmin.index - ysmid.index * (hueCoef - 1) + 1.0);newMid = (int)(newMin + (255 - newMin) * hueCoef + 0.5);newMax = 255;(ArgbArray*)&result)->vmax.index = newMax;(ArgbArray*)&result)->vmid.index = newMid;(ArgbArray*)&result)->vmin.index = newM
42、in;return result; ColorMix函數(shù)寫出了比較詳細(xì)的解方程過程代碼,并作了相應(yīng)的注釋;解三元一次方程組時,將灰度比例值擴大了100倍,可使用定點數(shù)運算,因為灰度比例關(guān)系恒等于100的緣故,運算過程中不會產(chǎn)生誤差;其中對值超出0 - 255范圍RGB值分別使用了2組二元一次方程進(jìn)行了處理;另外,由于定義了一個RgbSwap類型,使得在比較和交換最大、最小值過程中,保存了原R、G、B信息,這不僅方便了代碼中的運算,也使得前面的三元一次方程組的適用范圍從色相60度以內(nèi)和R>G>B,擴展到了色相全范圍以及任意大小的R、G、B值,同時也避免了HSB轉(zhuǎn)換為RGB
43、時通常使用的switch條件語句。 經(jīng)過一定量的顏色混合測試,ColorMix函數(shù)表現(xiàn)較好,運算結(jié)果與實際誤差始終在2的范圍內(nèi),這屬于正常的運算誤差和灰度比例取值誤差。 下面是一個對灰度圖象進(jìn)行著色的函數(shù)和測試代碼:view plaincopy to clipboardprint?1. / 圖像著色。bmp:灰度背景圖象,color:顏色 2. void PSGrayImageTint(Bitmap *bmp, Color color) 3. 4. &
44、#160; const double ys = 0.11, 0.59, 0.3; 5. 6. RgbSwap max, mid, min; 7. int newMax, newMid, newMin; 8. in
45、t max_min, mid_min; 9. double hueCoef; 10. 11. max.tmp = color.GetRed() + 0x20000; 12. mid.tmp = color.GetGreen() + 0x10000;
46、0; 13. min.tmp = color.GetBlue(); 14. 15. if (max.value < mid.value) 16. SwapRgb(max, mid); 17. i
47、f (max.value < min.value) 18. SwapRgb(max, min); 19. if (min.value > mid.value) 20. SwapRgb(min, mid)
48、; 21. 22. max_min = max.value - min.value; 23. / 飽和度為0,不著色返回 24. if (max_min = 0) return; 25. 26.
49、0; mid_min = mid.value - min.value; 27. hueCoef = (double)mid_min / (double)max_min; 28. 29. BitmapData data; 30. Gdiplus:Rect r
50、(0, 0, bmp->GetWidth(), bmp->GetHeight(); 31. bmp->LockBits(&r, ImageLockModeRead | ImageLockModeWrite, PixelFormat24bppRGB, &data); 32. try 33.
51、; 34. unsigned char *p = (unsigned char*)data.Scan0; 35. int offset = data.Stride - data.Width * 3; 36. &
52、#160; for (unsigned y = 0; y < data.Height; y +, p += offset) 37. 38. &
53、#160; for (unsigned x = 0; x < data.Width; x +, p += 3) 39. 40. &
54、#160; newMid = (int)(*p - (max_min - mid_min) * ysmax.index + 41. mid_min * ysmin.index
55、0;+ 0.5); 42. newMin = newMid - mid_min; 43. if (newMin&
56、#160;< 0 | newMid <= 0) 44. 45.
57、0;newMax = (int)(*p / (ysmax.index + ysmid.index * hueCoef) + 0.5); 46. newMid = (int)(newMax * hue
58、Coef + 0.5); 47. newMin = 0; 48.
59、60;49. else 50. 51.
60、; newMax = newMin + max_min; 52. if (newMax > 255) 53.
61、 54. newMin = (int)(*p
62、;- (ysmax.index + ysmid.index * hueCoef) * 255) / 55. (ysmin.index - ys
63、mid.index * (hueCoef - 1) + 0.5); 56. newMid = (int)(newMin + (255 - newMin) *
64、160;hueCoef + 0.5); 57. newMax = 255; 58.
65、 59. 60. pmax.index = newMa
66、x; 61. pmid.index = newMid; 62. pmin.index = newMin; 63
67、. 64. 65. 66. _finally 67. 68.
68、 bmp->UnlockBits(&data); 69. 70. 71. 72. 73. void ImageCompare(Bitmap *bmp1, Bitmap *bmp2) 74. 75. int count,
69、 r_count = 0, g_count = 0, b_count = 0; 76. int diff, r_diff = 0, g_diff = 0, b_diff = 0; 77. BitmapData data1, data2; &
70、#160;78. Gdiplus:Rect r(0, 0, bmp1->GetWidth(), bmp1->GetHeight(); 79. 80. bmp1->LockBits(&r, ImageLockModeRead, PixelFormat24bppRGB, &data1); 81. &
71、#160;bmp2->LockBits(&r, ImageLockModeRead, PixelFormat24bppRGB, &data2); 82. try 83. 84. PRGBTRIPLE p1 = (PRGBTriple)data1.Scan0;
72、 85. PRGBTRIPLE p2 = (PRGBTriple)data2.Scan0; 86. int offset = data1.Stride - data1.Width * sizeof(RGBTRIPLE); 87.
73、 for (unsigned y = 0; y < data1.Height; y +, (char*)p1 += offset, (char*)p2 += offset) 88. 89.
74、60; for (unsigned x = 0; x < data1.Width; x +, p1 +, p2 +) 90. 91.
75、; diff = p1->rgbtRed - p2->rgbtRed; 92. if (diff) 93.
76、160; 94. r_count +; 95.
77、60; if (diff < 0) diff = -diff; 96. if (r_diff < diff)
78、;r_diff = diff; 97. 98. diff = p1->rgbtGreen - p2-&g
79、t;rgbtGreen; 99. if (diff) 100. 101.
80、160; g_count +; 102. if (diff < 0) diff = -diff;
81、 103. if (g_diff < diff) g_diff = diff; 104.
82、160; 105. diff = p1->rgbtBlue - p2->rgbtBlue; 106.
83、60;if (diff) 107. 108. b_count +; 109. &
84、#160; if (diff < 0) diff = -diff; 110.
85、160; if (b_diff < diff) b_diff = diff; 111. 112. 113.
86、 114. 115. _finally 116. 117. bmp2->UnlockBits(&data2); 118.
87、 bmp1->UnlockBits(&data1); 119. 120. count = data1.Width * data1.Height; 121. String s; 122.
88、; s.sprintf("像素總數(shù):%dn" 123. "紅誤差數(shù):%d,誤差率:%d%,最大誤差:%dn" 124. &
89、#160;"綠誤差數(shù):%d,誤差率:%d%,最大誤差:%dn" 125. "藍(lán)誤差數(shù):%d,誤差率:%d%,最大誤差:%d", 126. count,
90、60;r_count, (r_count * 100) / count, r_diff, 127. g_count, (g_count * 100) / count, g_diff, 128. &
91、#160; b_count, (b_count * 100) / count, b_diff); 129. ShowMessage(s); 130. 131. /- 132. void _fastcall TForm1:Button2Click(TObject *Sender)
92、; 133. 134. Bitmap *bmp1 = new Bitmap(WideString("d:GraySource.bmp"); 135. PSGrayImageTint(bmp1, 0x314ead); 136. 137. Gdiplus:Graphics *g
93、 = new Gdiplus:Graphics(Canvas->Handle); 138. g->DrawImage(bmp1, 0, 0); 139. delete g; 140. 141. / 同PS混合圖比較,bmp2為PS混合圖像 142.
94、; Bitmap *bmp2 = new Bitmap(WideString("d:Source314ead.bmp"); 143. ImageCompare(bmp1, bmp2); 144. 145. delete bmp2; 146. delet
95、e bmp1; 147. 148. /- / 圖像著色。bmp:灰度背景圖象,color:顏色void PSGrayImageTint(Bitmap *bmp, Color color)const double ys = 0.11, 0.59, 0.3;RgbSwap max, mid, min;int newMax, newMid, newMin;int max_min, mid_min;double hueCoef;max.tmp = color.GetRed() + 0x20000;mid.tmp = colo
96、r.GetGreen() + 0x10000;min.tmp = color.GetBlue();if (max.value < mid.value)SwapRgb(max, mid);if (max.value < min.value)SwapRgb(max, min);if (min.value > mid.value)SwapRgb(min, mid);max_min = max.value - min.value;/ 飽和度為0,不著色返回if (max_min = 0) return;mid_min = mid.value - min.value;hueCoef =
97、 (double)mid_min / (double)max_min;BitmapData data;Gdiplus:Rect r(0, 0, bmp->GetWidth(), bmp->GetHeight();bmp->LockBits(&r, ImageLockModeRead | ImageLockModeWrite, PixelFormat24bppRGB, &data);tryunsigned char *p = (unsigned char*)data.Scan0;int offset = data.Stride - data.Width * 3;
98、for (unsigned y = 0; y < data.Height; y +, p += offset)for (unsigned x = 0; x < data.Width; x +, p += 3)newMid = (int)(*p - (max_min - mid_min) * ysmax.index +mid_min * ysmin.index + 0.5);newMin = newMid - mid_min;if (newMin < 0 | newMid <= 0)newMax = (int)(*p / (ysmax.index + ysmid.inde
99、x * hueCoef) + 0.5);newMid = (int)(newMax * hueCoef + 0.5);newMin = 0;elsenewMax = newMin + max_min;if (newMax > 255)newMin = (int)(*p - (ysmax.index + ysmid.index * hueCoef) * 255) /(ysmin.index - ysmid.index * (hueCoef - 1) + 0.5);newMid = (int)(newMin + (255 - newMin) * hueCoef + 0.5);newMax =
100、 255;pmax.index = newMax;pmid.index = newMid;pmin.index = newMin;_finallybmp->UnlockBits(&data);void ImageCompare(Bitmap *bmp1, Bitmap *bmp2)int count, r_count = 0, g_count = 0, b_count = 0;int diff, r_diff = 0, g_diff = 0, b_diff = 0;BitmapData data1, data2;Gdiplus:Rect r(0, 0, bmp1->GetW
101、idth(), bmp1->GetHeight();bmp1->LockBits(&r, ImageLockModeRead, PixelFormat24bppRGB, &data1);bmp2->LockBits(&r, ImageLockModeRead, PixelFormat24bppRGB, &data2);tryPRGBTRIPLE p1 = (PRGBTriple)data1.Scan0;PRGBTRIPLE p2 = (PRGBTriple)data2.Scan0;int offset = data1.Stride - data
102、1.Width * sizeof(RGBTRIPLE);for (unsigned y = 0; y < data1.Height; y +, (char*)p1 += offset, (char*)p2 += offset)for (unsigned x = 0; x < data1.Width; x +, p1 +, p2 +)diff = p1->rgbtRed - p2->rgbtRed;if (diff)r_count +;if (diff < 0) diff = -diff;if (r_diff < diff) r_diff = diff;dif
103、f = p1->rgbtGreen - p2->rgbtGreen;if (diff)g_count +;if (diff < 0) diff = -diff;if (g_diff < diff) g_diff = diff;diff = p1->rgbtBlue - p2->rgbtBlue;if (diff)b_count +;if (diff < 0) diff = -diff;if (b_diff < diff) b_diff = diff;_finallybmp2->UnlockBits(&data2);bmp1->UnlockBits(&data1);count = data1.Width * data1.Height;String s;s.
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 企業(yè)出資合同范本
- 農(nóng)村廚子采購合同范本
- 勘察設(shè)計合同范本全國
- 2024年河南信陽一五四醫(yī)院招聘筆試真題
- 2024重慶鏡辰美科技有限公司招聘筆試參考題庫附帶答案詳解
- 出售養(yǎng)殖用地合同范本
- 人教版七年級歷史與社會上冊 3.3.1耕海牧漁教學(xué)設(shè)計
- 買窯洞合同范本
- 臨勤合同范本
- 助播商務(wù)合同范本
- 預(yù)制裝配式鋼筋混凝土排水檢查井標(biāo)準(zhǔn)圖集
- 評估胎兒健康的技術(shù)
- 全自動甘蔗剝?nèi)~裝置的設(shè)計
- 梁湘潤.命學(xué)精華
- T-CSAE 11.3-2021 商用車潤滑導(dǎo)則 第3部分:潤滑脂的選用
- 工業(yè)級七水硫酸亞鐵
- 內(nèi)科休克急救
- 變電站的電氣主接線課件
- 婦科運用PDCA循環(huán)降低腹腔鏡術(shù)后腸脹氣的發(fā)生率品管圈成果匯報
- 新零售實務(wù)PPT完整全套教學(xué)課件
- 小學(xué)生1-6冊必背古詩楷書字帖(可直接打印-已排版)
評論
0/150
提交評論